1 package org
.argeo
.cms
.ui
.fs
;
3 import java
.io
.ByteArrayInputStream
;
4 import java
.io
.IOException
;
5 import java
.io
.InputStream
;
6 import java
.lang
.reflect
.Method
;
8 import java
.nio
.file
.Files
;
9 import java
.nio
.file
.Path
;
10 import java
.nio
.file
.Paths
;
11 import java
.util
.ArrayList
;
12 import java
.util
.HashMap
;
13 import java
.util
.Iterator
;
14 import java
.util
.List
;
17 import org
.apache
.commons
.io
.IOUtils
;
18 import org
.apache
.commons
.logging
.Log
;
19 import org
.apache
.commons
.logging
.LogFactory
;
20 import org
.argeo
.cms
.CmsException
;
21 import org
.argeo
.cms
.ui
.util
.CmsUiUtils
;
22 import org
.argeo
.eclipse
.ui
.EclipseUiUtils
;
23 import org
.argeo
.eclipse
.ui
.dialogs
.SingleValue
;
24 import org
.eclipse
.jface
.dialogs
.MessageDialog
;
25 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
26 import org
.eclipse
.swt
.SWT
;
27 import org
.eclipse
.swt
.events
.SelectionAdapter
;
28 import org
.eclipse
.swt
.events
.SelectionEvent
;
29 import org
.eclipse
.swt
.events
.ShellEvent
;
30 import org
.eclipse
.swt
.graphics
.Point
;
31 import org
.eclipse
.swt
.layout
.GridData
;
32 import org
.eclipse
.swt
.widgets
.Button
;
33 import org
.eclipse
.swt
.widgets
.Composite
;
34 import org
.eclipse
.swt
.widgets
.Control
;
35 import org
.eclipse
.swt
.widgets
.FileDialog
;
36 import org
.eclipse
.swt
.widgets
.Label
;
37 import org
.eclipse
.swt
.widgets
.Shell
;
39 /** Generic popup context menu to manage NIO Path in a Viewer. */
40 public class FsContextMenu
extends Shell
{
41 private static final long serialVersionUID
= -9120261153509855795L;
43 private final static Log log
= LogFactory
.getLog(FsContextMenu
.class);
45 // Default known actions
46 public final static String ACTION_ID_CREATE_FOLDER
= "createFolder";
47 public final static String ACTION_ID_BOOKMARK_FOLDER
= "bookmarkFolder";
48 public final static String ACTION_ID_SHARE_FOLDER
= "shareFolder";
49 public final static String ACTION_ID_DOWNLOAD_FOLDER
= "downloadFolder";
50 public final static String ACTION_ID_DELETE
= "delete";
51 public final static String ACTION_ID_UPLOAD_FILE
= "uploadFiles";
52 public final static String ACTION_ID_OPEN
= "open";
55 private final CmsFsBrowser browser
;
56 // private final Viewer viewer;
57 private final static String KEY_ACTION_ID
= "actionId";
58 private final static String
[] DEFAULT_ACTIONS
= { ACTION_ID_CREATE_FOLDER
, ACTION_ID_BOOKMARK_FOLDER
,
59 ACTION_ID_SHARE_FOLDER
, ACTION_ID_DOWNLOAD_FOLDER
, ACTION_ID_DELETE
, ACTION_ID_UPLOAD_FILE
,
61 private Map
<String
, Button
> actionButtons
= new HashMap
<String
, Button
>();
63 private Path currFolderPath
;
65 public FsContextMenu(CmsFsBrowser browser
) { // Viewer viewer, Display
67 super(browser
.getDisplay(), SWT
.NO_TRIM
| SWT
.BORDER
| SWT
.ON_TOP
);
68 this.browser
= browser
;
69 setLayout(EclipseUiUtils
.noSpaceGridLayout());
71 Composite boxCmp
= new Composite(this, SWT
.NO_FOCUS
| SWT
.BORDER
);
72 boxCmp
.setLayout(EclipseUiUtils
.noSpaceGridLayout());
73 CmsUiUtils
.style(boxCmp
, FsStyles
.CONTEXT_MENU_BOX
);
74 createContextMenu(boxCmp
);
76 addShellListener(new ActionsShellListener());
79 protected void createContextMenu(Composite boxCmp
) {
80 ActionsSelListener asl
= new ActionsSelListener();
81 for (String actionId
: DEFAULT_ACTIONS
) {
82 Button btn
= new Button(boxCmp
, SWT
.FLAT
| SWT
.PUSH
| SWT
.LEAD
);
83 btn
.setText(getLabel(actionId
));
84 btn
.setLayoutData(EclipseUiUtils
.fillWidth());
85 CmsUiUtils
.markup(btn
);
86 CmsUiUtils
.style(btn
, actionId
+ FsStyles
.BUTTON_SUFFIX
);
87 btn
.setData(KEY_ACTION_ID
, actionId
);
88 btn
.addSelectionListener(asl
);
89 actionButtons
.put(actionId
, btn
);
93 protected String
getLabel(String actionId
) {
95 case ACTION_ID_CREATE_FOLDER
:
96 return "Create Folder";
97 case ACTION_ID_BOOKMARK_FOLDER
:
98 return "Bookmark Folder";
99 case ACTION_ID_SHARE_FOLDER
:
100 return "Share Folder";
101 case ACTION_ID_DOWNLOAD_FOLDER
:
102 return "Download as zip archive";
103 case ACTION_ID_DELETE
:
105 case ACTION_ID_UPLOAD_FILE
:
106 return "Upload Files";
110 throw new IllegalArgumentException("Unknown action ID " + actionId
);
114 protected void aboutToShow(Control source
, Point location
) {
115 IStructuredSelection selection
= ((IStructuredSelection
) browser
.getViewer().getSelection());
116 boolean emptySel
= true;
117 boolean multiSel
= false;
118 boolean isFolder
= true;
119 if (selection
!= null && !selection
.isEmpty()) {
121 multiSel
= selection
.size() > 1;
122 if (!multiSel
&& selection
.getFirstElement() instanceof Path
) {
123 isFolder
= Files
.isDirectory((Path
) selection
.getFirstElement());
127 setVisible(true, ACTION_ID_CREATE_FOLDER
, ACTION_ID_UPLOAD_FILE
);
128 setVisible(false, ACTION_ID_SHARE_FOLDER
, ACTION_ID_DOWNLOAD_FOLDER
, ACTION_ID_DELETE
, ACTION_ID_OPEN
,
130 ACTION_ID_BOOKMARK_FOLDER
);
131 } else if (multiSel
) {
132 setVisible(true, ACTION_ID_CREATE_FOLDER
, ACTION_ID_UPLOAD_FILE
, ACTION_ID_DELETE
);
133 setVisible(false, ACTION_ID_SHARE_FOLDER
, ACTION_ID_DOWNLOAD_FOLDER
, ACTION_ID_OPEN
,
135 ACTION_ID_BOOKMARK_FOLDER
);
136 } else if (isFolder
) {
137 setVisible(true, ACTION_ID_CREATE_FOLDER
, ACTION_ID_UPLOAD_FILE
, ACTION_ID_DELETE
);
138 setVisible(false, ACTION_ID_OPEN
,
140 ACTION_ID_SHARE_FOLDER
, ACTION_ID_DOWNLOAD_FOLDER
, ACTION_ID_BOOKMARK_FOLDER
);
142 setVisible(true, ACTION_ID_CREATE_FOLDER
, ACTION_ID_UPLOAD_FILE
, ACTION_ID_OPEN
, ACTION_ID_DELETE
);
143 setVisible(false, ACTION_ID_SHARE_FOLDER
, ACTION_ID_DOWNLOAD_FOLDER
,
145 ACTION_ID_BOOKMARK_FOLDER
);
149 private void setVisible(boolean visible
, String
... buttonIds
) {
150 for (String id
: buttonIds
) {
151 Button button
= actionButtons
.get(id
);
152 button
.setVisible(visible
);
153 GridData gd
= (GridData
) button
.getLayoutData();
154 gd
.heightHint
= visible ? SWT
.DEFAULT
: 0;
158 public void show(Control source
, Point location
, Path currFolderPath
) {
161 // TODO find a better way to retrieve the parent path (cannot be deduced
162 // from table content because it will fail on an empty folder)
163 this.currFolderPath
= currFolderPath
;
164 aboutToShow(source
, location
);
167 if (source
instanceof Control
)
168 setLocation(((Control
) source
).toDisplay(location
.x
, location
.y
));
172 class StyleButton
extends Label
{
173 private static final long serialVersionUID
= 7731102609123946115L;
175 public StyleButton(Composite parent
, int swtStyle
) {
176 super(parent
, swtStyle
);
181 // class ActionsMouseListener extends MouseAdapter {
182 // private static final long serialVersionUID = -1041871937815812149L;
185 // public void mouseDown(MouseEvent e) {
186 // Object eventSource = e.getSource();
187 // if (e.button == 1) {
188 // if (eventSource instanceof Button) {
189 // Button pressedBtn = (Button) eventSource;
190 // String actionId = (String) pressedBtn.getData(KEY_ACTION_ID);
191 // switch (actionId) {
192 // case ACTION_ID_CREATE_FOLDER:
195 // case ACTION_ID_DELETE:
199 // throw new IllegalArgumentException("Unimplemented action " + actionId);
200 // // case ACTION_ID_SHARE_FOLDER:
201 // // return "Share Folder";
202 // // case ACTION_ID_DOWNLOAD_FOLDER:
203 // // return "Download as zip archive";
204 // // case ACTION_ID_UPLOAD_FILE:
205 // // return "Upload Files";
206 // // case ACTION_ID_OPEN:
211 // viewer.getControl().setFocus();
212 // // setVisible(false);
216 class ActionsSelListener
extends SelectionAdapter
{
217 private static final long serialVersionUID
= -1041871937815812149L;
220 public void widgetSelected(SelectionEvent e
) {
221 Object eventSource
= e
.getSource();
222 if (eventSource
instanceof Button
) {
223 Button pressedBtn
= (Button
) eventSource
;
224 String actionId
= (String
) pressedBtn
.getData(KEY_ACTION_ID
);
226 case ACTION_ID_CREATE_FOLDER
:
229 case ACTION_ID_DELETE
:
235 case ACTION_ID_UPLOAD_FILE
:
239 throw new IllegalArgumentException("Unimplemented action " + actionId
);
240 // case ACTION_ID_SHARE_FOLDER:
241 // return "Share Folder";
242 // case ACTION_ID_DOWNLOAD_FOLDER:
243 // return "Download as zip archive";
244 // case ACTION_ID_OPEN:
249 // viewer.getControl().setFocus();
250 // setVisible(false);
255 class ActionsShellListener
extends org
.eclipse
.swt
.events
.ShellAdapter
{
256 private static final long serialVersionUID
= -5092341449523150827L;
259 public void shellDeactivated(ShellEvent e
) {
264 private void openFile() {
265 log
.warn("Implement single sourced, workbench independant \"Open File\" action");
268 private void deleteItems() {
269 IStructuredSelection selection
= ((IStructuredSelection
) browser
.getViewer().getSelection());
270 if (selection
.isEmpty())
273 StringBuilder builder
= new StringBuilder();
274 @SuppressWarnings("unchecked")
275 Iterator
<Object
> iterator
= selection
.iterator();
276 List
<Path
> paths
= new ArrayList
<>();
278 while (iterator
.hasNext()) {
279 Path path
= (Path
) iterator
.next();
280 builder
.append(path
.getFileName() + ", ");
283 String msg
= "You are about to delete following elements: " + builder
.substring(0, builder
.length() - 2)
285 if (MessageDialog
.openConfirm(this, "Confirm deletion", msg
)) {
286 for (Path path
: paths
) {
288 // Might have already been deleted if we are in a tree
289 Files
.deleteIfExists(path
);
290 } catch (IOException e
) {
291 throw new CmsException("Cannot delete path " + path
, e
);
298 private void createFolder() {
299 String msg
= "Please provide a name.";
300 String name
= SingleValue
.ask("Create folder", msg
);
301 // TODO enhance check of name validity
302 if (EclipseUiUtils
.notEmpty(name
)) {
304 Path child
= currFolderPath
.resolve(name
);
305 if (Files
.exists(child
))
306 throw new CmsException("An item with name " + name
+ " already exists at "
307 + currFolderPath
.toString() + ", cannot create");
309 Files
.createDirectories(child
);
311 } catch (IOException e
) {
312 throw new CmsException("Cannot create folder " + name
+ " at " + currFolderPath
.toString(), e
);
317 private void uploadFiles() {
319 FileDialog dialog
= new FileDialog(browser
.getShell(), SWT
.MULTI
);
320 dialog
.setText("Choose one or more files to upload");
322 if (EclipseUiUtils
.notEmpty(dialog
.open())) {
323 String
[] names
= dialog
.getFileNames();
324 // Workaround small differences between RAP and RCP
325 // 1. returned names are absolute path on RAP and
327 // 2. in RCP we must use getFilterPath that does not
329 Method filterMethod
= null;
332 filterMethod
= dialog
.getClass().getDeclaredMethod("getFilterPath");
333 String filterPath
= (String
) filterMethod
.invoke(dialog
);
334 parPath
= Paths
.get(filterPath
);
335 } catch (NoSuchMethodException nsme
) { // RAP
337 if (names
.length
== 0)
340 loop
: for (String name
: names
) {
341 Path tmpPath
= Paths
.get(name
);
343 tmpPath
= parPath
.resolve(tmpPath
);
344 if (Files
.exists(tmpPath
)) {
345 URI uri
= tmpPath
.toUri();
346 String uriStr
= uri
.toString();
348 if (Files
.isDirectory(tmpPath
)) {
349 MessageDialog
.openError(browser
.getShell(), "Unimplemented directory import",
350 "Upload of directories in the system is not yet implemented");
353 Path targetPath
= currFolderPath
.resolve(tmpPath
.getFileName().toString());
354 InputStream in
= null;
356 in
= new ByteArrayInputStream(Files
.readAllBytes(tmpPath
));
357 Files
.copy(in
, targetPath
);
358 Files
.delete(tmpPath
);
360 IOUtils
.closeQuietly(in
);
362 if (log
.isDebugEnabled())
363 log
.debug("copied uploaded file " + uriStr
+ " to " + targetPath
.toString());
365 String msg
= "Cannot copy tmp file from " + tmpPath
.toString();
367 msg
+= "\nPlease remember that file upload fails when choosing files from the \"Recently Used\" bookmarks on some OS";
368 MessageDialog
.openError(browser
.getShell(), "Missing file", msg
);
375 } catch (Exception e
) {
377 MessageDialog
.openError(getShell(), "Upload has failed", "Cannot import files to " + currFolderPath
);
381 public void setCurrFolderPath(Path currFolderPath
) {
382 this.currFolderPath
= currFolderPath
;