]> git.argeo.org Git - gpl/argeo-suite.git/blob - library/DocumentsFolderComposite.java
Prepare next development cycle
[gpl/argeo-suite.git] / library / DocumentsFolderComposite.java
1 package org.argeo.app.ui.library;
2
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;
13
14 import javax.jcr.Node;
15
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;
55
56 /**
57 * Default Documents folder composite: a sashForm layout with a simple table in
58 * the middle and an overview at right hand side.
59 */
60 public class DocumentsFolderComposite extends Composite {
61 private final static CmsLog log = CmsLog.getLog(DocumentsFolderComposite.class);
62 private static final long serialVersionUID = -40347919096946585L;
63
64 private final Node currentBaseContext;
65
66 private final DocumentsUiService documentUiService = new DocumentsUiService();
67
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;
74
75 private DocumentsContextMenu contextMenu;
76 private DateFormat dateFormat = new SimpleDateFormat("YYYY-MM-dd HH:mm");
77
78 // Local context
79 private Path initialPath;
80 private Path currentFolder;
81
82 public DocumentsFolderComposite(Composite parent, int style, Node context) {
83 super(parent, style);
84 this.currentBaseContext = context;
85
86 this.setLayout(EclipseUiUtils.noSpaceGridLayout());
87
88 SashForm form = new SashForm(this, SWT.HORIZONTAL);
89
90 Composite centerCmp = new Composite(form, SWT.BORDER | SWT.NO_FOCUS);
91 createDisplay(centerCmp);
92
93 rightPanelCmp = new Composite(form, SWT.NO_FOCUS);
94
95 form.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
96 form.setWeights(new int[] { 55, 20 });
97 }
98
99 public void populate(Path path) {
100 initialPath = path;
101 directoryDisplayViewer.setInitialPath(initialPath);
102 setInput(path);
103 }
104
105 void refresh() {
106 modifyFilter(false);
107 }
108
109 private void createDisplay(final Composite parent) {
110 parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
111
112 // top filter
113 filterCmp = new Composite(parent, SWT.NO_FOCUS);
114 filterCmp.setLayoutData(EclipseUiUtils.fillWidth());
115 RowLayout rl = new RowLayout(SWT.HORIZONTAL);
116 rl.wrap = true;
117 rl.center = true;
118 filterCmp.setLayout(rl);
119 // addFilterPanel(filterCmp);
120
121 // Main display
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());
131
132 directoryDisplayViewer.addSelectionChangedListener(new ISelectionChangedListener() {
133
134 @Override
135 public void selectionChanged(SelectionChangedEvent event) {
136 IStructuredSelection selection = (IStructuredSelection) directoryDisplayViewer.getSelection();
137 Path selected = null;
138 if (selection.isEmpty())
139 setSelected(null);
140 else {
141 Object o = selection.getFirstElement();
142 if (o instanceof Path)
143 selected = (Path) o;
144 else if (o instanceof ParentDir)
145 selected = ((ParentDir) o).getPath();
146 }
147 if (selected != null) {
148 // TODO manage multiple selection
149 setSelected(selected);
150 }
151 }
152 });
153
154 directoryDisplayViewer.addDoubleClickListener(new IDoubleClickListener() {
155 @Override
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)
162 selected = (Path) o;
163 else if (o instanceof ParentDir)
164 selected = ((ParentDir) o).getPath();
165 }
166 if (selected != null) {
167 if (Files.isDirectory(selected))
168 setInput(selected);
169 else
170 externalNavigateTo(selected);
171 }
172 }
173 });
174
175 // The context menu
176 contextMenu = new DocumentsContextMenu(this, documentUiService);
177
178 table.addMouseListener(new MouseAdapter() {
179 private static final long serialVersionUID = 6737579410648595940L;
180
181 @Override
182 public void mouseDown(MouseEvent e) {
183 if (e.button == 3) {
184 // contextMenu.setCurrFolderPath(currDisplayedFolder);
185 contextMenu.show(table, new Point(e.x, e.y),
186 (IStructuredSelection) directoryDisplayViewer.getSelection(), currentFolder);
187 }
188 }
189 });
190
191 FileDrop fileDrop = new FileDrop() {
192
193 @Override
194 protected void processFileUpload(InputStream in, String fileName, String contetnType) throws IOException {
195 Path file = currentFolder.resolve(fileName);
196 Files.copy(in, file);
197 refresh();
198 }
199 };
200 fileDrop.createDropTarget(directoryDisplayViewer.getTable());
201 }
202
203 /**
204 * Overwrite to enable single sourcing between workbench and CMS navigation
205 */
206 protected void externalNavigateTo(Path path) {
207
208 }
209
210 private void addPathElementBtn(Path path) {
211 Button elemBtn = new Button(breadCrumbCmp, SWT.PUSH);
212 String nameStr;
213 if (path.toString().equals("/"))
214 nameStr = "[jcr:root]";
215 else
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;
222
223 @Override
224 public void widgetSelected(SelectionEvent e) {
225 setInput(path);
226 }
227 });
228 }
229
230 public void setInput(Path path) {
231 if (path.equals(currentFolder))
232 return;
233 // below initial path
234 if (!initialPath.equals(path) && initialPath.startsWith(path))
235 return;
236 currentFolder = path;
237
238 Path diff = initialPath.relativize(currentFolder);
239
240 for (Control child : filterCmp.getChildren())
241 if (!child.equals(filterTxt))
242 child.dispose();
243
244 // Bread crumbs
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);
260 }
261
262 if (filterTxt != null) {
263 filterTxt.setText("");
264 filterTxt.moveBelow(null);
265 } else {
266 modifyFilter(false);
267 }
268 setSelected(null);
269 filterCmp.getParent().layout(true, true);
270 }
271
272 private void setSelected(Path path) {
273 if (path == null)
274 setOverviewInput(currentFolder);
275 else
276 setOverviewInput(path);
277 }
278
279 public Viewer getViewer() {
280 return directoryDisplayViewer;
281 }
282
283 /**
284 * Recreates the content of the box that displays information about the current
285 * selected Path.
286 */
287 private void setOverviewInput(Path path) {
288 try {
289 EclipseUiUtils.clear(rightPanelCmp);
290 rightPanelCmp.setLayout(new GridLayout());
291 if (path != null) {
292 // if (isImg(context)) {
293 // EditableImage image = new Img(parent, RIGHT, context,
294 // imageWidth);
295 // image.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER,
296 // true, false,
297 // 2, 1));
298 // }
299
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)
305 try {
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", "-");
311 }
312 // addProperty(rightPannelCmp, "Owner",
313 // Files.getOwner(path).getName());
314 if (Files.isDirectory(path)) {
315 addProperty(rightPanelCmp, "Type", "Folder");
316 } else {
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));
322 }
323
324 // read all attributes
325 // Map<String, Object> attrs = Files.readAttributes(path, "*");
326 // for (String attr : attrs.keySet()) {
327 // Object value = attrs.get(attr);
328 // String str;
329 // if (value instanceof Calendar) {
330 // str = dateFormat.format(((Calendar) value).getTime());
331 // } else {
332 // str = value.toString();
333 // }
334 // addProperty(rightPanelCmp, attr, str);
335 //
336 // }
337 }
338 rightPanelCmp.layout(true, true);
339 } catch (IOException e) {
340 throw new IllegalStateException("Cannot display details for " + path.toString(), e);
341 }
342 }
343
344 private void addFilterPanel(Composite parent) {
345 // parent.setLayout(EclipseUiUtils.noSpaceGridLayout(new GridLayout(2,
346 // false)));
347
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;
353
354 public void modifyText(ModifyEvent event) {
355 modifyFilter(false);
356 }
357 });
358 filterTxt.addKeyListener(new KeyListener() {
359 private static final long serialVersionUID = 2533535233583035527L;
360
361 @Override
362 public void keyReleased(KeyEvent e) {
363 }
364
365 @Override
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;
375 // }
376 //
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();
389 // e.doit = false;
390 // }
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);
398 // }
399 // filterTxt.setFocus();
400 // e.doit = false;
401 // }
402 }
403 });
404 }
405
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;
414 // } else {
415 // moreThanOne = true;
416 // break loop;
417 // }
418 // }
419 // if (!moreThanOne)
420 // return uniqueChild;
421 // return null;
422 // } catch (IOException ioe) {
423 // throw new DocumentsException(
424 // "Unable to determine unique child existence and get it under " + parent +
425 // " with filter " + filter,
426 // ioe);
427 // }
428 // }
429
430 private void modifyFilter(boolean fromOutside) {
431 if (!fromOutside)
432 if (currentFolder != null) {
433 String filter;
434 if (filterTxt != null)
435 filter = filterTxt.getText() + "*";
436 else
437 filter = "*";
438 directoryDisplayViewer.setInput(currentFolder, filter);
439 }
440 }
441
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);
448 }
449
450 public Path getCurrentFolder() {
451 return currentFolder;
452 }
453
454 }