1 package org
.argeo
.library
.ui
;
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
.apache
.commons
.logging
.Log
;
17 import org
.apache
.commons
.logging
.LogFactory
;
18 import org
.argeo
.cms
.ui
.fs
.FileDrop
;
19 import org
.argeo
.cms
.ui
.fs
.FsStyles
;
20 import org
.argeo
.cms
.ui
.util
.CmsUiUtils
;
21 import org
.argeo
.eclipse
.ui
.ColumnDefinition
;
22 import org
.argeo
.eclipse
.ui
.EclipseUiUtils
;
23 import org
.argeo
.eclipse
.ui
.fs
.FileIconNameLabelProvider
;
24 import org
.argeo
.eclipse
.ui
.fs
.FsTableViewer
;
25 import org
.argeo
.eclipse
.ui
.fs
.FsUiConstants
;
26 import org
.argeo
.eclipse
.ui
.fs
.FsUiUtils
;
27 import org
.argeo
.eclipse
.ui
.fs
.NioFileLabelProvider
;
28 import org
.argeo
.eclipse
.ui
.fs
.ParentDir
;
29 import org
.eclipse
.jface
.viewers
.DoubleClickEvent
;
30 import org
.eclipse
.jface
.viewers
.IDoubleClickListener
;
31 import org
.eclipse
.jface
.viewers
.ISelectionChangedListener
;
32 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
33 import org
.eclipse
.jface
.viewers
.SelectionChangedEvent
;
34 import org
.eclipse
.jface
.viewers
.Viewer
;
35 import org
.eclipse
.swt
.SWT
;
36 import org
.eclipse
.swt
.custom
.SashForm
;
37 import org
.eclipse
.swt
.events
.KeyEvent
;
38 import org
.eclipse
.swt
.events
.KeyListener
;
39 import org
.eclipse
.swt
.events
.ModifyEvent
;
40 import org
.eclipse
.swt
.events
.ModifyListener
;
41 import org
.eclipse
.swt
.events
.MouseAdapter
;
42 import org
.eclipse
.swt
.events
.MouseEvent
;
43 import org
.eclipse
.swt
.events
.SelectionAdapter
;
44 import org
.eclipse
.swt
.events
.SelectionEvent
;
45 import org
.eclipse
.swt
.graphics
.Point
;
46 import org
.eclipse
.swt
.layout
.GridData
;
47 import org
.eclipse
.swt
.layout
.GridLayout
;
48 import org
.eclipse
.swt
.layout
.RowData
;
49 import org
.eclipse
.swt
.layout
.RowLayout
;
50 import org
.eclipse
.swt
.widgets
.Button
;
51 import org
.eclipse
.swt
.widgets
.Composite
;
52 import org
.eclipse
.swt
.widgets
.Control
;
53 import org
.eclipse
.swt
.widgets
.Label
;
54 import org
.eclipse
.swt
.widgets
.Table
;
55 import org
.eclipse
.swt
.widgets
.Text
;
58 * Default Documents folder composite: a sashForm layout with a simple table in
59 * the middle and an overview at right hand side.
61 public class DocumentsFolderComposite
extends Composite
{
62 private final static Log log
= LogFactory
.getLog(DocumentsFolderComposite
.class);
63 private static final long serialVersionUID
= -40347919096946585L;
65 private final Node currentBaseContext
;
67 private final DocumentsUiService documentUiService
= new DocumentsUiService();
69 // UI Parts for the browser
70 private Composite filterCmp
;
71 private Composite breadCrumbCmp
;
72 private Text filterTxt
;
73 private FsTableViewer directoryDisplayViewer
;
74 private Composite rightPanelCmp
;
76 private DocumentsContextMenu contextMenu
;
77 private DateFormat dateFormat
= new SimpleDateFormat("YYYY-MM-dd HH:mm");
80 private Path initialPath
;
81 private Path currentFolder
;
83 public DocumentsFolderComposite(Composite parent
, int style
, Node context
) {
85 this.currentBaseContext
= context
;
87 this.setLayout(EclipseUiUtils
.noSpaceGridLayout());
89 SashForm form
= new SashForm(this, SWT
.HORIZONTAL
);
91 Composite centerCmp
= new Composite(form
, SWT
.BORDER
| SWT
.NO_FOCUS
);
92 createDisplay(centerCmp
);
94 rightPanelCmp
= new Composite(form
, SWT
.NO_FOCUS
);
96 form
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
97 form
.setWeights(new int[] { 55, 20 });
100 public void populate(Path path
) {
102 directoryDisplayViewer
.setInitialPath(initialPath
);
110 private void createDisplay(final Composite parent
) {
111 parent
.setLayout(EclipseUiUtils
.noSpaceGridLayout());
114 filterCmp
= new Composite(parent
, SWT
.NO_FOCUS
);
115 filterCmp
.setLayoutData(EclipseUiUtils
.fillWidth());
116 RowLayout rl
= new RowLayout(SWT
.HORIZONTAL
);
119 filterCmp
.setLayout(rl
);
120 // addFilterPanel(filterCmp);
123 directoryDisplayViewer
= new FsTableViewer(parent
, SWT
.MULTI
);
124 List
<ColumnDefinition
> colDefs
= new ArrayList
<>();
125 colDefs
.add(new ColumnDefinition(new FileIconNameLabelProvider(), " Name", 250));
126 colDefs
.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants
.PROPERTY_SIZE
), "Size", 100));
127 // colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_TYPE), "Type", 150));
128 colDefs
.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants
.PROPERTY_LAST_MODIFIED
),
129 "Last modified", 400));
130 final Table table
= directoryDisplayViewer
.configureDefaultTable(colDefs
);
131 table
.setLayoutData(EclipseUiUtils
.fillAll());
133 directoryDisplayViewer
.addSelectionChangedListener(new ISelectionChangedListener() {
136 public void selectionChanged(SelectionChangedEvent event
) {
137 IStructuredSelection selection
= (IStructuredSelection
) directoryDisplayViewer
.getSelection();
138 Path selected
= null;
139 if (selection
.isEmpty())
142 Object o
= selection
.getFirstElement();
143 if (o
instanceof Path
)
145 else if (o
instanceof ParentDir
)
146 selected
= ((ParentDir
) o
).getPath();
148 if (selected
!= null) {
149 // TODO manage multiple selection
150 setSelected(selected
);
155 directoryDisplayViewer
.addDoubleClickListener(new IDoubleClickListener() {
157 public void doubleClick(DoubleClickEvent event
) {
158 IStructuredSelection selection
= (IStructuredSelection
) directoryDisplayViewer
.getSelection();
159 Path selected
= null;
160 if (!selection
.isEmpty()) {
161 Object o
= selection
.getFirstElement();
162 if (o
instanceof Path
)
164 else if (o
instanceof ParentDir
)
165 selected
= ((ParentDir
) o
).getPath();
167 if (selected
!= null) {
168 if (Files
.isDirectory(selected
))
171 externalNavigateTo(selected
);
177 contextMenu
= new DocumentsContextMenu(this, documentUiService
);
179 table
.addMouseListener(new MouseAdapter() {
180 private static final long serialVersionUID
= 6737579410648595940L;
183 public void mouseDown(MouseEvent e
) {
185 // contextMenu.setCurrFolderPath(currDisplayedFolder);
186 contextMenu
.show(table
, new Point(e
.x
, e
.y
),
187 (IStructuredSelection
) directoryDisplayViewer
.getSelection(), currentFolder
);
192 FileDrop fileDrop
= new FileDrop() {
195 protected void processFileUpload(InputStream in
, String fileName
, String contetnType
) throws IOException
{
196 Path file
= currentFolder
.resolve(fileName
);
197 Files
.copy(in
, file
);
201 fileDrop
.createDropTarget(directoryDisplayViewer
.getTable());
205 * Overwrite to enable single sourcing between workbench and CMS navigation
207 protected void externalNavigateTo(Path path
) {
211 private void addPathElementBtn(Path path
) {
212 Button elemBtn
= new Button(breadCrumbCmp
, SWT
.PUSH
);
214 if (path
.toString().equals("/"))
215 nameStr
= "[jcr:root]";
217 nameStr
= path
.getFileName().toString();
218 // elemBtn.setText(nameStr + " >> ");
219 elemBtn
.setText(nameStr
);
220 CmsUiUtils
.style(elemBtn
, FsStyles
.BREAD_CRUMB_BTN
);
221 elemBtn
.addSelectionListener(new SelectionAdapter() {
222 private static final long serialVersionUID
= -4103695476023480651L;
225 public void widgetSelected(SelectionEvent e
) {
231 public void setInput(Path path
) {
232 if (path
.equals(currentFolder
))
234 // below initial path
235 if (!initialPath
.equals(path
) && initialPath
.startsWith(path
))
237 currentFolder
= path
;
239 Path diff
= initialPath
.relativize(currentFolder
);
241 for (Control child
: filterCmp
.getChildren())
242 if (!child
.equals(filterTxt
))
246 breadCrumbCmp
= new Composite(filterCmp
, SWT
.NO_FOCUS
);
247 CmsUiUtils
.style(breadCrumbCmp
, FsStyles
.BREAD_CRUMB_BTN
);
248 RowLayout breadCrumbLayout
= new RowLayout();
249 breadCrumbLayout
.spacing
= 0;
250 breadCrumbLayout
.marginTop
= 0;
251 breadCrumbLayout
.marginBottom
= 0;
252 breadCrumbLayout
.marginRight
= 0;
253 breadCrumbLayout
.marginLeft
= 0;
254 breadCrumbCmp
.setLayout(breadCrumbLayout
);
255 addPathElementBtn(initialPath
);
256 Path currTarget
= initialPath
;
257 if (!diff
.toString().equals(""))
258 for (Path pathElem
: diff
) {
259 currTarget
= currTarget
.resolve(pathElem
);
260 addPathElementBtn(currTarget
);
263 if (filterTxt
!= null) {
264 filterTxt
.setText("");
265 filterTxt
.moveBelow(null);
270 filterCmp
.getParent().layout(true, true);
273 private void setSelected(Path path
) {
275 setOverviewInput(currentFolder
);
277 setOverviewInput(path
);
280 public Viewer
getViewer() {
281 return directoryDisplayViewer
;
285 * Recreates the content of the box that displays information about the current
288 private void setOverviewInput(Path path
) {
290 EclipseUiUtils
.clear(rightPanelCmp
);
291 rightPanelCmp
.setLayout(new GridLayout());
293 // if (isImg(context)) {
294 // EditableImage image = new Img(parent, RIGHT, context,
296 // image.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER,
301 Label contextL
= new Label(rightPanelCmp
, SWT
.NONE
);
302 contextL
.setText(path
.getFileName().toString());
303 contextL
.setFont(EclipseUiUtils
.getBoldFont(rightPanelCmp
));
304 FileTime lastModified
= Files
.getLastModifiedTime(path
);
305 if (lastModified
.toMillis() != 0)
307 String lastModifiedStr
= dateFormat
.format(new Date(lastModified
.toMillis()));
308 addProperty(rightPanelCmp
, "Last modified", lastModifiedStr
);
309 } catch (Exception e
) {
310 log
.error("Workarounded issue while getting last update date for " + path
, e
);
311 addProperty(rightPanelCmp
, "Last modified", "-");
313 // addProperty(rightPannelCmp, "Owner",
314 // Files.getOwner(path).getName());
315 if (Files
.isDirectory(path
)) {
316 addProperty(rightPanelCmp
, "Type", "Folder");
318 String mimeType
= Files
.probeContentType(path
);
319 if (EclipseUiUtils
.isEmpty(mimeType
))
320 mimeType
= "<i>Unknown</i>";
321 addProperty(rightPanelCmp
, "Type", mimeType
);
322 addProperty(rightPanelCmp
, "Size", FsUiUtils
.humanReadableByteCount(Files
.size(path
), false));
325 // read all attributes
326 // Map<String, Object> attrs = Files.readAttributes(path, "*");
327 // for (String attr : attrs.keySet()) {
328 // Object value = attrs.get(attr);
330 // if (value instanceof Calendar) {
331 // str = dateFormat.format(((Calendar) value).getTime());
333 // str = value.toString();
335 // addProperty(rightPanelCmp, attr, str);
339 rightPanelCmp
.layout(true, true);
340 } catch (IOException e
) {
341 throw new IllegalStateException("Cannot display details for " + path
.toString(), e
);
345 private void addFilterPanel(Composite parent
) {
346 // parent.setLayout(EclipseUiUtils.noSpaceGridLayout(new GridLayout(2,
349 filterTxt
= new Text(parent
, SWT
.SEARCH
| SWT
.ICON_CANCEL
);
350 filterTxt
.setMessage("Search current folder");
351 filterTxt
.setLayoutData(new RowData(250, SWT
.DEFAULT
));
352 filterTxt
.addModifyListener(new ModifyListener() {
353 private static final long serialVersionUID
= 1L;
355 public void modifyText(ModifyEvent event
) {
359 filterTxt
.addKeyListener(new KeyListener() {
360 private static final long serialVersionUID
= 2533535233583035527L;
363 public void keyReleased(KeyEvent e
) {
367 public void keyPressed(KeyEvent e
) {
368 // boolean shiftPressed = (e.stateMask & SWT.SHIFT) != 0;
369 // // boolean altPressed = (e.stateMask & SWT.ALT) != 0;
370 // FilterEntitiesVirtualTable currTable = null;
371 // if (currEdited != null) {
372 // FilterEntitiesVirtualTable table =
373 // browserCols.get(currEdited);
374 // if (table != null && !table.isDisposed())
375 // currTable = table;
378 // if (e.keyCode == SWT.ARROW_DOWN)
379 // currTable.setFocus();
380 // else if (e.keyCode == SWT.BS) {
381 // if (filterTxt.getText().equals("")
382 // && !(currEdited.getNameCount() == 1 ||
383 // currEdited.equals(initialPath))) {
384 // Path oldEdited = currEdited;
385 // Path parentPath = currEdited.getParent();
386 // setEdited(parentPath);
387 // if (browserCols.containsKey(parentPath))
388 // browserCols.get(parentPath).setSelected(oldEdited);
389 // filterTxt.setFocus();
392 // } else if (e.keyCode == SWT.TAB && !shiftPressed) {
393 // Path uniqueChild = getOnlyChild(currEdited,
394 // filterTxt.getText());
395 // if (uniqueChild != null) {
396 // // Highlight the unique chosen child
397 // currTable.setSelected(uniqueChild);
398 // setEdited(uniqueChild);
400 // filterTxt.setFocus();
407 // private Path getOnlyChild(Path parent, String filter) {
408 // try (DirectoryStream<Path> stream =
409 // Files.newDirectoryStream(currDisplayedFolder, filter + "*")) {
410 // Path uniqueChild = null;
411 // boolean moreThanOne = false;
412 // loop: for (Path entry : stream) {
413 // if (uniqueChild == null) {
414 // uniqueChild = entry;
416 // moreThanOne = true;
421 // return uniqueChild;
423 // } catch (IOException ioe) {
424 // throw new DocumentsException(
425 // "Unable to determine unique child existence and get it under " + parent +
426 // " with filter " + filter,
431 private void modifyFilter(boolean fromOutside
) {
433 if (currentFolder
!= null) {
435 if (filterTxt
!= null)
436 filter
= filterTxt
.getText() + "*";
439 directoryDisplayViewer
.setInput(currentFolder
, filter
);
443 // Simplify UI implementation
444 private void addProperty(Composite parent
, String propName
, String value
) {
445 Label propLbl
= new Label(parent
, SWT
.NONE
);
446 //propLbl.setText(ConnectUtils.replaceAmpersand(propName + ": " + value));
447 propLbl
.setText(value
);
448 //CmsUiUtils.markup(propLbl);
451 public Path
getCurrentFolder() {
452 return currentFolder
;