]> git.argeo.org Git - gpl/argeo-slc.git/blob - plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/ModuleListPage.java
Work on the various distribution editors.
[gpl/argeo-slc.git] / plugins / org.argeo.slc.client.ui.dist / src / main / java / org / argeo / slc / client / ui / dist / editors / ModuleListPage.java
1 /*
2 * Copyright (C) 2007-2012 Argeo GmbH
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16 package org.argeo.slc.client.ui.dist.editors;
17
18 import java.util.ArrayList;
19 import java.util.List;
20
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.QueryObjectModel;
31 import javax.jcr.query.qom.QueryObjectModelFactory;
32 import javax.jcr.query.qom.Selector;
33 import javax.jcr.query.qom.StaticOperand;
34
35 import org.argeo.ArgeoException;
36 import org.argeo.eclipse.ui.utils.CommandUtils;
37 import org.argeo.jcr.JcrUtils;
38 import org.argeo.slc.SlcException;
39 import org.argeo.slc.client.ui.dist.DistImages;
40 import org.argeo.slc.client.ui.dist.DistPlugin;
41 import org.argeo.slc.client.ui.dist.commands.DeleteArtifacts;
42 import org.argeo.slc.client.ui.dist.utils.NodeViewerComparator;
43 import org.argeo.slc.jcr.SlcNames;
44 import org.argeo.slc.jcr.SlcTypes;
45 import org.eclipse.jface.action.IMenuListener;
46 import org.eclipse.jface.action.IMenuManager;
47 import org.eclipse.jface.action.MenuManager;
48 import org.eclipse.jface.viewers.ColumnLabelProvider;
49 import org.eclipse.jface.viewers.DoubleClickEvent;
50 import org.eclipse.jface.viewers.IDoubleClickListener;
51 import org.eclipse.jface.viewers.IStructuredContentProvider;
52 import org.eclipse.jface.viewers.IStructuredSelection;
53 import org.eclipse.jface.viewers.TableViewer;
54 import org.eclipse.jface.viewers.TableViewerColumn;
55 import org.eclipse.jface.viewers.Viewer;
56 import org.eclipse.swt.SWT;
57 import org.eclipse.swt.events.ControlEvent;
58 import org.eclipse.swt.events.ControlListener;
59 import org.eclipse.swt.events.ModifyEvent;
60 import org.eclipse.swt.events.ModifyListener;
61 import org.eclipse.swt.events.SelectionAdapter;
62 import org.eclipse.swt.events.SelectionEvent;
63 import org.eclipse.swt.events.SelectionListener;
64 import org.eclipse.swt.layout.GridData;
65 import org.eclipse.swt.layout.GridLayout;
66 import org.eclipse.swt.widgets.Button;
67 import org.eclipse.swt.widgets.Composite;
68 import org.eclipse.swt.widgets.Menu;
69 import org.eclipse.swt.widgets.Table;
70 import org.eclipse.swt.widgets.Text;
71 import org.eclipse.ui.IWorkbenchWindow;
72 import org.eclipse.ui.PartInitException;
73 import org.eclipse.ui.forms.IManagedForm;
74 import org.eclipse.ui.forms.editor.FormEditor;
75 import org.eclipse.ui.forms.editor.FormPage;
76 import org.eclipse.ui.forms.widgets.FormToolkit;
77 import org.eclipse.ui.forms.widgets.ScrolledForm;
78
79 /**
80 * Show all modules contained in a given modular distribution as filter-able
81 * table
82 */
83 public class ModuleListPage extends FormPage implements SlcNames {
84
85 final static String PAGE_ID = "ModuleListPage";
86
87 // Business Objects
88 private Node modularDistribution;
89 // private Node modularDistributionBase;
90
91 // This page widgets
92 private NodeViewerComparator comparator;
93 private TableViewer viewer;
94 private FormToolkit tk;
95 private Composite header;
96 private Text filterTxt;
97 private final static String FILTER_HELP_MSG = "Enter filter criterion separated by a space";
98
99 public ModuleListPage(FormEditor formEditor, String title,
100 Node modularDistribution) {
101 super(formEditor, PAGE_ID, title);
102 this.modularDistribution = modularDistribution;
103 }
104
105 @Override
106 protected void createFormContent(IManagedForm managedForm) {
107 ScrolledForm form = managedForm.getForm();
108 tk = managedForm.getToolkit();
109
110 // Main Layout
111 GridLayout layout = new GridLayout(1, false);
112 Composite body = form.getBody();
113 body.setLayout(layout);
114 // Add the filter section
115 createFilterPart(body);
116 // Add the table
117 createTableViewer(body);
118
119 // Add a listener to enable custom resize process
120 form.addControlListener(new ControlListener() {
121 // form.addListener(SWT.RESIZE, new Listener() does not work
122 public void controlResized(ControlEvent e) {
123 refreshLayout();
124 }
125
126 public void controlMoved(ControlEvent e) {
127 }
128 });
129 refresh();
130 }
131
132 private void refresh() {
133 final List<Node> result = JcrUtils
134 .nodeIteratorToList(listBundleArtifacts());
135 viewer.setInput(result);
136 }
137
138 /** Build repository request */
139 private NodeIterator listBundleArtifacts() {
140 try {
141 Session session = modularDistribution.getSession();
142 QueryManager queryManager = session.getWorkspace()
143 .getQueryManager();
144 QueryObjectModelFactory factory = queryManager.getQOMFactory();
145
146 Selector source = factory.selector(SlcTypes.SLC_MODULE_COORDINATES,
147 SlcTypes.SLC_MODULE_COORDINATES);
148
149 // Create a dynamic operand for each property on which we want to
150 // filter
151 DynamicOperand catDO = factory.propertyValue(
152 source.getSelectorName(), SlcNames.SLC_CATEGORY);
153 DynamicOperand nameDO = factory.propertyValue(
154 source.getSelectorName(), SlcNames.SLC_NAME);
155 DynamicOperand versionDO = factory.propertyValue(
156 source.getSelectorName(), SlcNames.SLC_VERSION);
157
158 String path = modularDistribution.getPath() + "/"
159 + SlcNames.SLC_MODULES;
160
161 // Default Constraint: correct children
162 Constraint defaultC = factory.descendantNode(
163 source.getSelectorName(), path);
164
165 String filter = filterTxt.getText();
166
167 // Build constraints based the textArea content
168 if (filter != null && !"".equals(filter.trim())) {
169 // Parse the String
170 String[] strs = filter.trim().split(" ");
171 for (String token : strs) {
172 token = token.replace('*', '%');
173 StaticOperand so = factory.literal(session
174 .getValueFactory().createValue("%" + token + "%"));
175
176 Constraint currC = factory.comparison(catDO,
177 QueryObjectModelFactory.JCR_OPERATOR_LIKE, so);
178 currC = factory.or(currC, factory.comparison(versionDO,
179 QueryObjectModelFactory.JCR_OPERATOR_LIKE, so));
180 currC = factory.or(currC, factory.comparison(nameDO,
181 QueryObjectModelFactory.JCR_OPERATOR_LIKE, so));
182
183 defaultC = factory.and(defaultC, currC);
184 }
185 }
186
187 QueryObjectModel query = factory.createQuery(source, defaultC,
188 null, null);
189 QueryResult result = query.execute();
190 return result.getNodes();
191 } catch (RepositoryException re) {
192 throw new SlcException("Unable to refresh module list for node "
193 + modularDistribution, re);
194 }
195 }
196
197 private void createFilterPart(Composite parent) {
198 header = tk.createComposite(parent);
199 GridLayout layout = new GridLayout(2, false);
200 layout.marginWidth = layout.marginHeight = layout.verticalSpacing = 0;
201 layout.horizontalSpacing = 5;
202 header.setLayout(layout);
203 GridData gd = new GridData(SWT.FILL, SWT.FILL, false, false);
204 header.setLayoutData(gd);
205
206 // Text Area to filter
207 filterTxt = tk.createText(header, "", SWT.BORDER | SWT.SINGLE
208 | SWT.SEARCH | SWT.CANCEL);
209 filterTxt.setMessage(FILTER_HELP_MSG);
210 gd = new GridData(SWT.FILL, SWT.FILL, false, false);
211 gd.grabExcessHorizontalSpace = true;
212 filterTxt.setLayoutData(gd);
213 filterTxt.addModifyListener(new ModifyListener() {
214 public void modifyText(ModifyEvent event) {
215 refresh();
216 }
217 });
218
219 Button resetBtn = tk.createButton(header, null, SWT.PUSH);
220 resetBtn.setImage(DistImages.IMG_REPO_READONLY);
221 resetBtn.addSelectionListener(new SelectionListener() {
222
223 public void widgetSelected(SelectionEvent e) {
224 resetFilter();
225 }
226
227 public void widgetDefaultSelected(SelectionEvent e) {
228 }
229 });
230
231 }
232
233 private void resetFilter() {
234 filterTxt.setText("");
235 filterTxt.setMessage(FILTER_HELP_MSG);
236 }
237
238 private void createTableViewer(Composite parent) {
239 // helpers to enable sorting by column
240 List<String> propertiesList = new ArrayList<String>();
241 List<Integer> propertyTypesList = new ArrayList<Integer>();
242
243 // Define the TableViewer
244 viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL
245 | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER);
246
247 // Name
248 TableViewerColumn col = new TableViewerColumn(viewer, SWT.NONE);
249 col.getColumn().setWidth(220);
250 col.getColumn().setText("Category");
251 col.setLabelProvider(new ColumnLabelProvider() {
252 @Override
253 public String getText(Object element) {
254 return JcrUtils.get((Node) element, SlcNames.SLC_CATEGORY);
255 }
256 });
257 col.getColumn().addSelectionListener(getSelectionAdapter(0));
258 propertiesList.add(SlcNames.SLC_CATEGORY);
259 propertyTypesList.add(PropertyType.STRING);
260
261 // Symbolic name
262 col = new TableViewerColumn(viewer, SWT.NONE);
263 col.getColumn().setWidth(220);
264 col.getColumn().setText("Name");
265 col.setLabelProvider(new ColumnLabelProvider() {
266 @Override
267 public String getText(Object element) {
268 return JcrUtils.get((Node) element, SLC_NAME);
269 }
270 });
271 col.getColumn().addSelectionListener(getSelectionAdapter(1));
272 propertiesList.add(SLC_NAME);
273 propertyTypesList.add(PropertyType.STRING);
274
275 // Version
276 col = new TableViewerColumn(viewer, SWT.NONE);
277 col.getColumn().setWidth(160);
278 col.getColumn().setText("Version");
279 col.setLabelProvider(new ColumnLabelProvider() {
280 @Override
281 public String getText(Object element) {
282 return JcrUtils.get((Node) element, SLC_VERSION);
283 }
284 });
285 col.getColumn().addSelectionListener(getSelectionAdapter(2));
286 propertiesList.add(SLC_VERSION);
287 propertyTypesList.add(PropertyType.STRING);
288
289 final Table table = viewer.getTable();
290 table.setHeaderVisible(true);
291 table.setLinesVisible(true);
292
293 viewer.setContentProvider(new DistributionsContentProvider());
294 getSite().setSelectionProvider(viewer);
295
296 comparator = new NodeViewerComparator(2,
297 NodeViewerComparator.ASCENDING, propertiesList,
298 propertyTypesList);
299 viewer.setComparator(comparator);
300
301 // Context Menu
302 MenuManager menuManager = new MenuManager();
303 Menu menu = menuManager.createContextMenu(viewer.getTable());
304 menuManager.addMenuListener(new IMenuListener() {
305 public void menuAboutToShow(IMenuManager manager) {
306 contextMenuAboutToShow(manager);
307 }
308 });
309 viewer.getTable().setMenu(menu);
310 getSite().registerContextMenu(menuManager, viewer);
311
312 // Double click
313 viewer.addDoubleClickListener(new DoubleClickListener());
314 }
315
316 @Override
317 public void setFocus() {
318 viewer.getTable().setFocus();
319 }
320
321 /** Programmatically configure the context menu */
322 protected void contextMenuAboutToShow(IMenuManager menuManager) {
323 IWorkbenchWindow window = DistPlugin.getDefault().getWorkbench()
324 .getActiveWorkbenchWindow();
325 // Build conditions
326 // Delete selected artifacts
327 CommandUtils.refreshCommand(menuManager, window, DeleteArtifacts.ID,
328 DeleteArtifacts.DEFAULT_LABEL, DeleteArtifacts.DEFAULT_ICON,
329 true);
330 }
331
332 private SelectionAdapter getSelectionAdapter(final int index) {
333 SelectionAdapter selectionAdapter = new SelectionAdapter() {
334 @Override
335 public void widgetSelected(SelectionEvent e) {
336 Table table = viewer.getTable();
337 comparator.setColumn(index);
338 int dir = table.getSortDirection();
339 if (table.getSortColumn() == table.getColumn(index)) {
340 dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
341 } else {
342 dir = SWT.DOWN;
343 }
344 table.setSortDirection(dir);
345 table.setSortColumn(table.getColumn(index));
346 viewer.refresh();
347 }
348 };
349 return selectionAdapter;
350 }
351
352 /* LOCAL CLASSES */
353 private class DistributionsContentProvider implements
354 IStructuredContentProvider {
355 // we keep a cache of the Nodes in the content provider to be able to
356 // manage long request
357 private List<Node> nodes;
358
359 public void dispose() {
360 }
361
362 // We expect a list of nodes as a new input
363 @SuppressWarnings("unchecked")
364 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
365 nodes = (List<Node>) newInput;
366 }
367
368 public Object[] getElements(Object arg0) {
369 return nodes.toArray();
370 }
371 }
372
373 private class DoubleClickListener implements IDoubleClickListener {
374
375 public void doubleClick(DoubleClickEvent event) {
376 Object obj = ((IStructuredSelection) event.getSelection())
377 .getFirstElement();
378 try {
379 if (obj instanceof Node) {
380 Node node = (Node) obj;
381 if (node.isNodeType(SlcTypes.SLC_BUNDLE_ARTIFACT)) {
382 GenericBundleEditorInput gaei = new GenericBundleEditorInput(
383 node);
384 DistPlugin.getDefault().getWorkbench()
385 .getActiveWorkbenchWindow().getActivePage()
386 .openEditor(gaei, GenericBundleEditor.ID);
387 }
388 }
389 } catch (RepositoryException re) {
390 throw new ArgeoException(
391 "Repository error while getting node info", re);
392 } catch (PartInitException pie) {
393 throw new ArgeoException(
394 "Unexepected exception while opening artifact editor",
395 pie);
396 }
397 }
398 }
399
400 /**
401 * UI Trick to put scroll bar on the table rather than on the scrollform
402 */
403 private void refreshLayout() {
404 // Compute desired table size
405 int maxH = getManagedForm().getForm().getSize().y;
406 int maxW = getManagedForm().getForm().getParent().getSize().x;
407 maxH = maxH - header.getSize().y;
408 final Table table = viewer.getTable();
409 GridData gd = new GridData(SWT.LEFT, SWT.TOP, true, true);
410
411 // when table height is less than 200 px, we let the scroll bar on the
412 // scrollForm
413 // FIXME substract some spare space. There is room here for optimization
414 gd.heightHint = Math.max(maxH - 35, 200);
415 gd.widthHint = Math.max(maxW - 35, 200);
416
417 table.setLayoutData(gd);
418 getManagedForm().reflow(true);
419 }
420
421 @Override
422 public void setActive(boolean active) {
423 super.setActive(active);
424 if (active) {
425 refreshLayout();
426 }
427 }
428 }