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
.List
;
21 import javax
.jcr
.Node
;
22 import javax
.jcr
.NodeIterator
;
23 import javax
.jcr
.PropertyType
;
24 import javax
.jcr
.RepositoryException
;
25 import javax
.jcr
.Session
;
26 import javax
.jcr
.query
.QueryManager
;
27 import javax
.jcr
.query
.QueryResult
;
28 import javax
.jcr
.query
.qom
.Constraint
;
29 import javax
.jcr
.query
.qom
.DynamicOperand
;
30 import javax
.jcr
.query
.qom
.Ordering
;
31 import javax
.jcr
.query
.qom
.QueryObjectModel
;
32 import javax
.jcr
.query
.qom
.QueryObjectModelFactory
;
33 import javax
.jcr
.query
.qom
.Selector
;
34 import javax
.jcr
.query
.qom
.StaticOperand
;
36 import org
.argeo
.ArgeoException
;
37 import org
.argeo
.ArgeoMonitor
;
38 import org
.argeo
.eclipse
.ui
.EclipseArgeoMonitor
;
39 import org
.argeo
.jcr
.JcrUtils
;
40 import org
.argeo
.slc
.SlcException
;
41 import org
.argeo
.slc
.client
.ui
.dist
.DistConstants
;
42 import org
.argeo
.slc
.client
.ui
.dist
.DistImages
;
43 import org
.argeo
.slc
.client
.ui
.dist
.DistPlugin
;
44 import org
.argeo
.slc
.client
.ui
.dist
.PrivilegedJob
;
45 import org
.argeo
.slc
.client
.ui
.dist
.commands
.DeleteArtifacts
;
46 import org
.argeo
.slc
.client
.ui
.dist
.utils
.CommandHelpers
;
47 import org
.argeo
.slc
.client
.ui
.dist
.utils
.NodeViewerComparator
;
48 import org
.argeo
.slc
.jcr
.SlcNames
;
49 import org
.argeo
.slc
.jcr
.SlcTypes
;
50 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
51 import org
.eclipse
.core
.runtime
.IStatus
;
52 import org
.eclipse
.core
.runtime
.Status
;
53 import org
.eclipse
.jface
.action
.IMenuListener
;
54 import org
.eclipse
.jface
.action
.IMenuManager
;
55 import org
.eclipse
.jface
.action
.MenuManager
;
56 import org
.eclipse
.jface
.viewers
.ColumnLabelProvider
;
57 import org
.eclipse
.jface
.viewers
.DoubleClickEvent
;
58 import org
.eclipse
.jface
.viewers
.IDoubleClickListener
;
59 import org
.eclipse
.jface
.viewers
.IStructuredContentProvider
;
60 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
61 import org
.eclipse
.jface
.viewers
.TableViewer
;
62 import org
.eclipse
.jface
.viewers
.TableViewerColumn
;
63 import org
.eclipse
.jface
.viewers
.Viewer
;
64 import org
.eclipse
.swt
.SWT
;
65 import org
.eclipse
.swt
.events
.ControlEvent
;
66 import org
.eclipse
.swt
.events
.ControlListener
;
67 import org
.eclipse
.swt
.events
.ModifyEvent
;
68 import org
.eclipse
.swt
.events
.ModifyListener
;
69 import org
.eclipse
.swt
.events
.SelectionAdapter
;
70 import org
.eclipse
.swt
.events
.SelectionEvent
;
71 import org
.eclipse
.swt
.events
.SelectionListener
;
72 import org
.eclipse
.swt
.layout
.GridData
;
73 import org
.eclipse
.swt
.layout
.GridLayout
;
74 import org
.eclipse
.swt
.widgets
.Button
;
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
.PartInitException
;
83 import org
.eclipse
.ui
.forms
.IManagedForm
;
84 import org
.eclipse
.ui
.forms
.editor
.FormEditor
;
85 import org
.eclipse
.ui
.forms
.editor
.FormPage
;
86 import org
.eclipse
.ui
.forms
.widgets
.FormToolkit
;
87 import org
.eclipse
.ui
.forms
.widgets
.ScrolledForm
;
89 /** Table giving an overview of an OSGi distribution with corresponding filters */
90 public class DistributionOverviewPage
extends FormPage
implements SlcNames
{
91 final static String PAGE_ID
= "distributionOverviewPage";
92 // final private static Log log = LogFactory
93 // .getLog(DistributionOverviewPage.class);
96 private Session session
;
99 private NodeViewerComparator comparator
;
100 private TableViewer viewer
;
101 private Text artifactTxt
;
102 private FormToolkit tk
;
103 private Composite header
;
104 private final static String FILTER_HELP_MSG
= "Enter filter criterion separated by a space";
106 public DistributionOverviewPage(FormEditor formEditor
, String title
,
108 super(formEditor
, PAGE_ID
, title
);
109 this.session
= session
;
112 private void asynchronousRefresh() {
113 RefreshJob job
= new RefreshJob(artifactTxt
.getText(), viewer
,
114 getSite().getShell().getDisplay());
119 private class RefreshJob
extends PrivilegedJob
{
120 private TableViewer viewer
;
121 private String filter
;
122 private Display display
;
124 public RefreshJob(String filter
, TableViewer viewer
, Display display
) {
125 super("Get bundle list");
126 this.filter
= filter
;
127 this.viewer
= viewer
;
128 this.display
= display
;
132 protected IStatus
doRun(IProgressMonitor progressMonitor
) {
134 ArgeoMonitor monitor
= new EclipseArgeoMonitor(progressMonitor
);
135 monitor
.beginTask("Getting bundle list", -1);
136 final List
<Node
> result
= JcrUtils
137 .nodeIteratorToList(listBundleArtifacts(session
, filter
));
139 display
.asyncExec(new Runnable() {
141 viewer
.setInput(result
);
144 } catch (Exception e
) {
145 return new Status(IStatus
.ERROR
, DistPlugin
.ID
,
146 "Cannot get bundle list", e
);
148 return Status
.OK_STATUS
;
153 protected void createFormContent(IManagedForm managedForm
) {
154 ScrolledForm form
= managedForm
.getForm();
155 tk
= managedForm
.getToolkit();
158 GridLayout layout
= new GridLayout(1, false);
159 Composite body
= form
.getBody();
160 body
.setLayout(layout
);
162 // Add the filter section
163 createFilterPart(body
);
165 createTableViewer(body
);
166 viewer
.setInput(null);
167 // Add a listener to enable custom resize process
168 form
.addControlListener(new ControlListener() {
169 // form.addListener(SWT.RESIZE, new Listener() does not work
170 public void controlResized(ControlEvent e
) {
174 public void controlMoved(ControlEvent e
) {
177 asynchronousRefresh();
180 /** Build repository request */
181 private NodeIterator
listBundleArtifacts(Session session
, String filter
)
182 throws RepositoryException
{
183 QueryManager queryManager
= session
.getWorkspace().getQueryManager();
184 QueryObjectModelFactory factory
= queryManager
.getQOMFactory();
186 final String bundleArtifactsSelector
= "bundleArtifacts";
187 Selector source
= factory
.selector(SlcTypes
.SLC_BUNDLE_ARTIFACT
,
188 bundleArtifactsSelector
);
190 // Create a dynamic operand for each property on which we want to filter
191 DynamicOperand symbNameDO
= factory
.propertyValue(
192 source
.getSelectorName(), SlcNames
.SLC_SYMBOLIC_NAME
);
193 DynamicOperand versionDO
= factory
.propertyValue(
194 source
.getSelectorName(), SlcNames
.SLC_BUNDLE_VERSION
);
195 DynamicOperand nameDO
= factory
.propertyValue(source
.getSelectorName(),
196 DistConstants
.SLC_BUNDLE_NAME
);
198 // Default Constraint: no source artifacts
199 Constraint defaultC
= factory
.not(factory
.comparison(
201 QueryObjectModelFactory
.JCR_OPERATOR_LIKE
,
202 factory
.literal(session
.getValueFactory().createValue(
205 // Build constraints based the textArea content
206 if (filter
!= null && !"".equals(filter
.trim())) {
208 String
[] strs
= filter
.trim().split(" ");
209 for (String token
: strs
) {
210 token
= token
.replace('*', '%');
211 StaticOperand so
= factory
.literal(session
.getValueFactory()
212 .createValue("%" + token
+ "%"));
214 Constraint currC
= factory
.comparison(symbNameDO
,
215 QueryObjectModelFactory
.JCR_OPERATOR_LIKE
, so
);
216 currC
= factory
.or(currC
, factory
.comparison(versionDO
,
217 QueryObjectModelFactory
.JCR_OPERATOR_LIKE
, so
));
218 currC
= factory
.or(currC
, factory
.comparison(nameDO
,
219 QueryObjectModelFactory
.JCR_OPERATOR_LIKE
, so
));
221 defaultC
= factory
.and(defaultC
, currC
);
225 Ordering order
= factory
.descending(factory
.propertyValue(
226 bundleArtifactsSelector
, SlcNames
.SLC_BUNDLE_VERSION
));
227 Ordering order2
= factory
.ascending(factory
.propertyValue(
228 bundleArtifactsSelector
, SlcNames
.SLC_SYMBOLIC_NAME
));
229 Ordering
[] orderings
= { order
, order2
};
231 QueryObjectModel query
= factory
.createQuery(source
, defaultC
,
234 QueryResult result
= query
.execute();
235 return result
.getNodes();
239 private void createFilterPart(Composite parent
) {
240 header
= tk
.createComposite(parent
);
241 GridLayout layout
= new GridLayout(2, false);
242 header
.setLayout(layout
);
243 GridData gd
= new GridData(SWT
.FILL
, SWT
.FILL
, false, false);
244 header
.setLayoutData(gd
);
246 // Title: some meta information
247 String desc
= ((DistributionEditorInput
) getEditorInput())
248 .getRepositoryDescription();
249 Label lbl
= tk
.createLabel(header
, desc
, SWT
.NONE
);
251 gd
= new GridData(SWT
.FILL
, SWT
.FILL
, false, false);
252 gd
.horizontalSpan
= 2;
253 lbl
.setLayoutData(gd
);
255 // Text Area to filter
256 artifactTxt
= tk
.createText(header
, "", SWT
.BORDER
| SWT
.SINGLE
);
257 artifactTxt
.setMessage(FILTER_HELP_MSG
);
258 gd
= new GridData(SWT
.FILL
, SWT
.FILL
, false, false);
259 gd
.grabExcessHorizontalSpace
= true;
260 artifactTxt
.setLayoutData(gd
);
261 artifactTxt
.addModifyListener(new ModifyListener() {
262 public void modifyText(ModifyEvent event
) {
263 if ("".equals(artifactTxt
.getText().trim()))
264 asynchronousRefresh();
266 refreshFilteredList();
270 Button resetBtn
= tk
.createButton(header
, null, SWT
.PUSH
);
271 resetBtn
.setImage(DistImages
.IMG_REPO_READONLY
);
272 resetBtn
.addSelectionListener(new SelectionListener() {
274 public void widgetSelected(SelectionEvent e
) {
278 public void widgetDefaultSelected(SelectionEvent e
) {
284 private void resetFilter() {
285 artifactTxt
.setText("");
286 artifactTxt
.setMessage(FILTER_HELP_MSG
);
289 private void refreshFilteredList() {
292 nodes
= JcrUtils
.nodeIteratorToList(listBundleArtifacts(session
,
293 artifactTxt
.getText()));
294 viewer
.setInput(nodes
);
295 } catch (RepositoryException e
) {
296 throw new SlcException("Unable to list bundles", e
);
300 private void createTableViewer(Composite parent
) {
301 // helpers to enable sorting by column
302 List
<String
> propertiesList
= new ArrayList
<String
>();
303 List
<Integer
> propertyTypesList
= new ArrayList
<Integer
>();
305 // Define the TableViewer
306 viewer
= new TableViewer(parent
, SWT
.MULTI
| SWT
.H_SCROLL
307 | SWT
.V_SCROLL
| SWT
.FULL_SELECTION
| SWT
.BORDER
);
310 TableViewerColumn col
= new TableViewerColumn(viewer
, SWT
.NONE
);
311 col
.getColumn().setWidth(300);
312 col
.getColumn().setText("Name");
313 col
.setLabelProvider(new ColumnLabelProvider() {
315 public String
getText(Object element
) {
316 return JcrUtils
.get((Node
) element
,
317 DistConstants
.SLC_BUNDLE_NAME
);
320 col
.getColumn().addSelectionListener(getSelectionAdapter(0));
321 propertiesList
.add(DistConstants
.SLC_BUNDLE_NAME
);
322 propertyTypesList
.add(PropertyType
.STRING
);
325 col
= new TableViewerColumn(viewer
, SWT
.V_SCROLL
);
326 col
.getColumn().setWidth(300);
327 col
.getColumn().setText("Symbolic name");
328 col
.setLabelProvider(new ColumnLabelProvider() {
330 public String
getText(Object element
) {
331 return JcrUtils
.get((Node
) element
, SLC_SYMBOLIC_NAME
);
334 col
.getColumn().addSelectionListener(getSelectionAdapter(1));
335 propertiesList
.add(SLC_SYMBOLIC_NAME
);
336 propertyTypesList
.add(PropertyType
.STRING
);
339 col
= new TableViewerColumn(viewer
, SWT
.NONE
);
340 col
.getColumn().setWidth(130);
341 col
.getColumn().setText("Version");
342 col
.setLabelProvider(new ColumnLabelProvider() {
344 public String
getText(Object element
) {
345 return JcrUtils
.get((Node
) element
, SLC_BUNDLE_VERSION
);
348 col
.getColumn().addSelectionListener(getSelectionAdapter(2));
349 propertiesList
.add(SLC_BUNDLE_VERSION
);
350 propertyTypesList
.add(PropertyType
.STRING
);
352 final Table table
= viewer
.getTable();
353 table
.setHeaderVisible(true);
354 table
.setLinesVisible(true);
356 viewer
.setContentProvider(new DistributionsContentProvider());
357 getSite().setSelectionProvider(viewer
);
359 comparator
= new NodeViewerComparator(2,
360 NodeViewerComparator
.ASCENDING
, propertiesList
,
362 viewer
.setComparator(comparator
);
365 MenuManager menuManager
= new MenuManager();
366 Menu menu
= menuManager
.createContextMenu(viewer
.getTable());
367 menuManager
.addMenuListener(new IMenuListener() {
368 public void menuAboutToShow(IMenuManager manager
) {
369 contextMenuAboutToShow(manager
);
372 viewer
.getTable().setMenu(menu
);
373 getSite().registerContextMenu(menuManager
, viewer
);
376 viewer
.addDoubleClickListener(new DoubleClickListener());
380 public void setFocus() {
381 viewer
.getTable().setFocus();
384 /** force refresh of the artifact list */
385 public void refresh() {
386 asynchronousRefresh();
389 /** Programmatically configure the context menu */
390 protected void contextMenuAboutToShow(IMenuManager menuManager
) {
391 IWorkbenchWindow window
= DistPlugin
.getDefault().getWorkbench()
392 .getActiveWorkbenchWindow();
394 // Delete selected artifacts
395 CommandHelpers
.refreshCommand(menuManager
, window
, DeleteArtifacts
.ID
,
396 DeleteArtifacts
.DEFAULT_LABEL
,
397 DeleteArtifacts
.DEFAULT_ICON_PATH
, true);
400 private SelectionAdapter
getSelectionAdapter(final int index
) {
401 SelectionAdapter selectionAdapter
= new SelectionAdapter() {
403 public void widgetSelected(SelectionEvent e
) {
404 Table table
= viewer
.getTable();
405 comparator
.setColumn(index
);
406 int dir
= table
.getSortDirection();
407 if (table
.getSortColumn() == table
.getColumn(index
)) {
408 dir
= dir
== SWT
.UP ? SWT
.DOWN
: SWT
.UP
;
412 table
.setSortDirection(dir
);
413 table
.setSortColumn(table
.getColumn(index
));
417 return selectionAdapter
;
421 private class DistributionsContentProvider
implements
422 IStructuredContentProvider
{
423 // we keep a cache of the Nodes in the content provider to be able to
424 // manage long request
425 private List
<Node
> nodes
;
427 public void dispose() {
430 // We expect a list of nodes as a new input
431 @SuppressWarnings("unchecked")
432 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
433 nodes
= (List
<Node
>) newInput
;
436 public Object
[] getElements(Object arg0
) {
437 return nodes
.toArray();
441 private class DoubleClickListener
implements IDoubleClickListener
{
443 public void doubleClick(DoubleClickEvent event
) {
444 Object obj
= ((IStructuredSelection
) event
.getSelection())
447 if (obj
instanceof Node
) {
448 Node node
= (Node
) obj
;
449 if (node
.isNodeType(SlcTypes
.SLC_BUNDLE_ARTIFACT
)) {
450 GenericBundleEditorInput gaei
= new GenericBundleEditorInput(
452 DistPlugin
.getDefault().getWorkbench()
453 .getActiveWorkbenchWindow().getActivePage()
454 .openEditor(gaei
, GenericBundleEditor
.ID
);
457 } catch (RepositoryException re
) {
458 throw new ArgeoException(
459 "Repository error while getting node info", re
);
460 } catch (PartInitException pie
) {
461 throw new ArgeoException(
462 "Unexepected exception while opening artifact editor",
469 * UI Trick to put scroll bar on the table rather than on the scrollform
471 private void refreshLayout() {
472 // Compute desired table size
473 int maxH
= getManagedForm().getForm().getSize().y
;
474 int maxW
= getManagedForm().getForm().getParent().getSize().x
;
475 maxH
= maxH
- header
.getSize().y
;
476 final Table table
= viewer
.getTable();
477 GridData gd
= new GridData(SWT
.LEFT
, SWT
.TOP
, true, true);
479 // when table height is less than 200 px, we let the scroll bar on the
481 // FIXME substract some spare space. Here is room for optimization
482 gd
.heightHint
= Math
.max(maxH
- 35, 200);
483 gd
.widthHint
= Math
.max(maxW
- 35, 200);
485 table
.setLayoutData(gd
);
486 getManagedForm().reflow(true);
490 public void setActive(boolean active
) {
491 super.setActive(active
);