1 package org
.argeo
.cms
.ui
.fs
;
3 import java
.io
.IOException
;
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
;
17 import javax
.jcr
.Node
;
18 import javax
.jcr
.Repository
;
19 import javax
.jcr
.Session
;
21 import org
.argeo
.api
.NodeUtils
;
22 import org
.argeo
.cms
.CmsException
;
23 import org
.argeo
.cms
.auth
.CurrentUser
;
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
;
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.
65 public class CmsFsBrowser
extends Composite
{
66 // private final static Log log = LogFactory.getLog(CmsFsBrowser.class);
67 private static final long serialVersionUID
= -40347919096946585L;
69 private final FileSystemProvider nodeFileSystemProvider
;
70 private final Node currentBaseContext
;
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
;
79 private FsContextMenu contextMenu
;
81 // Local context (this composite is state full)
82 private Path initialPath
;
83 private Path currDisplayedFolder
;
84 private Path currSelected
;
86 // local variables (to be cleaned)
87 private int bookmarkColWith
= 500;
90 * WARNING: unfinalised implementation of the mechanism to retrieve base
94 private final static String NODE_PREFIX
= "node://";
96 private String
getCurrentHomePath() {
97 Session session
= null;
99 Repository repo
= currentBaseContext
.getSession().getRepository();
100 session
= CurrentUser
.tryAs(() -> repo
.login());
101 String homepath
= NodeUtils
.getUserHome(session
).getPath();
103 } catch (Exception e
) {
104 throw new CmsException("Cannot retrieve Current User Home Path", e
);
106 JcrUtils
.logoutQuietly(session
);
110 protected Path
[] getMyFilesPath() {
111 // return Paths.get(System.getProperty("user.dir"));
112 String currHomeUriStr
= NODE_PREFIX
+ getCurrentHomePath();
114 URI uri
= new URI(currHomeUriStr
);
115 FileSystem fileSystem
= nodeFileSystemProvider
.getFileSystem(uri
);
116 if (fileSystem
== null) {
117 PrivilegedExceptionAction
<FileSystem
> pea
= new PrivilegedExceptionAction
<FileSystem
>() {
119 public FileSystem
run() throws Exception
{
120 return nodeFileSystemProvider
.newFileSystem(uri
, null);
124 fileSystem
= CurrentUser
.tryAs(pea
);
126 Path
[] paths
= { fileSystem
.getPath(getCurrentHomePath()), fileSystem
.getPath("/") };
128 } catch (URISyntaxException
| PrivilegedActionException e
) {
129 throw new RuntimeException("unable to initialise home file system for " + currHomeUriStr
, e
);
133 private Path
[] getMyGroupsFilesPath() {
135 Path
[] paths
= { Paths
.get(System
.getProperty("user.dir")), Paths
.get("/tmp") };
139 private Path
[] getMyBookmarks() {
141 Path
[] paths
= { Paths
.get(System
.getProperty("user.dir")), Paths
.get("/tmp"), Paths
.get("/opt") };
147 public CmsFsBrowser(Composite parent
, int style
, Node context
, FileSystemProvider fileSystemProvider
) {
148 super(parent
, style
);
149 this.nodeFileSystemProvider
= fileSystemProvider
;
150 this.currentBaseContext
= context
;
152 this.setLayout(EclipseUiUtils
.noSpaceGridLayout());
154 SashForm form
= new SashForm(this, SWT
.HORIZONTAL
);
156 leftPannelCmp
= new Composite(form
, SWT
.NO_FOCUS
);
157 // Bookmarks are still static
158 populateBookmarks(leftPannelCmp
);
160 Composite centerCmp
= new Composite(form
, SWT
.BORDER
| SWT
.NO_FOCUS
);
161 createDisplay(centerCmp
);
163 rightPannelCmp
= new Composite(form
, SWT
.NO_FOCUS
);
165 form
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
166 form
.setWeights(new int[] { 15, 40, 20 });
171 // also refresh bookmarks and groups
174 private void createDisplay(final Composite parent
) {
175 parent
.setLayout(EclipseUiUtils
.noSpaceGridLayout());
178 filterCmp
= new Composite(parent
, SWT
.NO_FOCUS
);
179 filterCmp
.setLayoutData(EclipseUiUtils
.fillWidth());
180 addFilterPanel(filterCmp
);
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());
193 // table.addKeyListener(new KeyListener() {
194 // private static final long serialVersionUID = -8083424284436715709L;
197 // public void keyReleased(KeyEvent e) {
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))
212 // if (selected != null) {
213 // currDisplayedFolder = selected;
214 // directoryDisplayViewer.setInput(currDisplayedFolder, "*");
216 // } else if (e.keyCode == SWT.BS) {
217 // currDisplayedFolder = currDisplayedFolder.getParent();
218 // directoryDisplayViewer.setInput(currDisplayedFolder, "*");
219 // directoryDisplayViewer.getTable().setFocus();
224 directoryDisplayViewer
.addSelectionChangedListener(new ISelectionChangedListener() {
227 public void selectionChanged(SelectionChangedEvent event
) {
228 IStructuredSelection selection
= (IStructuredSelection
) directoryDisplayViewer
.getSelection();
229 Path selected
= null;
230 if (selection
.isEmpty())
233 selected
= ((Path
) selection
.getFirstElement());
234 if (selected
!= null) {
235 // TODO manage multiple selection
236 setSelected(selected
);
241 directoryDisplayViewer
.addDoubleClickListener(new IDoubleClickListener() {
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
))
257 contextMenu
= new FsContextMenu(this);
259 table
.addMouseListener(new MouseAdapter() {
260 private static final long serialVersionUID
= 6737579410648595940L;
263 public void mouseDown(MouseEvent e
) {
265 // contextMenu.setCurrFolderPath(currDisplayedFolder);
266 contextMenu
.show(table
, new Point(e
.x
, e
.y
), currDisplayedFolder
);
272 private void addPathElementBtn(Path path
) {
273 Button elemBtn
= new Button(filterCmp
, SWT
.PUSH
);
275 if (path
.toString().equals("/"))
276 nameStr
= "[jcr:root]";
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;
285 public void widgetSelected(SelectionEvent e
) {
291 public void setInput(Path path
) {
292 if (path
.equals(currDisplayedFolder
))
294 currDisplayedFolder
= path
;
296 Path diff
= initialPath
.relativize(currDisplayedFolder
);
298 for (Control child
: filterCmp
.getChildren())
299 if (!child
.equals(filterTxt
))
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
);
310 filterTxt
.setText("");
311 filterTxt
.moveBelow(null);
313 filterCmp
.getParent().layout(true, true);
316 private void setSelected(Path path
) {
318 setOverviewInput(path
);
321 public Viewer
getViewer() {
322 return directoryDisplayViewer
;
325 private void populateBookmarks(Composite parent
) {
326 CmsUiUtils
.clear(parent
);
327 parent
.setLayout(new GridLayout());
328 ISelectionChangedListener selList
= new BookmarksSelChangeListener();
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());
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());
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());
358 * Recreates the content of the box that displays information about the
359 * current selected Path.
361 private void setOverviewInput(Path path
) {
363 EclipseUiUtils
.clear(rightPannelCmp
);
364 rightPannelCmp
.setLayout(new GridLayout());
366 // if (isImg(context)) {
367 // EditableImage image = new Img(parent, RIGHT, context,
369 // image.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER,
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");
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));
390 rightPannelCmp
.layout(true, true);
391 } catch (IOException e
) {
392 throw new CmsException("Cannot display details for " + path
.toString(), e
);
396 private void addFilterPanel(Composite parent
) {
397 RowLayout rl
= new RowLayout(SWT
.HORIZONTAL
);
399 parent
.setLayout(rl
);
400 // parent.setLayout(EclipseUiUtils.noSpaceGridLayout(new GridLayout(2,
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;
409 public void modifyText(ModifyEvent event
) {
413 filterTxt
.addKeyListener(new KeyListener() {
414 private static final long serialVersionUID
= 2533535233583035527L;
417 public void keyReleased(KeyEvent e
) {
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;
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();
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);
454 // filterTxt.setFocus();
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) {
476 } catch (IOException ioe
) {
477 throw new CmsException(
478 "Unable to determine unique child existence and get it under " + parent
+ " with filter " + filter
,
483 private void modifyFilter(boolean fromOutside
) {
485 if (currDisplayedFolder
!= null) {
486 String filter
= filterTxt
.getText() + "*";
487 directoryDisplayViewer
.setInput(currDisplayedFolder
, filter
);
491 private class BookmarksSelChangeListener
implements ISelectionChangedListener
{
494 public void selectionChanged(SelectionChangedEvent event
) {
495 IStructuredSelection selection
= (IStructuredSelection
) event
.getSelection();
496 if (selection
.isEmpty())
499 Path newSelected
= (Path
) selection
.getFirstElement();
500 if (newSelected
.equals(currDisplayedFolder
) && newSelected
.equals(initialPath
))
502 initialPath
= newSelected
;
503 setInput(newSelected
);
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
);
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
);