]> git.argeo.org Git - gpl/argeo-slc.git/blob - org.argeo.slc.client.ui.dist/src/org/argeo/slc/client/ui/dist/editors/DistWkspSearchPage.java
Adapt to changes in Argeo Commons.
[gpl/argeo-slc.git] / org.argeo.slc.client.ui.dist / src / org / argeo / slc / client / ui / dist / editors / DistWkspSearchPage.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.slc.client.ui.dist.editors;
17
18 import java.util.ArrayList;
19 import java.util.HashMap;
20 import java.util.List;
21 import java.util.Map;
22
23 import javax.jcr.Node;
24 import javax.jcr.NodeIterator;
25 import javax.jcr.Property;
26 import javax.jcr.PropertyType;
27 import javax.jcr.RepositoryException;
28 import javax.jcr.Session;
29 import javax.jcr.nodetype.NodeType;
30 import javax.jcr.query.QueryManager;
31 import javax.jcr.query.QueryResult;
32 import javax.jcr.query.qom.Constraint;
33 import javax.jcr.query.qom.DynamicOperand;
34 import javax.jcr.query.qom.Ordering;
35 import javax.jcr.query.qom.QueryObjectModel;
36 import javax.jcr.query.qom.QueryObjectModelFactory;
37 import javax.jcr.query.qom.Selector;
38 import javax.jcr.query.qom.StaticOperand;
39
40 import org.argeo.cms.ui.workbench.util.CommandUtils;
41 import org.argeo.cms.ui.workbench.util.PrivilegedJob;
42 import org.argeo.eclipse.ui.EclipseJcrMonitor;
43 import org.argeo.jcr.JcrMonitor;
44 import org.argeo.jcr.JcrUtils;
45 import org.argeo.slc.SlcException;
46 import org.argeo.slc.SlcNames;
47 import org.argeo.slc.SlcTypes;
48 import org.argeo.slc.client.ui.dist.DistConstants;
49 import org.argeo.slc.client.ui.dist.DistPlugin;
50 import org.argeo.slc.client.ui.dist.commands.DeleteArtifacts;
51 import org.argeo.slc.client.ui.dist.commands.OpenModuleEditor;
52 import org.argeo.slc.client.ui.dist.utils.DistNodeViewerComparator;
53 import org.eclipse.core.runtime.IProgressMonitor;
54 import org.eclipse.core.runtime.IStatus;
55 import org.eclipse.core.runtime.Status;
56 import org.eclipse.jface.action.IMenuListener;
57 import org.eclipse.jface.action.IMenuManager;
58 import org.eclipse.jface.action.MenuManager;
59 import org.eclipse.jface.viewers.ColumnLabelProvider;
60 import org.eclipse.jface.viewers.DoubleClickEvent;
61 import org.eclipse.jface.viewers.IDoubleClickListener;
62 import org.eclipse.jface.viewers.IStructuredContentProvider;
63 import org.eclipse.jface.viewers.IStructuredSelection;
64 import org.eclipse.jface.viewers.TableViewer;
65 import org.eclipse.jface.viewers.TableViewerColumn;
66 import org.eclipse.jface.viewers.Viewer;
67 import org.eclipse.swt.SWT;
68 import org.eclipse.swt.events.ModifyEvent;
69 import org.eclipse.swt.events.ModifyListener;
70 import org.eclipse.swt.events.SelectionAdapter;
71 import org.eclipse.swt.events.SelectionEvent;
72 import org.eclipse.swt.layout.FillLayout;
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.Display;
77 import org.eclipse.swt.widgets.Label;
78 import org.eclipse.swt.widgets.Menu;
79 import org.eclipse.swt.widgets.Table;
80 import org.eclipse.swt.widgets.Text;
81 import org.eclipse.ui.IWorkbenchWindow;
82 import org.eclipse.ui.forms.IManagedForm;
83 import org.eclipse.ui.forms.editor.FormPage;
84 import org.eclipse.ui.forms.widgets.FormToolkit;
85 import org.eclipse.ui.forms.widgets.ScrolledForm;
86 import org.eclipse.ui.forms.widgets.Section;
87
88 /** Show all bundles contained in a given workspace as filter-able table */
89 public class DistWkspSearchPage extends FormPage implements SlcNames {
90 // final private static Log log = LogFactory
91 // .getLog(DistributionOverviewPage.class);
92
93 final static String PAGE_ID = "distributionOverviewPage";
94
95 // Business Objects
96 private Session session;
97
98 // This page widgets
99 private DistWorkspaceEditor formEditor;
100 private FormToolkit tk;
101
102 private DistNodeViewerComparator comparator;
103 private TableViewer viewer;
104
105 // private Composite header;
106 private Text artifactTxt;
107 private final static String FILTER_HELP_MSG = "Filter criterion, separated by a space";
108
109 public DistWkspSearchPage(DistWorkspaceEditor formEditor, String title,
110 Session session) {
111 super(formEditor, PAGE_ID, title);
112 this.formEditor = formEditor;
113 this.session = session;
114 }
115
116 private void asynchronousRefresh() {
117 RefreshJob job = new RefreshJob(artifactTxt.getText(), viewer,
118 getSite().getShell().getDisplay());
119 job.setUser(true);
120 job.schedule();
121 }
122
123 private class RefreshJob extends PrivilegedJob {
124 private TableViewer viewer;
125 private String filter;
126 private Display display;
127
128 public RefreshJob(String filter, TableViewer viewer, Display display) {
129 super("Get bundle list");
130 this.filter = filter;
131 this.viewer = viewer;
132 this.display = display;
133 }
134
135 @Override
136 protected IStatus doRun(IProgressMonitor progressMonitor) {
137 try {
138 JcrMonitor monitor = new EclipseJcrMonitor(progressMonitor);
139 monitor.beginTask("Getting bundle list", -1);
140 final List<Node> result = JcrUtils
141 .nodeIteratorToList(listBundleArtifacts(session, filter));
142
143 display.asyncExec(new Runnable() {
144 public void run() {
145 viewer.setInput(result);
146 }
147 });
148 } catch (Exception e) {
149 return new Status(IStatus.ERROR, DistPlugin.PLUGIN_ID,
150 "Cannot get bundle list", e);
151 }
152 return Status.OK_STATUS;
153 }
154 }
155
156 @Override
157 protected void createFormContent(IManagedForm managedForm) {
158 ScrolledForm form = managedForm.getForm();
159 tk = managedForm.getToolkit();
160
161 // Main Layout
162 GridLayout layout = new GridLayout(1, false);
163 Composite body = form.getBody();
164 body.setLayout(layout);
165
166 // Meta info about current workspace
167 Composite header = tk.createComposite(body);
168 header.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
169 createHeaderPart(form, header);
170
171 Composite modules = tk.createComposite(body);
172 modules.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
173 populateModuleSection(modules);
174 }
175
176 private void createHeaderPart(ScrolledForm form, Composite parent) {
177 GridLayout layout = new GridLayout(4, false);
178 // layout.marginWidth = layout.marginHeight = layout.verticalSpacing =
179 // 0;
180 // layout.horizontalSpacing = 2;
181 parent.setLayout(layout);
182
183 String wkspName = ((DistWkspEditorInput) getEditorInput())
184 .getWorkspaceName();
185 wkspName = wkspName.replaceAll("-", " ");
186 form.setText(wkspName);
187
188 String repoAlias = "";
189 Node repoNode = ((DistWorkspaceEditor) getEditor()).getRepoNode();
190 if (repoNode != null)
191 try {
192 repoAlias = repoNode.isNodeType(NodeType.MIX_TITLE) ? repoNode
193 .getProperty(Property.JCR_TITLE).getString() : repoNode
194 .getName();
195 } catch (RepositoryException e1) {
196 throw new SlcException("Unable to get repository alias ", e1);
197 }
198 else
199 repoAlias = " - ";
200
201 createLT(parent, "Repository alias", repoAlias);
202 createLT(parent, "URI",
203 ((DistWkspEditorInput) getEditorInput()).getUri());
204 }
205
206 private void populateModuleSection(Composite parent) {
207 GridLayout layout = new GridLayout(1, false);
208 layout.marginWidth = layout.horizontalSpacing = layout.horizontalSpacing = layout.marginHeight = 0;
209 parent.setLayout(layout);
210
211 Section section = tk.createSection(parent, Section.TITLE_BAR
212 | Section.DESCRIPTION);
213 section.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
214
215 section.setText("Artifacts");
216 section.setDescription("Search among all artifacts that are referenced in the current workspace");
217 section.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
218
219 Composite body = tk.createComposite(section);
220 layout = new GridLayout(1, false);
221 layout.marginWidth = layout.horizontalSpacing = layout.horizontalSpacing = layout.marginHeight = 0;
222 body.setLayout(new GridLayout());
223
224 // Filter
225 Composite filter = tk.createComposite(body);
226 filter.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
227 createFilterPart(filter);
228
229 // Table
230 Composite tableCmp = tk.createComposite(body);
231 tableCmp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
232 createTableViewer(tableCmp);
233
234 section.setClient(body);
235 }
236
237 /** Build repository request */
238 private NodeIterator listBundleArtifacts(Session session, String filter)
239 throws RepositoryException {
240 QueryManager queryManager = session.getWorkspace().getQueryManager();
241 QueryObjectModelFactory factory = queryManager.getQOMFactory();
242
243 final String bundleArtifactsSelector = "bundleArtifacts";
244 Selector source = factory.selector(SlcTypes.SLC_BUNDLE_ARTIFACT,
245 bundleArtifactsSelector);
246
247 // Create a dynamic operand for each property on which we want to filter
248 DynamicOperand symbNameDO = factory.propertyValue(
249 source.getSelectorName(), SlcNames.SLC_SYMBOLIC_NAME);
250 DynamicOperand versionDO = factory.propertyValue(
251 source.getSelectorName(), SlcNames.SLC_BUNDLE_VERSION);
252 DynamicOperand nameDO = factory.propertyValue(source.getSelectorName(),
253 DistConstants.SLC_BUNDLE_NAME);
254
255 // Default Constraint: no source artifacts
256 Constraint defaultC = factory.not(factory.comparison(
257 symbNameDO,
258 QueryObjectModelFactory.JCR_OPERATOR_LIKE,
259 factory.literal(session.getValueFactory().createValue(
260 "%.source"))));
261
262 // Build constraints based the textArea content
263 if (filter != null && !"".equals(filter.trim())) {
264 // Parse the String
265 String[] strs = filter.trim().split(" ");
266 for (String token : strs) {
267 token = token.replace('*', '%');
268 StaticOperand so = factory.literal(session.getValueFactory()
269 .createValue("%" + token + "%"));
270
271 Constraint currC = factory.comparison(symbNameDO,
272 QueryObjectModelFactory.JCR_OPERATOR_LIKE, so);
273 currC = factory.or(currC, factory.comparison(versionDO,
274 QueryObjectModelFactory.JCR_OPERATOR_LIKE, so));
275 currC = factory.or(currC, factory.comparison(nameDO,
276 QueryObjectModelFactory.JCR_OPERATOR_LIKE, so));
277
278 defaultC = factory.and(defaultC, currC);
279 }
280 }
281
282 Ordering order = factory.descending(factory.propertyValue(
283 bundleArtifactsSelector, SlcNames.SLC_BUNDLE_VERSION));
284 Ordering order2 = factory.ascending(factory.propertyValue(
285 bundleArtifactsSelector, SlcNames.SLC_SYMBOLIC_NAME));
286 Ordering[] orderings = { order, order2 };
287
288 QueryObjectModel query = factory.createQuery(source, defaultC,
289 orderings, null);
290
291 QueryResult result = query.execute();
292 return result.getNodes();
293
294 }
295
296 private Text createLT(Composite parent, String labelValue, String textValue) {
297 Label label = new Label(parent, SWT.RIGHT);
298 label.setText(labelValue);
299 // label.setFont(EclipseUiUtils.getBoldFont(parent));
300 label.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
301
302 // Add a trailing space to workaround a display glitch in RAP 1.3
303 Text text = new Text(parent, SWT.LEFT); // | SWT.BORDER
304 text.setText(textValue + " ");
305 text.setEditable(false);
306 return text;
307 }
308
309 private void createFilterPart(Composite parent) {
310 GridLayout layout = new GridLayout();
311 layout.marginWidth = layout.marginHeight = layout.verticalSpacing = 0;
312 layout.horizontalSpacing = 5;
313 parent.setLayout(layout);
314
315 // Text Area to filter
316 artifactTxt = tk.createText(parent, "", SWT.BORDER | SWT.SINGLE
317 | SWT.SEARCH | SWT.CANCEL);
318 artifactTxt.setMessage(FILTER_HELP_MSG);
319 GridData gd = new GridData(SWT.FILL, SWT.FILL, false, false);
320 gd.grabExcessHorizontalSpace = true;
321 artifactTxt.setLayoutData(gd);
322 artifactTxt.addModifyListener(new ModifyListener() {
323 private static final long serialVersionUID = -2422321852703208573L;
324
325 public void modifyText(ModifyEvent event) {
326 if ("".equals(artifactTxt.getText().trim()))
327 asynchronousRefresh();
328 else
329 refreshFilteredList();
330 }
331 });
332 }
333
334 private void refreshFilteredList() {
335 List<Node> nodes;
336 try {
337 nodes = JcrUtils.nodeIteratorToList(listBundleArtifacts(session,
338 artifactTxt.getText()));
339 viewer.setInput(nodes);
340 } catch (RepositoryException e) {
341 throw new SlcException("Unable to list bundles", e);
342 }
343 }
344
345 private void createTableViewer(Composite parent) {
346 parent.setLayout(new FillLayout());
347 // helpers to enable sorting by column
348 List<String> propertiesList = new ArrayList<String>();
349 List<Integer> propertyTypesList = new ArrayList<Integer>();
350
351 // Define the TableViewer
352 viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL
353 | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER);
354
355 // Name
356 TableViewerColumn col = new TableViewerColumn(viewer, SWT.NONE);
357 col.getColumn().setWidth(300);
358 col.getColumn().setText("Name");
359 col.setLabelProvider(new ColumnLabelProvider() {
360 private static final long serialVersionUID = -760226161605987538L;
361
362 @Override
363 public String getText(Object element) {
364 return JcrUtils.get((Node) element,
365 DistConstants.SLC_BUNDLE_NAME);
366 }
367 });
368 col.getColumn().addSelectionListener(getSelectionAdapter(0));
369 propertiesList.add(DistConstants.SLC_BUNDLE_NAME);
370 propertyTypesList.add(PropertyType.STRING);
371
372 // Symbolic name
373 col = new TableViewerColumn(viewer, SWT.V_SCROLL);
374 col.getColumn().setWidth(300);
375 col.getColumn().setText("Symbolic Name");
376 col.setLabelProvider(new ColumnLabelProvider() {
377 private static final long serialVersionUID = 4431447542158431355L;
378
379 @Override
380 public String getText(Object element) {
381 return JcrUtils.get((Node) element, SLC_SYMBOLIC_NAME);
382 }
383 });
384 col.getColumn().addSelectionListener(getSelectionAdapter(1));
385 propertiesList.add(SLC_SYMBOLIC_NAME);
386 propertyTypesList.add(PropertyType.STRING);
387
388 // Version
389 col = new TableViewerColumn(viewer, SWT.NONE);
390 col.getColumn().setWidth(130);
391 col.getColumn().setText("Version");
392 col.setLabelProvider(new ColumnLabelProvider() {
393 private static final long serialVersionUID = -5616215547236158504L;
394
395 @Override
396 public String getText(Object element) {
397 return JcrUtils.get((Node) element, SLC_BUNDLE_VERSION);
398 }
399 });
400 col.getColumn().addSelectionListener(getSelectionAdapter(2));
401 propertiesList.add(SLC_BUNDLE_VERSION);
402 propertyTypesList.add(DistNodeViewerComparator.VERSION_TYPE);
403
404 final Table table = viewer.getTable();
405 table.setHeaderVisible(true);
406 table.setLinesVisible(true);
407
408 viewer.setContentProvider(new DistributionsContentProvider());
409 getSite().setSelectionProvider(viewer);
410
411 comparator = new DistNodeViewerComparator(2,
412 DistNodeViewerComparator.ASCENDING, propertiesList,
413 propertyTypesList);
414 viewer.setComparator(comparator);
415
416 // Context Menu
417 MenuManager menuManager = new MenuManager();
418 Menu menu = menuManager.createContextMenu(viewer.getTable());
419 menuManager.addMenuListener(new IMenuListener() {
420 private static final long serialVersionUID = -3886983092940055195L;
421
422 public void menuAboutToShow(IMenuManager manager) {
423 contextMenuAboutToShow(manager);
424 }
425 });
426 viewer.getTable().setMenu(menu);
427 getSite().registerContextMenu(menuManager, viewer);
428
429 // Double click
430 viewer.addDoubleClickListener(new DoubleClickListener());
431 }
432
433 @Override
434 public void setFocus() {
435 viewer.getTable().setFocus();
436 }
437
438 /** force refresh of the artifact list */
439 public void refresh() {
440 asynchronousRefresh();
441 }
442
443 /** Programmatically configure the context menu */
444 protected void contextMenuAboutToShow(IMenuManager menuManager) {
445 IWorkbenchWindow window = DistPlugin.getDefault().getWorkbench()
446 .getActiveWorkbenchWindow();
447 // Build conditions
448 // Delete selected artifacts
449 CommandUtils.refreshCommand(menuManager, window, DeleteArtifacts.ID,
450 DeleteArtifacts.DEFAULT_LABEL, DeleteArtifacts.DEFAULT_ICON,
451 true);
452 }
453
454 private SelectionAdapter getSelectionAdapter(final int index) {
455 SelectionAdapter selectionAdapter = new SelectionAdapter() {
456 private static final long serialVersionUID = 5515884441510882460L;
457
458 @Override
459 public void widgetSelected(SelectionEvent e) {
460 Table table = viewer.getTable();
461 comparator.setColumn(index);
462 int dir = table.getSortDirection();
463 if (table.getSortColumn() == table.getColumn(index)) {
464 dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
465 } else {
466 dir = SWT.DOWN;
467 }
468 table.setSortDirection(dir);
469 table.setSortColumn(table.getColumn(index));
470 viewer.refresh();
471 }
472 };
473 return selectionAdapter;
474 }
475
476 /* LOCAL CLASSES */
477 private class DistributionsContentProvider implements
478 IStructuredContentProvider {
479 private static final long serialVersionUID = -635451814876234147L;
480
481 // we keep a cache of the Nodes in the content provider to be able to
482 // manage long request
483 private List<Node> nodes;
484
485 public void dispose() {
486 }
487
488 // We expect a list of nodes as a new input
489 @SuppressWarnings("unchecked")
490 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
491 nodes = (List<Node>) newInput;
492 }
493
494 public Object[] getElements(Object arg0) {
495 return nodes.toArray();
496 }
497 }
498
499 private class DoubleClickListener implements IDoubleClickListener {
500
501 public void doubleClick(DoubleClickEvent event) {
502 Object obj = ((IStructuredSelection) event.getSelection())
503 .getFirstElement();
504 if (obj instanceof Node) {
505 Node node = (Node) obj;
506 try {
507 if (node.isNodeType(SlcTypes.SLC_ARTIFACT)) {
508 DistWkspEditorInput dwip = (DistWkspEditorInput) formEditor
509 .getEditorInput();
510 Map<String, String> params = new HashMap<String, String>();
511 params.put(OpenModuleEditor.PARAM_REPO_NODE_PATH,
512 dwip.getRepoNodePath());
513 params.put(OpenModuleEditor.PARAM_REPO_URI,
514 dwip.getUri());
515 params.put(OpenModuleEditor.PARAM_WORKSPACE_NAME,
516 dwip.getWorkspaceName());
517 String path = node.getPath();
518 params.put(OpenModuleEditor.PARAM_MODULE_PATH, path);
519 CommandUtils.callCommand(OpenModuleEditor.ID, params);
520 }
521 } catch (RepositoryException re) {
522 throw new SlcException("Cannot get path for node " + node
523 + " while setting parameters for "
524 + "command OpenModuleEditor", re);
525 }
526
527 }
528 }
529 }
530 }