--- /dev/null
+package org.argeo.cms.fs;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileSystem;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.spi.FileSystemProvider;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.util.CmsUtils;
+import org.argeo.cms.util.UserAdminUtils;
+import org.argeo.eclipse.ui.ColumnDefinition;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.eclipse.ui.fs.FileIconNameLabelProvider;
+import org.argeo.eclipse.ui.fs.FsTableViewer;
+import org.argeo.eclipse.ui.fs.FsUiConstants;
+import org.argeo.eclipse.ui.fs.FsUiUtils;
+import org.argeo.eclipse.ui.fs.NioFileLabelProvider;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowData;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Default CMS single page browser: a sashForm layout with bookmarks at the left
+ * hand side, a simple table in the middle and an overview at right hand side.
+ */
+public class CmsFsBrowser extends Composite {
+ private final static Log log = LogFactory.getLog(CmsFsBrowser.class);
+ private static final long serialVersionUID = -40347919096946585L;
+
+ private final FileSystemProvider nodeFileSystemProvider;
+ private final Node currentBaseContext;
+
+ // UI Parts for the browser
+ private Composite leftPannelCmp;
+ private Composite filterCmp;
+ private Text filterTxt;
+ private FsTableViewer directoryDisplayViewer;
+ private Composite rightPannelCmp;
+
+ private FsContextMenu contextMenu;
+
+ // Local context (this composite is state full)
+ private Path initialPath;
+ private Path currDisplayedFolder;
+ private Path currSelected;
+
+ // local variables (to be cleaned)
+ private int bookmarkColWith = 500;
+
+ public CmsFsBrowser(Composite parent, int style, Node context, FileSystemProvider fileSystemProvider) {
+ super(parent, style);
+ this.nodeFileSystemProvider = fileSystemProvider;
+ this.currentBaseContext = context;
+
+ this.setLayout(EclipseUiUtils.noSpaceGridLayout());
+
+ SashForm form = new SashForm(this, SWT.HORIZONTAL);
+
+ leftPannelCmp = new Composite(form, SWT.NO_FOCUS);
+ // Bookmarks are still static
+ populateBookmarks(leftPannelCmp);
+
+ Composite centerCmp = new Composite(form, SWT.BORDER | SWT.NO_FOCUS);
+ createDisplay(centerCmp);
+
+ rightPannelCmp = new Composite(form, SWT.NO_FOCUS);
+
+ form.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ form.setWeights(new int[] { 15, 40, 20 });
+ }
+
+ void refresh() {
+ modifyFilter(false);
+ // also refresh bookmarks and groups
+ }
+
+ private void createDisplay(final Composite parent) {
+ parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
+
+ // top filter
+ filterCmp = new Composite(parent, SWT.NO_FOCUS);
+ filterCmp.setLayoutData(EclipseUiUtils.fillWidth());
+ addFilterPanel(filterCmp);
+
+ // Main display
+ directoryDisplayViewer = new FsTableViewer(parent, SWT.MULTI);
+ List<ColumnDefinition> colDefs = new ArrayList<>();
+ colDefs.add(new ColumnDefinition(new FileIconNameLabelProvider(), "Name", 250));
+ colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_SIZE), "Size", 100));
+ colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_TYPE), "Type", 150));
+ colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_LAST_MODIFIED),
+ "Last modified", 400));
+ final Table table = directoryDisplayViewer.configureDefaultTable(colDefs);
+ table.setLayoutData(EclipseUiUtils.fillAll());
+
+ // table.addKeyListener(new KeyListener() {
+ // private static final long serialVersionUID = -8083424284436715709L;
+ //
+ // @Override
+ // public void keyReleased(KeyEvent e) {
+ // }
+ //
+ // @Override
+ // public void keyPressed(KeyEvent e) {
+ // if (log.isDebugEnabled())
+ // log.debug("Key event received: " + e.keyCode);
+ // IStructuredSelection selection = (IStructuredSelection)
+ // directoryDisplayViewer.getSelection();
+ // Path selected = null;
+ // if (!selection.isEmpty())
+ // selected = ((Path) selection.getFirstElement());
+ // if (e.keyCode == SWT.CR) {
+ // if (!Files.isDirectory(selected))
+ // return;
+ // if (selected != null) {
+ // currDisplayedFolder = selected;
+ // directoryDisplayViewer.setInput(currDisplayedFolder, "*");
+ // }
+ // } else if (e.keyCode == SWT.BS) {
+ // currDisplayedFolder = currDisplayedFolder.getParent();
+ // directoryDisplayViewer.setInput(currDisplayedFolder, "*");
+ // directoryDisplayViewer.getTable().setFocus();
+ // }
+ // }
+ // });
+
+ directoryDisplayViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+
+ @Override
+ public void selectionChanged(SelectionChangedEvent event) {
+ IStructuredSelection selection = (IStructuredSelection) directoryDisplayViewer.getSelection();
+ Path selected = null;
+ if (selection.isEmpty())
+ setSelected(null);
+ else
+ selected = ((Path) selection.getFirstElement());
+ if (selected != null) {
+ // TODO manage multiple selection
+ setSelected(selected);
+ }
+ }
+ });
+
+ directoryDisplayViewer.addDoubleClickListener(new IDoubleClickListener() {
+ @Override
+ public void doubleClick(DoubleClickEvent event) {
+ IStructuredSelection selection = (IStructuredSelection) directoryDisplayViewer.getSelection();
+ Path selected = null;
+ if (!selection.isEmpty())
+ selected = ((Path) selection.getFirstElement());
+ if (selected != null) {
+ if (!Files.isDirectory(selected))
+ return;
+ setInput(selected);
+ }
+ }
+ });
+
+ // The context menu
+ contextMenu = new FsContextMenu(this);
+
+ table.addMouseListener(new MouseAdapter() {
+ private static final long serialVersionUID = 6737579410648595940L;
+
+ @Override
+ public void mouseDown(MouseEvent e) {
+ if (e.button == 3) {
+ // contextMenu.setCurrFolderPath(currDisplayedFolder);
+ contextMenu.show(table, new Point(e.x, e.y), currDisplayedFolder);
+ }
+ }
+ });
+ }
+
+ private void addPathElementBtn(Path path) {
+ Button elemBtn = new Button(filterCmp, SWT.PUSH);
+ elemBtn.setText(path.getFileName().toString() + " >> ");
+ CmsUtils.style(elemBtn, FsStyles.BREAD_CRUMB_BTN);
+ elemBtn.addSelectionListener(new SelectionAdapter() {
+ private static final long serialVersionUID = -4103695476023480651L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ setInput(path);
+ }
+ });
+ }
+
+ public void setInput(Path path) {
+ if (path.equals(currDisplayedFolder))
+ return;
+ currDisplayedFolder = path;
+
+ Path diff = initialPath.relativize(currDisplayedFolder);
+
+ for (Control child : filterCmp.getChildren())
+ if (!child.equals(filterTxt))
+ child.dispose();
+
+ addPathElementBtn(initialPath);
+ Path currTarget = initialPath;
+ if (!diff.toString().equals(""))
+ for (Path pathElem : diff) {
+ currTarget = currTarget.resolve(pathElem);
+ addPathElementBtn(currTarget);
+ }
+
+ filterTxt.setText("");
+ filterTxt.moveBelow(null);
+ setSelected(null);
+ filterCmp.getParent().layout(true, true);
+ }
+
+ private void setSelected(Path path) {
+ currSelected = path;
+ setOverviewInput(path);
+ }
+
+ private String getCurrentHomePath() {
+ // FIXME dirty retrieval of the default home path
+ String id = UserAdminUtils.getUserLocalId(CurrentUser.getUsername());
+ String homepath = "/home/" + JcrUtils.firstCharsToPath(id, 2) + "/" + id;
+ // FIXME also insure the file subfolder is here
+ try {
+ Session session = currentBaseContext.getSession();
+ Node home = session.getNode(homepath);
+ Node fileParent = JcrUtils.mkdirs(home, FS_FILES, NodeType.NT_FOLDER);
+ fileParent.addMixin(NodeType.MIX_TITLE);
+ fileParent.setProperty(Property.JCR_TITLE, "My Files");
+ if (session.hasPendingChanges())
+ session.save();
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot initialise parent node for My files at " + homepath, e);
+ }
+ return homepath;
+ }
+
+ private final static String NODE_PREFIX = "node://";
+ private final static String FS_FILES = "files";
+
+ protected Path getMyFilesPath() {
+ String currHomeUriStr = NODE_PREFIX + getCurrentHomePath() + "/" + FS_FILES;
+ try {
+ URI uri = new URI(currHomeUriStr);
+ FileSystem fileSystem = nodeFileSystemProvider.getFileSystem(uri);
+ if (fileSystem == null) {
+ PrivilegedExceptionAction<FileSystem> pea = new PrivilegedExceptionAction<FileSystem>() {
+ @Override
+ public FileSystem run() throws Exception {
+ return nodeFileSystemProvider.newFileSystem(uri, null);
+ }
+
+ };
+ fileSystem = CurrentUser.doAs(pea);
+ }
+ return fileSystem.getPath(getCurrentHomePath() + "/" + FS_FILES);
+ } catch (URISyntaxException | PrivilegedActionException e) {
+ throw new RuntimeException("unable to initialise home file system for " + currHomeUriStr, e);
+ }
+ // return Paths.get(System.getProperty("user.dir"));
+ }
+
+ private Path[] getMyGroupsFilesPath() {
+ // TODO
+ Path[] paths = { Paths.get(System.getProperty("user.dir")), Paths.get("/tmp") };
+ return paths;
+ }
+
+ private Path[] getMyBookmarks() {
+ // TODO
+ Path[] paths = { Paths.get(System.getProperty("user.dir")), Paths.get("/tmp"), Paths.get("/opt") };
+ return paths;
+ }
+
+ public Viewer getViewer() {
+ return directoryDisplayViewer;
+ }
+
+ private void populateBookmarks(Composite parent) {
+ CmsUtils.clear(parent);
+ parent.setLayout(new GridLayout());
+ ISelectionChangedListener selList = new BookmarksSelChangeListener();
+
+ FsTableViewer homeViewer = new FsTableViewer(parent, SWT.SINGLE | SWT.NO_SCROLL);
+ Table table = homeViewer.configureDefaultSingleColumnTable(bookmarkColWith);
+ GridData gd = EclipseUiUtils.fillWidth();
+ gd.horizontalIndent = 10;
+ table.setLayoutData(gd);
+ homeViewer.addSelectionChangedListener(selList);
+ homeViewer.setPathsInput(getMyFilesPath());
+
+ appendTitle(parent, "Shared files");
+ FsTableViewer groupsViewer = new FsTableViewer(parent, SWT.SINGLE | SWT.NO_SCROLL);
+ table = groupsViewer.configureDefaultSingleColumnTable(bookmarkColWith);
+ gd = EclipseUiUtils.fillWidth();
+ gd.horizontalIndent = 10;
+ table.setLayoutData(gd);
+ groupsViewer.addSelectionChangedListener(selList);
+ groupsViewer.setPathsInput(getMyGroupsFilesPath());
+
+ appendTitle(parent, "My bookmarks");
+ FsTableViewer bookmarksViewer = new FsTableViewer(parent, SWT.SINGLE | SWT.NO_SCROLL);
+ table = bookmarksViewer.configureDefaultSingleColumnTable(bookmarkColWith);
+ gd = EclipseUiUtils.fillWidth();
+ gd.horizontalIndent = 10;
+ table.setLayoutData(gd);
+ bookmarksViewer.addSelectionChangedListener(selList);
+ bookmarksViewer.setPathsInput(getMyBookmarks());
+ }
+
+ /**
+ * Recreates the content of the box that displays information about the
+ * current selected Path.
+ */
+ private void setOverviewInput(Path path) {
+ try {
+ EclipseUiUtils.clear(rightPannelCmp);
+ rightPannelCmp.setLayout(new GridLayout());
+ if (path != null) {
+ // if (isImg(context)) {
+ // EditableImage image = new Img(parent, RIGHT, context,
+ // imageWidth);
+ // image.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER,
+ // true, false,
+ // 2, 1));
+ // }
+
+ Label contextL = new Label(rightPannelCmp, SWT.NONE);
+ contextL.setText(path.getFileName().toString());
+ contextL.setFont(EclipseUiUtils.getBoldFont(rightPannelCmp));
+ addProperty(rightPannelCmp, "Last modified", Files.getLastModifiedTime(path).toString());
+ // addProperty(rightPannelCmp, "Owner",
+ // Files.getOwner(path).getName());
+ if (Files.isDirectory(path)) {
+ addProperty(rightPannelCmp, "Type", "Folder");
+ } else {
+ String mimeType = Files.probeContentType(path);
+ if (EclipseUiUtils.isEmpty(mimeType))
+ mimeType = "<i>Unknown</i>";
+ addProperty(rightPannelCmp, "Type", mimeType);
+ addProperty(rightPannelCmp, "Size", FsUiUtils.humanReadableByteCount(Files.size(path), false));
+ }
+ }
+ rightPannelCmp.layout(true, true);
+ } catch (IOException e) {
+ throw new CmsException("Cannot display details for " + path.toString(), e);
+ }
+ }
+
+ private void addFilterPanel(Composite parent) {
+ RowLayout rl = new RowLayout(SWT.HORIZONTAL);
+ rl.wrap = true;
+ parent.setLayout(rl);
+ // parent.setLayout(EclipseUiUtils.noSpaceGridLayout(new GridLayout(2,
+ // false)));
+
+ filterTxt = new Text(parent, SWT.SEARCH | SWT.ICON_CANCEL);
+ filterTxt.setMessage("Search current folder");
+ filterTxt.setLayoutData(new RowData(250, SWT.DEFAULT));
+ filterTxt.addModifyListener(new ModifyListener() {
+ private static final long serialVersionUID = 1L;
+
+ public void modifyText(ModifyEvent event) {
+ modifyFilter(false);
+ }
+ });
+ filterTxt.addKeyListener(new KeyListener() {
+ private static final long serialVersionUID = 2533535233583035527L;
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ // boolean shiftPressed = (e.stateMask & SWT.SHIFT) != 0;
+ // // boolean altPressed = (e.stateMask & SWT.ALT) != 0;
+ // FilterEntitiesVirtualTable currTable = null;
+ // if (currEdited != null) {
+ // FilterEntitiesVirtualTable table =
+ // browserCols.get(currEdited);
+ // if (table != null && !table.isDisposed())
+ // currTable = table;
+ // }
+ //
+ // if (e.keyCode == SWT.ARROW_DOWN)
+ // currTable.setFocus();
+ // else if (e.keyCode == SWT.BS) {
+ // if (filterTxt.getText().equals("")
+ // && !(currEdited.getNameCount() == 1 ||
+ // currEdited.equals(initialPath))) {
+ // Path oldEdited = currEdited;
+ // Path parentPath = currEdited.getParent();
+ // setEdited(parentPath);
+ // if (browserCols.containsKey(parentPath))
+ // browserCols.get(parentPath).setSelected(oldEdited);
+ // filterTxt.setFocus();
+ // e.doit = false;
+ // }
+ // } else if (e.keyCode == SWT.TAB && !shiftPressed) {
+ // Path uniqueChild = getOnlyChild(currEdited,
+ // filterTxt.getText());
+ // if (uniqueChild != null) {
+ // // Highlight the unique chosen child
+ // currTable.setSelected(uniqueChild);
+ // setEdited(uniqueChild);
+ // }
+ // filterTxt.setFocus();
+ // e.doit = false;
+ // }
+ }
+ });
+ }
+
+ private Path getOnlyChild(Path parent, String filter) {
+ try (DirectoryStream<Path> stream = Files.newDirectoryStream(currDisplayedFolder, filter + "*")) {
+ Path uniqueChild = null;
+ boolean moreThanOne = false;
+ loop: for (Path entry : stream) {
+ if (uniqueChild == null) {
+ uniqueChild = entry;
+ } else {
+ moreThanOne = true;
+ break loop;
+ }
+ }
+ if (!moreThanOne)
+ return uniqueChild;
+ return null;
+ } catch (IOException ioe) {
+ throw new CmsException(
+ "Unable to determine unique child existence and get it under " + parent + " with filter " + filter,
+ ioe);
+ }
+ }
+
+ private void modifyFilter(boolean fromOutside) {
+ if (!fromOutside)
+ if (currDisplayedFolder != null) {
+ String filter = filterTxt.getText() + "*";
+ directoryDisplayViewer.setInput(currDisplayedFolder, filter);
+ }
+ }
+
+ private class BookmarksSelChangeListener implements ISelectionChangedListener {
+
+ @Override
+ public void selectionChanged(SelectionChangedEvent event) {
+ IStructuredSelection selection = (IStructuredSelection) event.getSelection();
+ if (selection.isEmpty())
+ return;
+ else {
+ Path newSelected = (Path) selection.getFirstElement();
+ if (newSelected.equals(currDisplayedFolder) && newSelected.equals(initialPath))
+ return;
+ initialPath = newSelected;
+ setInput(newSelected);
+ }
+ }
+ }
+
+ // Simplify UI implementation
+ private void addProperty(Composite parent, String propName, String value) {
+ Label contextL = new Label(parent, SWT.NONE);
+ contextL.setText(propName + ": " + value);
+ }
+
+ private Label appendTitle(Composite parent, String value) {
+ Label titleLbl = new Label(parent, SWT.NONE);
+ titleLbl.setText(value);
+ titleLbl.setFont(EclipseUiUtils.getBoldFont(parent));
+ GridData gd = EclipseUiUtils.fillWidth();
+ gd.horizontalIndent = 5;
+ gd.verticalIndent = 5;
+ titleLbl.setLayoutData(gd);
+ return titleLbl;
+ }
+}
--- /dev/null
+package org.argeo.cms.fs;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.util.CmsUtils;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.eclipse.ui.dialogs.SingleValue;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.ShellEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+
+/** Generic popup context menu to manage NIO Path in a Viewer. */
+public class FsContextMenu extends Shell {
+ private static final long serialVersionUID = -9120261153509855795L;
+
+ private final static Log log = LogFactory.getLog(FsContextMenu.class);
+
+ // Default known actions
+ public final static String ACTION_ID_CREATE_FOLDER = "createFolder";
+ public final static String ACTION_ID_BOOKMARK_FOLDER = "bookmarkFolder";
+ public final static String ACTION_ID_SHARE_FOLDER = "shareFolder";
+ public final static String ACTION_ID_DOWNLOAD_FOLDER = "downloadFolder";
+ public final static String ACTION_ID_DELETE = "delete";
+ public final static String ACTION_ID_UPLOAD_FILE = "uploadFiles";
+ public final static String ACTION_ID_OPEN = "open";
+
+ // TODO
+ private final static String cmBox = "contextMenu_box";
+ private final static String button_suffix = "_btn";
+
+ // Local context
+ private final CmsFsBrowser browser;
+ // private final Viewer viewer;
+ private final static String KEY_ACTION_ID = "actionId";
+ private final static String[] DEFAULT_ACTIONS = { ACTION_ID_CREATE_FOLDER, ACTION_ID_BOOKMARK_FOLDER,
+ ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER, ACTION_ID_DELETE, ACTION_ID_UPLOAD_FILE,
+ ACTION_ID_OPEN };
+ private Map<String, Button> actionButtons = new HashMap<String, Button>();
+
+ private Path currFolderPath;
+
+ public FsContextMenu(CmsFsBrowser browser) { // Viewer viewer, Display
+ // display) {
+ super(browser.getDisplay(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
+ this.browser = browser;
+ setLayout(EclipseUiUtils.noSpaceGridLayout());
+
+ Composite boxCmp = new Composite(this, SWT.NO_FOCUS | SWT.BORDER);
+ boxCmp.setLayout(EclipseUiUtils.noSpaceGridLayout());
+ CmsUtils.style(boxCmp, cmBox);
+ createContextMenu(boxCmp);
+
+ addShellListener(new ActionsShellListener());
+ }
+
+ protected void createContextMenu(Composite boxCmp) {
+ ActionsSelListener asl = new ActionsSelListener();
+ for (String actionId : DEFAULT_ACTIONS) {
+ Button btn = new Button(boxCmp, SWT.FLAT | SWT.PUSH | SWT.LEAD);
+ btn.setText(getLabel(actionId));
+ btn.setLayoutData(EclipseUiUtils.fillWidth());
+ CmsUtils.markup(btn);
+ CmsUtils.style(btn, actionId + button_suffix);
+ btn.setData(KEY_ACTION_ID, actionId);
+ btn.addSelectionListener(asl);
+ actionButtons.put(actionId, btn);
+ }
+ }
+
+ protected String getLabel(String actionId) {
+ switch (actionId) {
+ case ACTION_ID_CREATE_FOLDER:
+ return "Create Folder";
+ case ACTION_ID_BOOKMARK_FOLDER:
+ return "Bookmark Folder";
+ case ACTION_ID_SHARE_FOLDER:
+ return "Share Folder";
+ case ACTION_ID_DOWNLOAD_FOLDER:
+ return "Download as zip archive";
+ case ACTION_ID_DELETE:
+ return "Delete";
+ case ACTION_ID_UPLOAD_FILE:
+ return "Upload Files";
+ case ACTION_ID_OPEN:
+ return "Open";
+ default:
+ throw new IllegalArgumentException("Unknown action ID " + actionId);
+ }
+ }
+
+ protected void aboutToShow(Control source, Point location) {
+ IStructuredSelection selection = ((IStructuredSelection) browser.getViewer().getSelection());
+ boolean emptySel = true;
+ boolean multiSel = false;
+ boolean isFolder = true;
+ if (selection != null && !selection.isEmpty()) {
+ emptySel = false;
+ multiSel = selection.size() > 1;
+ if (!multiSel && selection.getFirstElement() instanceof Path) {
+ isFolder = Files.isDirectory((Path) selection.getFirstElement());
+ }
+ }
+ if (emptySel) {
+ setVisible(true, ACTION_ID_CREATE_FOLDER, ACTION_ID_UPLOAD_FILE);
+ setVisible(false, ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER, ACTION_ID_DELETE, ACTION_ID_OPEN,
+ // to be implemented
+ ACTION_ID_BOOKMARK_FOLDER);
+ } else if (multiSel) {
+ setVisible(true, ACTION_ID_CREATE_FOLDER, ACTION_ID_UPLOAD_FILE, ACTION_ID_DELETE);
+ setVisible(false, ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER, ACTION_ID_OPEN,
+ // to be implemented
+ ACTION_ID_BOOKMARK_FOLDER);
+ } else if (isFolder) {
+ setVisible(true, ACTION_ID_CREATE_FOLDER, ACTION_ID_UPLOAD_FILE, ACTION_ID_DELETE);
+ setVisible(false, ACTION_ID_OPEN,
+ // to be implemented
+ ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER, ACTION_ID_BOOKMARK_FOLDER);
+ } else {
+ setVisible(true, ACTION_ID_CREATE_FOLDER, ACTION_ID_UPLOAD_FILE, ACTION_ID_OPEN, ACTION_ID_DELETE);
+ setVisible(false, ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER,
+ // to be implemented
+ ACTION_ID_BOOKMARK_FOLDER);
+ }
+ }
+
+ private void setVisible(boolean visible, String... buttonIds) {
+ for (String id : buttonIds) {
+ Button button = actionButtons.get(id);
+ button.setVisible(visible);
+ GridData gd = (GridData) button.getLayoutData();
+ gd.heightHint = visible ? SWT.DEFAULT : 0;
+ }
+ }
+
+ public void show(Control source, Point location, Path currFolderPath) {
+ if (isVisible())
+ setVisible(false);
+ // TODO find a better way to retrieve the parent path (cannot be deduced
+ // from table content because it will fail on an empty folder)
+ this.currFolderPath = currFolderPath;
+ aboutToShow(source, location);
+ pack();
+ layout();
+ if (source instanceof Control)
+ setLocation(((Control) source).toDisplay(location.x, location.y));
+ open();
+ }
+
+ class StyleButton extends Label {
+ private static final long serialVersionUID = 7731102609123946115L;
+
+ public StyleButton(Composite parent, int swtStyle) {
+ super(parent, swtStyle);
+ }
+
+ }
+
+ // class ActionsMouseListener extends MouseAdapter {
+ // private static final long serialVersionUID = -1041871937815812149L;
+ //
+ // @Override
+ // public void mouseDown(MouseEvent e) {
+ // Object eventSource = e.getSource();
+ // if (e.button == 1) {
+ // if (eventSource instanceof Button) {
+ // Button pressedBtn = (Button) eventSource;
+ // String actionId = (String) pressedBtn.getData(KEY_ACTION_ID);
+ // switch (actionId) {
+ // case ACTION_ID_CREATE_FOLDER:
+ // createFolder();
+ // break;
+ // case ACTION_ID_DELETE:
+ // deleteItems();
+ // break;
+ // default:
+ // throw new IllegalArgumentException("Unimplemented action " + actionId);
+ // // case ACTION_ID_SHARE_FOLDER:
+ // // return "Share Folder";
+ // // case ACTION_ID_DOWNLOAD_FOLDER:
+ // // return "Download as zip archive";
+ // // case ACTION_ID_UPLOAD_FILE:
+ // // return "Upload Files";
+ // // case ACTION_ID_OPEN:
+ // // return "Open";
+ // }
+ // }
+ // }
+ // viewer.getControl().setFocus();
+ // // setVisible(false);
+ // }
+ // }
+
+ class ActionsSelListener extends SelectionAdapter {
+ private static final long serialVersionUID = -1041871937815812149L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ Object eventSource = e.getSource();
+ if (eventSource instanceof Button) {
+ Button pressedBtn = (Button) eventSource;
+ String actionId = (String) pressedBtn.getData(KEY_ACTION_ID);
+ switch (actionId) {
+ case ACTION_ID_CREATE_FOLDER:
+ createFolder();
+ break;
+ case ACTION_ID_DELETE:
+ deleteItems();
+ break;
+ case ACTION_ID_OPEN:
+ openFile();
+ break;
+ case ACTION_ID_UPLOAD_FILE:
+ uploadFiles();
+ break;
+ default:
+ throw new IllegalArgumentException("Unimplemented action " + actionId);
+ // case ACTION_ID_SHARE_FOLDER:
+ // return "Share Folder";
+ // case ACTION_ID_DOWNLOAD_FOLDER:
+ // return "Download as zip archive";
+ // case ACTION_ID_OPEN:
+ // return "Open";
+ }
+ }
+ browser.setFocus();
+ // viewer.getControl().setFocus();
+ // setVisible(false);
+
+ }
+ }
+
+ class ActionsShellListener extends org.eclipse.swt.events.ShellAdapter {
+ private static final long serialVersionUID = -5092341449523150827L;
+
+ @Override
+ public void shellDeactivated(ShellEvent e) {
+ setVisible(false);
+ }
+ }
+
+ private void openFile() {
+ log.warn("Implement single sourced, workbench independant \"Open File\" action");
+ }
+
+ private void deleteItems() {
+ IStructuredSelection selection = ((IStructuredSelection) browser.getViewer().getSelection());
+ if (selection.isEmpty())
+ return;
+
+ StringBuilder builder = new StringBuilder();
+ @SuppressWarnings("unchecked")
+ Iterator<Object> iterator = selection.iterator();
+ List<Path> paths = new ArrayList<>();
+
+ while (iterator.hasNext()) {
+ Path path = (Path) iterator.next();
+ builder.append(path.getFileName() + ", ");
+ paths.add(path);
+ }
+ String msg = "You are about to delete following elements: " + builder.substring(0, builder.length() - 2)
+ + ". Are you sure?";
+ if (MessageDialog.openConfirm(this, "Confirm deletion", msg)) {
+ for (Path path : paths) {
+ try {
+ // Might have already been deleted if we are in a tree
+ Files.deleteIfExists(path);
+ } catch (IOException e) {
+ throw new CmsException("Cannot delete path " + path, e);
+ }
+ }
+ browser.refresh();
+ }
+ }
+
+ private void createFolder() {
+ String msg = "Please provide a name.";
+ String name = SingleValue.ask("Create folder", msg);
+ // TODO enhance check of name validity
+ if (EclipseUiUtils.notEmpty(name)) {
+ try {
+ Path child = currFolderPath.resolve(name);
+ if (Files.exists(child))
+ throw new CmsException("An item with name " + name + " already exists at "
+ + currFolderPath.toString() + ", cannot create");
+ else
+ Files.createDirectories(child);
+ browser.refresh();
+ } catch (IOException e) {
+ throw new CmsException("Cannot create folder " + name + " at " + currFolderPath.toString(), e);
+ }
+ }
+ }
+
+ private void uploadFiles() {
+ try {
+ FileDialog dialog = new FileDialog(browser.getShell(), SWT.MULTI);
+ dialog.setText("Choose one or more files to upload");
+
+ if (EclipseUiUtils.notEmpty(dialog.open())) {
+ String[] names = dialog.getFileNames();
+ // Workaround small differences between RAP and RCP
+ // 1. returned names are absolute path on RAP and
+ // relative in RCP
+ // 2. in RCP we must use getFilterPath that does not
+ // exists on RAP
+ Method filterMethod = null;
+ Path parPath = null;
+ try {
+ filterMethod = dialog.getClass().getDeclaredMethod("getFilterPath");
+ String filterPath = (String) filterMethod.invoke(dialog);
+ parPath = Paths.get(filterPath);
+ } catch (NoSuchMethodException nsme) { // RAP
+ }
+ if (names.length == 0)
+ return;
+ else {
+ loop: for (String name : names) {
+ Path tmpPath = Paths.get(name);
+ if (parPath != null)
+ tmpPath = parPath.resolve(tmpPath);
+ if (Files.exists(tmpPath)) {
+ URI uri = tmpPath.toUri();
+ String uriStr = uri.toString();
+
+ if (Files.isDirectory(tmpPath)) {
+ MessageDialog.openError(browser.getShell(), "Unimplemented directory import",
+ "Upload of directories in the system is not yet implemented");
+ continue loop;
+ }
+ Path targetPath = currFolderPath.resolve(tmpPath.getFileName().toString());
+ InputStream in = null;
+ try {
+ in = new ByteArrayInputStream(Files.readAllBytes(tmpPath));
+ Files.copy(in, targetPath);
+ Files.delete(tmpPath);
+ } finally {
+ IOUtils.closeQuietly(in);
+ }
+ if (log.isDebugEnabled())
+ log.debug("copied uploaded file " + uriStr + " to " + targetPath.toString());
+ } else {
+ String msg = "Cannot copy tmp file from " + tmpPath.toString();
+ if (parPath != null)
+ msg += "\nPlease remember that file upload fails when choosing files from the \"Recently Used\" bookmarks on some OS";
+ MessageDialog.openError(browser.getShell(), "Missing file", msg);
+ continue loop;
+ }
+ }
+ browser.refresh();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ MessageDialog.openError(getShell(), "Upload has failed", "Cannot import files to " + currFolderPath);
+ }
+ }
+
+ public void setCurrFolderPath(Path currFolderPath) {
+ this.currFolderPath = currFolderPath;
+ }
+}