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