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