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
.eclipse
.ui
.utils
.CommandUtils
;
40 import org
.argeo
.jcr
.JcrUtils
;
41 import org
.argeo
.slc
.SlcException
;
42 import org
.argeo
.slc
.client
.ui
.dist
.DistConstants
;
43 import org
.argeo
.slc
.client
.ui
.dist
.DistImages
;
44 import org
.argeo
.slc
.client
.ui
.dist
.DistPlugin
;
45 import org
.argeo
.slc
.client
.ui
.dist
.PrivilegedJob
;
46 import org
.argeo
.slc
.client
.ui
.dist
.commands
.DeleteArtifacts
;
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 /** Show all bundles contained in a given workspace as filter-able table */
90 public class DistributionOverviewPage
extends FormPage
implements SlcNames
{
91 // final private static Log log = LogFactory
92 // .getLog(DistributionOverviewPage.class);
94 final static String PAGE_ID
= "distributionOverviewPage";
97 private Session session
;
100 private NodeViewerComparator comparator
;
101 private TableViewer viewer
;
102 private FormToolkit tk
;
103 private Composite header
;
104 private Text artifactTxt
;
105 private final static String FILTER_HELP_MSG
= "Enter filter criterion separated by a space";
107 public DistributionOverviewPage(FormEditor formEditor
, String title
,
109 super(formEditor
, PAGE_ID
, title
);
110 this.session
= session
;
113 private void asynchronousRefresh() {
114 RefreshJob job
= new RefreshJob(artifactTxt
.getText(), viewer
,
115 getSite().getShell().getDisplay());
120 private class RefreshJob
extends PrivilegedJob
{
121 private TableViewer viewer
;
122 private String filter
;
123 private Display display
;
125 public RefreshJob(String filter
, TableViewer viewer
, Display display
) {
126 super("Get bundle list");
127 this.filter
= filter
;
128 this.viewer
= viewer
;
129 this.display
= display
;
133 protected IStatus
doRun(IProgressMonitor progressMonitor
) {
135 ArgeoMonitor monitor
= new EclipseArgeoMonitor(progressMonitor
);
136 monitor
.beginTask("Getting bundle list", -1);
137 final List
<Node
> result
= JcrUtils
138 .nodeIteratorToList(listBundleArtifacts(session
, filter
));
140 display
.asyncExec(new Runnable() {
142 viewer
.setInput(result
);
145 } catch (Exception e
) {
146 return new Status(IStatus
.ERROR
, DistPlugin
.ID
,
147 "Cannot get bundle list", e
);
149 return Status
.OK_STATUS
;
154 protected void createFormContent(IManagedForm managedForm
) {
155 ScrolledForm form
= managedForm
.getForm();
156 tk
= managedForm
.getToolkit();
159 GridLayout layout
= new GridLayout(1, false);
160 Composite body
= form
.getBody();
161 body
.setLayout(layout
);
163 // Add the filter section
164 createFilterPart(body
);
166 createTableViewer(body
);
167 // viewer.setInput(null);
168 // Add a listener to enable custom resize process
169 form
.addControlListener(new ControlListener() {
170 // form.addListener(SWT.RESIZE, new Listener() does not work
171 public void controlResized(ControlEvent e
) {
175 public void controlMoved(ControlEvent e
) {
178 asynchronousRefresh();
181 /** Build repository request */
182 private NodeIterator
listBundleArtifacts(Session session
, String filter
)
183 throws RepositoryException
{
184 QueryManager queryManager
= session
.getWorkspace().getQueryManager();
185 QueryObjectModelFactory factory
= queryManager
.getQOMFactory();
187 final String bundleArtifactsSelector
= "bundleArtifacts";
188 Selector source
= factory
.selector(SlcTypes
.SLC_BUNDLE_ARTIFACT
,
189 bundleArtifactsSelector
);
191 // Create a dynamic operand for each property on which we want to filter
192 DynamicOperand symbNameDO
= factory
.propertyValue(
193 source
.getSelectorName(), SlcNames
.SLC_SYMBOLIC_NAME
);
194 DynamicOperand versionDO
= factory
.propertyValue(
195 source
.getSelectorName(), SlcNames
.SLC_BUNDLE_VERSION
);
196 DynamicOperand nameDO
= factory
.propertyValue(source
.getSelectorName(),
197 DistConstants
.SLC_BUNDLE_NAME
);
199 // Default Constraint: no source artifacts
200 Constraint defaultC
= factory
.not(factory
.comparison(
202 QueryObjectModelFactory
.JCR_OPERATOR_LIKE
,
203 factory
.literal(session
.getValueFactory().createValue(
206 // Build constraints based the textArea content
207 if (filter
!= null && !"".equals(filter
.trim())) {
209 String
[] strs
= filter
.trim().split(" ");
210 for (String token
: strs
) {
211 token
= token
.replace('*', '%');
212 StaticOperand so
= factory
.literal(session
.getValueFactory()
213 .createValue("%" + token
+ "%"));
215 Constraint currC
= factory
.comparison(symbNameDO
,
216 QueryObjectModelFactory
.JCR_OPERATOR_LIKE
, so
);
217 currC
= factory
.or(currC
, factory
.comparison(versionDO
,
218 QueryObjectModelFactory
.JCR_OPERATOR_LIKE
, so
));
219 currC
= factory
.or(currC
, factory
.comparison(nameDO
,
220 QueryObjectModelFactory
.JCR_OPERATOR_LIKE
, so
));
222 defaultC
= factory
.and(defaultC
, currC
);
226 Ordering order
= factory
.descending(factory
.propertyValue(
227 bundleArtifactsSelector
, SlcNames
.SLC_BUNDLE_VERSION
));
228 Ordering order2
= factory
.ascending(factory
.propertyValue(
229 bundleArtifactsSelector
, SlcNames
.SLC_SYMBOLIC_NAME
));
230 Ordering
[] orderings
= { order
, order2
};
232 QueryObjectModel query
= factory
.createQuery(source
, defaultC
,
235 QueryResult result
= query
.execute();
236 return result
.getNodes();
240 private void createFilterPart(Composite parent
) {
241 header
= tk
.createComposite(parent
);
242 GridLayout layout
= new GridLayout(2, false);
243 layout
.marginWidth
= layout
.marginHeight
= layout
.verticalSpacing
= 0;
244 layout
.horizontalSpacing
= 5;
245 header
.setLayout(layout
);
246 GridData gd
= new GridData(SWT
.FILL
, SWT
.FILL
, false, false);
247 header
.setLayoutData(gd
);
249 // Title: some meta information
250 String desc
= ((DistributionEditorInput
) getEditorInput())
251 .getRepositoryDescription();
252 Label lbl
= tk
.createLabel(header
, desc
, SWT
.NONE
);
254 gd
= new GridData(SWT
.FILL
, SWT
.FILL
, false, false);
255 gd
.horizontalSpan
= 2;
256 lbl
.setLayoutData(gd
);
258 // Text Area to filter
259 artifactTxt
= tk
.createText(header
, "", SWT
.BORDER
| SWT
.SINGLE
260 | SWT
.SEARCH
| SWT
.CANCEL
);
261 artifactTxt
.setMessage(FILTER_HELP_MSG
);
262 gd
= new GridData(SWT
.FILL
, SWT
.FILL
, false, false);
263 gd
.grabExcessHorizontalSpace
= true;
264 artifactTxt
.setLayoutData(gd
);
265 artifactTxt
.addModifyListener(new ModifyListener() {
266 public void modifyText(ModifyEvent event
) {
267 if ("".equals(artifactTxt
.getText().trim()))
268 asynchronousRefresh();
270 refreshFilteredList();
274 Button resetBtn
= tk
.createButton(header
, null, SWT
.PUSH
);
275 resetBtn
.setImage(DistImages
.IMG_REPO_READONLY
);
276 resetBtn
.addSelectionListener(new SelectionListener() {
278 public void widgetSelected(SelectionEvent e
) {
282 public void widgetDefaultSelected(SelectionEvent e
) {
288 private void resetFilter() {
289 artifactTxt
.setText("");
290 artifactTxt
.setMessage(FILTER_HELP_MSG
);
293 private void refreshFilteredList() {
296 nodes
= JcrUtils
.nodeIteratorToList(listBundleArtifacts(session
,
297 artifactTxt
.getText()));
298 viewer
.setInput(nodes
);
299 } catch (RepositoryException e
) {
300 throw new SlcException("Unable to list bundles", e
);
304 private void createTableViewer(Composite parent
) {
305 // helpers to enable sorting by column
306 List
<String
> propertiesList
= new ArrayList
<String
>();
307 List
<Integer
> propertyTypesList
= new ArrayList
<Integer
>();
309 // Define the TableViewer
310 viewer
= new TableViewer(parent
, SWT
.MULTI
| SWT
.H_SCROLL
311 | SWT
.V_SCROLL
| SWT
.FULL_SELECTION
| SWT
.BORDER
);
314 TableViewerColumn col
= new TableViewerColumn(viewer
, SWT
.NONE
);
315 col
.getColumn().setWidth(300);
316 col
.getColumn().setText("Name");
317 col
.setLabelProvider(new ColumnLabelProvider() {
319 public String
getText(Object element
) {
320 return JcrUtils
.get((Node
) element
,
321 DistConstants
.SLC_BUNDLE_NAME
);
324 col
.getColumn().addSelectionListener(getSelectionAdapter(0));
325 propertiesList
.add(DistConstants
.SLC_BUNDLE_NAME
);
326 propertyTypesList
.add(PropertyType
.STRING
);
329 col
= new TableViewerColumn(viewer
, SWT
.V_SCROLL
);
330 col
.getColumn().setWidth(300);
331 col
.getColumn().setText("Symbolic Name");
332 col
.setLabelProvider(new ColumnLabelProvider() {
334 public String
getText(Object element
) {
335 return JcrUtils
.get((Node
) element
, SLC_SYMBOLIC_NAME
);
338 col
.getColumn().addSelectionListener(getSelectionAdapter(1));
339 propertiesList
.add(SLC_SYMBOLIC_NAME
);
340 propertyTypesList
.add(PropertyType
.STRING
);
343 col
= new TableViewerColumn(viewer
, SWT
.NONE
);
344 col
.getColumn().setWidth(130);
345 col
.getColumn().setText("Version");
346 col
.setLabelProvider(new ColumnLabelProvider() {
348 public String
getText(Object element
) {
349 return JcrUtils
.get((Node
) element
, SLC_BUNDLE_VERSION
);
352 col
.getColumn().addSelectionListener(getSelectionAdapter(2));
353 propertiesList
.add(SLC_BUNDLE_VERSION
);
354 propertyTypesList
.add(PropertyType
.STRING
);
356 final Table table
= viewer
.getTable();
357 table
.setHeaderVisible(true);
358 table
.setLinesVisible(true);
360 viewer
.setContentProvider(new DistributionsContentProvider());
361 getSite().setSelectionProvider(viewer
);
363 comparator
= new NodeViewerComparator(2,
364 NodeViewerComparator
.ASCENDING
, propertiesList
,
366 viewer
.setComparator(comparator
);
369 MenuManager menuManager
= new MenuManager();
370 Menu menu
= menuManager
.createContextMenu(viewer
.getTable());
371 menuManager
.addMenuListener(new IMenuListener() {
372 public void menuAboutToShow(IMenuManager manager
) {
373 contextMenuAboutToShow(manager
);
376 viewer
.getTable().setMenu(menu
);
377 getSite().registerContextMenu(menuManager
, viewer
);
380 viewer
.addDoubleClickListener(new DoubleClickListener());
384 public void setFocus() {
385 viewer
.getTable().setFocus();
388 /** force refresh of the artifact list */
389 public void refresh() {
390 asynchronousRefresh();
393 /** Programmatically configure the context menu */
394 protected void contextMenuAboutToShow(IMenuManager menuManager
) {
395 IWorkbenchWindow window
= DistPlugin
.getDefault().getWorkbench()
396 .getActiveWorkbenchWindow();
398 // Delete selected artifacts
399 CommandUtils
.refreshCommand(menuManager
, window
, DeleteArtifacts
.ID
,
400 DeleteArtifacts
.DEFAULT_LABEL
, DeleteArtifacts
.DEFAULT_ICON
,
404 private SelectionAdapter
getSelectionAdapter(final int index
) {
405 SelectionAdapter selectionAdapter
= new SelectionAdapter() {
407 public void widgetSelected(SelectionEvent e
) {
408 Table table
= viewer
.getTable();
409 comparator
.setColumn(index
);
410 int dir
= table
.getSortDirection();
411 if (table
.getSortColumn() == table
.getColumn(index
)) {
412 dir
= dir
== SWT
.UP ? SWT
.DOWN
: SWT
.UP
;
416 table
.setSortDirection(dir
);
417 table
.setSortColumn(table
.getColumn(index
));
421 return selectionAdapter
;
425 private class DistributionsContentProvider
implements
426 IStructuredContentProvider
{
427 // we keep a cache of the Nodes in the content provider to be able to
428 // manage long request
429 private List
<Node
> nodes
;
431 public void dispose() {
434 // We expect a list of nodes as a new input
435 @SuppressWarnings("unchecked")
436 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
437 nodes
= (List
<Node
>) newInput
;
440 public Object
[] getElements(Object arg0
) {
441 return nodes
.toArray();
445 private class DoubleClickListener
implements IDoubleClickListener
{
447 public void doubleClick(DoubleClickEvent event
) {
448 Object obj
= ((IStructuredSelection
) event
.getSelection())
451 if (obj
instanceof Node
) {
452 Node node
= (Node
) obj
;
453 if (node
.isNodeType(SlcTypes
.SLC_BUNDLE_ARTIFACT
)) {
454 GenericBundleEditorInput gaei
= new GenericBundleEditorInput(
456 DistPlugin
.getDefault().getWorkbench()
457 .getActiveWorkbenchWindow().getActivePage()
458 .openEditor(gaei
, GenericBundleEditor
.ID
);
461 } catch (RepositoryException re
) {
462 throw new ArgeoException(
463 "Repository error while getting node info", re
);
464 } catch (PartInitException pie
) {
465 throw new ArgeoException(
466 "Unexepected exception while opening artifact editor",
473 * UI Trick to put scroll bar on the table rather than on the scrollform
475 private void refreshLayout() {
476 // Compute desired table size
477 int maxH
= getManagedForm().getForm().getSize().y
;
478 int maxW
= getManagedForm().getForm().getParent().getSize().x
;
479 maxH
= maxH
- header
.getSize().y
;
480 final Table table
= viewer
.getTable();
481 GridData gd
= new GridData(SWT
.LEFT
, SWT
.TOP
, true, true);
483 // when table height is less than 200 px, we let the scroll bar on the
485 // FIXME substract some spare space. There is room here for optimization
486 gd
.heightHint
= Math
.max(maxH
- 35, 200);
487 gd
.widthHint
= Math
.max(maxW
- 35, 200);
489 table
.setLayoutData(gd
);
490 getManagedForm().reflow(true);
494 public void setActive(boolean active
) {
495 super.setActive(active
);