1 package org
.argeo
.slc
.client
.ui
.dist
.editors
;
3 import java
.util
.ArrayList
;
4 import java
.util
.HashMap
;
9 import javax
.jcr
.NodeIterator
;
10 import javax
.jcr
.Property
;
11 import javax
.jcr
.PropertyType
;
12 import javax
.jcr
.RepositoryException
;
13 import javax
.jcr
.Session
;
14 import javax
.jcr
.nodetype
.NodeType
;
15 import javax
.jcr
.query
.QueryManager
;
16 import javax
.jcr
.query
.QueryResult
;
17 import javax
.jcr
.query
.qom
.Constraint
;
18 import javax
.jcr
.query
.qom
.DynamicOperand
;
19 import javax
.jcr
.query
.qom
.Ordering
;
20 import javax
.jcr
.query
.qom
.QueryObjectModel
;
21 import javax
.jcr
.query
.qom
.QueryObjectModelFactory
;
22 import javax
.jcr
.query
.qom
.Selector
;
23 import javax
.jcr
.query
.qom
.StaticOperand
;
25 import org
.argeo
.cms
.ui
.workbench
.util
.CommandUtils
;
26 import org
.argeo
.cms
.ui
.workbench
.util
.PrivilegedJob
;
27 import org
.argeo
.eclipse
.ui
.jcr
.EclipseJcrMonitor
;
28 import org
.argeo
.jcr
.JcrMonitor
;
29 import org
.argeo
.jcr
.JcrUtils
;
30 import org
.argeo
.slc
.SlcException
;
31 import org
.argeo
.slc
.SlcNames
;
32 import org
.argeo
.slc
.SlcTypes
;
33 import org
.argeo
.slc
.client
.ui
.dist
.DistConstants
;
34 import org
.argeo
.slc
.client
.ui
.dist
.DistPlugin
;
35 import org
.argeo
.slc
.client
.ui
.dist
.commands
.DeleteArtifacts
;
36 import org
.argeo
.slc
.client
.ui
.dist
.commands
.OpenModuleEditor
;
37 import org
.argeo
.slc
.client
.ui
.dist
.utils
.DistNodeViewerComparator
;
38 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
39 import org
.eclipse
.core
.runtime
.IStatus
;
40 import org
.eclipse
.core
.runtime
.Status
;
41 import org
.eclipse
.jface
.action
.IMenuListener
;
42 import org
.eclipse
.jface
.action
.IMenuManager
;
43 import org
.eclipse
.jface
.action
.MenuManager
;
44 import org
.eclipse
.jface
.viewers
.ColumnLabelProvider
;
45 import org
.eclipse
.jface
.viewers
.DoubleClickEvent
;
46 import org
.eclipse
.jface
.viewers
.IDoubleClickListener
;
47 import org
.eclipse
.jface
.viewers
.IStructuredContentProvider
;
48 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
49 import org
.eclipse
.jface
.viewers
.TableViewer
;
50 import org
.eclipse
.jface
.viewers
.TableViewerColumn
;
51 import org
.eclipse
.jface
.viewers
.Viewer
;
52 import org
.eclipse
.swt
.SWT
;
53 import org
.eclipse
.swt
.events
.ModifyEvent
;
54 import org
.eclipse
.swt
.events
.ModifyListener
;
55 import org
.eclipse
.swt
.events
.SelectionAdapter
;
56 import org
.eclipse
.swt
.events
.SelectionEvent
;
57 import org
.eclipse
.swt
.layout
.FillLayout
;
58 import org
.eclipse
.swt
.layout
.GridData
;
59 import org
.eclipse
.swt
.layout
.GridLayout
;
60 import org
.eclipse
.swt
.widgets
.Composite
;
61 import org
.eclipse
.swt
.widgets
.Display
;
62 import org
.eclipse
.swt
.widgets
.Label
;
63 import org
.eclipse
.swt
.widgets
.Menu
;
64 import org
.eclipse
.swt
.widgets
.Table
;
65 import org
.eclipse
.swt
.widgets
.Text
;
66 import org
.eclipse
.ui
.IWorkbenchWindow
;
67 import org
.eclipse
.ui
.forms
.IManagedForm
;
68 import org
.eclipse
.ui
.forms
.editor
.FormPage
;
69 import org
.eclipse
.ui
.forms
.widgets
.FormToolkit
;
70 import org
.eclipse
.ui
.forms
.widgets
.ScrolledForm
;
71 import org
.eclipse
.ui
.forms
.widgets
.Section
;
73 /** Show all bundles contained in a given workspace as filter-able table */
74 public class DistWkspSearchPage
extends FormPage
implements SlcNames
{
75 // final private static CmsLog log = CmsLog
76 // .getLog(DistributionOverviewPage.class);
78 final static String PAGE_ID
= "distributionOverviewPage";
81 private Session session
;
84 private DistWorkspaceEditor formEditor
;
85 private FormToolkit tk
;
87 private DistNodeViewerComparator comparator
;
88 private TableViewer viewer
;
90 // private Composite header;
91 private Text artifactTxt
;
92 private final static String FILTER_HELP_MSG
= "Filter criterion, separated by a space";
94 public DistWkspSearchPage(DistWorkspaceEditor formEditor
, String title
,
96 super(formEditor
, PAGE_ID
, title
);
97 this.formEditor
= formEditor
;
98 this.session
= session
;
101 private void asynchronousRefresh() {
102 RefreshJob job
= new RefreshJob(artifactTxt
.getText(), viewer
,
103 getSite().getShell().getDisplay());
108 private class RefreshJob
extends PrivilegedJob
{
109 private TableViewer viewer
;
110 private String filter
;
111 private Display display
;
113 public RefreshJob(String filter
, TableViewer viewer
, Display display
) {
114 super("Get bundle list");
115 this.filter
= filter
;
116 this.viewer
= viewer
;
117 this.display
= display
;
121 protected IStatus
doRun(IProgressMonitor progressMonitor
) {
123 JcrMonitor monitor
= new EclipseJcrMonitor(progressMonitor
);
124 monitor
.beginTask("Getting bundle list", -1);
125 final List
<Node
> result
= JcrUtils
126 .nodeIteratorToList(listBundleArtifacts(session
, filter
));
128 display
.asyncExec(new Runnable() {
130 viewer
.setInput(result
);
133 } catch (Exception e
) {
134 return new Status(IStatus
.ERROR
, DistPlugin
.PLUGIN_ID
,
135 "Cannot get bundle list", e
);
137 return Status
.OK_STATUS
;
142 protected void createFormContent(IManagedForm managedForm
) {
143 ScrolledForm form
= managedForm
.getForm();
144 tk
= managedForm
.getToolkit();
147 GridLayout layout
= new GridLayout(1, false);
148 Composite body
= form
.getBody();
149 body
.setLayout(layout
);
151 // Meta info about current workspace
152 Composite header
= tk
.createComposite(body
);
153 header
.setLayoutData(new GridData(SWT
.FILL
, SWT
.TOP
, true, false));
154 createHeaderPart(form
, header
);
156 Composite modules
= tk
.createComposite(body
);
157 modules
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
158 populateModuleSection(modules
);
161 private void createHeaderPart(ScrolledForm form
, Composite parent
) {
162 GridLayout layout
= new GridLayout(4, false);
163 // layout.marginWidth = layout.marginHeight = layout.verticalSpacing =
165 // layout.horizontalSpacing = 2;
166 parent
.setLayout(layout
);
168 String wkspName
= ((DistWkspEditorInput
) getEditorInput())
170 wkspName
= wkspName
.replaceAll("-", " ");
171 form
.setText(wkspName
);
173 String repoAlias
= "";
174 Node repoNode
= ((DistWorkspaceEditor
) getEditor()).getRepoNode();
175 if (repoNode
!= null)
177 repoAlias
= repoNode
.isNodeType(NodeType
.MIX_TITLE
) ? repoNode
178 .getProperty(Property
.JCR_TITLE
).getString() : repoNode
180 } catch (RepositoryException e1
) {
181 throw new SlcException("Unable to get repository alias ", e1
);
186 createLT(parent
, "Repository alias", repoAlias
);
187 createLT(parent
, "URI",
188 ((DistWkspEditorInput
) getEditorInput()).getUri());
191 private void populateModuleSection(Composite parent
) {
192 GridLayout layout
= new GridLayout(1, false);
193 layout
.marginWidth
= layout
.horizontalSpacing
= layout
.horizontalSpacing
= layout
.marginHeight
= 0;
194 parent
.setLayout(layout
);
196 Section section
= tk
.createSection(parent
, Section
.TITLE_BAR
197 | Section
.DESCRIPTION
);
198 section
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
200 section
.setText("Artifacts");
201 section
.setDescription("Search among all artifacts that are referenced in the current workspace");
202 section
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
204 Composite body
= tk
.createComposite(section
);
205 layout
= new GridLayout(1, false);
206 layout
.marginWidth
= layout
.horizontalSpacing
= layout
.horizontalSpacing
= layout
.marginHeight
= 0;
207 body
.setLayout(new GridLayout());
210 Composite filter
= tk
.createComposite(body
);
211 filter
.setLayoutData(new GridData(SWT
.FILL
, SWT
.TOP
, true, false));
212 createFilterPart(filter
);
215 Composite tableCmp
= tk
.createComposite(body
);
216 tableCmp
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
217 createTableViewer(tableCmp
);
219 section
.setClient(body
);
222 /** Build repository request */
223 private NodeIterator
listBundleArtifacts(Session session
, String filter
)
224 throws RepositoryException
{
225 QueryManager queryManager
= session
.getWorkspace().getQueryManager();
226 QueryObjectModelFactory factory
= queryManager
.getQOMFactory();
228 final String bundleArtifactsSelector
= "bundleArtifacts";
229 Selector source
= factory
.selector(SlcTypes
.SLC_BUNDLE_ARTIFACT
,
230 bundleArtifactsSelector
);
232 // Create a dynamic operand for each property on which we want to filter
233 DynamicOperand symbNameDO
= factory
.propertyValue(
234 source
.getSelectorName(), SlcNames
.SLC_SYMBOLIC_NAME
);
235 DynamicOperand versionDO
= factory
.propertyValue(
236 source
.getSelectorName(), SlcNames
.SLC_BUNDLE_VERSION
);
237 DynamicOperand nameDO
= factory
.propertyValue(source
.getSelectorName(),
238 DistConstants
.SLC_BUNDLE_NAME
);
240 // Default Constraint: no source artifacts
241 Constraint defaultC
= factory
.not(factory
.comparison(
243 QueryObjectModelFactory
.JCR_OPERATOR_LIKE
,
244 factory
.literal(session
.getValueFactory().createValue(
247 // Build constraints based the textArea content
248 if (filter
!= null && !"".equals(filter
.trim())) {
250 String
[] strs
= filter
.trim().split(" ");
251 for (String token
: strs
) {
252 token
= token
.replace('*', '%');
253 StaticOperand so
= factory
.literal(session
.getValueFactory()
254 .createValue("%" + token
+ "%"));
256 Constraint currC
= factory
.comparison(symbNameDO
,
257 QueryObjectModelFactory
.JCR_OPERATOR_LIKE
, so
);
258 currC
= factory
.or(currC
, factory
.comparison(versionDO
,
259 QueryObjectModelFactory
.JCR_OPERATOR_LIKE
, so
));
260 currC
= factory
.or(currC
, factory
.comparison(nameDO
,
261 QueryObjectModelFactory
.JCR_OPERATOR_LIKE
, so
));
263 defaultC
= factory
.and(defaultC
, currC
);
267 Ordering order
= factory
.descending(factory
.propertyValue(
268 bundleArtifactsSelector
, SlcNames
.SLC_BUNDLE_VERSION
));
269 Ordering order2
= factory
.ascending(factory
.propertyValue(
270 bundleArtifactsSelector
, SlcNames
.SLC_SYMBOLIC_NAME
));
271 Ordering
[] orderings
= { order
, order2
};
273 QueryObjectModel query
= factory
.createQuery(source
, defaultC
,
276 QueryResult result
= query
.execute();
277 return result
.getNodes();
281 private Text
createLT(Composite parent
, String labelValue
, String textValue
) {
282 Label label
= new Label(parent
, SWT
.RIGHT
);
283 label
.setText(labelValue
);
284 // label.setFont(EclipseUiUtils.getBoldFont(parent));
285 label
.setLayoutData(new GridData(SWT
.RIGHT
, SWT
.CENTER
, false, false));
287 // Add a trailing space to workaround a display glitch in RAP 1.3
288 Text text
= new Text(parent
, SWT
.LEFT
); // | SWT.BORDER
289 text
.setText(textValue
+ " ");
290 text
.setEditable(false);
294 private void createFilterPart(Composite parent
) {
295 GridLayout layout
= new GridLayout();
296 layout
.marginWidth
= layout
.marginHeight
= layout
.verticalSpacing
= 0;
297 layout
.horizontalSpacing
= 5;
298 parent
.setLayout(layout
);
300 // Text Area to filter
301 artifactTxt
= tk
.createText(parent
, "", SWT
.BORDER
| SWT
.SINGLE
302 | SWT
.SEARCH
| SWT
.CANCEL
);
303 artifactTxt
.setMessage(FILTER_HELP_MSG
);
304 GridData gd
= new GridData(SWT
.FILL
, SWT
.FILL
, false, false);
305 gd
.grabExcessHorizontalSpace
= true;
306 artifactTxt
.setLayoutData(gd
);
307 artifactTxt
.addModifyListener(new ModifyListener() {
308 private static final long serialVersionUID
= -2422321852703208573L;
310 public void modifyText(ModifyEvent event
) {
311 if ("".equals(artifactTxt
.getText().trim()))
312 asynchronousRefresh();
314 refreshFilteredList();
319 private void refreshFilteredList() {
322 nodes
= JcrUtils
.nodeIteratorToList(listBundleArtifacts(session
,
323 artifactTxt
.getText()));
324 viewer
.setInput(nodes
);
325 } catch (RepositoryException e
) {
326 throw new SlcException("Unable to list bundles", e
);
330 private void createTableViewer(Composite parent
) {
331 parent
.setLayout(new FillLayout());
332 // helpers to enable sorting by column
333 List
<String
> propertiesList
= new ArrayList
<String
>();
334 List
<Integer
> propertyTypesList
= new ArrayList
<Integer
>();
336 // Define the TableViewer
337 viewer
= new TableViewer(parent
, SWT
.MULTI
| SWT
.H_SCROLL
338 | SWT
.V_SCROLL
| SWT
.FULL_SELECTION
| SWT
.BORDER
);
341 TableViewerColumn col
= new TableViewerColumn(viewer
, SWT
.NONE
);
342 col
.getColumn().setWidth(300);
343 col
.getColumn().setText("Name");
344 col
.setLabelProvider(new ColumnLabelProvider() {
345 private static final long serialVersionUID
= -760226161605987538L;
348 public String
getText(Object element
) {
349 return JcrUtils
.get((Node
) element
,
350 DistConstants
.SLC_BUNDLE_NAME
);
353 col
.getColumn().addSelectionListener(getSelectionAdapter(0));
354 propertiesList
.add(DistConstants
.SLC_BUNDLE_NAME
);
355 propertyTypesList
.add(PropertyType
.STRING
);
358 col
= new TableViewerColumn(viewer
, SWT
.V_SCROLL
);
359 col
.getColumn().setWidth(300);
360 col
.getColumn().setText("Symbolic Name");
361 col
.setLabelProvider(new ColumnLabelProvider() {
362 private static final long serialVersionUID
= 4431447542158431355L;
365 public String
getText(Object element
) {
366 return JcrUtils
.get((Node
) element
, SLC_SYMBOLIC_NAME
);
369 col
.getColumn().addSelectionListener(getSelectionAdapter(1));
370 propertiesList
.add(SLC_SYMBOLIC_NAME
);
371 propertyTypesList
.add(PropertyType
.STRING
);
374 col
= new TableViewerColumn(viewer
, SWT
.NONE
);
375 col
.getColumn().setWidth(130);
376 col
.getColumn().setText("Version");
377 col
.setLabelProvider(new ColumnLabelProvider() {
378 private static final long serialVersionUID
= -5616215547236158504L;
381 public String
getText(Object element
) {
382 return JcrUtils
.get((Node
) element
, SLC_BUNDLE_VERSION
);
385 col
.getColumn().addSelectionListener(getSelectionAdapter(2));
386 propertiesList
.add(SLC_BUNDLE_VERSION
);
387 propertyTypesList
.add(DistNodeViewerComparator
.VERSION_TYPE
);
389 final Table table
= viewer
.getTable();
390 table
.setHeaderVisible(true);
391 table
.setLinesVisible(true);
393 viewer
.setContentProvider(new DistributionsContentProvider());
394 getSite().setSelectionProvider(viewer
);
396 comparator
= new DistNodeViewerComparator(2,
397 DistNodeViewerComparator
.ASCENDING
, propertiesList
,
399 viewer
.setComparator(comparator
);
402 MenuManager menuManager
= new MenuManager();
403 Menu menu
= menuManager
.createContextMenu(viewer
.getTable());
404 menuManager
.addMenuListener(new IMenuListener() {
405 private static final long serialVersionUID
= -3886983092940055195L;
407 public void menuAboutToShow(IMenuManager manager
) {
408 contextMenuAboutToShow(manager
);
411 viewer
.getTable().setMenu(menu
);
412 getSite().registerContextMenu(menuManager
, viewer
);
415 viewer
.addDoubleClickListener(new DoubleClickListener());
419 public void setFocus() {
420 viewer
.getTable().setFocus();
423 /** force refresh of the artifact list */
424 public void refresh() {
425 asynchronousRefresh();
428 /** Programmatically configure the context menu */
429 protected void contextMenuAboutToShow(IMenuManager menuManager
) {
430 IWorkbenchWindow window
= DistPlugin
.getDefault().getWorkbench()
431 .getActiveWorkbenchWindow();
433 // Delete selected artifacts
434 CommandUtils
.refreshCommand(menuManager
, window
, DeleteArtifacts
.ID
,
435 DeleteArtifacts
.DEFAULT_LABEL
, DeleteArtifacts
.DEFAULT_ICON
,
439 private SelectionAdapter
getSelectionAdapter(final int index
) {
440 SelectionAdapter selectionAdapter
= new SelectionAdapter() {
441 private static final long serialVersionUID
= 5515884441510882460L;
444 public void widgetSelected(SelectionEvent e
) {
445 Table table
= viewer
.getTable();
446 comparator
.setColumn(index
);
447 int dir
= table
.getSortDirection();
448 if (table
.getSortColumn() == table
.getColumn(index
)) {
449 dir
= dir
== SWT
.UP ? SWT
.DOWN
: SWT
.UP
;
453 table
.setSortDirection(dir
);
454 table
.setSortColumn(table
.getColumn(index
));
458 return selectionAdapter
;
462 private class DistributionsContentProvider
implements
463 IStructuredContentProvider
{
464 private static final long serialVersionUID
= -635451814876234147L;
466 // we keep a cache of the Nodes in the content provider to be able to
467 // manage long request
468 private List
<Node
> nodes
;
470 public void dispose() {
473 // We expect a list of nodes as a new input
474 @SuppressWarnings("unchecked")
475 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
476 nodes
= (List
<Node
>) newInput
;
479 public Object
[] getElements(Object arg0
) {
480 return nodes
.toArray();
484 private class DoubleClickListener
implements IDoubleClickListener
{
486 public void doubleClick(DoubleClickEvent event
) {
487 Object obj
= ((IStructuredSelection
) event
.getSelection())
489 if (obj
instanceof Node
) {
490 Node node
= (Node
) obj
;
492 if (node
.isNodeType(SlcTypes
.SLC_ARTIFACT
)) {
493 DistWkspEditorInput dwip
= (DistWkspEditorInput
) formEditor
495 Map
<String
, String
> params
= new HashMap
<String
, String
>();
496 params
.put(OpenModuleEditor
.PARAM_REPO_NODE_PATH
,
497 dwip
.getRepoNodePath());
498 params
.put(OpenModuleEditor
.PARAM_REPO_URI
,
500 params
.put(OpenModuleEditor
.PARAM_WORKSPACE_NAME
,
501 dwip
.getWorkspaceName());
502 String path
= node
.getPath();
503 params
.put(OpenModuleEditor
.PARAM_MODULE_PATH
, path
);
504 CommandUtils
.callCommand(OpenModuleEditor
.ID
, params
);
506 } catch (RepositoryException re
) {
507 throw new SlcException("Cannot get path for node " + node
508 + " while setting parameters for "
509 + "command OpenModuleEditor", re
);