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