View Javadoc
1   /*
2    * Copyright (C) 2007-2012 Argeo GmbH
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *         http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.argeo.documents.e4.parts;
17  
18  import java.net.URI;
19  import java.net.URISyntaxException;
20  import java.nio.file.Path;
21  import java.nio.file.spi.FileSystemProvider;
22  import java.util.List;
23  
24  import javax.annotation.PostConstruct;
25  import javax.annotation.PreDestroy;
26  import javax.inject.Inject;
27  import javax.inject.Named;
28  import javax.jcr.Node;
29  import javax.jcr.NodeIterator;
30  import javax.jcr.Repository;
31  import javax.jcr.RepositoryException;
32  import javax.jcr.Session;
33  import javax.jcr.query.Query;
34  import javax.jcr.query.QueryManager;
35  import javax.jcr.query.QueryResult;
36  
37  import org.argeo.cms.util.CmsUtils;
38  import org.argeo.connect.ui.ConnectUiConstants;
39  import org.argeo.connect.ui.Refreshable;
40  import org.argeo.connect.ui.SystemWorkbenchService;
41  import org.argeo.connect.ui.widgets.DelayedText;
42  import org.argeo.connect.util.ConnectJcrUtils;
43  import org.argeo.connect.util.XPathUtils;
44  import org.argeo.documents.DocumentsException;
45  import org.argeo.documents.DocumentsNames;
46  import org.argeo.documents.DocumentsService;
47  import org.argeo.documents.DocumentsTypes;
48  import org.argeo.documents.composites.BookmarksTableViewer;
49  import org.argeo.eclipse.ui.EclipseUiUtils;
50  import org.argeo.eclipse.ui.fs.FsTableViewer;
51  import org.argeo.jcr.JcrUtils;
52  import org.argeo.node.NodeNames;
53  import org.argeo.node.NodeTypes;
54  import org.eclipse.jface.dialogs.MessageDialog;
55  import org.eclipse.jface.layout.TableColumnLayout;
56  import org.eclipse.jface.viewers.CellLabelProvider;
57  import org.eclipse.jface.viewers.ColumnLabelProvider;
58  import org.eclipse.jface.viewers.ColumnWeightData;
59  import org.eclipse.jface.viewers.DoubleClickEvent;
60  import org.eclipse.jface.viewers.IDoubleClickListener;
61  import org.eclipse.jface.viewers.ILabelProvider;
62  import org.eclipse.jface.viewers.IStructuredContentProvider;
63  import org.eclipse.jface.viewers.IStructuredSelection;
64  import org.eclipse.jface.viewers.StructuredSelection;
65  import org.eclipse.jface.viewers.TableViewer;
66  import org.eclipse.jface.viewers.Viewer;
67  import org.eclipse.swt.SWT;
68  import org.eclipse.swt.events.KeyEvent;
69  import org.eclipse.swt.events.KeyListener;
70  import org.eclipse.swt.events.ModifyEvent;
71  import org.eclipse.swt.events.ModifyListener;
72  import org.eclipse.swt.graphics.Image;
73  import org.eclipse.swt.layout.GridData;
74  import org.eclipse.swt.layout.GridLayout;
75  import org.eclipse.swt.widgets.Composite;
76  import org.eclipse.swt.widgets.Label;
77  import org.eclipse.swt.widgets.Table;
78  import org.eclipse.swt.widgets.TableColumn;
79  import org.eclipse.swt.widgets.Text;
80  
81  /** Browse the node file system. */
82  public class MyFilesView implements IDoubleClickListener, Refreshable {
83  	// public final static String ID = DocumentsUiPlugin.PLUGIN_ID + ".myFilesView";
84  
85  	@Inject
86  	@Named("(cn=home)")
87  	private Repository repository;
88  	@Inject
89  	private SystemWorkbenchService systemWorkbenchService;
90  	@Inject
91  	private FileSystemProvider nodeFileSystemProvider;
92  	@Inject
93  	private DocumentsService documentsService;
94  
95  	private Session session;
96  	private Text filterTxt;
97  	private TableViewer searchResultsViewer;
98  	private Composite searchCmp;
99  	private Composite bookmarkCmp;
100 
101 	@PostConstruct
102 	public void createPartControl(Composite parent) {
103 		session = ConnectJcrUtils.login(repository);
104 		// MainLayout
105 		parent.setLayout(new GridLayout());
106 //		addFilterPanel(parent);
107 //		searchCmp = new Composite(parent, SWT.NO_FOCUS);
108 //		searchCmp.setLayout(EclipseUiUtils.noSpaceGridLayout());
109 //		searchResultsViewer = createListPart(searchCmp, new DocumentsSingleColumnLP(systemWorkbenchService));
110 //		GridData gd = EclipseUiUtils.fillWidth();
111 //		gd.heightHint = 0;
112 //		searchCmp.setLayoutData(gd);
113 
114 		bookmarkCmp = new Composite(parent, SWT.NO_FOCUS);
115 		bookmarkCmp.setLayoutData(EclipseUiUtils.fillAll());
116 		populateBookmarks(bookmarkCmp);
117 	}
118 
119 	@Override
120 	public void forceRefresh(Object object) {
121 		populateBookmarks(bookmarkCmp);
122 		bookmarkCmp.getParent().layout(true, true);
123 	}
124 
125 	public void addFilterPanel(Composite parent) {
126 		// Use a delayed text: the query won't be done until the user stop
127 		// typing for 800ms
128 		int style = SWT.BORDER | SWT.SEARCH | SWT.ICON_CANCEL;
129 		DelayedText delayedText = new DelayedText(parent, style, ConnectUiConstants.SEARCH_TEXT_DELAY);
130 		filterTxt = delayedText.getText();
131 		filterTxt.setLayoutData(EclipseUiUtils.fillWidth());
132 
133 		// final ServerPushSession pushSession = new ServerPushSession();
134 		delayedText.addDelayedModifyListener(null, new ModifyListener() {
135 			private static final long serialVersionUID = 5003010530960334977L;
136 
137 			public void modifyText(ModifyEvent event) {
138 				delayedText.getText().getDisplay().asyncExec(new Runnable() {
139 					@Override
140 					public void run() {
141 						int resultNb = refreshFilteredList();
142 						if (resultNb > 0)
143 							((GridData) searchCmp.getLayoutData()).heightHint = 120;
144 						else
145 							((GridData) searchCmp.getLayoutData()).heightHint = 0;
146 						parent.layout(true, true);
147 					}
148 				});
149 				// pushSession.stop();
150 			}
151 		});
152 
153 		// Jump to the first item of the list using the down arrow
154 		filterTxt.addKeyListener(new KeyListener() {
155 			private static final long serialVersionUID = -4523394262771183968L;
156 
157 			@Override
158 			public void keyReleased(KeyEvent e) {
159 			}
160 
161 			@Override
162 			public void keyPressed(KeyEvent e) {
163 				// boolean shiftPressed = (e.stateMask & SWT.SHIFT) != 0;
164 				// boolean altPressed = (e.stateMask & SWT.ALT) != 0;
165 				if (e.keyCode == SWT.ARROW_DOWN || e.keyCode == SWT.TAB) {
166 					Object first = searchResultsViewer.getElementAt(0);
167 					if (first != null) {
168 						searchResultsViewer.getTable().setFocus();
169 						searchResultsViewer.setSelection(new StructuredSelection(first), true);
170 					}
171 					e.doit = false;
172 				}
173 			}
174 		});
175 	}
176 
177 	protected TableViewer createListPart(Composite parent, ILabelProvider labelProvider) {
178 		parent.setLayout(new GridLayout());
179 
180 		Composite tableComposite = new Composite(parent, SWT.NONE);
181 		tableComposite.setLayoutData(EclipseUiUtils.fillAll());
182 
183 		TableViewer v = new TableViewer(tableComposite);
184 		v.setLabelProvider(labelProvider);
185 
186 		TableColumn singleColumn = new TableColumn(v.getTable(), SWT.V_SCROLL);
187 		TableColumnLayout tableColumnLayout = new TableColumnLayout();
188 		tableColumnLayout.setColumnData(singleColumn, new ColumnWeightData(100));
189 		tableComposite.setLayout(tableColumnLayout);
190 
191 		// Corresponding table & style
192 		Table table = v.getTable();
193 		table.setLinesVisible(false);
194 		table.setHeaderVisible(false);
195 		CmsUtils.markup(table);
196 		CmsUtils.setItemHeight(table, 26);
197 
198 		v.setContentProvider(new BasicNodeListContentProvider());
199 		v.addDoubleClickListener(this);
200 		return v;
201 	}
202 
203 	@PreDestroy
204 	public void dispose() {
205 		JcrUtils.logoutQuietly(session);
206 	}
207 
208 	protected int refreshFilteredList() {
209 		try {
210 			String filter = filterTxt.getText();
211 			if (EclipseUiUtils.isEmpty(filter)) {
212 				searchResultsViewer.setInput(null);
213 				return 0;
214 			}
215 			// XPATH Query
216 			// String cf = XPathUtils.encodeXPathStringValue(filter);
217 			// String xpathQueryStr = "//element(*, nt:hierarchyNode)";
218 			// // + ConnectJcrUtils.getLocalJcrItemName(NodeType.NT_FILE) + ")";
219 			// String xpathFilter = XPathUtils.getFreeTextConstraint(filter);
220 			// if (notEmpty(xpathFilter))
221 			// xpathQueryStr += "[(" + xpathFilter + ") or "
222 			// //
223 			// + "(fn:name() = '" + cf + "' )" + "]";
224 			// QueryManager queryManager =
225 			// session.getWorkspace().getQueryManager();
226 			// Query xpathQuery = queryManager.createQuery(xpathQueryStr,
227 			// ConnectConstants.QUERY_XPATH);
228 
229 			// SQL2 QUERY
230 			String cf = XPathUtils.encodeXPathStringValue(filter);
231 			String qStr = "SELECT * FROM [nt:hierarchyNode] WHERE UPPER(LOCALNAME()) LIKE '%" + cf.toUpperCase() + "%'";
232 			QueryManager queryManager = session.getWorkspace().getQueryManager();
233 			Query xpathQuery = queryManager.createQuery(qStr, Query.JCR_SQL2);
234 
235 			// xpathQuery.setLimit(TrackerUiConstants.SEARCH_DEFAULT_LIMIT);
236 			QueryResult result = xpathQuery.execute();
237 			NodeIterator nit = result.getNodes();
238 			searchResultsViewer.setInput(JcrUtils.nodeIteratorToList(nit));
239 
240 			return (int) nit.getSize();
241 		} catch (RepositoryException e) {
242 			throw new DocumentsException("Unable to list files", e);
243 		}
244 	}
245 
246 	private void populateBookmarks(Composite parent) {
247 		CmsUtils.clear(parent);
248 		GridLayout layout = EclipseUiUtils.noSpaceGridLayout();
249 		layout.verticalSpacing = 5;
250 		parent.setLayout(layout);
251 		int bookmarkColWith = 200;
252 
253 		CellLabelProvider lp = new MyLabelProvider();
254 
255 		FsTableViewer homeViewer = new FsTableViewer(parent, SWT.SINGLE | SWT.NO_SCROLL);
256 		Table table = homeViewer.configureDefaultSingleColumnTable(bookmarkColWith, lp);
257 		GridData gd = EclipseUiUtils.fillWidth();
258 		gd.horizontalIndent = 10;
259 		table.setLayoutData(gd);
260 		homeViewer.addDoubleClickListener(this);
261 		homeViewer.setPathsInput(documentsService.getMyDocumentsPath(nodeFileSystemProvider, session));
262 
263 		Path[] wkGpHomes = documentsService.getMyGroupsFilesPath(nodeFileSystemProvider, session);
264 		if (wkGpHomes != null && wkGpHomes.length > 0) {
265 			appendTitle(parent, "Shared");
266 			FsTableViewer groupsViewer = new FsTableViewer(parent, SWT.SINGLE | SWT.NO_SCROLL);
267 			table = groupsViewer.configureDefaultSingleColumnTable(bookmarkColWith, lp);
268 			gd = EclipseUiUtils.fillWidth();
269 			gd.horizontalIndent = 10;
270 			table.setLayoutData(gd);
271 			groupsViewer.addDoubleClickListener(this);
272 			groupsViewer.setPathsInput(wkGpHomes);
273 		}
274 
275 		appendTitle(parent, "Bookmarks");
276 		BookmarksTableViewer bookmarksViewer = new BookmarksTableViewer(parent, SWT.MULTI | SWT.NO_SCROLL,
277 				documentsService.getMyBookmarksParent(session), documentsService, systemWorkbenchService);
278 		table = bookmarksViewer.configureDefaultSingleColumnTable(bookmarkColWith);
279 		gd = EclipseUiUtils.fillWidth();
280 		gd.horizontalIndent = 10;
281 		table.setLayoutData(gd);
282 		bookmarksViewer.addDoubleClickListener(this);
283 	}
284 
285 	private class MyLabelProvider extends ColumnLabelProvider {
286 		private static final long serialVersionUID = -3406927207142514035L;
287 
288 		public MyLabelProvider() {
289 			super();
290 		}
291 
292 		@Override
293 		public String getText(Object element) {
294 			Path curr = ((Path) element);
295 			try {
296 				String path = curr.toString();
297 				Node currNode = session.getNode(path);
298 //				Node parent = currNode.getParent();
299 				if (currNode.isNodeType(NodeTypes.NODE_USER_HOME))
300 					return currNode.getName();
301 				else if (currNode.isNodeType(NodeTypes.NODE_GROUP_HOME))
302 					return currNode.getProperty(NodeNames.LDAP_CN).getString();
303 
304 				else
305 					return super.getText(element);
306 			} catch (RepositoryException e) {
307 				throw new DocumentsException("Cannot retrieve label for " + curr, e);
308 			}
309 		}
310 
311 		@Override
312 		public Image getImage(Object element) {
313 			if (element instanceof Path) {
314 				Path curr = ((Path) element);
315 				String path = curr.toString();
316 				Node currNode = ConnectJcrUtils.getNode(session, path);
317 				return systemWorkbenchService.getIconForType(currNode);
318 			}
319 			return null;
320 		}
321 	}
322 
323 	private Label appendTitle(Composite parent, String value) {
324 		Label titleLbl = new Label(parent, SWT.NONE);
325 		titleLbl.setText(value);
326 		titleLbl.setFont(EclipseUiUtils.getBoldFont(parent));
327 		GridData gd = EclipseUiUtils.fillWidth();
328 		gd.horizontalIndent = 5;
329 		gd.verticalIndent = 5;
330 		titleLbl.setLayoutData(gd);
331 		return titleLbl;
332 	}
333 
334 	@Override
335 	public void doubleClick(DoubleClickEvent event) {
336 		IStructuredSelection selection = (IStructuredSelection) event.getSelection();
337 		if (selection.isEmpty())
338 			return;
339 		else {
340 			Object element = selection.getFirstElement();
341 			Node currNode;
342 
343 			if (element instanceof Node) {
344 				Node tmpNode = (Node) element;
345 				if (ConnectJcrUtils.isNodeType(tmpNode, DocumentsTypes.DOCUMENTS_BOOKMARK)) {
346 					String uriStr = ConnectJcrUtils.get(tmpNode, DocumentsNames.DOCUMENTS_URI);
347 					try {
348 						Path currPath = documentsService.getPath(nodeFileSystemProvider, new URI(uriStr));
349 						String jcrPath = currPath.toString();
350 						if (!session.itemExists(jcrPath)) {
351 							String msg = "Bookmarked folder at URI " + uriStr
352 									+ " cannot be found. If it is a local folder "
353 									+ "it has been removed or renamed.\nDo you want to delete corresponding bookmark?";
354 							boolean remove = MessageDialog.openConfirm(event.getViewer().getControl().getShell(),
355 									"Missing target folder", msg);
356 							if (remove) {
357 								tmpNode.remove();
358 								session.save();
359 								forceRefresh(null);
360 							}
361 							return;
362 						} else
363 							currNode = session.getNode(jcrPath);
364 					} catch (URISyntaxException | RepositoryException e) {
365 						throw new DocumentsException("Cannot get target node for bookmark " + tmpNode, e);
366 					}
367 				} else
368 					currNode = tmpNode;
369 			} else if (element instanceof Path) {
370 				Path currPath = (Path) element;
371 				String jcrPath = currPath.toString();
372 				// TODO rather directly use the jcrPath / an URI?
373 				currNode = ConnectJcrUtils.getNode(session, jcrPath);
374 			} else
375 				throw new IllegalArgumentException("Cannot manage " + element + ", only Node and Path are supported.");
376 			// String nodeId = ConnectJcrUtils.getIdentifier(currNode);
377 			// FIXME hard coded parameter name
378 			// CommandUtils.callCommand(systemWorkbenchService.getOpenEntityEditorCmdId(),
379 			// "param.jcrId", nodeId);
380 			systemWorkbenchService.openEntityEditor(currNode);
381 		}
382 	}
383 
384 	/* DEPENDENCY INJECTION */
385 	// public void setRepository(Repository repository) {
386 	// this.repository = repository;
387 	// }
388 	//
389 	// public void setSystemWorkbenchService(SystemWorkbenchService
390 	// systemWorkbenchService) {
391 	// this.systemWorkbenchService = systemWorkbenchService;
392 	// }
393 	//
394 	// public void setNodeFileSystemProvider(FileSystemProvider
395 	// nodeFileSystemProvider) {
396 	// this.nodeFileSystemProvider = nodeFileSystemProvider;
397 	// }
398 	//
399 	// public void setDocumentsService(DocumentsService documentsService) {
400 	// this.documentsService = documentsService;
401 	// }
402 
403 	private class BasicNodeListContentProvider implements IStructuredContentProvider {
404 		private static final long serialVersionUID = 1L;
405 		private List<Node> nodes;
406 
407 		public void dispose() {
408 		}
409 
410 		/** Expects a list of nodes as a new input */
411 		@SuppressWarnings("unchecked")
412 		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
413 			nodes = (List<Node>) newInput;
414 		}
415 
416 		public Object[] getElements(Object arg0) {
417 			return nodes.toArray();
418 		}
419 	}
420 }