org.simantics.scenegraph.ontology;bundle-version="1.0.0",
org.simantics.viewpoint.ontology;bundle-version="1.0.0",
org.simantics.selectionview.ontology;bundle-version="1.1.0",
- org.simantics.graphfile.ontology;bundle-version="0.1.0"
+ org.simantics.graphfile.ontology;bundle-version="0.1.0",
+ org.simantics.action.ontology;bundle-version="1.1.0"
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Export-Package: org.simantics.document
SG = <http://www.simantics.org/Scenegraph-1.1>
SEL = <http://www.simantics.org/SelectionView-1.2>
GF = <http://www.simantics.org/GraphFile-0.1>
+ACT = <http://www.simantics.org/Action-1.1>
DOC = <http://www.simantics.org/Document-1.2> : L0.Ontology
@L0.new
DOC.DocumentLibrary <T L0.Library
+
+DOC.Actions : L0.Library
+
+DOC.Actions.ImportFileDocument : ACT.Action
\ No newline at end of file
public class DocumentResource {
+ public final Resource Actions;
+ public final Resource Actions_ImportFileDocument;
public final Resource Document;
public final Resource DocumentLibrary;
public final Resource DocumentSettings;
public final Resource documentSettings_Inverse;
public static class URIs {
+ public static final String Actions = "http://www.simantics.org/Document-1.2/Actions";
+ public static final String Actions_ImportFileDocument = "http://www.simantics.org/Document-1.2/Actions/ImportFileDocument";
public static final String Document = "http://www.simantics.org/Document-1.2/Document";
public static final String DocumentLibrary = "http://www.simantics.org/Document-1.2/DocumentLibrary";
public static final String DocumentSettings = "http://www.simantics.org/Document-1.2/DocumentSettings";
}
public DocumentResource(ReadGraph graph) {
+ Actions = getResourceOrNull(graph, URIs.Actions);
+ Actions_ImportFileDocument = getResourceOrNull(graph, URIs.Actions_ImportFileDocument);
Document = getResourceOrNull(graph, URIs.Document);
DocumentLibrary = getResourceOrNull(graph, URIs.DocumentLibrary);
DocumentSettings = getResourceOrNull(graph, URIs.DocumentSettings);
import org.simantics.db.WriteGraph;
import org.simantics.db.common.request.WriteRequest;
import org.simantics.db.exception.DatabaseException;
+import org.simantics.document.AddDocumentAction;
import org.simantics.document.DocumentResource;
import org.simantics.layer0.Layer0;
import org.simantics.utils.datastructures.Callback;
import org.simantics.db.exception.DatabaseException;
import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;
import org.simantics.db.exception.ServiceException;
+import org.simantics.document.AddDocumentAction;
import org.simantics.document.DocumentResource;
import org.simantics.document.ui.dialogs.UrlDetailDialog;
import org.simantics.layer0.Layer0;
import org.simantics.db.Resource;
import org.simantics.db.exception.DatabaseException;
import org.simantics.db.layer0.adapter.ActionFactory;
+import org.simantics.document.FileDocumentUtil;
import org.simantics.document.ui.Activator;
-import org.simantics.document.ui.graphfile.FileDocumentUtil;
import org.simantics.graphfile.util.GraphFileUtil;
/**
import org.simantics.db.common.request.WriteRequest;
import org.simantics.db.exception.DatabaseException;
import org.simantics.db.layer0.adapter.ActionFactory;
+import org.simantics.document.FileDocumentUtil;
import org.simantics.document.ui.Activator;
-import org.simantics.document.ui.graphfile.FileDocumentUtil;
/**
* Action for importing files as documents.
import org.simantics.db.WriteGraph;
import org.simantics.db.common.request.WriteRequest;
import org.simantics.db.exception.DatabaseException;
+import org.simantics.document.AddDocumentAction;
+import org.simantics.document.FileDocumentUtil;
import org.simantics.document.ui.dialogs.FileDetailDialog;
-import org.simantics.document.ui.graphfile.FileDocumentUtil;
import org.simantics.layer0.Layer0;
import org.simantics.utils.datastructures.Callback;
import org.simantics.utils.ui.ExceptionUtils;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.Wizard;
import org.simantics.db.Resource;
-import org.simantics.document.ui.graphfile.FileDocumentUtil;
+import org.simantics.document.FileDocumentUtil;
public abstract class FileDocumentImportWizard extends Wizard{
org.simantics.wiki.ui;bundle-version="1.1.0",
org.simantics.export.core;bundle-version="1.0.0",
org.simantics.utils.ui;bundle-version="1.1.0",
- org.simantics.image2.ontology;bundle-version="1.2.0"
+ org.simantics.image2.ontology;bundle-version="1.2.0",
+ org.simantics.graphfile.ontology;bundle-version="0.1.0",
+ org.simantics.graphfile;bundle-version="0.1.0"
Export-Package: org.simantics.document,
org.simantics.document.export,
org.simantics.document.function,
public class Activator implements BundleActivator {
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.simantics.document"; //$NON-NLS-1$
+
private static BundleContext context;
static BundleContext getContext() {
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.document;
+
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.adapter.ActionFactory;
+
+/**
+ * Abstract base class for adding documents.
+ *
+ * If import target is an document, a new version of a document is created.
+ *
+ * Document version creation has two modes:
+ * FLAT: new version is added to the same library as the old document.
+ * TREE: new version replaces the old document in the library, and old document is moved under the new document.
+ *
+ *
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
+ *
+ */
+public abstract class AddDocumentAction implements ActionFactory {
+
+ private Resource relation;
+
+ public AddDocumentAction(ReadGraph graph, String relationUri) throws DatabaseException {
+ relation = graph.getResource(relationUri);
+ }
+
+
+ protected Resource getRelation() {
+ return relation;
+ }
+
+ protected void linkDocument(WriteGraph graph, Resource target, Resource newDocument) throws DatabaseException{
+ DocumentResource doc = DocumentResource.getInstance(graph);
+
+ if (graph.isInstanceOf(target, doc.Document)) {
+ // adding a new revision
+ DocumentVersionUtils.createNewVersion(graph, target, newDocument, relation);
+
+
+ } else {
+ graph.claim(target, relation, newDocument);
+ FileDocumentUtil.createUniqueName(graph, newDocument);
+ }
+ }
+
+}
--- /dev/null
+package org.simantics.document;
+
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.utils.NameUtils;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.document.DocumentResource;
+import org.simantics.layer0.Layer0;
+/**
+ * Util class for managing document versions
+ *
+ * Document version history mode is searched with relations:
+ * 1. l0.PartOf
+ * 2. l0.IsOwnedBy
+ * 3. l0.IsDependencyOf
+ *
+ * If library is not found, history mode is assumed to be flat.
+ *
+ * In order to have working tree history, the library must contain proper configuration for relations:
+ * doc.HasLibraryRelation
+ * doc.HasVersionType
+ *
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
+ *
+ */
+public class DocumentVersionUtils {
+
+ public enum VersionMode{FLAT,TREE};
+
+
+ /**
+ * Adds a new document version.
+ *
+ * Expects that newDocument is not part of document version chain, and oldDocument does not have newer version.
+ *
+ * @param graph
+ * @param oldDocument
+ * @param newDocument
+ * @param relation
+ * @throws DatabaseException
+ */
+ public static void createNewVersion(WriteGraph graph, Resource oldDocument, Resource newDocument, Resource relation) throws DatabaseException{
+ DocumentResource doc = DocumentResource.getInstance(graph);
+ if (graph.hasStatement(oldDocument, doc.HasNewerVersion))
+ throw new DatabaseException("Document " + NameUtils.getSafeName(graph, oldDocument) +" has already new version");
+
+ Resource inverse = graph.getInverse(relation);
+ Resource lib = graph.getSingleObject(oldDocument, inverse);
+ String modeString = graph.getPossibleRelatedValue(lib, doc.HasVersionType);
+ VersionMode mode = VersionMode.FLAT;
+ if (modeString != null)
+ mode = VersionMode.valueOf(modeString);
+
+ graph.claim(oldDocument, doc.HasNewerVersion, newDocument);
+ graph.claim(lib, relation, newDocument);
+
+ if (mode == VersionMode.TREE) {
+ graph.deny(lib,relation,oldDocument);
+ graph.claim(newDocument,relation,oldDocument);
+ }
+ FileDocumentUtil.createUniqueName(graph, newDocument);
+ }
+
+ /**
+ * Sets document version relationship between two documents.
+ *
+ * If the documents are already part of the same version chain this method does nothing.
+ *
+ * If documents are already set to some version chain with given relation, this method replaces the exiting links.
+ *
+ * @param graph
+ * @param document1
+ * @param document2
+ * @param versionRel
+ * @throws DatabaseException
+ */
+ public static void setVersion(WriteGraph graph, Resource document1, Resource document2, Resource versionRel) throws DatabaseException {
+ DocumentResource doc = DocumentResource.getInstance(graph);
+ // document type must match
+ if (!graph.getSingleType(document2, doc.Document).equals(graph.getSingleType(document1, doc.Document)))
+ return;
+ if (!versionRel.equals(doc.HasNewerVersion) && !(versionRel.equals(doc.HasOlderVersion)))
+ throw new IllegalArgumentException("Unknow version relation + " + graph.getPossibleURI(versionRel));
+
+ Resource versionRelInv = graph.getInverse(versionRel);
+ // toSet must not be part of the document's version history
+ Resource r = document1;
+ while (r != null) {
+ if (r.equals(document2))
+ return;
+ r = graph.getPossibleObject(r, versionRel);
+ }
+
+ r = document2;
+ while (r != null) {
+ if (r.equals(document1))
+ return;
+ r = graph.getPossibleObject(r, versionRel);
+ }
+ // At the moment document revision history is linear (no branching).
+ Resource document1Ver = graph.getPossibleObject(document1, versionRel);
+ if (document1Ver != null)
+ unsetVersion(graph, document1, document1Ver, versionRel);
+ Resource document2Ver = graph.getPossibleObject(document2, versionRelInv);
+ if (document2Ver != null)
+ unsetVersion(graph, document2, document2Ver, versionRelInv);
+
+ graph.claim(document1, versionRel, document2);
+
+ Resource lib = getLib(graph, document1);
+ if (lib != null) {
+ Resource relation = graph.getPossibleObject(lib, doc.HasLibraryRelation);
+ String type= graph.getPossibleRelatedValue(lib, doc.HasVersionType);
+ if ("TREE".equals(type) && relation != null) {
+ if (versionRel.equals(doc.HasOlderVersion)) {
+ graph.deny(document2, graph.getInverse(relation));
+ graph.claim(document1,relation,document2);
+ } else {
+ graph.deny(document1, graph.getInverse(relation));
+ graph.claim(document2,relation,document1);
+ }
+ }
+
+ }
+ }
+
+ /**
+ * Unlinks document version relationship between two documents.
+ * @param graph
+ * @param document1
+ * @param document2
+ * @param versionRel
+ * @throws DatabaseException
+ */
+ public static void unsetVersion(WriteGraph graph, Resource document1, Resource document2, Resource versionRel) throws DatabaseException {
+ DocumentResource doc = DocumentResource.getInstance(graph);
+ if (!versionRel.equals(doc.HasNewerVersion) && !(versionRel.equals(doc.HasOlderVersion)))
+ throw new IllegalArgumentException("Unknow version relation + " + graph.getPossibleURI(versionRel));
+
+ graph.deny(document1, versionRel,document2);
+ Resource lib = getLib(graph, document1);
+ if (lib != null) {
+ Resource relation = graph.getPossibleObject(lib, doc.HasLibraryRelation);
+ String type= graph.getPossibleRelatedValue(lib, doc.HasVersionType);
+ if ("TREE".equals(type) && relation != null) {
+ if (versionRel.equals(doc.HasOlderVersion)) {
+ graph.deny(document1, relation);
+ graph.claim(lib,relation,document2);
+ FileDocumentUtil.createUniqueName(graph, document2);
+ } else {
+ graph.deny(document1, graph.getInverse(relation));
+ graph.claim(lib,relation,document1);
+ FileDocumentUtil.createUniqueName(graph, document1);
+ }
+ }
+
+ }
+ }
+
+ private static Resource getLib(ReadGraph graph, Resource document) throws DatabaseException {
+ Layer0 l0 = Layer0.getInstance(graph);
+ DocumentResource doc = DocumentResource.getInstance(graph);
+ Resource r = document;
+ while (true) {
+ Resource lib = graph.getPossibleObject(r, l0.PartOf);
+ if (lib == null)
+ lib = graph.getPossibleObject(r, l0.IsOwnedBy);
+ if (lib == null)
+ lib = graph.getPossibleObject(r, l0.IsDependencyOf);
+ if (lib == null)
+ return null;
+ if (!graph.isInstanceOf(lib, doc.Document))
+ return lib;
+ r = lib;
+ }
+ }
+}
--- /dev/null
+package org.simantics.document;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.simantics.Simantics;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.request.ReadRequest;
+import org.simantics.db.common.request.WriteRequest;
+import org.simantics.db.common.request.WriteResultRequest;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.graphfile.ontology.GraphFileResource;
+import org.simantics.graphfile.util.GraphFileUtil;
+import org.simantics.layer0.Layer0;
+import org.simantics.utils.ui.ExceptionUtils;
+
+/**
+ *
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
+ *
+ */
+public class FileDocumentUtil {
+
+ /**
+ * Imports file, sets its L0.hasName, and and adds it to a library
+ *
+ * Note: if library relation is L0.ConsistsOf, L0.HasName is set to next available unique name.
+ *
+ * @param fileName
+ * @param lib
+ * @param rel
+ * @throws DatabaseException
+ */
+ public static Resource importFile(final String fileName, final Resource lib, final Resource rel) throws DatabaseException {
+ return Simantics.getSession().syncRequest(new WriteResultRequest<Resource>() {
+ @Override
+ public Resource perform(WriteGraph graph) throws DatabaseException {
+ return importFile(graph, fileName,lib,rel);
+ }
+ });
+
+
+ }
+
+ public static void importFileAsync(final String fileName, final Resource lib, final Resource rel) {
+ Simantics.getSession().asyncRequest(new WriteRequest() {
+
+ @Override
+ public void perform(WriteGraph graph) throws DatabaseException {
+ importFile(graph, fileName,lib,rel);
+
+ }
+ },new org.simantics.utils.datastructures.Callback<DatabaseException>() {
+
+ @Override
+ public void run(DatabaseException parameter) {
+ if (parameter != null)
+ ExceptionUtils.logAndShowError("Cannot import file " + fileName, parameter);
+
+ }
+ });
+
+
+ }
+
+ /**
+ * Imports file, sets its L0.HasName, and and adds it to a library
+ *
+ * Note: if library relation is L0.ConsistsOf, L0.HasName is set to next available unique name.
+ *
+ * @param graph
+ * @param fileName
+ * @param lib
+ * @param rel
+ * @throws DatabaseException
+ */
+ public static Resource importFile(WriteGraph graph, String fileName, Resource lib, Resource rel) throws DatabaseException{
+ Layer0 l0 = Layer0.getInstance(graph);
+ Resource fileResource = importFile(graph, fileName);
+ graph.claim(lib, rel, fileResource);
+ File file = new File(fileName);
+ String name = file.getName();
+ graph.claimLiteral(fileResource, l0.HasName, name);
+ setUniqueName(graph, fileResource, lib, rel);
+ return fileResource;
+ }
+
+ public static Resource importFileWithName(WriteGraph graph, String fileName) throws DatabaseException{
+ Layer0 l0 = Layer0.getInstance(graph);
+ Resource fileResource = importFile(graph, fileName);
+ File file = new File(fileName);
+ String name = file.getName();
+ graph.claimLiteral(fileResource, l0.HasName, name);
+ return fileResource;
+ }
+
+ /**
+ * Imports folder of documents recursively (including all sub folders).
+ * @param graph
+ * @param folderName Name of imported folder
+ * @param lib Library, where imported folder is attached.
+ * @param folderType Type of folders
+ * @param relation Relation used to create file/folder hierarchy
+ * @return the imported folder
+ * @throws DatabaseException
+ */
+ public static Resource importFolderWithName(WriteGraph graph, String folderName, Resource lib, Resource folderType, Resource relation, IProgressMonitor monitor) throws Exception{
+ Resource folderRes = importFolderWithName(graph, folderName, folderType, relation,monitor);
+ graph.claim(lib, relation, folderRes);
+ FileDocumentUtil.createUniqueName(graph, folderRes);
+ return folderRes;
+ }
+
+ /**
+ * Imports folder of documents recursively (including all sub folders).
+ * @param graph
+ * @param folderName Name of imported folder
+ * @param folderType Type of folders
+ * @param relation Relation used to create file/folder hierarchy
+ * @param monitor ProgessMonitor or null
+ * @return the imported folder
+ * @throws DatabaseException
+ */
+ public static Resource importFolderWithName(WriteGraph graph, String folderName, Resource folderType, Resource relation, IProgressMonitor monitor) throws Exception{
+ Layer0 l0 = Layer0.getInstance(graph);
+ File folder = new File(folderName);
+ Resource rootFolderRes = graph.newResource();
+ graph.claim(rootFolderRes, l0.InstanceOf, folderType);
+ graph.claimLiteral(rootFolderRes, l0.HasName, folder.getName());
+ importFolder(graph, folder, rootFolderRes, relation, monitor);
+ return rootFolderRes;
+ }
+
+ /**
+ * Imports folder of documents recursively (including all sub folders).
+ * @param graph
+ * @param folder Imported folder
+ * @param folderResource Resource folder matching file system folder
+ * @param relation Relation used to create file/folder hierarchy
+ * @throws DatabaseException
+ */
+ public static void importFolder(WriteGraph graph, File folder, Resource folderResource, Resource relation, IProgressMonitor monitor) throws Exception{
+ if (monitor != null) {
+ int count = _countFiles(folder);
+ monitor.beginTask("Import files", count);
+ }
+ _importFolder(graph, folder, folderResource, relation, monitor);
+ if (monitor != null)
+ monitor.done();
+ }
+
+ private static void _importFolder(WriteGraph graph, File folder, Resource folderResource, Resource relation, IProgressMonitor monitor) throws Exception{
+ Layer0 l0 = Layer0.getInstance(graph);
+ File files[] = folder.listFiles();
+ for (File f : files) {
+ if (f.isDirectory()) {
+ Resource newFolderRes = graph.newResource();
+ graph.claim(newFolderRes, l0.InstanceOf, graph.getSingleType(folderResource));
+ graph.claim(folderResource, relation, newFolderRes);
+ graph.claimLiteral(newFolderRes, l0.HasName, f.getName());
+ _importFolder(graph, f, newFolderRes, relation,monitor);
+ } else {
+ Resource fileRes = null;
+ if (isUrl(f)) {
+ } else {
+ fileRes = importURL(graph, f);
+ fileRes = importFileWithName(graph, f.getAbsolutePath());
+ }
+ graph.claim(folderResource, relation, fileRes);
+ if (monitor != null)
+ monitor.worked(1);
+ }
+ }
+ }
+
+ private static int _countFiles(File folder) {
+
+ int count = 0;
+ File files[] = folder.listFiles();
+ for (File f : files) {
+ if (f.isDirectory()) {
+ count += _countFiles(f);
+ } else {
+ count++;
+ }
+ }
+ return count;
+ }
+
+
+ public static void createUniqueName(WriteGraph graph, Resource document) throws DatabaseException {
+ Layer0 l0 = Layer0.getInstance(graph);
+ Resource lib = graph.getPossibleObject(document, l0.PartOf);
+ if (lib == null)
+ return;
+ setUniqueName(graph, document, lib, l0.ConsistsOf);
+ }
+
+ public static void setUniqueName(WriteGraph graph, Resource res, Resource lib, Resource rel) throws DatabaseException{
+ Layer0 l0 = Layer0.getInstance(graph);
+ Set<String> names = new HashSet<String>();
+ for (Resource r : graph.getObjects(lib, rel)) {
+ if (r.equals(res))
+ continue;
+ names.add((String)graph.getRelatedValue(r, l0.HasName));
+ }
+ String name = graph.getRelatedValue(res, l0.HasName);
+ if (!names.contains(name))
+ return;
+ int i = 1;
+ while (true) {
+ String proposal = name +" (" + i +")";
+ if (!names.contains(proposal)) {
+ graph.claimLiteral(res, l0.HasName, proposal);
+ return;
+ }
+ i++;
+ }
+
+ }
+
+ /**
+ * Imports a file
+ *
+ * @param graph
+ * @param fileName
+ * @return
+ * @throws DatabaseException
+ */
+ public static Resource importFile(WriteGraph graph, String fileName) throws DatabaseException{
+ Layer0 l0 = Layer0.getInstance(graph);
+ DocumentResource doc = DocumentResource.getInstance(graph);
+
+ Resource fileResource = graph.newResource();
+ graph.claim(fileResource, l0.InstanceOf, doc.FileDocument);
+ try {
+ GraphFileUtil.toGraph(graph,fileName, fileResource);
+
+ } catch (IOException e) {
+ throw new DatabaseException(e);
+ }
+ return fileResource;
+
+ }
+
+ /**
+ * Exports graph folder recursively to file system.
+ * @param graph
+ * @param folderResource
+ * @param folder
+ * @param relation
+ * @throws DatabaseException
+ */
+ public static void exportDocumentFolder(final Resource folderResource, final File folder, final Resource relation, boolean useResourceNames, final IProgressMonitor monitor) throws Exception{
+ Simantics.getSession().syncRequest(new ReadRequest() {
+
+ @Override
+ public void run(ReadGraph graph) throws DatabaseException {
+ try {
+ exportDocumentFolder(graph, folderResource, folder, relation, useResourceNames, monitor);
+ } catch (Exception e) {
+ throw new DatabaseException(e);
+ }
+
+ }
+ });
+ }
+
+
+ /**
+ * Exports graph folder recursively to file system.
+ * @param graph
+ * @param folderResource
+ * @param folder
+ * @param relation
+ * @throws DatabaseException
+ */
+ public static void exportDocumentFolder(ReadGraph graph, Resource folderResource, File folder, Resource relation, boolean useResourceNames, IProgressMonitor monitor) throws Exception{
+ Layer0 l0 = Layer0.getInstance(graph);
+ DocumentResource doc = DocumentResource.getInstance(graph);
+ GraphFileResource gf = GraphFileResource.getInstance(graph);
+ Set<String> names = new HashSet<String>();
+ Collection<Resource> folderType = graph.getPrincipalTypes(folderResource);
+ for (Resource r : graph.getObjects(folderResource, relation)) {
+ if (graph.isInstanceOf(r, doc.Document)) {
+ String name = null;
+ boolean canExport = false;
+ if (graph.isInstanceOf(r, doc.FileDocument)) {
+ name = graph.getRelatedValue(r, useResourceNames ? gf.HasResourceName : l0.HasName);
+ canExport = true;
+ } else if (graph.isInstanceOf(r, doc.UrlDocument)) {
+ name = graph.getRelatedValue(r, l0.HasName) +".url";
+ canExport = true;
+ }
+ if (canExport) {
+ name = resolveName(folder, name, names, true);
+ File file = new File(folder.getAbsolutePath()+"/"+name);
+ if (graph.isInstanceOf(r, doc.FileDocument)) {
+ GraphFileUtil.writeDataToFile(graph,r, file);
+ } else if (graph.isInstanceOf(r, doc.UrlDocument)) {
+ String url = graph.getRelatedValue(r, doc.HasUrl);
+ String n = graph.getRelatedValue(r, l0.HasName);
+ exportUrl(file, n, url);
+ }
+ if (monitor != null)
+ monitor.worked(1);
+ }
+
+ } else {
+ Collection<Resource> type = graph.getPrincipalTypes(r);
+ if (type.size() == folderType.size() && folderType.containsAll(type)) {
+ String name = graph.getRelatedValue(r, l0.HasName);
+ name = resolveName(folder, name, names, false);
+ File subFolder = new File(folder.getAbsolutePath()+"/"+name);
+ if (!subFolder.exists()) {
+ if (!subFolder.mkdir()) {
+ // TODO : error.
+ continue;
+ }
+ }
+ exportDocumentFolder(graph, r, subFolder, relation, useResourceNames, monitor);
+ }
+ }
+ }
+ }
+
+ /**
+ * Print URL to a file (Windows specific format?)
+ * @param toFile
+ * @param url
+ * @throws DatabaseException
+ */
+ private static void exportUrl(File toFile, String name, String url) throws Exception{
+ PrintStream os = new PrintStream(toFile,"UTF-8");
+ os.println("[InternetShortcut]");
+ os.println("URL="+url);
+ os.println("name="+name);
+ os.flush();
+ os.close();
+ }
+
+ public static Resource importURL(WriteGraph graph, File file) throws Exception{
+ String s = null;
+ String url = null;
+ String name = null;
+ BufferedReader is = null;
+ try {
+ is = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
+ while ((s = is.readLine()) != null) {
+ if (s.startsWith("URL=")) {
+ url = s.substring(4);
+ } else if (s.startsWith("name=")) {
+ name = s.substring(5);
+ }
+ }
+ } finally {
+ if (is != null)
+ is.close();
+ }
+
+ if (url == null)
+ return null;
+
+ Layer0 l0 = Layer0.getInstance(graph);
+ DocumentResource doc = DocumentResource.getInstance(graph);
+
+ Resource fileResource = graph.newResource();
+ graph.claim(fileResource, l0.InstanceOf, doc.UrlDocument);
+ if (name == null) {
+ name = file.getName();
+ name = unescape(name);
+ name = name.substring(0,name.length()-4);
+ }
+ graph.claimLiteral(fileResource, l0.HasName, name);
+ graph.claimLiteral(fileResource, doc.HasUrl, url);
+ return fileResource;
+ }
+
+ private static boolean isUrl(File file) throws Exception{
+ return (file.getAbsolutePath().endsWith(".url"));
+ }
+
+ private static final char ESCAPE = '%';
+
+ private static String escape(String s) {
+
+ int len = s.length();
+ StringBuilder sb = new StringBuilder(len);
+ for (int i = 0; i < len; i++) {
+ char ch = s.charAt(i);
+ if (ch < ' ' || ch >= 0x7F || ch == '/' || ch == '\\' || ch == ':' || ch == ESCAPE) {
+ sb.append(ESCAPE);
+ if (ch < 0x10) {
+ sb.append('0');
+ }
+ sb.append(Integer.toHexString(ch));
+ } else {
+ sb.append(ch);
+ }
+ }
+ return sb.toString();
+ }
+
+ private static String unescape(String s) {
+ int len = s.length();
+ StringBuilder sb = new StringBuilder(len);
+ for (int i = 0; i < len; i++) {
+ char ch = s.charAt(i);
+ if (ch == ESCAPE) {
+ String num = "0x";
+ num += s.charAt(++i);
+ num += s.charAt(++i);
+ ch = (char)Integer.decode(num).intValue();
+ }
+ sb.append(ch);
+ }
+ return sb.toString();
+
+ }
+
+ private static String resolveName(File parentFolder, String proposal, Set<String> used, boolean file) {
+ String current = escape(proposal);
+ int i = 0;
+ if (file) {
+ while (true) {
+ i++;
+ if (used.contains(current)) {
+ current = createFileName(proposal, i);
+ } else {
+ File subFile = new File(parentFolder.getAbsolutePath()+"/"+current);
+ if (!subFile.exists())
+ break;
+ if (subFile.exists() && subFile.isFile() && subFile.canWrite()) {
+ break;
+ }
+ }
+ }
+ } else {
+ while (true) {
+ i++;
+ if (used.contains(current)) {
+ current = proposal+i;
+ } else {
+ File subFolder = new File(parentFolder.getAbsolutePath()+"/"+current);
+ if (!subFolder.exists())
+ break;
+ if (subFolder.exists() && subFolder.isDirectory()) {
+ break;
+ }
+ }
+ }
+ }
+ used.add(current);
+ return current;
+ }
+
+ private static String createFileName(String original, int i) {
+ int extIndex = original.lastIndexOf(".");
+ if (extIndex == -1)
+ return original+i;
+ return original.substring(0,extIndex) + i + original.substring(extIndex);
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.document;
+
+import java.io.File;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FileDialog;
+import org.simantics.DatabaseJob;
+import org.simantics.Simantics;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.request.WriteRequest;
+import org.simantics.db.exception.DatabaseException;
+
+/**
+ * Action for importing files as documents.
+ *
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
+ *
+ */
+public class ImportDocument extends AddDocumentAction {
+
+
+ public ImportDocument(ReadGraph graph, String relationUri) throws DatabaseException {
+ super(graph, relationUri);
+ }
+
+ @Override
+ public Runnable create(Object target) {
+ if(!(target instanceof Resource))
+ return null;
+ final Resource resource = (Resource)target;
+ return new Runnable() {
+
+ @Override
+ public void run() {
+ FileDialog dialog = new FileDialog(Display.getCurrent().getActiveShell(),SWT.OPEN | SWT.MULTI);
+ // TODO : is there any way to read file/executable bindings from OS?
+ // if is, use those extensions to filter this list.
+ // note: in windows using "reg query ..." to read bindings form registry would work.
+ // Note : If the above mentioned filtering is implemented it should be made optional / configurable.
+ dialog.setFilterExtensions(new String[]{"*.*"});
+ if (dialog.open() == null) return;
+
+ String filterPath = dialog.getFilterPath();
+ String[] filenames = dialog.getFileNames();
+
+ ImportJob job = new ImportJob(filenames.length > 1 ? "Import files" : "Import file", resource, filterPath, filenames);
+ job.setUser(true);
+ job.schedule();
+ }
+ };
+ }
+
+ private class ImportJob extends DatabaseJob {
+
+ public ImportJob(String name, Resource resource, String path, String[] filenames) {
+ super(name);
+ this.resource = resource;
+ this.path = path;
+ this.filenames = filenames;
+ }
+
+ Resource resource;
+ String path;
+ String[] filenames;
+
+ @Override
+ protected IStatus run(final IProgressMonitor monitor) {
+ monitor.beginTask("Importing...", filenames.length);
+ try {
+ Simantics.getSession().syncRequest(new WriteRequest() {
+ @Override
+ public void perform(WriteGraph graph) throws DatabaseException {
+ try {
+ graph.markUndoPoint();
+ for (String filename : filenames) {
+ File f = new File(path, filename);
+ Resource newDoc = FileDocumentUtil.importFileWithName(graph, f.getAbsolutePath());
+ linkDocument(graph, resource, newDoc);
+ monitor.worked(1);
+ }
+ } catch (Exception e) {
+ throw new DatabaseException(e);
+ }
+ }
+ });
+ return new Status(IStatus.OK, Activator.PLUGIN_ID, "Import succesful.");
+ } catch (DatabaseException e) {
+ return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Import failed.", e);
+ } finally {
+ monitor.done();
+ }
+ }
+ }
+
+}