2 * Copyright (C) 2007-2012 Argeo GmbH
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org
.argeo
.slc
.client
.ui
.dist
.editors
;
18 import java
.util
.ArrayList
;
19 import java
.util
.HashMap
;
20 import java
.util
.List
;
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
;
40 import org
.argeo
.ArgeoMonitor
;
41 import org
.argeo
.eclipse
.ui
.EclipseArgeoMonitor
;
42 import org
.argeo
.eclipse
.ui
.workbench
.CommandUtils
;
43 import org
.argeo
.jcr
.JcrUtils
;
44 import org
.argeo
.slc
.SlcException
;
45 import org
.argeo
.slc
.client
.ui
.dist
.DistConstants
;
46 import org
.argeo
.slc
.client
.ui
.dist
.DistPlugin
;
47 import org
.argeo
.security
.ui
.PrivilegedJob
;
48 import org
.argeo
.slc
.client
.ui
.dist
.commands
.DeleteArtifacts
;
49 import org
.argeo
.slc
.client
.ui
.dist
.commands
.OpenModuleEditor
;
50 import org
.argeo
.slc
.client
.ui
.dist
.utils
.DistNodeViewerComparator
;
51 import org
.argeo
.slc
.jcr
.SlcNames
;
52 import org
.argeo
.slc
.jcr
.SlcTypes
;
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
;
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);
93 final static String PAGE_ID
= "distributionOverviewPage";
96 private Session session
;
99 private DistWorkspaceEditor formEditor
;
100 private FormToolkit tk
;
102 private DistNodeViewerComparator comparator
;
103 private TableViewer viewer
;
105 // private Composite header;
106 private Text artifactTxt
;
107 private final static String FILTER_HELP_MSG
= "Filter criterion, separated by a space";
109 public DistWkspSearchPage(DistWorkspaceEditor formEditor
, String title
,
111 super(formEditor
, PAGE_ID
, title
);
112 this.formEditor
= formEditor
;
113 this.session
= session
;
116 private void asynchronousRefresh() {
117 RefreshJob job
= new RefreshJob(artifactTxt
.getText(), viewer
,
118 getSite().getShell().getDisplay());
123 private class RefreshJob
extends PrivilegedJob
{
124 private TableViewer viewer
;
125 private String filter
;
126 private Display display
;
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
;
136 protected IStatus
doRun(IProgressMonitor progressMonitor
) {
138 ArgeoMonitor monitor
= new EclipseArgeoMonitor(progressMonitor
);
139 monitor
.beginTask("Getting bundle list", -1);
140 final List
<Node
> result
= JcrUtils
141 .nodeIteratorToList(listBundleArtifacts(session
, filter
));
143 display
.asyncExec(new Runnable() {
145 viewer
.setInput(result
);
148 } catch (Exception e
) {
149 return new Status(IStatus
.ERROR
, DistPlugin
.PLUGIN_ID
,
150 "Cannot get bundle list", e
);
152 return Status
.OK_STATUS
;
157 protected void createFormContent(IManagedForm managedForm
) {
158 ScrolledForm form
= managedForm
.getForm();
159 tk
= managedForm
.getToolkit();
162 GridLayout layout
= new GridLayout(1, false);
163 Composite body
= form
.getBody();
164 body
.setLayout(layout
);
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
);
171 Composite modules
= tk
.createComposite(body
);
172 modules
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
173 populateModuleSection(modules
);
176 private void createHeaderPart(ScrolledForm form
, Composite parent
) {
177 GridLayout layout
= new GridLayout(4, false);
178 // layout.marginWidth = layout.marginHeight = layout.verticalSpacing =
180 // layout.horizontalSpacing = 2;
181 parent
.setLayout(layout
);
183 String wkspName
= ((DistWkspEditorInput
) getEditorInput())
185 wkspName
= wkspName
.replaceAll("-", " ");
186 form
.setText(wkspName
);
188 String repoAlias
= "";
189 Node repoNode
= ((DistWorkspaceEditor
) getEditor()).getRepoNode();
190 if (repoNode
!= null)
192 repoAlias
= repoNode
.isNodeType(NodeType
.MIX_TITLE
) ? repoNode
193 .getProperty(Property
.JCR_TITLE
).getString() : repoNode
195 } catch (RepositoryException e1
) {
196 throw new SlcException("Unable to get repository alias ", e1
);
201 createLT(parent
, "Repository alias", repoAlias
);
202 createLT(parent
, "URI",
203 ((DistWkspEditorInput
) getEditorInput()).getUri());
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
);
211 Section section
= tk
.createSection(parent
, Section
.TITLE_BAR
212 | Section
.DESCRIPTION
);
213 section
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
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));
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());
225 Composite filter
= tk
.createComposite(body
);
226 filter
.setLayoutData(new GridData(SWT
.FILL
, SWT
.TOP
, true, false));
227 createFilterPart(filter
);
230 Composite tableCmp
= tk
.createComposite(body
);
231 tableCmp
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
232 createTableViewer(tableCmp
);
234 section
.setClient(body
);
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();
243 final String bundleArtifactsSelector
= "bundleArtifacts";
244 Selector source
= factory
.selector(SlcTypes
.SLC_BUNDLE_ARTIFACT
,
245 bundleArtifactsSelector
);
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
);
255 // Default Constraint: no source artifacts
256 Constraint defaultC
= factory
.not(factory
.comparison(
258 QueryObjectModelFactory
.JCR_OPERATOR_LIKE
,
259 factory
.literal(session
.getValueFactory().createValue(
262 // Build constraints based the textArea content
263 if (filter
!= null && !"".equals(filter
.trim())) {
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
+ "%"));
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
));
278 defaultC
= factory
.and(defaultC
, currC
);
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
};
288 QueryObjectModel query
= factory
.createQuery(source
, defaultC
,
291 QueryResult result
= query
.execute();
292 return result
.getNodes();
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));
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);
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
);
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;
325 public void modifyText(ModifyEvent event
) {
326 if ("".equals(artifactTxt
.getText().trim()))
327 asynchronousRefresh();
329 refreshFilteredList();
334 private void refreshFilteredList() {
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
);
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
>();
351 // Define the TableViewer
352 viewer
= new TableViewer(parent
, SWT
.MULTI
| SWT
.H_SCROLL
353 | SWT
.V_SCROLL
| SWT
.FULL_SELECTION
| SWT
.BORDER
);
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;
363 public String
getText(Object element
) {
364 return JcrUtils
.get((Node
) element
,
365 DistConstants
.SLC_BUNDLE_NAME
);
368 col
.getColumn().addSelectionListener(getSelectionAdapter(0));
369 propertiesList
.add(DistConstants
.SLC_BUNDLE_NAME
);
370 propertyTypesList
.add(PropertyType
.STRING
);
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;
380 public String
getText(Object element
) {
381 return JcrUtils
.get((Node
) element
, SLC_SYMBOLIC_NAME
);
384 col
.getColumn().addSelectionListener(getSelectionAdapter(1));
385 propertiesList
.add(SLC_SYMBOLIC_NAME
);
386 propertyTypesList
.add(PropertyType
.STRING
);
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;
396 public String
getText(Object element
) {
397 return JcrUtils
.get((Node
) element
, SLC_BUNDLE_VERSION
);
400 col
.getColumn().addSelectionListener(getSelectionAdapter(2));
401 propertiesList
.add(SLC_BUNDLE_VERSION
);
402 propertyTypesList
.add(DistNodeViewerComparator
.VERSION_TYPE
);
404 final Table table
= viewer
.getTable();
405 table
.setHeaderVisible(true);
406 table
.setLinesVisible(true);
408 viewer
.setContentProvider(new DistributionsContentProvider());
409 getSite().setSelectionProvider(viewer
);
411 comparator
= new DistNodeViewerComparator(2,
412 DistNodeViewerComparator
.ASCENDING
, propertiesList
,
414 viewer
.setComparator(comparator
);
417 MenuManager menuManager
= new MenuManager();
418 Menu menu
= menuManager
.createContextMenu(viewer
.getTable());
419 menuManager
.addMenuListener(new IMenuListener() {
420 private static final long serialVersionUID
= -3886983092940055195L;
422 public void menuAboutToShow(IMenuManager manager
) {
423 contextMenuAboutToShow(manager
);
426 viewer
.getTable().setMenu(menu
);
427 getSite().registerContextMenu(menuManager
, viewer
);
430 viewer
.addDoubleClickListener(new DoubleClickListener());
434 public void setFocus() {
435 viewer
.getTable().setFocus();
438 /** force refresh of the artifact list */
439 public void refresh() {
440 asynchronousRefresh();
443 /** Programmatically configure the context menu */
444 protected void contextMenuAboutToShow(IMenuManager menuManager
) {
445 IWorkbenchWindow window
= DistPlugin
.getDefault().getWorkbench()
446 .getActiveWorkbenchWindow();
448 // Delete selected artifacts
449 CommandUtils
.refreshCommand(menuManager
, window
, DeleteArtifacts
.ID
,
450 DeleteArtifacts
.DEFAULT_LABEL
, DeleteArtifacts
.DEFAULT_ICON
,
454 private SelectionAdapter
getSelectionAdapter(final int index
) {
455 SelectionAdapter selectionAdapter
= new SelectionAdapter() {
456 private static final long serialVersionUID
= 5515884441510882460L;
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
;
468 table
.setSortDirection(dir
);
469 table
.setSortColumn(table
.getColumn(index
));
473 return selectionAdapter
;
477 private class DistributionsContentProvider
implements
478 IStructuredContentProvider
{
479 private static final long serialVersionUID
= -635451814876234147L;
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
;
485 public void dispose() {
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
;
494 public Object
[] getElements(Object arg0
) {
495 return nodes
.toArray();
499 private class DoubleClickListener
implements IDoubleClickListener
{
501 public void doubleClick(DoubleClickEvent event
) {
502 Object obj
= ((IStructuredSelection
) event
.getSelection())
504 if (obj
instanceof Node
) {
505 Node node
= (Node
) obj
;
507 if (node
.isNodeType(SlcTypes
.SLC_ARTIFACT
)) {
508 DistWkspEditorInput dwip
= (DistWkspEditorInput
) formEditor
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
,
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
);
521 } catch (RepositoryException re
) {
522 throw new SlcException("Cannot get path for node " + node
523 + " while setting parameters for "
524 + "command OpenModuleEditor", re
);