/* * Copyright (C) 2007-2012 Argeo GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.argeo.slc.client.ui.dist.editors; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.Property; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.nodetype.NodeType; import javax.jcr.query.QueryManager; import javax.jcr.query.QueryResult; import javax.jcr.query.qom.Constraint; import javax.jcr.query.qom.DynamicOperand; import javax.jcr.query.qom.Ordering; import javax.jcr.query.qom.QueryObjectModel; import javax.jcr.query.qom.QueryObjectModelFactory; import javax.jcr.query.qom.Selector; import javax.jcr.query.qom.StaticOperand; import org.argeo.cms.ui.workbench.util.CommandUtils; import org.argeo.cms.ui.workbench.util.PrivilegedJob; import org.argeo.eclipse.ui.EclipseJcrMonitor; import org.argeo.jcr.JcrMonitor; import org.argeo.jcr.JcrUtils; import org.argeo.slc.SlcException; import org.argeo.slc.client.ui.dist.DistConstants; import org.argeo.slc.client.ui.dist.DistPlugin; import org.argeo.slc.client.ui.dist.commands.DeleteArtifacts; import org.argeo.slc.client.ui.dist.commands.OpenModuleEditor; import org.argeo.slc.client.ui.dist.utils.DistNodeViewerComparator; import org.argeo.slc.jcr.SlcNames; import org.argeo.slc.jcr.SlcTypes; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.forms.IManagedForm; import org.eclipse.ui.forms.editor.FormPage; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.ScrolledForm; import org.eclipse.ui.forms.widgets.Section; /** Show all bundles contained in a given workspace as filter-able table */ public class DistWkspSearchPage extends FormPage implements SlcNames { // final private static Log log = LogFactory // .getLog(DistributionOverviewPage.class); final static String PAGE_ID = "distributionOverviewPage"; // Business Objects private Session session; // This page widgets private DistWorkspaceEditor formEditor; private FormToolkit tk; private DistNodeViewerComparator comparator; private TableViewer viewer; // private Composite header; private Text artifactTxt; private final static String FILTER_HELP_MSG = "Filter criterion, separated by a space"; public DistWkspSearchPage(DistWorkspaceEditor formEditor, String title, Session session) { super(formEditor, PAGE_ID, title); this.formEditor = formEditor; this.session = session; } private void asynchronousRefresh() { RefreshJob job = new RefreshJob(artifactTxt.getText(), viewer, getSite().getShell().getDisplay()); job.setUser(true); job.schedule(); } private class RefreshJob extends PrivilegedJob { private TableViewer viewer; private String filter; private Display display; public RefreshJob(String filter, TableViewer viewer, Display display) { super("Get bundle list"); this.filter = filter; this.viewer = viewer; this.display = display; } @Override protected IStatus doRun(IProgressMonitor progressMonitor) { try { JcrMonitor monitor = new EclipseJcrMonitor(progressMonitor); monitor.beginTask("Getting bundle list", -1); final List result = JcrUtils .nodeIteratorToList(listBundleArtifacts(session, filter)); display.asyncExec(new Runnable() { public void run() { viewer.setInput(result); } }); } catch (Exception e) { return new Status(IStatus.ERROR, DistPlugin.PLUGIN_ID, "Cannot get bundle list", e); } return Status.OK_STATUS; } } @Override protected void createFormContent(IManagedForm managedForm) { ScrolledForm form = managedForm.getForm(); tk = managedForm.getToolkit(); // Main Layout GridLayout layout = new GridLayout(1, false); Composite body = form.getBody(); body.setLayout(layout); // Meta info about current workspace Composite header = tk.createComposite(body); header.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); createHeaderPart(form, header); Composite modules = tk.createComposite(body); modules.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); populateModuleSection(modules); } private void createHeaderPart(ScrolledForm form, Composite parent) { GridLayout layout = new GridLayout(4, false); // layout.marginWidth = layout.marginHeight = layout.verticalSpacing = // 0; // layout.horizontalSpacing = 2; parent.setLayout(layout); String wkspName = ((DistWkspEditorInput) getEditorInput()) .getWorkspaceName(); wkspName = wkspName.replaceAll("-", " "); form.setText(wkspName); String repoAlias = ""; Node repoNode = ((DistWorkspaceEditor) getEditor()).getRepoNode(); if (repoNode != null) try { repoAlias = repoNode.isNodeType(NodeType.MIX_TITLE) ? repoNode .getProperty(Property.JCR_TITLE).getString() : repoNode .getName(); } catch (RepositoryException e1) { throw new SlcException("Unable to get repository alias ", e1); } else repoAlias = " - "; createLT(parent, "Repository alias", repoAlias); createLT(parent, "URI", ((DistWkspEditorInput) getEditorInput()).getUri()); } private void populateModuleSection(Composite parent) { GridLayout layout = new GridLayout(1, false); layout.marginWidth = layout.horizontalSpacing = layout.horizontalSpacing = layout.marginHeight = 0; parent.setLayout(layout); Section section = tk.createSection(parent, Section.TITLE_BAR | Section.DESCRIPTION); section.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); section.setText("Artifacts"); section.setDescription("Search among all artifacts that are referenced in the current workspace"); section.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); Composite body = tk.createComposite(section); layout = new GridLayout(1, false); layout.marginWidth = layout.horizontalSpacing = layout.horizontalSpacing = layout.marginHeight = 0; body.setLayout(new GridLayout()); // Filter Composite filter = tk.createComposite(body); filter.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); createFilterPart(filter); // Table Composite tableCmp = tk.createComposite(body); tableCmp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); createTableViewer(tableCmp); section.setClient(body); } /** Build repository request */ private NodeIterator listBundleArtifacts(Session session, String filter) throws RepositoryException { QueryManager queryManager = session.getWorkspace().getQueryManager(); QueryObjectModelFactory factory = queryManager.getQOMFactory(); final String bundleArtifactsSelector = "bundleArtifacts"; Selector source = factory.selector(SlcTypes.SLC_BUNDLE_ARTIFACT, bundleArtifactsSelector); // Create a dynamic operand for each property on which we want to filter DynamicOperand symbNameDO = factory.propertyValue( source.getSelectorName(), SlcNames.SLC_SYMBOLIC_NAME); DynamicOperand versionDO = factory.propertyValue( source.getSelectorName(), SlcNames.SLC_BUNDLE_VERSION); DynamicOperand nameDO = factory.propertyValue(source.getSelectorName(), DistConstants.SLC_BUNDLE_NAME); // Default Constraint: no source artifacts Constraint defaultC = factory.not(factory.comparison( symbNameDO, QueryObjectModelFactory.JCR_OPERATOR_LIKE, factory.literal(session.getValueFactory().createValue( "%.source")))); // Build constraints based the textArea content if (filter != null && !"".equals(filter.trim())) { // Parse the String String[] strs = filter.trim().split(" "); for (String token : strs) { token = token.replace('*', '%'); StaticOperand so = factory.literal(session.getValueFactory() .createValue("%" + token + "%")); Constraint currC = factory.comparison(symbNameDO, QueryObjectModelFactory.JCR_OPERATOR_LIKE, so); currC = factory.or(currC, factory.comparison(versionDO, QueryObjectModelFactory.JCR_OPERATOR_LIKE, so)); currC = factory.or(currC, factory.comparison(nameDO, QueryObjectModelFactory.JCR_OPERATOR_LIKE, so)); defaultC = factory.and(defaultC, currC); } } Ordering order = factory.descending(factory.propertyValue( bundleArtifactsSelector, SlcNames.SLC_BUNDLE_VERSION)); Ordering order2 = factory.ascending(factory.propertyValue( bundleArtifactsSelector, SlcNames.SLC_SYMBOLIC_NAME)); Ordering[] orderings = { order, order2 }; QueryObjectModel query = factory.createQuery(source, defaultC, orderings, null); QueryResult result = query.execute(); return result.getNodes(); } private Text createLT(Composite parent, String labelValue, String textValue) { Label label = new Label(parent, SWT.RIGHT); label.setText(labelValue); // label.setFont(EclipseUiUtils.getBoldFont(parent)); label.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); // Add a trailing space to workaround a display glitch in RAP 1.3 Text text = new Text(parent, SWT.LEFT); // | SWT.BORDER text.setText(textValue + " "); text.setEditable(false); return text; } private void createFilterPart(Composite parent) { GridLayout layout = new GridLayout(); layout.marginWidth = layout.marginHeight = layout.verticalSpacing = 0; layout.horizontalSpacing = 5; parent.setLayout(layout); // Text Area to filter artifactTxt = tk.createText(parent, "", SWT.BORDER | SWT.SINGLE | SWT.SEARCH | SWT.CANCEL); artifactTxt.setMessage(FILTER_HELP_MSG); GridData gd = new GridData(SWT.FILL, SWT.FILL, false, false); gd.grabExcessHorizontalSpace = true; artifactTxt.setLayoutData(gd); artifactTxt.addModifyListener(new ModifyListener() { private static final long serialVersionUID = -2422321852703208573L; public void modifyText(ModifyEvent event) { if ("".equals(artifactTxt.getText().trim())) asynchronousRefresh(); else refreshFilteredList(); } }); } private void refreshFilteredList() { List nodes; try { nodes = JcrUtils.nodeIteratorToList(listBundleArtifacts(session, artifactTxt.getText())); viewer.setInput(nodes); } catch (RepositoryException e) { throw new SlcException("Unable to list bundles", e); } } private void createTableViewer(Composite parent) { parent.setLayout(new FillLayout()); // helpers to enable sorting by column List propertiesList = new ArrayList(); List propertyTypesList = new ArrayList(); // Define the TableViewer viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER); // Name TableViewerColumn col = new TableViewerColumn(viewer, SWT.NONE); col.getColumn().setWidth(300); col.getColumn().setText("Name"); col.setLabelProvider(new ColumnLabelProvider() { private static final long serialVersionUID = -760226161605987538L; @Override public String getText(Object element) { return JcrUtils.get((Node) element, DistConstants.SLC_BUNDLE_NAME); } }); col.getColumn().addSelectionListener(getSelectionAdapter(0)); propertiesList.add(DistConstants.SLC_BUNDLE_NAME); propertyTypesList.add(PropertyType.STRING); // Symbolic name col = new TableViewerColumn(viewer, SWT.V_SCROLL); col.getColumn().setWidth(300); col.getColumn().setText("Symbolic Name"); col.setLabelProvider(new ColumnLabelProvider() { private static final long serialVersionUID = 4431447542158431355L; @Override public String getText(Object element) { return JcrUtils.get((Node) element, SLC_SYMBOLIC_NAME); } }); col.getColumn().addSelectionListener(getSelectionAdapter(1)); propertiesList.add(SLC_SYMBOLIC_NAME); propertyTypesList.add(PropertyType.STRING); // Version col = new TableViewerColumn(viewer, SWT.NONE); col.getColumn().setWidth(130); col.getColumn().setText("Version"); col.setLabelProvider(new ColumnLabelProvider() { private static final long serialVersionUID = -5616215547236158504L; @Override public String getText(Object element) { return JcrUtils.get((Node) element, SLC_BUNDLE_VERSION); } }); col.getColumn().addSelectionListener(getSelectionAdapter(2)); propertiesList.add(SLC_BUNDLE_VERSION); propertyTypesList.add(DistNodeViewerComparator.VERSION_TYPE); final Table table = viewer.getTable(); table.setHeaderVisible(true); table.setLinesVisible(true); viewer.setContentProvider(new DistributionsContentProvider()); getSite().setSelectionProvider(viewer); comparator = new DistNodeViewerComparator(2, DistNodeViewerComparator.ASCENDING, propertiesList, propertyTypesList); viewer.setComparator(comparator); // Context Menu MenuManager menuManager = new MenuManager(); Menu menu = menuManager.createContextMenu(viewer.getTable()); menuManager.addMenuListener(new IMenuListener() { private static final long serialVersionUID = -3886983092940055195L; public void menuAboutToShow(IMenuManager manager) { contextMenuAboutToShow(manager); } }); viewer.getTable().setMenu(menu); getSite().registerContextMenu(menuManager, viewer); // Double click viewer.addDoubleClickListener(new DoubleClickListener()); } @Override public void setFocus() { viewer.getTable().setFocus(); } /** force refresh of the artifact list */ public void refresh() { asynchronousRefresh(); } /** Programmatically configure the context menu */ protected void contextMenuAboutToShow(IMenuManager menuManager) { IWorkbenchWindow window = DistPlugin.getDefault().getWorkbench() .getActiveWorkbenchWindow(); // Build conditions // Delete selected artifacts CommandUtils.refreshCommand(menuManager, window, DeleteArtifacts.ID, DeleteArtifacts.DEFAULT_LABEL, DeleteArtifacts.DEFAULT_ICON, true); } private SelectionAdapter getSelectionAdapter(final int index) { SelectionAdapter selectionAdapter = new SelectionAdapter() { private static final long serialVersionUID = 5515884441510882460L; @Override public void widgetSelected(SelectionEvent e) { Table table = viewer.getTable(); comparator.setColumn(index); int dir = table.getSortDirection(); if (table.getSortColumn() == table.getColumn(index)) { dir = dir == SWT.UP ? SWT.DOWN : SWT.UP; } else { dir = SWT.DOWN; } table.setSortDirection(dir); table.setSortColumn(table.getColumn(index)); viewer.refresh(); } }; return selectionAdapter; } /* LOCAL CLASSES */ private class DistributionsContentProvider implements IStructuredContentProvider { private static final long serialVersionUID = -635451814876234147L; // we keep a cache of the Nodes in the content provider to be able to // manage long request private List nodes; public void dispose() { } // We expect a list of nodes as a new input @SuppressWarnings("unchecked") public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { nodes = (List) newInput; } public Object[] getElements(Object arg0) { return nodes.toArray(); } } private class DoubleClickListener implements IDoubleClickListener { public void doubleClick(DoubleClickEvent event) { Object obj = ((IStructuredSelection) event.getSelection()) .getFirstElement(); if (obj instanceof Node) { Node node = (Node) obj; try { if (node.isNodeType(SlcTypes.SLC_ARTIFACT)) { DistWkspEditorInput dwip = (DistWkspEditorInput) formEditor .getEditorInput(); Map params = new HashMap(); params.put(OpenModuleEditor.PARAM_REPO_NODE_PATH, dwip.getRepoNodePath()); params.put(OpenModuleEditor.PARAM_REPO_URI, dwip.getUri()); params.put(OpenModuleEditor.PARAM_WORKSPACE_NAME, dwip.getWorkspaceName()); String path = node.getPath(); params.put(OpenModuleEditor.PARAM_MODULE_PATH, path); CommandUtils.callCommand(OpenModuleEditor.ID, params); } } catch (RepositoryException re) { throw new SlcException("Cannot get path for node " + node + " while setting parameters for " + "command OpenModuleEditor", re); } } } } }