X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=cms%2Forg.argeo.slc.client.ui.dist%2Fsrc%2Forg%2Fargeo%2Fslc%2Fclient%2Fui%2Fdist%2Feditors%2FDistWkspSearchPage.java;fp=cms%2Forg.argeo.slc.client.ui.dist%2Fsrc%2Forg%2Fargeo%2Fslc%2Fclient%2Fui%2Fdist%2Feditors%2FDistWkspSearchPage.java;h=1a959a511b8ca9e804a754581837a4cfcadbaa67;hb=ecc22e604e47533c79de9cecdcdeacbc752cbff1;hp=0000000000000000000000000000000000000000;hpb=e07ded4632e53f8b8869763bc1f1f4091361e76e;p=gpl%2Fargeo-slc.git diff --git a/cms/org.argeo.slc.client.ui.dist/src/org/argeo/slc/client/ui/dist/editors/DistWkspSearchPage.java b/cms/org.argeo.slc.client.ui.dist/src/org/argeo/slc/client/ui/dist/editors/DistWkspSearchPage.java new file mode 100644 index 000000000..1a959a511 --- /dev/null +++ b/cms/org.argeo.slc.client.ui.dist/src/org/argeo/slc/client/ui/dist/editors/DistWkspSearchPage.java @@ -0,0 +1,515 @@ +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.SlcNames; +import org.argeo.slc.SlcTypes; +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.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); + } + + } + } + } +} \ No newline at end of file