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
.utils
.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
.DistImages
;
47 import org
.argeo
.slc
.client
.ui
.dist
.DistPlugin
;
48 import org
.argeo
.slc
.client
.ui
.dist
.PrivilegedJob
;
49 import org
.argeo
.slc
.client
.ui
.dist
.commands
.DeleteArtifacts
;
50 import org
.argeo
.slc
.client
.ui
.dist
.commands
.OpenModuleEditor
;
51 import org
.argeo
.slc
.client
.ui
.dist
.utils
.NodeViewerComparator
;
52 import org
.argeo
.slc
.jcr
.SlcNames
;
53 import org
.argeo
.slc
.jcr
.SlcTypes
;
54 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
55 import org
.eclipse
.core
.runtime
.IStatus
;
56 import org
.eclipse
.core
.runtime
.Status
;
57 import org
.eclipse
.jface
.action
.IMenuListener
;
58 import org
.eclipse
.jface
.action
.IMenuManager
;
59 import org
.eclipse
.jface
.action
.MenuManager
;
60 import org
.eclipse
.jface
.viewers
.ColumnLabelProvider
;
61 import org
.eclipse
.jface
.viewers
.DoubleClickEvent
;
62 import org
.eclipse
.jface
.viewers
.IDoubleClickListener
;
63 import org
.eclipse
.jface
.viewers
.IStructuredContentProvider
;
64 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
65 import org
.eclipse
.jface
.viewers
.TableViewer
;
66 import org
.eclipse
.jface
.viewers
.TableViewerColumn
;
67 import org
.eclipse
.jface
.viewers
.Viewer
;
68 import org
.eclipse
.swt
.SWT
;
69 import org
.eclipse
.swt
.events
.ModifyEvent
;
70 import org
.eclipse
.swt
.events
.ModifyListener
;
71 import org
.eclipse
.swt
.events
.SelectionAdapter
;
72 import org
.eclipse
.swt
.events
.SelectionEvent
;
73 import org
.eclipse
.swt
.events
.SelectionListener
;
74 import org
.eclipse
.swt
.layout
.FillLayout
;
75 import org
.eclipse
.swt
.layout
.GridData
;
76 import org
.eclipse
.swt
.layout
.GridLayout
;
77 import org
.eclipse
.swt
.widgets
.Button
;
78 import org
.eclipse
.swt
.widgets
.Composite
;
79 import org
.eclipse
.swt
.widgets
.Display
;
80 import org
.eclipse
.swt
.widgets
.Label
;
81 import org
.eclipse
.swt
.widgets
.Menu
;
82 import org
.eclipse
.swt
.widgets
.Table
;
83 import org
.eclipse
.swt
.widgets
.Text
;
84 import org
.eclipse
.ui
.IWorkbenchWindow
;
85 import org
.eclipse
.ui
.forms
.IManagedForm
;
86 import org
.eclipse
.ui
.forms
.editor
.FormPage
;
87 import org
.eclipse
.ui
.forms
.widgets
.FormToolkit
;
88 import org
.eclipse
.ui
.forms
.widgets
.ScrolledForm
;
89 import org
.eclipse
.ui
.forms
.widgets
.Section
;
91 /** Show all bundles contained in a given workspace as filter-able table */
92 public class DistWkspSearchPage
extends FormPage
implements SlcNames
{
93 // final private static Log log = LogFactory
94 // .getLog(DistributionOverviewPage.class);
96 final static String PAGE_ID
= "distributionOverviewPage";
99 private Session session
;
102 private DistWorkspaceEditor formEditor
;
103 private FormToolkit tk
;
105 private NodeViewerComparator comparator
;
106 private TableViewer viewer
;
108 // private Composite header;
109 private Text artifactTxt
;
110 private final static String FILTER_HELP_MSG
= "Filter criterion, separated by a space";
112 public DistWkspSearchPage(DistWorkspaceEditor formEditor
, String title
,
114 super(formEditor
, PAGE_ID
, title
);
115 this.formEditor
= formEditor
;
116 this.session
= session
;
119 private void asynchronousRefresh() {
120 RefreshJob job
= new RefreshJob(artifactTxt
.getText(), viewer
,
121 getSite().getShell().getDisplay());
126 private class RefreshJob
extends PrivilegedJob
{
127 private TableViewer viewer
;
128 private String filter
;
129 private Display display
;
131 public RefreshJob(String filter
, TableViewer viewer
, Display display
) {
132 super("Get bundle list");
133 this.filter
= filter
;
134 this.viewer
= viewer
;
135 this.display
= display
;
139 protected IStatus
doRun(IProgressMonitor progressMonitor
) {
141 ArgeoMonitor monitor
= new EclipseArgeoMonitor(progressMonitor
);
142 monitor
.beginTask("Getting bundle list", -1);
143 final List
<Node
> result
= JcrUtils
144 .nodeIteratorToList(listBundleArtifacts(session
, filter
));
146 display
.asyncExec(new Runnable() {
148 viewer
.setInput(result
);
151 } catch (Exception e
) {
152 return new Status(IStatus
.ERROR
, DistPlugin
.ID
,
153 "Cannot get bundle list", e
);
155 return Status
.OK_STATUS
;
160 protected void createFormContent(IManagedForm managedForm
) {
161 ScrolledForm form
= managedForm
.getForm();
162 tk
= managedForm
.getToolkit();
165 GridLayout layout
= new GridLayout(1, false);
166 Composite body
= form
.getBody();
167 body
.setLayout(layout
);
169 // Meta info about current workspace
170 Composite header
= tk
.createComposite(body
);
171 header
.setLayoutData(new GridData(SWT
.FILL
, SWT
.TOP
, true, false));
172 createHeaderPart(form
, header
);
174 Composite modules
= tk
.createComposite(body
);
175 modules
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
176 populateModuleSection(modules
);
179 private void createHeaderPart(ScrolledForm form
, Composite parent
) {
180 GridLayout layout
= new GridLayout(4, false);
181 // layout.marginWidth = layout.marginHeight = layout.verticalSpacing =
183 // layout.horizontalSpacing = 2;
184 parent
.setLayout(layout
);
186 String wkspName
= ((DistWkspEditorInput
) getEditorInput())
188 wkspName
= wkspName
.replaceAll("-", " ");
189 form
.setText(wkspName
);
191 String repoAlias
= "";
192 Node repoNode
= ((DistWorkspaceEditor
) getEditor()).getRepoNode();
193 if (repoNode
!= null)
195 repoAlias
= repoNode
.isNodeType(NodeType
.MIX_TITLE
) ? repoNode
196 .getProperty(Property
.JCR_TITLE
).getString() : repoNode
198 } catch (RepositoryException e1
) {
199 throw new SlcException("Unable to get repository alias ", e1
);
204 createLT(parent
, "Repository alias", repoAlias
);
205 createLT(parent
, "URI",
206 ((DistWkspEditorInput
) getEditorInput()).getUri());
209 private void populateModuleSection(Composite parent
) {
210 GridLayout layout
= new GridLayout(1, false);
211 layout
.marginWidth
= layout
.horizontalSpacing
= layout
.horizontalSpacing
= layout
.marginHeight
= 0;
212 parent
.setLayout(layout
);
214 Section section
= tk
.createSection(parent
, Section
.TITLE_BAR
215 | Section
.DESCRIPTION
);
216 section
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
218 section
.setText("Artifacts");
219 section
.setDescription("Search among all artifacts that are referenced in the current workspace");
220 section
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
222 Composite body
= tk
.createComposite(section
);
223 layout
= new GridLayout(1, false);
224 layout
.marginWidth
= layout
.horizontalSpacing
= layout
.horizontalSpacing
= layout
.marginHeight
= 0;
225 body
.setLayout(new GridLayout());
227 Composite filter
= tk
.createComposite(body
);
228 filter
.setLayoutData(new GridData(SWT
.FILL
, SWT
.TOP
, true, false));
229 createFilterPart(filter
);
232 Composite tableCmp
= tk
.createComposite(body
);
233 tableCmp
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
234 createTableViewer(tableCmp
);
236 section
.setClient(body
);
239 /** Build repository request */
240 private NodeIterator
listBundleArtifacts(Session session
, String filter
)
241 throws RepositoryException
{
242 QueryManager queryManager
= session
.getWorkspace().getQueryManager();
243 QueryObjectModelFactory factory
= queryManager
.getQOMFactory();
245 final String bundleArtifactsSelector
= "bundleArtifacts";
246 Selector source
= factory
.selector(SlcTypes
.SLC_BUNDLE_ARTIFACT
,
247 bundleArtifactsSelector
);
249 // Create a dynamic operand for each property on which we want to filter
250 DynamicOperand symbNameDO
= factory
.propertyValue(
251 source
.getSelectorName(), SlcNames
.SLC_SYMBOLIC_NAME
);
252 DynamicOperand versionDO
= factory
.propertyValue(
253 source
.getSelectorName(), SlcNames
.SLC_BUNDLE_VERSION
);
254 DynamicOperand nameDO
= factory
.propertyValue(source
.getSelectorName(),
255 DistConstants
.SLC_BUNDLE_NAME
);
257 // Default Constraint: no source artifacts
258 Constraint defaultC
= factory
.not(factory
.comparison(
260 QueryObjectModelFactory
.JCR_OPERATOR_LIKE
,
261 factory
.literal(session
.getValueFactory().createValue(
264 // Build constraints based the textArea content
265 if (filter
!= null && !"".equals(filter
.trim())) {
267 String
[] strs
= filter
.trim().split(" ");
268 for (String token
: strs
) {
269 token
= token
.replace('*', '%');
270 StaticOperand so
= factory
.literal(session
.getValueFactory()
271 .createValue("%" + token
+ "%"));
273 Constraint currC
= factory
.comparison(symbNameDO
,
274 QueryObjectModelFactory
.JCR_OPERATOR_LIKE
, so
);
275 currC
= factory
.or(currC
, factory
.comparison(versionDO
,
276 QueryObjectModelFactory
.JCR_OPERATOR_LIKE
, so
));
277 currC
= factory
.or(currC
, factory
.comparison(nameDO
,
278 QueryObjectModelFactory
.JCR_OPERATOR_LIKE
, so
));
280 defaultC
= factory
.and(defaultC
, currC
);
284 Ordering order
= factory
.descending(factory
.propertyValue(
285 bundleArtifactsSelector
, SlcNames
.SLC_BUNDLE_VERSION
));
286 Ordering order2
= factory
.ascending(factory
.propertyValue(
287 bundleArtifactsSelector
, SlcNames
.SLC_SYMBOLIC_NAME
));
288 Ordering
[] orderings
= { order
, order2
};
290 QueryObjectModel query
= factory
.createQuery(source
, defaultC
,
293 QueryResult result
= query
.execute();
294 return result
.getNodes();
298 private Text
createLT(Composite parent
, String labelValue
, String textValue
) {
299 Label label
= new Label(parent
, SWT
.RIGHT
);
300 label
.setText(labelValue
);
301 // label.setFont(EclipseUiUtils.getBoldFont(parent));
302 label
.setLayoutData(new GridData(SWT
.RIGHT
, SWT
.CENTER
, false, false));
304 // Add a trailing space to workaround a display glitch in RAP 1.3
305 Text text
= new Text(parent
, SWT
.LEFT
); // | SWT.BORDER
306 text
.setText(textValue
+ " ");
307 text
.setEditable(false);
311 private void createFilterPart(Composite parent
) {
312 GridLayout layout
= new GridLayout(2, false);
313 layout
.marginWidth
= layout
.marginHeight
= layout
.verticalSpacing
= 0;
314 layout
.horizontalSpacing
= 5;
315 parent
.setLayout(layout
);
317 // Text Area to filter
318 artifactTxt
= tk
.createText(parent
, "", SWT
.BORDER
| SWT
.SINGLE
319 | SWT
.SEARCH
| SWT
.CANCEL
);
320 artifactTxt
.setMessage(FILTER_HELP_MSG
);
321 GridData gd
= new GridData(SWT
.FILL
, SWT
.FILL
, false, false);
322 gd
.grabExcessHorizontalSpace
= true;
323 artifactTxt
.setLayoutData(gd
);
324 artifactTxt
.addModifyListener(new ModifyListener() {
325 public void modifyText(ModifyEvent event
) {
326 if ("".equals(artifactTxt
.getText().trim()))
327 asynchronousRefresh();
329 refreshFilteredList();
333 Button resetBtn
= tk
.createButton(parent
, null, SWT
.PUSH
);
334 resetBtn
.setImage(DistImages
.IMG_REPO_READONLY
);
335 resetBtn
.addSelectionListener(new SelectionListener() {
337 public void widgetSelected(SelectionEvent e
) {
341 public void widgetDefaultSelected(SelectionEvent e
) {
346 private void resetFilter() {
347 artifactTxt
.setText("");
348 artifactTxt
.setMessage(FILTER_HELP_MSG
);
351 private void refreshFilteredList() {
354 nodes
= JcrUtils
.nodeIteratorToList(listBundleArtifacts(session
,
355 artifactTxt
.getText()));
356 viewer
.setInput(nodes
);
357 } catch (RepositoryException e
) {
358 throw new SlcException("Unable to list bundles", e
);
362 private void createTableViewer(Composite parent
) {
363 parent
.setLayout(new FillLayout());
364 // helpers to enable sorting by column
365 List
<String
> propertiesList
= new ArrayList
<String
>();
366 List
<Integer
> propertyTypesList
= new ArrayList
<Integer
>();
368 // Define the TableViewer
369 viewer
= new TableViewer(parent
, SWT
.MULTI
| SWT
.H_SCROLL
370 | SWT
.V_SCROLL
| SWT
.FULL_SELECTION
| SWT
.BORDER
);
373 TableViewerColumn col
= new TableViewerColumn(viewer
, SWT
.NONE
);
374 col
.getColumn().setWidth(300);
375 col
.getColumn().setText("Name");
376 col
.setLabelProvider(new ColumnLabelProvider() {
378 public String
getText(Object element
) {
379 return JcrUtils
.get((Node
) element
,
380 DistConstants
.SLC_BUNDLE_NAME
);
383 col
.getColumn().addSelectionListener(getSelectionAdapter(0));
384 propertiesList
.add(DistConstants
.SLC_BUNDLE_NAME
);
385 propertyTypesList
.add(PropertyType
.STRING
);
388 col
= new TableViewerColumn(viewer
, SWT
.V_SCROLL
);
389 col
.getColumn().setWidth(300);
390 col
.getColumn().setText("Symbolic Name");
391 col
.setLabelProvider(new ColumnLabelProvider() {
393 public String
getText(Object element
) {
394 return JcrUtils
.get((Node
) element
, SLC_SYMBOLIC_NAME
);
397 col
.getColumn().addSelectionListener(getSelectionAdapter(1));
398 propertiesList
.add(SLC_SYMBOLIC_NAME
);
399 propertyTypesList
.add(PropertyType
.STRING
);
402 col
= new TableViewerColumn(viewer
, SWT
.NONE
);
403 col
.getColumn().setWidth(130);
404 col
.getColumn().setText("Version");
405 col
.setLabelProvider(new ColumnLabelProvider() {
407 public String
getText(Object element
) {
408 return JcrUtils
.get((Node
) element
, SLC_BUNDLE_VERSION
);
411 col
.getColumn().addSelectionListener(getSelectionAdapter(2));
412 propertiesList
.add(SLC_BUNDLE_VERSION
);
413 propertyTypesList
.add(PropertyType
.STRING
);
415 final Table table
= viewer
.getTable();
416 table
.setHeaderVisible(true);
417 table
.setLinesVisible(true);
419 viewer
.setContentProvider(new DistributionsContentProvider());
420 getSite().setSelectionProvider(viewer
);
422 comparator
= new NodeViewerComparator(2,
423 NodeViewerComparator
.ASCENDING
, propertiesList
,
425 viewer
.setComparator(comparator
);
428 MenuManager menuManager
= new MenuManager();
429 Menu menu
= menuManager
.createContextMenu(viewer
.getTable());
430 menuManager
.addMenuListener(new IMenuListener() {
431 public void menuAboutToShow(IMenuManager manager
) {
432 contextMenuAboutToShow(manager
);
435 viewer
.getTable().setMenu(menu
);
436 getSite().registerContextMenu(menuManager
, viewer
);
439 viewer
.addDoubleClickListener(new DoubleClickListener());
443 public void setFocus() {
444 viewer
.getTable().setFocus();
447 /** force refresh of the artifact list */
448 public void refresh() {
449 asynchronousRefresh();
452 /** Programmatically configure the context menu */
453 protected void contextMenuAboutToShow(IMenuManager menuManager
) {
454 IWorkbenchWindow window
= DistPlugin
.getDefault().getWorkbench()
455 .getActiveWorkbenchWindow();
457 // Delete selected artifacts
458 CommandUtils
.refreshCommand(menuManager
, window
, DeleteArtifacts
.ID
,
459 DeleteArtifacts
.DEFAULT_LABEL
, DeleteArtifacts
.DEFAULT_ICON
,
463 private SelectionAdapter
getSelectionAdapter(final int index
) {
464 SelectionAdapter selectionAdapter
= new SelectionAdapter() {
466 public void widgetSelected(SelectionEvent e
) {
467 Table table
= viewer
.getTable();
468 comparator
.setColumn(index
);
469 int dir
= table
.getSortDirection();
470 if (table
.getSortColumn() == table
.getColumn(index
)) {
471 dir
= dir
== SWT
.UP ? SWT
.DOWN
: SWT
.UP
;
475 table
.setSortDirection(dir
);
476 table
.setSortColumn(table
.getColumn(index
));
480 return selectionAdapter
;
484 private class DistributionsContentProvider
implements
485 IStructuredContentProvider
{
486 // we keep a cache of the Nodes in the content provider to be able to
487 // manage long request
488 private List
<Node
> nodes
;
490 public void dispose() {
493 // We expect a list of nodes as a new input
494 @SuppressWarnings("unchecked")
495 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
496 nodes
= (List
<Node
>) newInput
;
499 public Object
[] getElements(Object arg0
) {
500 return nodes
.toArray();
504 private class DoubleClickListener
implements IDoubleClickListener
{
506 public void doubleClick(DoubleClickEvent event
) {
507 Object obj
= ((IStructuredSelection
) event
.getSelection())
509 if (obj
instanceof Node
) {
510 Node node
= (Node
) obj
;
512 if (node
.isNodeType(SlcTypes
.SLC_ARTIFACT
)) {
513 DistWkspEditorInput dwip
= (DistWkspEditorInput
) formEditor
515 Map
<String
, String
> params
= new HashMap
<String
, String
>();
516 params
.put(OpenModuleEditor
.PARAM_REPO_NODE_PATH
,
517 dwip
.getRepoNodePath());
518 params
.put(OpenModuleEditor
.PARAM_REPO_URI
,
520 params
.put(OpenModuleEditor
.PARAM_WORKSPACE_NAME
,
521 dwip
.getWorkspaceName());
522 String path
= node
.getPath();
523 params
.put(OpenModuleEditor
.PARAM_MODULE_PATH
, path
);
524 CommandUtils
.callCommand(OpenModuleEditor
.ID
, params
);
526 } catch (RepositoryException re
) {
527 throw new SlcException("Cannot get path for node " + node
528 + " while setting parameters for "
529 + "command OpenModuleEditor", re
);
537 * UI Trick to put scroll bar on the table rather than on the scrollform
539 private void refreshLayout() {
540 // // Compute desired table size
541 // int maxH = getManagedForm().getForm().getSize().y;
542 // int maxW = getManagedForm().getForm().getParent().getSize().x;
543 // // maxH = maxH - header.getSize().y;
544 // final Table table = viewer.getTable();
545 // GridData gd = new GridData(SWT.LEFT, SWT.TOP, true, true);
547 // // when table height is less than 200 px, we let the scroll bar on
550 // // FIXME substract some spare space. There is room here for
552 // gd.heightHint = Math.max(maxH - 35, 200);
553 // gd.widthHint = Math.max(maxW - 35, 200);
555 // table.setLayoutData(gd);
556 // getManagedForm().reflow(true);
560 public void setActive(boolean active
) {
561 super.setActive(active
);