]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms.e4/src/org/argeo/cms/e4/jcr/JcrBrowserView.java
29037983b61d8918ca5bda2d64713bba5ab504af
[lgpl/argeo-commons.git] / org.argeo.cms.e4 / src / org / argeo / cms / e4 / jcr / JcrBrowserView.java
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.cms.e4.jcr;
17
18 import java.util.List;
19
20 import javax.annotation.PostConstruct;
21 import javax.annotation.PreDestroy;
22 import javax.inject.Inject;
23 import javax.jcr.Property;
24 import javax.jcr.PropertyType;
25 import javax.jcr.Repository;
26 import javax.jcr.RepositoryException;
27 import javax.jcr.RepositoryFactory;
28 import javax.jcr.Session;
29 import javax.jcr.Value;
30 import javax.jcr.observation.Event;
31 import javax.jcr.observation.EventListener;
32 import javax.jcr.observation.ObservationManager;
33
34 import org.argeo.cms.CmsException;
35 import org.argeo.cms.ui.jcr.JcrBrowserUtils;
36 import org.argeo.cms.ui.jcr.JcrDClickListener;
37 import org.argeo.cms.ui.jcr.NodeContentProvider;
38 import org.argeo.cms.ui.jcr.NodeLabelProvider;
39 import org.argeo.cms.ui.jcr.OsgiRepositoryRegister;
40 import org.argeo.cms.ui.jcr.PropertiesContentProvider;
41 import org.argeo.cms.ui.jcr.model.SingleJcrNodeElem;
42 import org.argeo.cms.util.CmsUtils;
43 import org.argeo.eclipse.ui.EclipseUiException;
44 import org.argeo.eclipse.ui.TreeParent;
45 import org.argeo.eclipse.ui.jcr.AsyncUiEventListener;
46 import org.argeo.eclipse.ui.jcr.utils.NodeViewerComparer;
47 import org.argeo.node.security.CryptoKeyring;
48 import org.eclipse.e4.ui.services.EMenuService;
49 import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
50 import org.eclipse.jface.viewers.ColumnLabelProvider;
51 import org.eclipse.jface.viewers.IBaseLabelProvider;
52 import org.eclipse.jface.viewers.ISelectionChangedListener;
53 import org.eclipse.jface.viewers.IStructuredSelection;
54 import org.eclipse.jface.viewers.ITreeContentProvider;
55 import org.eclipse.jface.viewers.SelectionChangedEvent;
56 import org.eclipse.jface.viewers.StructuredSelection;
57 import org.eclipse.jface.viewers.TableViewer;
58 import org.eclipse.jface.viewers.TableViewerColumn;
59 import org.eclipse.jface.viewers.TreeViewer;
60 import org.eclipse.swt.SWT;
61 import org.eclipse.swt.custom.SashForm;
62 import org.eclipse.swt.layout.FillLayout;
63 import org.eclipse.swt.layout.GridData;
64 import org.eclipse.swt.widgets.Composite;
65 import org.eclipse.swt.widgets.Display;
66
67 /**
68 * Basic View to display a sash form to browse a JCR compliant multiple
69 * repository environment
70 */
71 public class JcrBrowserView {
72 final static String ID = "org.argeo.cms.e4.jcrbrowser";
73 final static String NODE_VIEWER_POPUP_MENU_ID = "org.argeo.cms.e4.popupmenu.nodeViewer";
74
75 private boolean sortChildNodes = true;
76
77 /* DEPENDENCY INJECTION */
78 private CryptoKeyring keyring;
79 @Inject
80 private RepositoryFactory repositoryFactory;
81 @Inject
82 private Repository nodeRepository;
83
84 // Current user session on the "Argeo node" default workspace
85 private Session userSession;
86
87 private OsgiRepositoryRegister repositoryRegister = new OsgiRepositoryRegister();
88
89 // This page widgets
90 private TreeViewer nodesViewer;
91 private NodeContentProvider nodeContentProvider;
92 private TableViewer propertiesViewer;
93 private EventListener resultsObserver;
94
95 @PostConstruct
96 public void createPartControl(Composite parent, ESelectionService selectionService, EMenuService menuService) {
97 repositoryRegister.init();
98
99 parent.setLayout(new FillLayout());
100 SashForm sashForm = new SashForm(parent, SWT.VERTICAL);
101 // sashForm.setSashWidth(4);
102 // sashForm.setLayout(new FillLayout());
103
104 // Create the tree on top of the view
105 Composite top = new Composite(sashForm, SWT.NONE);
106 // GridLayout gl = new GridLayout(1, false);
107 top.setLayout(CmsUtils.noSpaceGridLayout());
108
109 try {
110 this.userSession = this.nodeRepository.login();
111 } catch (RepositoryException e) {
112 throw new CmsException("Cannot open user session", e);
113 }
114
115 nodeContentProvider = new NodeContentProvider(userSession, keyring, repositoryRegister, repositoryFactory,
116 sortChildNodes);
117
118 // nodes viewer
119 nodesViewer = createNodeViewer(top, nodeContentProvider);
120
121 // context menu : it is completely defined in the plugin.xml file.
122 // MenuManager menuManager = new MenuManager();
123 // Menu menu = menuManager.createContextMenu(nodesViewer.getTree());
124
125 // nodesViewer.getTree().setMenu(menu);
126
127 nodesViewer.setInput("");
128
129 // Create the property viewer on the bottom
130 Composite bottom = new Composite(sashForm, SWT.NONE);
131 bottom.setLayout(CmsUtils.noSpaceGridLayout());
132 propertiesViewer = createPropertiesViewer(bottom);
133
134 sashForm.setWeights(getWeights());
135 nodesViewer.setComparer(new NodeViewerComparer());
136 nodesViewer.addSelectionChangedListener(new ISelectionChangedListener() {
137 public void selectionChanged(SelectionChangedEvent event) {
138 IStructuredSelection selection = (IStructuredSelection) event.getSelection();
139 selectionService.setSelection(selection.toList());
140 }
141 });
142 menuService.registerContextMenu(nodesViewer.getControl(), NODE_VIEWER_POPUP_MENU_ID);
143 // getSite().registerContextMenu(menuManager, nodesViewer);
144 // getSite().setSelectionProvider(nodesViewer);
145 }
146
147 @PreDestroy
148 public void dispose() {
149 repositoryRegister.destroy();
150 }
151
152 public void refresh(Object obj) {
153 // Enable full refresh from a command when no element of the tree is
154 // selected
155 if (obj == null) {
156 Object[] elements = nodeContentProvider.getElements(null);
157 for (Object el : elements) {
158 if (el instanceof TreeParent)
159 JcrBrowserUtils.forceRefreshIfNeeded((TreeParent) el);
160 getNodeViewer().refresh(el);
161 }
162 } else
163 getNodeViewer().refresh(obj);
164 }
165
166 /**
167 * To be overridden to adapt size of form and result frames.
168 */
169 protected int[] getWeights() {
170 return new int[] { 70, 30 };
171 }
172
173 protected TreeViewer createNodeViewer(Composite parent, final ITreeContentProvider nodeContentProvider) {
174
175 final TreeViewer tmpNodeViewer = new TreeViewer(parent, SWT.MULTI);
176
177 tmpNodeViewer.getTree().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
178
179 tmpNodeViewer.setContentProvider(nodeContentProvider);
180 tmpNodeViewer.setLabelProvider((IBaseLabelProvider) new NodeLabelProvider());
181 tmpNodeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
182 public void selectionChanged(SelectionChangedEvent event) {
183 if (!event.getSelection().isEmpty()) {
184 IStructuredSelection sel = (IStructuredSelection) event.getSelection();
185 Object firstItem = sel.getFirstElement();
186 if (firstItem instanceof SingleJcrNodeElem)
187 propertiesViewer.setInput(((SingleJcrNodeElem) firstItem).getNode());
188 } else {
189 propertiesViewer.setInput("");
190 }
191 }
192 });
193
194 resultsObserver = new TreeObserver(tmpNodeViewer.getTree().getDisplay());
195 if (keyring != null)
196 try {
197 ObservationManager observationManager = userSession.getWorkspace().getObservationManager();
198 observationManager.addEventListener(resultsObserver, Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED, "/",
199 true, null, null, false);
200 } catch (RepositoryException e) {
201 throw new EclipseUiException("Cannot register listeners", e);
202 }
203
204 tmpNodeViewer.addDoubleClickListener(new JcrDClickListener(tmpNodeViewer));
205 return tmpNodeViewer;
206 }
207
208 protected TableViewer createPropertiesViewer(Composite parent) {
209 propertiesViewer = new TableViewer(parent, SWT.NONE);
210 propertiesViewer.getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
211 propertiesViewer.getTable().setHeaderVisible(true);
212 propertiesViewer.setContentProvider(new PropertiesContentProvider());
213 TableViewerColumn col = new TableViewerColumn(propertiesViewer, SWT.NONE);
214 col.getColumn().setText("Name");
215 col.getColumn().setWidth(200);
216 col.setLabelProvider(new ColumnLabelProvider() {
217 private static final long serialVersionUID = -6684361063107478595L;
218
219 public String getText(Object element) {
220 try {
221 return ((Property) element).getName();
222 } catch (RepositoryException e) {
223 throw new EclipseUiException("Unexpected exception in label provider", e);
224 }
225 }
226 });
227 col = new TableViewerColumn(propertiesViewer, SWT.NONE);
228 col.getColumn().setText("Value");
229 col.getColumn().setWidth(400);
230 col.setLabelProvider(new ColumnLabelProvider() {
231 private static final long serialVersionUID = -8201994187693336657L;
232
233 public String getText(Object element) {
234 try {
235 Property property = (Property) element;
236 if (property.getType() == PropertyType.BINARY)
237 return "<binary>";
238 else if (property.isMultiple()) {
239 StringBuffer buf = new StringBuffer("[");
240 Value[] values = property.getValues();
241 for (int i = 0; i < values.length; i++) {
242 if (i != 0)
243 buf.append(", ");
244 buf.append(values[i].getString());
245 }
246 buf.append(']');
247 return buf.toString();
248 } else
249 return property.getValue().getString();
250 } catch (RepositoryException e) {
251 throw new EclipseUiException("Unexpected exception in label provider", e);
252 }
253 }
254 });
255 col = new TableViewerColumn(propertiesViewer, SWT.NONE);
256 col.getColumn().setText("Type");
257 col.getColumn().setWidth(200);
258 col.setLabelProvider(new ColumnLabelProvider() {
259 private static final long serialVersionUID = -6009599998150286070L;
260
261 public String getText(Object element) {
262 return JcrBrowserUtils.getPropertyTypeAsString((Property) element);
263 }
264 });
265 propertiesViewer.setInput("");
266 return propertiesViewer;
267 }
268
269 protected TreeViewer getNodeViewer() {
270 return nodesViewer;
271 }
272
273 /**
274 * Resets the tree content provider
275 *
276 * @param sortChildNodes
277 * if true the content provider will use a comparer to sort nodes
278 * that might slow down the display
279 */
280 public void setSortChildNodes(boolean sortChildNodes) {
281 this.sortChildNodes = sortChildNodes;
282 ((NodeContentProvider) nodesViewer.getContentProvider()).setSortChildren(sortChildNodes);
283 nodesViewer.setInput("");
284 }
285
286 /** Notifies the current view that a node has been added */
287 public void nodeAdded(TreeParent parentNode) {
288 // insure that Ui objects have been correctly created:
289 JcrBrowserUtils.forceRefreshIfNeeded(parentNode);
290 getNodeViewer().refresh(parentNode);
291 getNodeViewer().expandToLevel(parentNode, 1);
292 }
293
294 /** Notifies the current view that a node has been removed */
295 public void nodeRemoved(TreeParent parentNode) {
296 IStructuredSelection newSel = new StructuredSelection(parentNode);
297 getNodeViewer().setSelection(newSel, true);
298 // Force refresh
299 IStructuredSelection tmpSel = (IStructuredSelection) getNodeViewer().getSelection();
300 getNodeViewer().refresh(tmpSel.getFirstElement());
301 }
302
303 class TreeObserver extends AsyncUiEventListener {
304
305 public TreeObserver(Display display) {
306 super(display);
307 }
308
309 @Override
310 protected Boolean willProcessInUiThread(List<Event> events) throws RepositoryException {
311 for (Event event : events) {
312 if (getLog().isTraceEnabled())
313 getLog().debug("Received event " + event);
314 String path = event.getPath();
315 int index = path.lastIndexOf('/');
316 String propertyName = path.substring(index + 1);
317 if (getLog().isTraceEnabled())
318 getLog().debug("Concerned property " + propertyName);
319 }
320 return false;
321 }
322
323 protected void onEventInUiThread(List<Event> events) throws RepositoryException {
324 if (getLog().isTraceEnabled())
325 getLog().trace("Refresh result list");
326 nodesViewer.refresh();
327 }
328
329 }
330
331 public boolean getSortChildNodes() {
332 return sortChildNodes;
333 }
334
335 public void setFocus() {
336 getNodeViewer().getTree().setFocus();
337 }
338
339 /* DEPENDENCY INJECTION */
340 // public void setRepositoryRegister(RepositoryRegister repositoryRegister) {
341 // this.repositoryRegister = repositoryRegister;
342 // }
343
344 public void setKeyring(CryptoKeyring keyring) {
345 this.keyring = keyring;
346 }
347
348 public void setRepositoryFactory(RepositoryFactory repositoryFactory) {
349 this.repositoryFactory = repositoryFactory;
350 }
351
352 public void setNodeRepository(Repository nodeRepository) {
353 this.nodeRepository = nodeRepository;
354 }
355 }