]> git.argeo.org Git - gpl/argeo-slc.git/blob - cms/org.argeo.slc.client.ui.dist/src/org/argeo/slc/client/ui/dist/editors/WkspCategoryBaseListPage.java
Clarify SLC project structure.
[gpl/argeo-slc.git] / cms / org.argeo.slc.client.ui.dist / src / org / argeo / slc / client / ui / dist / editors / WkspCategoryBaseListPage.java
1 package org.argeo.slc.client.ui.dist.editors;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.List;
6 import java.util.Map;
7
8 import javax.jcr.Node;
9 import javax.jcr.NodeIterator;
10 import javax.jcr.PropertyType;
11 import javax.jcr.RepositoryException;
12 import javax.jcr.Session;
13 import javax.jcr.observation.Event;
14 import javax.jcr.query.QueryManager;
15 import javax.jcr.query.QueryResult;
16 import javax.jcr.query.qom.Constraint;
17 import javax.jcr.query.qom.DynamicOperand;
18 import javax.jcr.query.qom.QueryObjectModel;
19 import javax.jcr.query.qom.QueryObjectModelFactory;
20 import javax.jcr.query.qom.Selector;
21 import javax.jcr.query.qom.StaticOperand;
22
23 import org.argeo.cms.ui.workbench.util.CommandUtils;
24 import org.argeo.eclipse.ui.jcr.AsyncUiEventListener;
25 import org.argeo.jcr.JcrUtils;
26 import org.argeo.slc.SlcException;
27 import org.argeo.slc.SlcNames;
28 import org.argeo.slc.SlcTypes;
29 import org.argeo.slc.client.ui.dist.DistConstants;
30 import org.argeo.slc.client.ui.dist.DistImages;
31 import org.argeo.slc.client.ui.dist.DistPlugin;
32 import org.argeo.slc.client.ui.dist.commands.OpenGenerateBinariesWizard;
33 import org.argeo.slc.client.ui.dist.commands.OpenModuleEditor;
34 import org.argeo.slc.client.ui.dist.utils.DistNodeViewerComparator;
35 import org.argeo.slc.repo.RepoConstants;
36 import org.eclipse.jface.action.IMenuListener;
37 import org.eclipse.jface.action.IMenuManager;
38 import org.eclipse.jface.action.MenuManager;
39 import org.eclipse.jface.dialogs.IMessageProvider;
40 import org.eclipse.jface.viewers.ColumnLabelProvider;
41 import org.eclipse.jface.viewers.DoubleClickEvent;
42 import org.eclipse.jface.viewers.IDoubleClickListener;
43 import org.eclipse.jface.viewers.IStructuredContentProvider;
44 import org.eclipse.jface.viewers.IStructuredSelection;
45 import org.eclipse.jface.viewers.TableViewer;
46 import org.eclipse.jface.viewers.TableViewerColumn;
47 import org.eclipse.jface.viewers.Viewer;
48 import org.eclipse.swt.SWT;
49 import org.eclipse.swt.events.ModifyEvent;
50 import org.eclipse.swt.events.ModifyListener;
51 import org.eclipse.swt.events.SelectionAdapter;
52 import org.eclipse.swt.events.SelectionEvent;
53 import org.eclipse.swt.layout.FillLayout;
54 import org.eclipse.swt.layout.GridData;
55 import org.eclipse.swt.layout.GridLayout;
56 import org.eclipse.swt.widgets.Button;
57 import org.eclipse.swt.widgets.Composite;
58 import org.eclipse.swt.widgets.Display;
59 import org.eclipse.swt.widgets.Menu;
60 import org.eclipse.swt.widgets.Table;
61 import org.eclipse.swt.widgets.Text;
62 import org.eclipse.ui.IWorkbenchWindow;
63 import org.eclipse.ui.forms.IManagedForm;
64 import org.eclipse.ui.forms.editor.FormEditor;
65 import org.eclipse.ui.forms.editor.FormPage;
66 import org.eclipse.ui.forms.widgets.FormToolkit;
67 import org.eclipse.ui.forms.widgets.ScrolledForm;
68
69 /**
70 * Show all category base (currently only Aether group base) contained in a
71 * given workspace as filter-able table. Enable to definition of which of them
72 * should be managed as modular distribution
73 */
74 public class WkspCategoryBaseListPage extends FormPage implements SlcNames {
75
76 final static String PAGE_ID = "WkspCategoryBaseListPage";
77
78 // Business Objects
79 private Session session;
80
81 // This page widgets
82 private DistNodeViewerComparator comparator;
83 private TableViewer viewer;
84 private FormToolkit tk;
85 private Text filterTxt;
86 private final static String FILTER_HELP_MSG = "Enter filter criterion separated by a space";
87
88 // Observes changes
89 // private final static String[] observedTypes = { SlcTypes.SLC_GROUP_BASE
90 // };
91 // private CategoryObserver categoriesObserver;
92
93 public WkspCategoryBaseListPage(FormEditor formEditor, String title,
94 Session session) {
95 super(formEditor, PAGE_ID, title);
96 this.session = session;
97 }
98
99 @Override
100 protected void createFormContent(IManagedForm managedForm) {
101 ScrolledForm form = managedForm.getForm();
102 tk = managedForm.getToolkit();
103
104 form.setText("Define Relevant Categories");
105 form.setMessage("Choose in the below list "
106 + "the categories that can be used as base for "
107 + "modular distributions maintained via the current workspace",
108 IMessageProvider.NONE);
109
110 // Main Layout
111 GridLayout layout = new GridLayout(1, false);
112 Composite body = form.getBody();
113 body.setLayout(layout);
114
115 // filter section
116 Composite header = tk.createComposite(body);
117 header.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
118 createFilterPart(header);
119
120 // the table
121 Composite tableCmp = tk.createComposite(body);
122 tableCmp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
123 createTableViewer(tableCmp);
124
125 // categoriesObserver = new CategoryObserver(viewer.getTable()
126 // .getDisplay());
127 // try {
128 // ObservationManager observationManager = session.getWorkspace()
129 // .getObservationManager();
130 // // FIXME Will not be notified if empty result is deleted
131 // observationManager.addEventListener(categoriesObserver,
132 // Event.PROPERTY_CHANGED, "/", true, null, observedTypes,
133 // false);
134 // } catch (RepositoryException e) {
135 // throw new SlcException("Cannot register listeners", e);
136 // }
137
138 refresh();
139 }
140
141 private void refresh() {
142 final List<Node> result = JcrUtils.nodeIteratorToList(listGroupBase());
143 viewer.setInput(result);
144 }
145
146 /** Build repository request */
147 private NodeIterator listGroupBase() {
148 try {
149 QueryManager queryManager = session.getWorkspace()
150 .getQueryManager();
151 QueryObjectModelFactory factory = queryManager.getQOMFactory();
152
153 Selector source = factory.selector(SlcTypes.SLC_GROUP_BASE,
154 SlcTypes.SLC_MODULE_COORDINATES);
155
156 // Create a dynamic operand for each property on which we want to
157 // filter
158 DynamicOperand catDO = factory.propertyValue(
159 source.getSelectorName(), SlcNames.SLC_CATEGORY);
160 DynamicOperand nameDO = factory.propertyValue(
161 source.getSelectorName(), SlcNames.SLC_NAME);
162
163 String filter = filterTxt.getText();
164
165 Constraint defaultC = null;
166 // Build constraints based the textArea content
167 if (filter != null && !"".equals(filter.trim())) {
168 // Parse the String
169 String[] strs = filter.trim().split(" ");
170 for (String token : strs) {
171 token = token.replace('*', '%');
172 StaticOperand so = factory.literal(session
173 .getValueFactory().createValue("%" + token + "%"));
174
175 Constraint currC = factory.comparison(catDO,
176 QueryObjectModelFactory.JCR_OPERATOR_LIKE, so);
177 currC = factory.or(currC, factory.comparison(nameDO,
178 QueryObjectModelFactory.JCR_OPERATOR_LIKE, so));
179
180 if (defaultC == null)
181 defaultC = currC;
182 else
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(
193 "Unable to refresh group list for workspace "
194 + getEditorInput().getName(), re);
195 }
196 }
197
198 private void createFilterPart(Composite parent) {
199 GridLayout layout = new GridLayout(2, false);
200 layout.marginWidth = layout.marginHeight = layout.verticalSpacing = 0;
201 layout.horizontalSpacing = 5;
202 parent.setLayout(layout);
203
204 // Text Area to filter
205 filterTxt = tk.createText(parent, "", SWT.BORDER | SWT.SINGLE
206 | SWT.SEARCH | SWT.CANCEL);
207 filterTxt.setMessage(FILTER_HELP_MSG);
208 filterTxt.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
209 filterTxt.addModifyListener(new ModifyListener() {
210 private static final long serialVersionUID = 8727389523069041623L;
211
212 public void modifyText(ModifyEvent event) {
213 refresh();
214 }
215 });
216
217 Button resetBtn = tk.createButton(parent, null, SWT.PUSH);
218 resetBtn.setImage(DistImages.IMG_REPO_READONLY);
219 resetBtn.addSelectionListener(new SelectionAdapter() {
220 private static final long serialVersionUID = -6523538838444581321L;
221
222 public void widgetSelected(SelectionEvent e) {
223 resetFilter();
224 }
225 });
226 }
227
228 private void resetFilter() {
229 filterTxt.setText("");
230 filterTxt.setMessage(FILTER_HELP_MSG);
231 }
232
233 private void createTableViewer(Composite parent) {
234 parent.setLayout(new FillLayout());
235 // helpers to enable sorting by column
236 List<String> propertiesList = new ArrayList<String>();
237 List<Integer> propertyTypesList = new ArrayList<Integer>();
238
239 // Define the TableViewer
240 viewer = new TableViewer(parent, SWT.SINGLE | SWT.H_SCROLL
241 | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER);
242
243 TableViewerColumn col;
244 // Name
245 // TableViewerColumn col = new TableViewerColumn(viewer, SWT.NONE);
246 // col.getColumn().setWidth(220);
247 // col.getColumn().setText("Category");
248 // col.setLabelProvider(new ColumnLabelProvider() {
249 // @Override
250 // public String getText(Object element) {
251 // return JcrUtils.get((Node) element, SlcNames.SLC_CATEGORY);
252 // }
253 // });
254 // col.getColumn().addSelectionListener(getSelectionAdapter(0));
255 // propertiesList.add(SlcNames.SLC_CATEGORY);
256 // propertyTypesList.add(PropertyType.STRING);
257
258 // Group base name
259 col = new TableViewerColumn(viewer, SWT.NONE);
260 col.getColumn().setWidth(220);
261 col.getColumn().setText("Group Name");
262 col.setLabelProvider(new ColumnLabelProvider() {
263 private static final long serialVersionUID = 6186787928630825293L;
264
265 @Override
266 public String getText(Object element) {
267 return JcrUtils.get((Node) element, SLC_GROUP_BASE_ID);
268 }
269 });
270 col.getColumn().addSelectionListener(getSelectionAdapter(0));
271 propertiesList.add(SLC_GROUP_BASE_ID);
272 propertyTypesList.add(PropertyType.STRING);
273
274 // Version
275 col = new TableViewerColumn(viewer, SWT.NONE);
276 col.getColumn().setWidth(80);
277 col.getColumn().setText("Has binaries");
278 col.setLabelProvider(new ColumnLabelProvider() {
279 private static final long serialVersionUID = -2017377132642062464L;
280
281 @Override
282 public String getText(Object element) {
283 try {
284 Node currNode = (Node) element;
285
286 return currNode.hasNode(RepoConstants.BINARIES_ARTIFACT_ID) ? "Yes"
287 : "No";
288 } catch (RepositoryException e) {
289 throw new SlcException("unable to check type of node "
290 + element, e);
291 }
292 }
293 });
294 // col.getColumn().addSelectionListener(getSelectionAdapter(2));
295 // propertiesList.add(SLC_VERSION);
296 // propertyTypesList.add(PropertyType.STRING);
297
298 final Table table = viewer.getTable();
299 table.setHeaderVisible(true);
300 table.setLinesVisible(true);
301
302 viewer.setContentProvider(new DistributionsContentProvider());
303 getSite().setSelectionProvider(viewer);
304
305 comparator = new DistNodeViewerComparator(0,
306 DistNodeViewerComparator.ASCENDING, propertiesList,
307 propertyTypesList);
308 viewer.setComparator(comparator);
309
310 // Context Menu
311 MenuManager menuManager = new MenuManager();
312 Menu menu = menuManager.createContextMenu(viewer.getTable());
313 menuManager.addMenuListener(new IMenuListener() {
314 private static final long serialVersionUID = 739004528695501335L;
315
316 public void menuAboutToShow(IMenuManager manager) {
317 contextMenuAboutToShow(manager);
318 }
319 });
320 viewer.getTable().setMenu(menu);
321 getSite().registerContextMenu(menuManager, viewer);
322
323 // Double click
324 viewer.addDoubleClickListener(new DoubleClickListener());
325 }
326
327 @Override
328 public void setFocus() {
329 viewer.getTable().setFocus();
330 }
331
332 /** Programmatically configure the context menu */
333 protected void contextMenuAboutToShow(IMenuManager menuManager) {
334 IWorkbenchWindow window = DistPlugin.getDefault().getWorkbench()
335 .getActiveWorkbenchWindow();
336 // Build conditions
337 // Mark as category base
338 Object firstElement = ((IStructuredSelection) viewer.getSelection())
339 .getFirstElement();
340 Node currSelected = (Node) firstElement;
341
342 DistWkspEditorInput input = (DistWkspEditorInput) getEditorInput();
343
344 Map<String, String> params = new HashMap<String, String>();
345 params.put(OpenGenerateBinariesWizard.PARAM_REPO_NODE_PATH,
346 input.getRepoNodePath());
347 try {
348 params.put(OpenGenerateBinariesWizard.PARAM_MODULE_PATH,
349 currSelected.getPath());
350 } catch (RepositoryException e) {
351 throw new SlcException("Unable to get path for " + currSelected, e);
352 }
353 params.put(OpenGenerateBinariesWizard.PARAM_WORKSPACE_NAME,
354 input.getWorkspaceName());
355
356 CommandUtils.refreshParameterizedCommand(menuManager, window,
357 OpenGenerateBinariesWizard.ID,
358 OpenGenerateBinariesWizard.DEFAULT_LABEL,
359 OpenGenerateBinariesWizard.DEFAULT_ICON, true, params);
360
361 // boolean isRelevant = false;
362 // try {
363 // isRelevant = currSelected.isNodeType(SlcTypes.SLC_CATEGORY);
364 // boolean canEdit = currSelected.canAddMixin(SlcTypes.SLC_CATEGORY);
365 //
366 // } catch (RepositoryException e) {
367 // throw new SlcException("unable to check type of node "
368 // + firstElement, e);
369 // }
370 // // Add
371 // if (isRelevant) {// Remove
372 // CommandUtils.refreshCommand(menuManager, window,
373 // MarkAsRelevantCategory.ID,
374 // MarkAsRelevantCategory.DEFAULT_REMOVE_LABEL,
375 // MarkAsRelevantCategory.DEFAULT_REMOVE_ICON, true);
376 // } else {
377 // CommandUtils.refreshCommand(menuManager, window,
378 // MarkAsRelevantCategory.ID,
379 // MarkAsRelevantCategory.DEFAULT_LABEL,
380 // MarkAsRelevantCategory.DEFAULT_ICON, true);
381 // }
382 }
383
384 private SelectionAdapter getSelectionAdapter(final int index) {
385 SelectionAdapter selectionAdapter = new SelectionAdapter() {
386 private static final long serialVersionUID = -1723894288128081757L;
387
388 @Override
389 public void widgetSelected(SelectionEvent e) {
390 Table table = viewer.getTable();
391 comparator.setColumn(index);
392 int dir = table.getSortDirection();
393 if (table.getSortColumn() == table.getColumn(index)) {
394 dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
395 } else {
396 dir = SWT.DOWN;
397 }
398 table.setSortDirection(dir);
399 table.setSortColumn(table.getColumn(index));
400 viewer.refresh();
401 }
402 };
403 return selectionAdapter;
404 }
405
406 /* LOCAL CLASSES */
407 private class DistributionsContentProvider implements
408 IStructuredContentProvider {
409 private static final long serialVersionUID = -5939763615620837492L;
410
411 // we keep a cache of the Nodes in the content provider to be able to
412 // manage long request
413 private List<Node> nodes;
414
415 public void dispose() {
416 }
417
418 // We expect a list of nodes as a new input
419 @SuppressWarnings("unchecked")
420 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
421 nodes = (List<Node>) newInput;
422 }
423
424 public Object[] getElements(Object arg0) {
425 return nodes.toArray();
426 }
427 }
428
429 private class DoubleClickListener implements IDoubleClickListener {
430
431 public void doubleClick(DoubleClickEvent event) {
432 Object obj = ((IStructuredSelection) event.getSelection())
433 .getFirstElement();
434 if (obj instanceof Node) {
435 Node node = (Node) obj;
436 try {
437 if (node.isNodeType(SlcTypes.SLC_ARTIFACT)) {
438 DistWkspEditorInput dwip = (DistWkspEditorInput) getEditorInput();
439 Map<String, String> params = new HashMap<String, String>();
440 params.put(OpenModuleEditor.PARAM_REPO_NODE_PATH,
441 dwip.getRepoNodePath());
442 params.put(OpenModuleEditor.PARAM_REPO_URI,
443 dwip.getUri());
444 params.put(OpenModuleEditor.PARAM_WORKSPACE_NAME,
445 dwip.getWorkspaceName());
446 String path = node.getPath();
447 params.put(OpenModuleEditor.PARAM_MODULE_PATH, path);
448 CommandUtils.callCommand(OpenModuleEditor.ID, params);
449 }
450 } catch (RepositoryException re) {
451 throw new SlcException("Cannot get path for node " + node
452 + " while setting parameters for "
453 + "command OpenModuleEditor", re);
454 }
455
456 }
457 }
458 }
459
460 class CategoryObserver extends AsyncUiEventListener {
461
462 public CategoryObserver(Display display) {
463 super(display);
464 }
465
466 @Override
467 protected Boolean willProcessInUiThread(List<Event> events)
468 throws RepositoryException {
469 for (Event event : events) {
470 String path = event.getPath();
471 if (JcrUtils.lastPathElement(path).equals(
472 DistConstants.JCR_MIXIN_TYPES))
473 return true;
474 }
475 return false;
476 }
477
478 protected void onEventInUiThread(List<Event> events)
479 throws RepositoryException {
480 if (getLog().isTraceEnabled())
481 getLog().trace("Refresh table");
482 viewer.refresh();
483 }
484 }
485
486 @Override
487 public void setActive(boolean active) {
488 super.setActive(active);
489 if (active) {
490 }
491 }
492 }