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