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