1 package org.argeo.documents.ui;
2
3 import java.io.File;
4 import java.io.FileInputStream;
5 import java.io.FileOutputStream;
6 import java.io.IOException;
7 import java.io.InputStream;
8 import java.io.OutputStream;
9 import java.lang.reflect.Method;
10 import java.net.URI;
11 import java.nio.file.DirectoryNotEmptyException;
12 import java.nio.file.FileVisitResult;
13 import java.nio.file.Files;
14 import java.nio.file.Path;
15 import java.nio.file.Paths;
16 import java.nio.file.SimpleFileVisitor;
17 import java.nio.file.attribute.BasicFileAttributes;
18 import java.util.ArrayList;
19 import java.util.HashMap;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Map;
23
24 import javax.jcr.Node;
25 import javax.jcr.Property;
26 import javax.jcr.PropertyType;
27 import javax.jcr.Repository;
28 import javax.jcr.RepositoryException;
29 import javax.jcr.Session;
30
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33 import org.argeo.connect.ui.widgets.SingleQuestion;
34 import org.argeo.connect.util.ConnectJcrUtils;
35 import org.argeo.documents.DocumentsException;
36 import org.argeo.documents.DocumentsService;
37 import org.argeo.eclipse.ui.EclipseUiUtils;
38 import org.argeo.eclipse.ui.specific.OpenFile;
39 import org.argeo.jcr.JcrUtils;
40 import org.eclipse.jface.dialogs.MessageDialog;
41 import org.eclipse.jface.viewers.IStructuredSelection;
42 import org.eclipse.swt.SWT;
43 import org.eclipse.swt.widgets.FileDialog;
44 import org.eclipse.swt.widgets.Shell;
45
46 public class DocumentsUiService {
47 private final static Log log = LogFactory.getLog(DocumentsUiService.class);
48
49
50 public final static String ACTION_ID_CREATE_FOLDER = "createFolder";
51 public final static String ACTION_ID_BOOKMARK_FOLDER = "bookmarkFolder";
52 public final static String ACTION_ID_SHARE_FOLDER = "shareFolder";
53 public final static String ACTION_ID_DOWNLOAD_FOLDER = "downloadFolder";
54 public final static String ACTION_ID_RENAME = "rename";
55 public final static String ACTION_ID_DELETE = "delete";
56 public final static String ACTION_ID_UPLOAD_FILE = "uploadFiles";
57
58 public final static String ACTION_ID_DELETE_BOOKMARK = "deleteBookmark";
59 public final static String ACTION_ID_RENAME_BOOKMARK = "renameBookmark";
60
61 public String getLabel(String actionId) {
62 switch (actionId) {
63 case ACTION_ID_CREATE_FOLDER:
64 return "Create Folder";
65 case ACTION_ID_BOOKMARK_FOLDER:
66 return "Bookmark Folder";
67 case ACTION_ID_SHARE_FOLDER:
68 return "Share Folder";
69 case ACTION_ID_DOWNLOAD_FOLDER:
70 return "Download as zip archive";
71 case ACTION_ID_RENAME:
72 return "Rename";
73 case ACTION_ID_DELETE:
74 return "Delete";
75 case ACTION_ID_UPLOAD_FILE:
76 return "Upload Files";
77
78
79 case ACTION_ID_DELETE_BOOKMARK:
80 return "Delete bookmark";
81 case ACTION_ID_RENAME_BOOKMARK:
82 return "Rename bookmark";
83 default:
84 throw new IllegalArgumentException("Unknown action ID " + actionId);
85 }
86 }
87
88 public void openFile(Path toOpenPath) {
89 try {
90 String name = toOpenPath.getFileName().toString();
91 File tmpFile = File.createTempFile("tmp", name);
92 tmpFile.deleteOnExit();
93 try (OutputStream os = new FileOutputStream(tmpFile)) {
94 Files.copy(toOpenPath, os);
95 } catch (IOException e) {
96 throw new DocumentsException("Cannot open copy " + name + " to tmpFile.", e);
97 }
98 String uri = Paths.get(tmpFile.getAbsolutePath()).toUri().toString();
99 Map<String, String> params = new HashMap<String, String>();
100 params.put(OpenFile.PARAM_FILE_NAME, name);
101 params.put(OpenFile.PARAM_FILE_URI, uri);
102
103
104 } catch (IOException e1) {
105 throw new DocumentsException("Cannot create tmp copy of " + toOpenPath, e1);
106 }
107 }
108
109 public boolean deleteItems(Shell shell, IStructuredSelection selection) {
110 if (selection.isEmpty())
111 return false;
112
113 StringBuilder builder = new StringBuilder();
114 @SuppressWarnings("unchecked")
115 Iterator<Object> iterator = selection.iterator();
116 List<Path> paths = new ArrayList<>();
117
118 while (iterator.hasNext()) {
119 Path path = (Path) iterator.next();
120 builder.append(path.getFileName() + ", ");
121 paths.add(path);
122 }
123 String msg = "You are about to delete following elements: " + builder.substring(0, builder.length() - 2)
124 + ". Are you sure?";
125 if (MessageDialog.openConfirm(shell, "Confirm deletion", msg)) {
126 for (Path path : paths) {
127 try {
128
129 Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
130 @Override
131 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
132 Files.delete(file);
133 return FileVisitResult.CONTINUE;
134 }
135
136 @Override
137 public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
138 Files.delete(dir);
139 return FileVisitResult.CONTINUE;
140 }
141 });
142 } catch (DirectoryNotEmptyException e) {
143 String errMsg = path.getFileName() + " cannot be deleted: directory is not empty.";
144 MessageDialog.openError(shell, "Deletion forbidden", errMsg);
145 throw new DocumentsException("Cannot delete path " + path, e);
146 } catch (IOException e) {
147 String errMsg = e.toString();
148 MessageDialog.openError(shell, "Deletion forbidden", errMsg);
149 throw new DocumentsException("Cannot delete path " + path, e);
150 }
151 }
152 return true;
153 }
154 return false;
155 }
156
157 public boolean renameItem(Shell shell, Path parentFolderPath, Path toRenamePath) {
158 String msg = "Enter a new name:";
159 String name = SingleQuestion.ask("Rename item", msg, toRenamePath.getFileName().toString());
160
161 if (EclipseUiUtils.notEmpty(name)) {
162 try {
163 Path child = parentFolderPath.resolve(name);
164 if (Files.exists(child)) {
165 String errMsg = "An object named " + name + " already exists at " + parentFolderPath.toString()
166 + ", please provide another name";
167 MessageDialog.openError(shell, "Invallid new name: duplicated entry", errMsg);
168 throw new DocumentsException(errMsg);
169 } else {
170 Files.move(toRenamePath, child);
171 return true;
172 }
173 } catch (IOException e) {
174 throw new DocumentsException("Cannot create folder " + name + " at " + parentFolderPath.toString(), e);
175 }
176 }
177 return false;
178 }
179
180 public boolean createFolder(Shell shell, Path currFolderPath) {
181 String msg = "Enter a name:";
182 String name = SingleQuestion.ask("Create folder", msg);
183
184 if (EclipseUiUtils.notEmpty(name)) {
185 name = name.trim();
186 try {
187 Path child = currFolderPath.resolve(name);
188 if (Files.exists(child)) {
189 String errMsg = "A folder named " + name + " already exists at " + currFolderPath.toString()
190 + ", cannot create";
191 MessageDialog.openError(shell, "Creation forbidden: dupplicated name", errMsg);
192 throw new DocumentsException(errMsg);
193 } else {
194 Files.createDirectories(child);
195 return true;
196 }
197 } catch (IOException e) {
198 throw new DocumentsException("Cannot create folder " + name + " at " + currFolderPath.toString(), e);
199 }
200 }
201 return false;
202 }
203
204 public void bookmarkFolder(Path toBookmarkPath, Repository repository, DocumentsService documentsService) {
205 String msg = "Provide a name:";
206 String name = SingleQuestion.ask("Create bookmark", msg, toBookmarkPath.getFileName().toString());
207 if (EclipseUiUtils.notEmpty(name))
208 documentsService.createFolderBookmark(toBookmarkPath, name, repository);
209 }
210
211 public boolean uploadFiles(Shell shell, Path currFolderPath) {
212
213 try {
214 FileDialog dialog = new FileDialog(shell, SWT.MULTI);
215 dialog.setText("Choose one or more files to upload");
216
217 if (EclipseUiUtils.notEmpty(dialog.open())) {
218 String[] names = dialog.getFileNames();
219
220
221
222
223
224 Method filterMethod = null;
225 Path parPath = null;
226 try {
227 filterMethod = dialog.getClass().getDeclaredMethod("getFilterPath");
228 String filterPath = (String) filterMethod.invoke(dialog);
229 parPath = Paths.get(filterPath);
230 } catch (NoSuchMethodException nsme) {
231 }
232 if (names.length == 0)
233 return false;
234 else {
235 loop: for (String name : names) {
236 Path tmpPath = Paths.get(name);
237 if (parPath != null)
238 tmpPath = parPath.resolve(tmpPath);
239 if (Files.exists(tmpPath)) {
240 URI uri = tmpPath.toUri();
241 String uriStr = uri.toString();
242
243 if (Files.isDirectory(tmpPath)) {
244 MessageDialog.openError(shell, "Unimplemented directory import",
245 "Upload of directories in the system is not yet implemented");
246 continue loop;
247 }
248 Path targetPath = currFolderPath.resolve(tmpPath.getFileName().toString());
249 try (InputStream in = new FileInputStream(tmpPath.toFile())) {
250 Files.copy(in, targetPath);
251 Files.delete(tmpPath);
252 }
253 if (log.isDebugEnabled())
254 log.debug("copied uploaded file " + uriStr + " to " + targetPath.toString());
255 } else {
256 String msg = "Cannot copy tmp file from " + tmpPath.toString();
257 if (parPath != null)
258 msg += "\nPlease remember that file upload fails when choosing files from the \"Recently Used\" bookmarks on some OS";
259 MessageDialog.openError(shell, "Missing file", msg);
260 continue loop;
261 }
262 }
263 return true;
264 }
265 }
266 } catch (Exception e) {
267 e.printStackTrace();
268 MessageDialog.openError(shell, "Upload has failed", "Cannot import files to " + currFolderPath);
269 }
270 return false;
271 }
272
273 public boolean deleteBookmark(Shell shell, IStructuredSelection selection, Node bookmarkParent) {
274 if (selection.isEmpty())
275 return false;
276
277 StringBuilder builder = new StringBuilder();
278 @SuppressWarnings("unchecked")
279 Iterator<Object> iterator = selection.iterator();
280 List<Node> nodes = new ArrayList<>();
281
282 while (iterator.hasNext()) {
283 Node node = (Node) iterator.next();
284 builder.append(ConnectJcrUtils.get(node, Property.JCR_TITLE) + ", ");
285 nodes.add(node);
286 }
287 String msg = "You are about to delete following bookmark: " + builder.substring(0, builder.length() - 2)
288 + ". Are you sure?";
289 if (MessageDialog.openConfirm(shell, "Confirm deletion", msg)) {
290 Session session = ConnectJcrUtils.getSession(bookmarkParent);
291 try {
292 if (session.hasPendingChanges())
293 throw new DocumentsException("Cannot remove bookmarks, session is not clean");
294 for (Node path : nodes)
295 path.remove();
296 bookmarkParent.getSession().save();
297 return true;
298 } catch (RepositoryException e) {
299 JcrUtils.discardQuietly(session);
300 throw new DocumentsException("Cannot delete bookmarks " + builder.toString(), e);
301 }
302 }
303 return false;
304 }
305
306 public boolean renameBookmark(IStructuredSelection selection) {
307 if (selection.isEmpty() || selection.size() > 1)
308 return false;
309 Node toRename = (Node) selection.getFirstElement();
310 String msg = "Please provide a new name.";
311 String name = SingleQuestion.ask("Rename bookmark", msg, ConnectJcrUtils.get(toRename, Property.JCR_TITLE));
312 if (EclipseUiUtils.notEmpty(name)
313 && ConnectJcrUtils.setJcrProperty(toRename, Property.JCR_TITLE, PropertyType.STRING, name)) {
314 ConnectJcrUtils.saveIfNecessary(toRename);
315 return true;
316 }
317 return false;
318 }
319 }