1 package org.argeo.documents.composites;
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.Calendar;
12 import java.util.Date;
13 import java.util.List;
14 import java.util.Map;
15
16 import javax.jcr.Node;
17
18 import org.apache.commons.logging.Log;
19 import org.apache.commons.logging.LogFactory;
20 import org.argeo.cms.ui.fs.FileDrop;
21 import org.argeo.cms.ui.fs.FsStyles;
22 import org.argeo.cms.util.CmsUtils;
23 import org.argeo.connect.util.ConnectJcrUtils;
24 import org.argeo.connect.util.ConnectUtils;
25 import org.argeo.documents.DocumentsException;
26 import org.argeo.documents.DocumentsService;
27 import org.argeo.documents.ui.DocumentsUiService;
28 import org.argeo.eclipse.ui.ColumnDefinition;
29 import org.argeo.eclipse.ui.EclipseUiUtils;
30 import org.argeo.eclipse.ui.fs.FileIconNameLabelProvider;
31 import org.argeo.eclipse.ui.fs.FsTableViewer;
32 import org.argeo.eclipse.ui.fs.FsUiConstants;
33 import org.argeo.eclipse.ui.fs.FsUiUtils;
34 import org.argeo.eclipse.ui.fs.NioFileLabelProvider;
35 import org.argeo.eclipse.ui.fs.ParentDir;
36 import org.eclipse.jface.viewers.DoubleClickEvent;
37 import org.eclipse.jface.viewers.IDoubleClickListener;
38 import org.eclipse.jface.viewers.ISelectionChangedListener;
39 import org.eclipse.jface.viewers.IStructuredSelection;
40 import org.eclipse.jface.viewers.SelectionChangedEvent;
41 import org.eclipse.jface.viewers.Viewer;
42 import org.eclipse.swt.SWT;
43 import org.eclipse.swt.custom.SashForm;
44 import org.eclipse.swt.events.KeyEvent;
45 import org.eclipse.swt.events.KeyListener;
46 import org.eclipse.swt.events.ModifyEvent;
47 import org.eclipse.swt.events.ModifyListener;
48 import org.eclipse.swt.events.MouseAdapter;
49 import org.eclipse.swt.events.MouseEvent;
50 import org.eclipse.swt.events.SelectionAdapter;
51 import org.eclipse.swt.events.SelectionEvent;
52 import org.eclipse.swt.graphics.Point;
53 import org.eclipse.swt.layout.GridData;
54 import org.eclipse.swt.layout.GridLayout;
55 import org.eclipse.swt.layout.RowData;
56 import org.eclipse.swt.layout.RowLayout;
57 import org.eclipse.swt.widgets.Button;
58 import org.eclipse.swt.widgets.Composite;
59 import org.eclipse.swt.widgets.Control;
60 import org.eclipse.swt.widgets.Label;
61 import org.eclipse.swt.widgets.Table;
62 import org.eclipse.swt.widgets.Text;
63
64
65
66
67
68 public class DocumentsFolderComposite extends Composite {
69 private final static Log log = LogFactory.getLog(DocumentsFolderComposite.class);
70 private static final long serialVersionUID = -40347919096946585L;
71
72 private final Node currentBaseContext;
73
74 private final DocumentsService documentService;
75 private final DocumentsUiService documentUiService = new DocumentsUiService();
76
77
78 private Composite filterCmp;
79 private Composite breadCrumbCmp;
80 private Text filterTxt;
81 private FsTableViewer directoryDisplayViewer;
82 private Composite rightPanelCmp;
83
84 private DocumentsContextMenu contextMenu;
85 private DateFormat dateFormat = new SimpleDateFormat("YYYY-MM-dd HH:mm");
86
87
88 private Path initialPath;
89 private Path currentFolder;
90
91 public DocumentsFolderComposite(Composite parent, int style, Node context, DocumentsService documentService) {
92 super(parent, style);
93 this.documentService = documentService;
94 this.currentBaseContext = context;
95
96 this.setLayout(EclipseUiUtils.noSpaceGridLayout());
97
98 SashForm form = new SashForm(this, SWT.HORIZONTAL);
99
100 Composite centerCmp = new Composite(form, SWT.BORDER | SWT.NO_FOCUS);
101 createDisplay(centerCmp);
102
103 rightPanelCmp = new Composite(form, SWT.NO_FOCUS);
104
105 form.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
106 form.setWeights(new int[] { 55, 20 });
107 }
108
109 public void populate(Path path) {
110 initialPath = path;
111 directoryDisplayViewer.setInitialPath(initialPath);
112 setInput(path);
113 }
114
115 void refresh() {
116 modifyFilter(false);
117 }
118
119 private void createDisplay(final Composite parent) {
120 parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
121
122
123 filterCmp = new Composite(parent, SWT.NO_FOCUS);
124 filterCmp.setLayoutData(EclipseUiUtils.fillWidth());
125 RowLayout rl = new RowLayout(SWT.HORIZONTAL);
126 rl.wrap = true;
127 rl.center = true;
128 filterCmp.setLayout(rl);
129
130
131
132 directoryDisplayViewer = new FsTableViewer(parent, SWT.MULTI);
133 List<ColumnDefinition> colDefs = new ArrayList<>();
134 colDefs.add(new ColumnDefinition(new FileIconNameLabelProvider(), " Name", 250));
135 colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_SIZE), "Size", 100));
136
137 colDefs.add(new ColumnDefinition(new NioFileLabelProvider(FsUiConstants.PROPERTY_LAST_MODIFIED),
138 "Last modified", 400));
139 final Table table = directoryDisplayViewer.configureDefaultTable(colDefs);
140 table.setLayoutData(EclipseUiUtils.fillAll());
141
142 directoryDisplayViewer.addSelectionChangedListener(new ISelectionChangedListener() {
143
144 @Override
145 public void selectionChanged(SelectionChangedEvent event) {
146 IStructuredSelection selection = (IStructuredSelection) directoryDisplayViewer.getSelection();
147 Path selected = null;
148 if (selection.isEmpty())
149 setSelected(null);
150 else {
151 Object o = selection.getFirstElement();
152 if (o instanceof Path)
153 selected = (Path) o;
154 else if (o instanceof ParentDir)
155 selected = ((ParentDir) o).getPath();
156 }
157 if (selected != null) {
158
159 setSelected(selected);
160 }
161 }
162 });
163
164 directoryDisplayViewer.addDoubleClickListener(new IDoubleClickListener() {
165 @Override
166 public void doubleClick(DoubleClickEvent event) {
167 IStructuredSelection selection = (IStructuredSelection) directoryDisplayViewer.getSelection();
168 Path selected = null;
169 if (!selection.isEmpty()) {
170 Object o = selection.getFirstElement();
171 if (o instanceof Path)
172 selected = (Path) o;
173 else if (o instanceof ParentDir)
174 selected = ((ParentDir) o).getPath();
175 }
176 if (selected != null) {
177 if (Files.isDirectory(selected))
178 setInput(selected);
179 else
180 externalNavigateTo(selected);
181 }
182 }
183 });
184
185
186 contextMenu = new DocumentsContextMenu(this, documentService, documentUiService,
187 ConnectJcrUtils.getRepository(currentBaseContext));
188
189 table.addMouseListener(new MouseAdapter() {
190 private static final long serialVersionUID = 6737579410648595940L;
191
192 @Override
193 public void mouseDown(MouseEvent e) {
194 if (e.button == 3) {
195
196 contextMenu.show(table, new Point(e.x, e.y),
197 (IStructuredSelection) directoryDisplayViewer.getSelection(), currentFolder);
198 }
199 }
200 });
201
202 FileDrop fileDrop = new FileDrop() {
203
204 @Override
205 protected void processFileUpload(InputStream in, String fileName, String contetnType) throws IOException {
206 Path file = currentFolder.resolve(fileName);
207 Files.copy(in, file);
208 refresh();
209 }
210 };
211 fileDrop.createDropTarget(directoryDisplayViewer.getTable());
212 }
213
214
215
216
217 protected void externalNavigateTo(Path path) {
218
219 }
220
221 private void addPathElementBtn(Path path) {
222 Button elemBtn = new Button(breadCrumbCmp, SWT.PUSH);
223 String nameStr;
224 if (path.toString().equals("/"))
225 nameStr = "[jcr:root]";
226 else
227 nameStr = path.getFileName().toString();
228
229 elemBtn.setText(nameStr);
230 CmsUtils.style(elemBtn, FsStyles.BREAD_CRUMB_BTN);
231 elemBtn.addSelectionListener(new SelectionAdapter() {
232 private static final long serialVersionUID = -4103695476023480651L;
233
234 @Override
235 public void widgetSelected(SelectionEvent e) {
236 setInput(path);
237 }
238 });
239 }
240
241 public void setInput(Path path) {
242 if (path.equals(currentFolder))
243 return;
244
245 if (!initialPath.equals(path) && initialPath.startsWith(path))
246 return;
247 currentFolder = path;
248
249 Path diff = initialPath.relativize(currentFolder);
250
251 for (Control child : filterCmp.getChildren())
252 if (!child.equals(filterTxt))
253 child.dispose();
254
255
256 breadCrumbCmp = new Composite(filterCmp, SWT.NO_FOCUS);
257 CmsUtils.style(breadCrumbCmp, FsStyles.BREAD_CRUMB_BTN);
258 RowLayout breadCrumbLayout = new RowLayout();
259 breadCrumbLayout.spacing = 0;
260 breadCrumbLayout.marginTop = 0;
261 breadCrumbLayout.marginBottom = 0;
262 breadCrumbLayout.marginRight = 0;
263 breadCrumbLayout.marginLeft = 0;
264 breadCrumbCmp.setLayout(breadCrumbLayout);
265 addPathElementBtn(initialPath);
266 Path currTarget = initialPath;
267 if (!diff.toString().equals(""))
268 for (Path pathElem : diff) {
269 currTarget = currTarget.resolve(pathElem);
270 addPathElementBtn(currTarget);
271 }
272
273 if (filterTxt != null) {
274 filterTxt.setText("");
275 filterTxt.moveBelow(null);
276 } else {
277 modifyFilter(false);
278 }
279 setSelected(null);
280 filterCmp.getParent().layout(true, true);
281 }
282
283 private void setSelected(Path path) {
284 if (path == null)
285 setOverviewInput(currentFolder);
286 else
287 setOverviewInput(path);
288 }
289
290 public Viewer getViewer() {
291 return directoryDisplayViewer;
292 }
293
294
295
296
297
298 private void setOverviewInput(Path path) {
299 try {
300 EclipseUiUtils.clear(rightPanelCmp);
301 rightPanelCmp.setLayout(new GridLayout());
302 if (path != null) {
303
304
305
306
307
308
309
310
311 Label contextL = new Label(rightPanelCmp, SWT.NONE);
312 contextL.setText(path.getFileName().toString());
313 contextL.setFont(EclipseUiUtils.getBoldFont(rightPanelCmp));
314 FileTime lastModified = Files.getLastModifiedTime(path);
315 if (lastModified.toMillis() != 0)
316 try {
317 String lastModifiedStr = dateFormat.format(new Date(lastModified.toMillis()));
318 addProperty(rightPanelCmp, "Last modified", lastModifiedStr);
319 } catch (Exception e) {
320 log.error("Workarounded issue while getting last update date for " + path, e);
321 addProperty(rightPanelCmp, "Last modified", "-");
322 }
323
324
325 if (Files.isDirectory(path)) {
326 addProperty(rightPanelCmp, "Type", "Folder");
327 } else {
328 String mimeType = Files.probeContentType(path);
329 if (EclipseUiUtils.isEmpty(mimeType))
330 mimeType = "<i>Unknown</i>";
331 addProperty(rightPanelCmp, "Type", mimeType);
332 addProperty(rightPanelCmp, "Size", FsUiUtils.humanReadableByteCount(Files.size(path), false));
333 }
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348 }
349 rightPanelCmp.layout(true, true);
350 } catch (IOException e) {
351 throw new DocumentsException("Cannot display details for " + path.toString(), e);
352 }
353 }
354
355 private void addFilterPanel(Composite parent) {
356
357
358
359 filterTxt = new Text(parent, SWT.SEARCH | SWT.ICON_CANCEL);
360 filterTxt.setMessage("Search current folder");
361 filterTxt.setLayoutData(new RowData(250, SWT.DEFAULT));
362 filterTxt.addModifyListener(new ModifyListener() {
363 private static final long serialVersionUID = 1L;
364
365 public void modifyText(ModifyEvent event) {
366 modifyFilter(false);
367 }
368 });
369 filterTxt.addKeyListener(new KeyListener() {
370 private static final long serialVersionUID = 2533535233583035527L;
371
372 @Override
373 public void keyReleased(KeyEvent e) {
374 }
375
376 @Override
377 public void keyPressed(KeyEvent e) {
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413 }
414 });
415 }
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441 private void modifyFilter(boolean fromOutside) {
442 if (!fromOutside)
443 if (currentFolder != null) {
444 String filter;
445 if (filterTxt != null)
446 filter = filterTxt.getText() + "*";
447 else
448 filter = "*";
449 directoryDisplayViewer.setInput(currentFolder, filter);
450 }
451 }
452
453
454 private void addProperty(Composite parent, String propName, String value) {
455 Label propLbl = new Label(parent, SWT.NONE);
456 propLbl.setText(ConnectUtils.replaceAmpersand(propName + ": " + value));
457 CmsUtils.markup(propLbl);
458 }
459
460 public Path getCurrentFolder() {
461 return currentFolder;
462 }
463
464 }