1 package org
.argeo
.app
.ui
.library
;
3 import java
.io
.IOException
;
4 import java
.io
.InputStream
;
5 import java
.nio
.file
.Files
;
6 import java
.nio
.file
.Path
;
7 import java
.nio
.file
.attribute
.FileTime
;
8 import java
.text
.DateFormat
;
9 import java
.text
.SimpleDateFormat
;
10 import java
.util
.ArrayList
;
11 import java
.util
.Date
;
12 import java
.util
.List
;
14 import javax
.jcr
.Node
;
16 import org
.argeo
.api
.cms
.CmsLog
;
17 import org
.argeo
.cms
.swt
.CmsSwtUtils
;
18 import org
.argeo
.cms
.ui
.fs
.FileDrop
;
19 import org
.argeo
.cms
.ui
.fs
.FsStyles
;
20 import org
.argeo
.eclipse
.ui
.ColumnDefinition
;
21 import org
.argeo
.eclipse
.ui
.EclipseUiUtils
;
22 import org
.argeo
.eclipse
.ui
.fs
.FileIconNameLabelProvider
;
23 import org
.argeo
.eclipse
.ui
.fs
.FsTableViewer
;
24 import org
.argeo
.eclipse
.ui
.fs
.FsUiConstants
;
25 import org
.argeo
.eclipse
.ui
.fs
.FsUiUtils
;
26 import org
.argeo
.eclipse
.ui
.fs
.NioFileLabelProvider
;
27 import org
.argeo
.eclipse
.ui
.fs
.ParentDir
;
28 import org
.eclipse
.jface
.viewers
.DoubleClickEvent
;
29 import org
.eclipse
.jface
.viewers
.IDoubleClickListener
;
30 import org
.eclipse
.jface
.viewers
.ISelectionChangedListener
;
31 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
32 import org
.eclipse
.jface
.viewers
.SelectionChangedEvent
;
33 import org
.eclipse
.jface
.viewers
.Viewer
;
34 import org
.eclipse
.swt
.SWT
;
35 import org
.eclipse
.swt
.custom
.SashForm
;
36 import org
.eclipse
.swt
.events
.KeyEvent
;
37 import org
.eclipse
.swt
.events
.KeyListener
;
38 import org
.eclipse
.swt
.events
.ModifyEvent
;
39 import org
.eclipse
.swt
.events
.ModifyListener
;
40 import org
.eclipse
.swt
.events
.MouseAdapter
;
41 import org
.eclipse
.swt
.events
.MouseEvent
;
42 import org
.eclipse
.swt
.events
.SelectionAdapter
;
43 import org
.eclipse
.swt
.events
.SelectionEvent
;
44 import org
.eclipse
.swt
.graphics
.Point
;
45 import org
.eclipse
.swt
.layout
.GridData
;
46 import org
.eclipse
.swt
.layout
.GridLayout
;
47 import org
.eclipse
.swt
.layout
.RowData
;
48 import org
.eclipse
.swt
.layout
.RowLayout
;
49 import org
.eclipse
.swt
.widgets
.Button
;
50 import org
.eclipse
.swt
.widgets
.Composite
;
51 import org
.eclipse
.swt
.widgets
.Control
;
52 import org
.eclipse
.swt
.widgets
.Label
;
53 import org
.eclipse
.swt
.widgets
.Table
;
54 import org
.eclipse
.swt
.widgets
.Text
;
57 * Default Documents folder composite: a sashForm layout with a simple table in
58 * the middle and an overview at right hand side.
60 public class DocumentsFolderComposite
extends Composite
{
61 private final static CmsLog log
= CmsLog
.getLog(DocumentsFolderComposite
.class);
62 private static final long serialVersionUID
= -40347919096946585L;
64 private final Node currentBaseContext
;
66 private final DocumentsUiService documentUiService
= new DocumentsUiService();
68 // UI Parts for the browser
69 private Composite filterCmp
;
70 private Composite breadCrumbCmp
;
71 private Text filterTxt
;
72 private FsTableViewer directoryDisplayViewer
;
73 private Composite rightPanelCmp
;
75 private DocumentsContextMenu contextMenu
;
76 private DateFormat dateFormat
= new SimpleDateFormat("YYYY-MM-dd HH:mm");
79 private Path initialPath
;
80 private Path currentFolder
;
82 public DocumentsFolderComposite(Composite parent
, int style
, Node context
) {
84 this.currentBaseContext
= context
;
86 this.setLayout(EclipseUiUtils
.noSpaceGridLayout());
88 SashForm form
= new SashForm(this, SWT
.HORIZONTAL
);
90 Composite centerCmp
= new Composite(form
, SWT
.BORDER
| SWT
.NO_FOCUS
);
91 createDisplay(centerCmp
);
93 rightPanelCmp
= new Composite(form
, SWT
.NO_FOCUS
);
95 form
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
96 form
.setWeights(new int[] { 55, 20 });
99 public void populate(Path path
) {
101 directoryDisplayViewer
.setInitialPath(initialPath
);
109 private void createDisplay(final Composite parent
) {
110 parent
.setLayout(EclipseUiUtils
.noSpaceGridLayout());
113 filterCmp
= new Composite(parent
, SWT
.NO_FOCUS
);
114 filterCmp
.setLayoutData(EclipseUiUtils
.fillWidth());
115 RowLayout rl
= new RowLayout(SWT
.HORIZONTAL
);
118 filterCmp
.setLayout(rl
);
119 // addFilterPanel(filterCmp);
122 directoryDisplayViewer
= new FsTableViewer(parent
, SWT
.MULTI
);
123 List
<ColumnDefinition
> colDefs
= new ArrayList
<>();
124 colDefs
.add(new ColumnDefinition(new FileIconNameLabelProvider(), " Name", 250));
125 colDefs
.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants
.PROPERTY_SIZE
), "Size", 100));
126 // colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_TYPE), "Type", 150));
127 colDefs
.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants
.PROPERTY_LAST_MODIFIED
),
128 "Last modified", 400));
129 final Table table
= directoryDisplayViewer
.configureDefaultTable(colDefs
);
130 table
.setLayoutData(EclipseUiUtils
.fillAll());
132 directoryDisplayViewer
.addSelectionChangedListener(new ISelectionChangedListener() {
135 public void selectionChanged(SelectionChangedEvent event
) {
136 IStructuredSelection selection
= (IStructuredSelection
) directoryDisplayViewer
.getSelection();
137 Path selected
= null;
138 if (selection
.isEmpty())
141 Object o
= selection
.getFirstElement();
142 if (o
instanceof Path
)
144 else if (o
instanceof ParentDir
)
145 selected
= ((ParentDir
) o
).getPath();
147 if (selected
!= null) {
148 // TODO manage multiple selection
149 setSelected(selected
);
154 directoryDisplayViewer
.addDoubleClickListener(new IDoubleClickListener() {
156 public void doubleClick(DoubleClickEvent event
) {
157 IStructuredSelection selection
= (IStructuredSelection
) directoryDisplayViewer
.getSelection();
158 Path selected
= null;
159 if (!selection
.isEmpty()) {
160 Object o
= selection
.getFirstElement();
161 if (o
instanceof Path
)
163 else if (o
instanceof ParentDir
)
164 selected
= ((ParentDir
) o
).getPath();
166 if (selected
!= null) {
167 if (Files
.isDirectory(selected
))
170 externalNavigateTo(selected
);
176 contextMenu
= new DocumentsContextMenu(this, documentUiService
);
178 table
.addMouseListener(new MouseAdapter() {
179 private static final long serialVersionUID
= 6737579410648595940L;
182 public void mouseDown(MouseEvent e
) {
184 // contextMenu.setCurrFolderPath(currDisplayedFolder);
185 contextMenu
.show(table
, new Point(e
.x
, e
.y
),
186 (IStructuredSelection
) directoryDisplayViewer
.getSelection(), currentFolder
);
191 FileDrop fileDrop
= new FileDrop() {
194 protected void processFileUpload(InputStream in
, String fileName
, String contetnType
) throws IOException
{
195 Path file
= currentFolder
.resolve(fileName
);
196 Files
.copy(in
, file
);
200 fileDrop
.createDropTarget(directoryDisplayViewer
.getTable());
204 * Overwrite to enable single sourcing between workbench and CMS navigation
206 protected void externalNavigateTo(Path path
) {
210 private void addPathElementBtn(Path path
) {
211 Button elemBtn
= new Button(breadCrumbCmp
, SWT
.PUSH
);
213 if (path
.toString().equals("/"))
214 nameStr
= "[jcr:root]";
216 nameStr
= path
.getFileName().toString();
217 // elemBtn.setText(nameStr + " >> ");
218 elemBtn
.setText(nameStr
);
219 CmsSwtUtils
.style(elemBtn
, FsStyles
.BREAD_CRUMB_BTN
);
220 elemBtn
.addSelectionListener(new SelectionAdapter() {
221 private static final long serialVersionUID
= -4103695476023480651L;
224 public void widgetSelected(SelectionEvent e
) {
230 public void setInput(Path path
) {
231 if (path
.equals(currentFolder
))
233 // below initial path
234 if (!initialPath
.equals(path
) && initialPath
.startsWith(path
))
236 currentFolder
= path
;
238 Path diff
= initialPath
.relativize(currentFolder
);
240 for (Control child
: filterCmp
.getChildren())
241 if (!child
.equals(filterTxt
))
245 breadCrumbCmp
= new Composite(filterCmp
, SWT
.NO_FOCUS
);
246 CmsSwtUtils
.style(breadCrumbCmp
, FsStyles
.BREAD_CRUMB_BTN
);
247 RowLayout breadCrumbLayout
= new RowLayout();
248 breadCrumbLayout
.spacing
= 0;
249 breadCrumbLayout
.marginTop
= 0;
250 breadCrumbLayout
.marginBottom
= 0;
251 breadCrumbLayout
.marginRight
= 0;
252 breadCrumbLayout
.marginLeft
= 0;
253 breadCrumbCmp
.setLayout(breadCrumbLayout
);
254 addPathElementBtn(initialPath
);
255 Path currTarget
= initialPath
;
256 if (!diff
.toString().equals(""))
257 for (Path pathElem
: diff
) {
258 currTarget
= currTarget
.resolve(pathElem
);
259 addPathElementBtn(currTarget
);
262 if (filterTxt
!= null) {
263 filterTxt
.setText("");
264 filterTxt
.moveBelow(null);
269 filterCmp
.getParent().layout(true, true);
272 private void setSelected(Path path
) {
274 setOverviewInput(currentFolder
);
276 setOverviewInput(path
);
279 public Viewer
getViewer() {
280 return directoryDisplayViewer
;
284 * Recreates the content of the box that displays information about the current
287 private void setOverviewInput(Path path
) {
289 EclipseUiUtils
.clear(rightPanelCmp
);
290 rightPanelCmp
.setLayout(new GridLayout());
292 // if (isImg(context)) {
293 // EditableImage image = new Img(parent, RIGHT, context,
295 // image.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER,
300 Label contextL
= new Label(rightPanelCmp
, SWT
.NONE
);
301 contextL
.setText(path
.getFileName().toString());
302 contextL
.setFont(EclipseUiUtils
.getBoldFont(rightPanelCmp
));
303 FileTime lastModified
= Files
.getLastModifiedTime(path
);
304 if (lastModified
.toMillis() != 0)
306 String lastModifiedStr
= dateFormat
.format(new Date(lastModified
.toMillis()));
307 addProperty(rightPanelCmp
, "Last modified", lastModifiedStr
);
308 } catch (Exception e
) {
309 log
.error("Workarounded issue while getting last update date for " + path
, e
);
310 addProperty(rightPanelCmp
, "Last modified", "-");
312 // addProperty(rightPannelCmp, "Owner",
313 // Files.getOwner(path).getName());
314 if (Files
.isDirectory(path
)) {
315 addProperty(rightPanelCmp
, "Type", "Folder");
317 String mimeType
= Files
.probeContentType(path
);
318 if (EclipseUiUtils
.isEmpty(mimeType
))
319 mimeType
= "<i>Unknown</i>";
320 addProperty(rightPanelCmp
, "Type", mimeType
);
321 addProperty(rightPanelCmp
, "Size", FsUiUtils
.humanReadableByteCount(Files
.size(path
), false));
324 // read all attributes
325 // Map<String, Object> attrs = Files.readAttributes(path, "*");
326 // for (String attr : attrs.keySet()) {
327 // Object value = attrs.get(attr);
329 // if (value instanceof Calendar) {
330 // str = dateFormat.format(((Calendar) value).getTime());
332 // str = value.toString();
334 // addProperty(rightPanelCmp, attr, str);
338 rightPanelCmp
.layout(true, true);
339 } catch (IOException e
) {
340 throw new IllegalStateException("Cannot display details for " + path
.toString(), e
);
344 private void addFilterPanel(Composite parent
) {
345 // parent.setLayout(EclipseUiUtils.noSpaceGridLayout(new GridLayout(2,
348 filterTxt
= new Text(parent
, SWT
.SEARCH
| SWT
.ICON_CANCEL
);
349 filterTxt
.setMessage("Search current folder");
350 filterTxt
.setLayoutData(new RowData(250, SWT
.DEFAULT
));
351 filterTxt
.addModifyListener(new ModifyListener() {
352 private static final long serialVersionUID
= 1L;
354 public void modifyText(ModifyEvent event
) {
358 filterTxt
.addKeyListener(new KeyListener() {
359 private static final long serialVersionUID
= 2533535233583035527L;
362 public void keyReleased(KeyEvent e
) {
366 public void keyPressed(KeyEvent e
) {
367 // boolean shiftPressed = (e.stateMask & SWT.SHIFT) != 0;
368 // // boolean altPressed = (e.stateMask & SWT.ALT) != 0;
369 // FilterEntitiesVirtualTable currTable = null;
370 // if (currEdited != null) {
371 // FilterEntitiesVirtualTable table =
372 // browserCols.get(currEdited);
373 // if (table != null && !table.isDisposed())
374 // currTable = table;
377 // if (e.keyCode == SWT.ARROW_DOWN)
378 // currTable.setFocus();
379 // else if (e.keyCode == SWT.BS) {
380 // if (filterTxt.getText().equals("")
381 // && !(currEdited.getNameCount() == 1 ||
382 // currEdited.equals(initialPath))) {
383 // Path oldEdited = currEdited;
384 // Path parentPath = currEdited.getParent();
385 // setEdited(parentPath);
386 // if (browserCols.containsKey(parentPath))
387 // browserCols.get(parentPath).setSelected(oldEdited);
388 // filterTxt.setFocus();
391 // } else if (e.keyCode == SWT.TAB && !shiftPressed) {
392 // Path uniqueChild = getOnlyChild(currEdited,
393 // filterTxt.getText());
394 // if (uniqueChild != null) {
395 // // Highlight the unique chosen child
396 // currTable.setSelected(uniqueChild);
397 // setEdited(uniqueChild);
399 // filterTxt.setFocus();
406 // private Path getOnlyChild(Path parent, String filter) {
407 // try (DirectoryStream<Path> stream =
408 // Files.newDirectoryStream(currDisplayedFolder, filter + "*")) {
409 // Path uniqueChild = null;
410 // boolean moreThanOne = false;
411 // loop: for (Path entry : stream) {
412 // if (uniqueChild == null) {
413 // uniqueChild = entry;
415 // moreThanOne = true;
420 // return uniqueChild;
422 // } catch (IOException ioe) {
423 // throw new DocumentsException(
424 // "Unable to determine unique child existence and get it under " + parent +
425 // " with filter " + filter,
430 private void modifyFilter(boolean fromOutside
) {
432 if (currentFolder
!= null) {
434 if (filterTxt
!= null)
435 filter
= filterTxt
.getText() + "*";
438 directoryDisplayViewer
.setInput(currentFolder
, filter
);
442 // Simplify UI implementation
443 private void addProperty(Composite parent
, String propName
, String value
) {
444 Label propLbl
= new Label(parent
, SWT
.NONE
);
445 //propLbl.setText(ConnectUtils.replaceAmpersand(propName + ": " + value));
446 propLbl
.setText(value
);
447 //CmsUiUtils.markup(propLbl);
450 public Path
getCurrentFolder() {
451 return currentFolder
;