]> git.argeo.org Git - lgpl/argeo-commons.git/blob - CmsFsBrowser.java
4a7e9bd3fb8dc3cc7702af54c4a7aca83e7ffec5
[lgpl/argeo-commons.git] / CmsFsBrowser.java
1 package org.argeo.cms.ui.fs;
2
3 import java.io.IOException;
4 import java.net.URI;
5 import java.net.URISyntaxException;
6 import java.nio.file.DirectoryStream;
7 import java.nio.file.FileSystem;
8 import java.nio.file.Files;
9 import java.nio.file.Path;
10 import java.nio.file.Paths;
11 import java.nio.file.spi.FileSystemProvider;
12 import java.security.PrivilegedActionException;
13 import java.security.PrivilegedExceptionAction;
14 import java.util.ArrayList;
15 import java.util.List;
16
17 import javax.jcr.Node;
18 import javax.jcr.Repository;
19 import javax.jcr.Session;
20
21 import org.argeo.cms.CmsException;
22 import org.argeo.cms.auth.CurrentUser;
23 import org.argeo.cms.jcr.CmsJcrUtils;
24 import org.argeo.cms.ui.util.CmsUiUtils;
25 import org.argeo.eclipse.ui.ColumnDefinition;
26 import org.argeo.eclipse.ui.EclipseUiUtils;
27 import org.argeo.eclipse.ui.fs.FileIconNameLabelProvider;
28 import org.argeo.eclipse.ui.fs.FsTableViewer;
29 import org.argeo.eclipse.ui.fs.FsUiConstants;
30 import org.argeo.eclipse.ui.fs.FsUiUtils;
31 import org.argeo.eclipse.ui.fs.NioFileLabelProvider;
32 import org.argeo.jcr.JcrUtils;
33 import org.eclipse.jface.viewers.DoubleClickEvent;
34 import org.eclipse.jface.viewers.IDoubleClickListener;
35 import org.eclipse.jface.viewers.ISelectionChangedListener;
36 import org.eclipse.jface.viewers.IStructuredSelection;
37 import org.eclipse.jface.viewers.SelectionChangedEvent;
38 import org.eclipse.jface.viewers.Viewer;
39 import org.eclipse.swt.SWT;
40 import org.eclipse.swt.custom.SashForm;
41 import org.eclipse.swt.events.KeyEvent;
42 import org.eclipse.swt.events.KeyListener;
43 import org.eclipse.swt.events.ModifyEvent;
44 import org.eclipse.swt.events.ModifyListener;
45 import org.eclipse.swt.events.MouseAdapter;
46 import org.eclipse.swt.events.MouseEvent;
47 import org.eclipse.swt.events.SelectionAdapter;
48 import org.eclipse.swt.events.SelectionEvent;
49 import org.eclipse.swt.graphics.Point;
50 import org.eclipse.swt.layout.GridData;
51 import org.eclipse.swt.layout.GridLayout;
52 import org.eclipse.swt.layout.RowData;
53 import org.eclipse.swt.layout.RowLayout;
54 import org.eclipse.swt.widgets.Button;
55 import org.eclipse.swt.widgets.Composite;
56 import org.eclipse.swt.widgets.Control;
57 import org.eclipse.swt.widgets.Label;
58 import org.eclipse.swt.widgets.Table;
59 import org.eclipse.swt.widgets.Text;
60
61 /**
62 * Default CMS browser composite: a sashForm layout with bookmarks at the left
63 * hand side, a simple table in the middle and an overview at right hand side.
64 */
65 public class CmsFsBrowser extends Composite {
66 // private final static Log log = LogFactory.getLog(CmsFsBrowser.class);
67 private static final long serialVersionUID = -40347919096946585L;
68
69 private final FileSystemProvider nodeFileSystemProvider;
70 private final Node currentBaseContext;
71
72 // UI Parts for the browser
73 private Composite leftPannelCmp;
74 private Composite filterCmp;
75 private Text filterTxt;
76 private FsTableViewer directoryDisplayViewer;
77 private Composite rightPannelCmp;
78
79 private FsContextMenu contextMenu;
80
81 // Local context (this composite is state full)
82 private Path initialPath;
83 private Path currDisplayedFolder;
84 private Path currSelected;
85
86 // local variables (to be cleaned)
87 private int bookmarkColWith = 500;
88
89 /*
90 * WARNING: unfinalised implementation of the mechanism to retrieve base
91 * paths
92 */
93
94 private final static String NODE_PREFIX = "node://";
95
96 private String getCurrentHomePath() {
97 Session session = null;
98 try {
99 Repository repo = currentBaseContext.getSession().getRepository();
100 session = CurrentUser.tryAs(() -> repo.login());
101 String homepath = CmsJcrUtils.getUserHome(session).getPath();
102 return homepath;
103 } catch (Exception e) {
104 throw new CmsException("Cannot retrieve Current User Home Path", e);
105 } finally {
106 JcrUtils.logoutQuietly(session);
107 }
108 }
109
110 protected Path[] getMyFilesPath() {
111 // return Paths.get(System.getProperty("user.dir"));
112 String currHomeUriStr = NODE_PREFIX + getCurrentHomePath();
113 try {
114 URI uri = new URI(currHomeUriStr);
115 FileSystem fileSystem = nodeFileSystemProvider.getFileSystem(uri);
116 if (fileSystem == null) {
117 PrivilegedExceptionAction<FileSystem> pea = new PrivilegedExceptionAction<FileSystem>() {
118 @Override
119 public FileSystem run() throws Exception {
120 return nodeFileSystemProvider.newFileSystem(uri, null);
121 }
122
123 };
124 fileSystem = CurrentUser.tryAs(pea);
125 }
126 Path[] paths = { fileSystem.getPath(getCurrentHomePath()), fileSystem.getPath("/") };
127 return paths;
128 } catch (URISyntaxException | PrivilegedActionException e) {
129 throw new RuntimeException("unable to initialise home file system for " + currHomeUriStr, e);
130 }
131 }
132
133 private Path[] getMyGroupsFilesPath() {
134 // TODO
135 Path[] paths = { Paths.get(System.getProperty("user.dir")), Paths.get("/tmp") };
136 return paths;
137 }
138
139 private Path[] getMyBookmarks() {
140 // TODO
141 Path[] paths = { Paths.get(System.getProperty("user.dir")), Paths.get("/tmp"), Paths.get("/opt") };
142 return paths;
143 }
144
145 /* End of warning */
146
147 public CmsFsBrowser(Composite parent, int style, Node context, FileSystemProvider fileSystemProvider) {
148 super(parent, style);
149 this.nodeFileSystemProvider = fileSystemProvider;
150 this.currentBaseContext = context;
151
152 this.setLayout(EclipseUiUtils.noSpaceGridLayout());
153
154 SashForm form = new SashForm(this, SWT.HORIZONTAL);
155
156 leftPannelCmp = new Composite(form, SWT.NO_FOCUS);
157 // Bookmarks are still static
158 populateBookmarks(leftPannelCmp);
159
160 Composite centerCmp = new Composite(form, SWT.BORDER | SWT.NO_FOCUS);
161 createDisplay(centerCmp);
162
163 rightPannelCmp = new Composite(form, SWT.NO_FOCUS);
164
165 form.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
166 form.setWeights(new int[] { 15, 40, 20 });
167 }
168
169 void refresh() {
170 modifyFilter(false);
171 // also refresh bookmarks and groups
172 }
173
174 private void createDisplay(final Composite parent) {
175 parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
176
177 // top filter
178 filterCmp = new Composite(parent, SWT.NO_FOCUS);
179 filterCmp.setLayoutData(EclipseUiUtils.fillWidth());
180 addFilterPanel(filterCmp);
181
182 // Main display
183 directoryDisplayViewer = new FsTableViewer(parent, SWT.MULTI);
184 List<ColumnDefinition> colDefs = new ArrayList<>();
185 colDefs.add(new ColumnDefinition(new FileIconNameLabelProvider(), "Name", 250));
186 colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_SIZE), "Size", 100));
187 colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_TYPE), "Type", 150));
188 colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_LAST_MODIFIED),
189 "Last modified", 400));
190 final Table table = directoryDisplayViewer.configureDefaultTable(colDefs);
191 table.setLayoutData(EclipseUiUtils.fillAll());
192
193 // table.addKeyListener(new KeyListener() {
194 // private static final long serialVersionUID = -8083424284436715709L;
195 //
196 // @Override
197 // public void keyReleased(KeyEvent e) {
198 // }
199 //
200 // @Override
201 // public void keyPressed(KeyEvent e) {
202 // if (log.isDebugEnabled())
203 // log.debug("Key event received: " + e.keyCode);
204 // IStructuredSelection selection = (IStructuredSelection)
205 // directoryDisplayViewer.getSelection();
206 // Path selected = null;
207 // if (!selection.isEmpty())
208 // selected = ((Path) selection.getFirstElement());
209 // if (e.keyCode == SWT.CR) {
210 // if (!Files.isDirectory(selected))
211 // return;
212 // if (selected != null) {
213 // currDisplayedFolder = selected;
214 // directoryDisplayViewer.setInput(currDisplayedFolder, "*");
215 // }
216 // } else if (e.keyCode == SWT.BS) {
217 // currDisplayedFolder = currDisplayedFolder.getParent();
218 // directoryDisplayViewer.setInput(currDisplayedFolder, "*");
219 // directoryDisplayViewer.getTable().setFocus();
220 // }
221 // }
222 // });
223
224 directoryDisplayViewer.addSelectionChangedListener(new ISelectionChangedListener() {
225
226 @Override
227 public void selectionChanged(SelectionChangedEvent event) {
228 IStructuredSelection selection = (IStructuredSelection) directoryDisplayViewer.getSelection();
229 Path selected = null;
230 if (selection.isEmpty())
231 setSelected(null);
232 else
233 selected = ((Path) selection.getFirstElement());
234 if (selected != null) {
235 // TODO manage multiple selection
236 setSelected(selected);
237 }
238 }
239 });
240
241 directoryDisplayViewer.addDoubleClickListener(new IDoubleClickListener() {
242 @Override
243 public void doubleClick(DoubleClickEvent event) {
244 IStructuredSelection selection = (IStructuredSelection) directoryDisplayViewer.getSelection();
245 Path selected = null;
246 if (!selection.isEmpty())
247 selected = ((Path) selection.getFirstElement());
248 if (selected != null) {
249 if (!Files.isDirectory(selected))
250 return;
251 setInput(selected);
252 }
253 }
254 });
255
256 // The context menu
257 contextMenu = new FsContextMenu(this);
258
259 table.addMouseListener(new MouseAdapter() {
260 private static final long serialVersionUID = 6737579410648595940L;
261
262 @Override
263 public void mouseDown(MouseEvent e) {
264 if (e.button == 3) {
265 // contextMenu.setCurrFolderPath(currDisplayedFolder);
266 contextMenu.show(table, new Point(e.x, e.y), currDisplayedFolder);
267 }
268 }
269 });
270 }
271
272 private void addPathElementBtn(Path path) {
273 Button elemBtn = new Button(filterCmp, SWT.PUSH);
274 String nameStr;
275 if (path.toString().equals("/"))
276 nameStr = "[jcr:root]";
277 else
278 nameStr = path.getFileName().toString();
279 elemBtn.setText(nameStr + " >> ");
280 CmsUiUtils.style(elemBtn, FsStyles.BREAD_CRUMB_BTN);
281 elemBtn.addSelectionListener(new SelectionAdapter() {
282 private static final long serialVersionUID = -4103695476023480651L;
283
284 @Override
285 public void widgetSelected(SelectionEvent e) {
286 setInput(path);
287 }
288 });
289 }
290
291 public void setInput(Path path) {
292 if (path.equals(currDisplayedFolder))
293 return;
294 currDisplayedFolder = path;
295
296 Path diff = initialPath.relativize(currDisplayedFolder);
297
298 for (Control child : filterCmp.getChildren())
299 if (!child.equals(filterTxt))
300 child.dispose();
301
302 addPathElementBtn(initialPath);
303 Path currTarget = initialPath;
304 if (!diff.toString().equals(""))
305 for (Path pathElem : diff) {
306 currTarget = currTarget.resolve(pathElem);
307 addPathElementBtn(currTarget);
308 }
309
310 filterTxt.setText("");
311 filterTxt.moveBelow(null);
312 setSelected(null);
313 filterCmp.getParent().layout(true, true);
314 }
315
316 private void setSelected(Path path) {
317 currSelected = path;
318 setOverviewInput(path);
319 }
320
321 public Viewer getViewer() {
322 return directoryDisplayViewer;
323 }
324
325 private void populateBookmarks(Composite parent) {
326 CmsUiUtils.clear(parent);
327 parent.setLayout(new GridLayout());
328 ISelectionChangedListener selList = new BookmarksSelChangeListener();
329
330 FsTableViewer homeViewer = new FsTableViewer(parent, SWT.SINGLE | SWT.NO_SCROLL);
331 Table table = homeViewer.configureDefaultSingleColumnTable(bookmarkColWith);
332 GridData gd = EclipseUiUtils.fillWidth();
333 gd.horizontalIndent = 10;
334 table.setLayoutData(gd);
335 homeViewer.addSelectionChangedListener(selList);
336 homeViewer.setPathsInput(getMyFilesPath());
337
338 appendTitle(parent, "Shared files");
339 FsTableViewer groupsViewer = new FsTableViewer(parent, SWT.SINGLE | SWT.NO_SCROLL);
340 table = groupsViewer.configureDefaultSingleColumnTable(bookmarkColWith);
341 gd = EclipseUiUtils.fillWidth();
342 gd.horizontalIndent = 10;
343 table.setLayoutData(gd);
344 groupsViewer.addSelectionChangedListener(selList);
345 groupsViewer.setPathsInput(getMyGroupsFilesPath());
346
347 appendTitle(parent, "My bookmarks");
348 FsTableViewer bookmarksViewer = new FsTableViewer(parent, SWT.SINGLE | SWT.NO_SCROLL);
349 table = bookmarksViewer.configureDefaultSingleColumnTable(bookmarkColWith);
350 gd = EclipseUiUtils.fillWidth();
351 gd.horizontalIndent = 10;
352 table.setLayoutData(gd);
353 bookmarksViewer.addSelectionChangedListener(selList);
354 bookmarksViewer.setPathsInput(getMyBookmarks());
355 }
356
357 /**
358 * Recreates the content of the box that displays information about the
359 * current selected Path.
360 */
361 private void setOverviewInput(Path path) {
362 try {
363 EclipseUiUtils.clear(rightPannelCmp);
364 rightPannelCmp.setLayout(new GridLayout());
365 if (path != null) {
366 // if (isImg(context)) {
367 // EditableImage image = new Img(parent, RIGHT, context,
368 // imageWidth);
369 // image.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER,
370 // true, false,
371 // 2, 1));
372 // }
373
374 Label contextL = new Label(rightPannelCmp, SWT.NONE);
375 contextL.setText(path.getFileName().toString());
376 contextL.setFont(EclipseUiUtils.getBoldFont(rightPannelCmp));
377 addProperty(rightPannelCmp, "Last modified", Files.getLastModifiedTime(path).toString());
378 // addProperty(rightPannelCmp, "Owner",
379 // Files.getOwner(path).getName());
380 if (Files.isDirectory(path)) {
381 addProperty(rightPannelCmp, "Type", "Folder");
382 } else {
383 String mimeType = Files.probeContentType(path);
384 if (EclipseUiUtils.isEmpty(mimeType))
385 mimeType = "<i>Unknown</i>";
386 addProperty(rightPannelCmp, "Type", mimeType);
387 addProperty(rightPannelCmp, "Size", FsUiUtils.humanReadableByteCount(Files.size(path), false));
388 }
389 }
390 rightPannelCmp.layout(true, true);
391 } catch (IOException e) {
392 throw new CmsException("Cannot display details for " + path.toString(), e);
393 }
394 }
395
396 private void addFilterPanel(Composite parent) {
397 RowLayout rl = new RowLayout(SWT.HORIZONTAL);
398 rl.wrap = true;
399 parent.setLayout(rl);
400 // parent.setLayout(EclipseUiUtils.noSpaceGridLayout(new GridLayout(2,
401 // false)));
402
403 filterTxt = new Text(parent, SWT.SEARCH | SWT.ICON_CANCEL);
404 filterTxt.setMessage("Search current folder");
405 filterTxt.setLayoutData(new RowData(250, SWT.DEFAULT));
406 filterTxt.addModifyListener(new ModifyListener() {
407 private static final long serialVersionUID = 1L;
408
409 public void modifyText(ModifyEvent event) {
410 modifyFilter(false);
411 }
412 });
413 filterTxt.addKeyListener(new KeyListener() {
414 private static final long serialVersionUID = 2533535233583035527L;
415
416 @Override
417 public void keyReleased(KeyEvent e) {
418 }
419
420 @Override
421 public void keyPressed(KeyEvent e) {
422 // boolean shiftPressed = (e.stateMask & SWT.SHIFT) != 0;
423 // // boolean altPressed = (e.stateMask & SWT.ALT) != 0;
424 // FilterEntitiesVirtualTable currTable = null;
425 // if (currEdited != null) {
426 // FilterEntitiesVirtualTable table =
427 // browserCols.get(currEdited);
428 // if (table != null && !table.isDisposed())
429 // currTable = table;
430 // }
431 //
432 // if (e.keyCode == SWT.ARROW_DOWN)
433 // currTable.setFocus();
434 // else if (e.keyCode == SWT.BS) {
435 // if (filterTxt.getText().equals("")
436 // && !(currEdited.getNameCount() == 1 ||
437 // currEdited.equals(initialPath))) {
438 // Path oldEdited = currEdited;
439 // Path parentPath = currEdited.getParent();
440 // setEdited(parentPath);
441 // if (browserCols.containsKey(parentPath))
442 // browserCols.get(parentPath).setSelected(oldEdited);
443 // filterTxt.setFocus();
444 // e.doit = false;
445 // }
446 // } else if (e.keyCode == SWT.TAB && !shiftPressed) {
447 // Path uniqueChild = getOnlyChild(currEdited,
448 // filterTxt.getText());
449 // if (uniqueChild != null) {
450 // // Highlight the unique chosen child
451 // currTable.setSelected(uniqueChild);
452 // setEdited(uniqueChild);
453 // }
454 // filterTxt.setFocus();
455 // e.doit = false;
456 // }
457 }
458 });
459 }
460
461 private Path getOnlyChild(Path parent, String filter) {
462 try (DirectoryStream<Path> stream = Files.newDirectoryStream(currDisplayedFolder, filter + "*")) {
463 Path uniqueChild = null;
464 boolean moreThanOne = false;
465 loop: for (Path entry : stream) {
466 if (uniqueChild == null) {
467 uniqueChild = entry;
468 } else {
469 moreThanOne = true;
470 break loop;
471 }
472 }
473 if (!moreThanOne)
474 return uniqueChild;
475 return null;
476 } catch (IOException ioe) {
477 throw new CmsException(
478 "Unable to determine unique child existence and get it under " + parent + " with filter " + filter,
479 ioe);
480 }
481 }
482
483 private void modifyFilter(boolean fromOutside) {
484 if (!fromOutside)
485 if (currDisplayedFolder != null) {
486 String filter = filterTxt.getText() + "*";
487 directoryDisplayViewer.setInput(currDisplayedFolder, filter);
488 }
489 }
490
491 private class BookmarksSelChangeListener implements ISelectionChangedListener {
492
493 @Override
494 public void selectionChanged(SelectionChangedEvent event) {
495 IStructuredSelection selection = (IStructuredSelection) event.getSelection();
496 if (selection.isEmpty())
497 return;
498 else {
499 Path newSelected = (Path) selection.getFirstElement();
500 if (newSelected.equals(currDisplayedFolder) && newSelected.equals(initialPath))
501 return;
502 initialPath = newSelected;
503 setInput(newSelected);
504 }
505 }
506 }
507
508 // Simplify UI implementation
509 private void addProperty(Composite parent, String propName, String value) {
510 Label contextL = new Label(parent, SWT.NONE);
511 contextL.setText(propName + ": " + value);
512 }
513
514 private Label appendTitle(Composite parent, String value) {
515 Label titleLbl = new Label(parent, SWT.NONE);
516 titleLbl.setText(value);
517 titleLbl.setFont(EclipseUiUtils.getBoldFont(parent));
518 GridData gd = EclipseUiUtils.fillWidth();
519 gd.horizontalIndent = 5;
520 gd.verticalIndent = 5;
521 titleLbl.setLayoutData(gd);
522 return titleLbl;
523 }
524 }