2 * Copyright (C) 2007-2012 Argeo GmbH
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org
.argeo
.slc
.client
.ui
.dist
.editors
;
18 import java
.util
.ArrayList
;
19 import java
.util
.HashMap
;
20 import java
.util
.List
;
23 import javax
.jcr
.Node
;
24 import javax
.jcr
.NodeIterator
;
25 import javax
.jcr
.PropertyType
;
26 import javax
.jcr
.RepositoryException
;
27 import javax
.jcr
.Session
;
28 import javax
.jcr
.observation
.Event
;
29 import javax
.jcr
.query
.QueryManager
;
30 import javax
.jcr
.query
.QueryResult
;
31 import javax
.jcr
.query
.qom
.Constraint
;
32 import javax
.jcr
.query
.qom
.DynamicOperand
;
33 import javax
.jcr
.query
.qom
.QueryObjectModel
;
34 import javax
.jcr
.query
.qom
.QueryObjectModelFactory
;
35 import javax
.jcr
.query
.qom
.Selector
;
36 import javax
.jcr
.query
.qom
.StaticOperand
;
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
.OpenGenerateBinariesWizard
;
46 import org
.argeo
.slc
.client
.ui
.dist
.commands
.OpenModuleEditor
;
47 import org
.argeo
.slc
.client
.ui
.dist
.utils
.DistNodeViewerComparator
;
48 import org
.argeo
.slc
.jcr
.SlcNames
;
49 import org
.argeo
.slc
.jcr
.SlcTypes
;
50 import org
.argeo
.slc
.repo
.RepoConstants
;
51 import org
.eclipse
.jface
.action
.IMenuListener
;
52 import org
.eclipse
.jface
.action
.IMenuManager
;
53 import org
.eclipse
.jface
.action
.MenuManager
;
54 import org
.eclipse
.jface
.dialogs
.IMessageProvider
;
55 import org
.eclipse
.jface
.viewers
.ColumnLabelProvider
;
56 import org
.eclipse
.jface
.viewers
.DoubleClickEvent
;
57 import org
.eclipse
.jface
.viewers
.IDoubleClickListener
;
58 import org
.eclipse
.jface
.viewers
.IStructuredContentProvider
;
59 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
60 import org
.eclipse
.jface
.viewers
.TableViewer
;
61 import org
.eclipse
.jface
.viewers
.TableViewerColumn
;
62 import org
.eclipse
.jface
.viewers
.Viewer
;
63 import org
.eclipse
.swt
.SWT
;
64 import org
.eclipse
.swt
.events
.ModifyEvent
;
65 import org
.eclipse
.swt
.events
.ModifyListener
;
66 import org
.eclipse
.swt
.events
.SelectionAdapter
;
67 import org
.eclipse
.swt
.events
.SelectionEvent
;
68 import org
.eclipse
.swt
.layout
.FillLayout
;
69 import org
.eclipse
.swt
.layout
.GridData
;
70 import org
.eclipse
.swt
.layout
.GridLayout
;
71 import org
.eclipse
.swt
.widgets
.Button
;
72 import org
.eclipse
.swt
.widgets
.Composite
;
73 import org
.eclipse
.swt
.widgets
.Display
;
74 import org
.eclipse
.swt
.widgets
.Menu
;
75 import org
.eclipse
.swt
.widgets
.Table
;
76 import org
.eclipse
.swt
.widgets
.Text
;
77 import org
.eclipse
.ui
.IWorkbenchWindow
;
78 import org
.eclipse
.ui
.forms
.IManagedForm
;
79 import org
.eclipse
.ui
.forms
.editor
.FormEditor
;
80 import org
.eclipse
.ui
.forms
.editor
.FormPage
;
81 import org
.eclipse
.ui
.forms
.widgets
.FormToolkit
;
82 import org
.eclipse
.ui
.forms
.widgets
.ScrolledForm
;
85 * Show all category base (currently only Aether group base) contained in a
86 * given workspace as filter-able table. Enable to definition of which of them
87 * should be managed as modular distribution
89 public class WkspCategoryBaseListPage
extends FormPage
implements SlcNames
{
91 final static String PAGE_ID
= "WkspCategoryBaseListPage";
94 private Session session
;
97 private DistNodeViewerComparator comparator
;
98 private TableViewer viewer
;
99 private FormToolkit tk
;
100 private Text filterTxt
;
101 private final static String FILTER_HELP_MSG
= "Enter filter criterion separated by a space";
104 // private final static String[] observedTypes = { SlcTypes.SLC_GROUP_BASE
106 // private CategoryObserver categoriesObserver;
108 public WkspCategoryBaseListPage(FormEditor formEditor
, String title
,
110 super(formEditor
, PAGE_ID
, title
);
111 this.session
= session
;
115 protected void createFormContent(IManagedForm managedForm
) {
116 ScrolledForm form
= managedForm
.getForm();
117 tk
= managedForm
.getToolkit();
119 form
.setText("Define Relevant Categories");
120 form
.setMessage("Choose in the below list "
121 + "the categories that can be used as base for "
122 + "modular distributions maintained via the current workspace",
123 IMessageProvider
.NONE
);
126 GridLayout layout
= new GridLayout(1, false);
127 Composite body
= form
.getBody();
128 body
.setLayout(layout
);
131 Composite header
= tk
.createComposite(body
);
132 header
.setLayoutData(new GridData(SWT
.FILL
, SWT
.TOP
, true, false));
133 createFilterPart(header
);
136 Composite tableCmp
= tk
.createComposite(body
);
137 tableCmp
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
138 createTableViewer(tableCmp
);
140 // categoriesObserver = new CategoryObserver(viewer.getTable()
143 // ObservationManager observationManager = session.getWorkspace()
144 // .getObservationManager();
145 // // FIXME Will not be notified if empty result is deleted
146 // observationManager.addEventListener(categoriesObserver,
147 // Event.PROPERTY_CHANGED, "/", true, null, observedTypes,
149 // } catch (RepositoryException e) {
150 // throw new SlcException("Cannot register listeners", e);
156 private void refresh() {
157 final List
<Node
> result
= JcrUtils
.nodeIteratorToList(listGroupBase());
158 viewer
.setInput(result
);
161 /** Build repository request */
162 private NodeIterator
listGroupBase() {
164 QueryManager queryManager
= session
.getWorkspace()
166 QueryObjectModelFactory factory
= queryManager
.getQOMFactory();
168 Selector source
= factory
.selector(SlcTypes
.SLC_GROUP_BASE
,
169 SlcTypes
.SLC_MODULE_COORDINATES
);
171 // Create a dynamic operand for each property on which we want to
173 DynamicOperand catDO
= factory
.propertyValue(
174 source
.getSelectorName(), SlcNames
.SLC_CATEGORY
);
175 DynamicOperand nameDO
= factory
.propertyValue(
176 source
.getSelectorName(), SlcNames
.SLC_NAME
);
178 String filter
= filterTxt
.getText();
180 Constraint defaultC
= null;
181 // Build constraints based the textArea content
182 if (filter
!= null && !"".equals(filter
.trim())) {
184 String
[] strs
= filter
.trim().split(" ");
185 for (String token
: strs
) {
186 token
= token
.replace('*', '%');
187 StaticOperand so
= factory
.literal(session
188 .getValueFactory().createValue("%" + token
+ "%"));
190 Constraint currC
= factory
.comparison(catDO
,
191 QueryObjectModelFactory
.JCR_OPERATOR_LIKE
, so
);
192 currC
= factory
.or(currC
, factory
.comparison(nameDO
,
193 QueryObjectModelFactory
.JCR_OPERATOR_LIKE
, so
));
195 if (defaultC
== null)
198 defaultC
= factory
.and(defaultC
, currC
);
202 QueryObjectModel query
= factory
.createQuery(source
, defaultC
,
204 QueryResult result
= query
.execute();
205 return result
.getNodes();
206 } catch (RepositoryException re
) {
207 throw new SlcException(
208 "Unable to refresh group list for workspace "
209 + getEditorInput().getName(), re
);
213 private void createFilterPart(Composite parent
) {
214 GridLayout layout
= new GridLayout(2, false);
215 layout
.marginWidth
= layout
.marginHeight
= layout
.verticalSpacing
= 0;
216 layout
.horizontalSpacing
= 5;
217 parent
.setLayout(layout
);
219 // Text Area to filter
220 filterTxt
= tk
.createText(parent
, "", SWT
.BORDER
| SWT
.SINGLE
221 | SWT
.SEARCH
| SWT
.CANCEL
);
222 filterTxt
.setMessage(FILTER_HELP_MSG
);
223 filterTxt
.setLayoutData(new GridData(SWT
.FILL
, SWT
.TOP
, true, false));
224 filterTxt
.addModifyListener(new ModifyListener() {
225 public void modifyText(ModifyEvent event
) {
230 Button resetBtn
= tk
.createButton(parent
, null, SWT
.PUSH
);
231 resetBtn
.setImage(DistImages
.IMG_REPO_READONLY
);
232 resetBtn
.addSelectionListener(new SelectionAdapter() {
233 public void widgetSelected(SelectionEvent e
) {
239 private void resetFilter() {
240 filterTxt
.setText("");
241 filterTxt
.setMessage(FILTER_HELP_MSG
);
244 private void createTableViewer(Composite parent
) {
245 parent
.setLayout(new FillLayout());
246 // helpers to enable sorting by column
247 List
<String
> propertiesList
= new ArrayList
<String
>();
248 List
<Integer
> propertyTypesList
= new ArrayList
<Integer
>();
250 // Define the TableViewer
251 viewer
= new TableViewer(parent
, SWT
.SINGLE
| SWT
.H_SCROLL
252 | SWT
.V_SCROLL
| SWT
.FULL_SELECTION
| SWT
.BORDER
);
254 TableViewerColumn col
;
256 // TableViewerColumn col = new TableViewerColumn(viewer, SWT.NONE);
257 // col.getColumn().setWidth(220);
258 // col.getColumn().setText("Category");
259 // col.setLabelProvider(new ColumnLabelProvider() {
261 // public String getText(Object element) {
262 // return JcrUtils.get((Node) element, SlcNames.SLC_CATEGORY);
265 // col.getColumn().addSelectionListener(getSelectionAdapter(0));
266 // propertiesList.add(SlcNames.SLC_CATEGORY);
267 // propertyTypesList.add(PropertyType.STRING);
270 col
= new TableViewerColumn(viewer
, SWT
.NONE
);
271 col
.getColumn().setWidth(220);
272 col
.getColumn().setText("Group Name");
273 col
.setLabelProvider(new ColumnLabelProvider() {
275 public String
getText(Object element
) {
276 return JcrUtils
.get((Node
) element
, SLC_GROUP_BASE_ID
);
279 col
.getColumn().addSelectionListener(getSelectionAdapter(0));
280 propertiesList
.add(SLC_GROUP_BASE_ID
);
281 propertyTypesList
.add(PropertyType
.STRING
);
284 col
= new TableViewerColumn(viewer
, SWT
.NONE
);
285 col
.getColumn().setWidth(80);
286 col
.getColumn().setText("Has binaries");
287 col
.setLabelProvider(new ColumnLabelProvider() {
289 public String
getText(Object element
) {
291 Node currNode
= (Node
) element
;
293 return currNode
.hasNode(RepoConstants
.BINARIES_ARTIFACT_ID
) ?
"Yes"
295 } catch (RepositoryException e
) {
296 throw new SlcException("unable to check type of node "
301 // col.getColumn().addSelectionListener(getSelectionAdapter(2));
302 // propertiesList.add(SLC_VERSION);
303 // propertyTypesList.add(PropertyType.STRING);
305 final Table table
= viewer
.getTable();
306 table
.setHeaderVisible(true);
307 table
.setLinesVisible(true);
309 viewer
.setContentProvider(new DistributionsContentProvider());
310 getSite().setSelectionProvider(viewer
);
312 comparator
= new DistNodeViewerComparator(0,
313 DistNodeViewerComparator
.ASCENDING
, propertiesList
,
315 viewer
.setComparator(comparator
);
318 MenuManager menuManager
= new MenuManager();
319 Menu menu
= menuManager
.createContextMenu(viewer
.getTable());
320 menuManager
.addMenuListener(new IMenuListener() {
321 public void menuAboutToShow(IMenuManager manager
) {
322 contextMenuAboutToShow(manager
);
325 viewer
.getTable().setMenu(menu
);
326 getSite().registerContextMenu(menuManager
, viewer
);
329 viewer
.addDoubleClickListener(new DoubleClickListener());
333 public void setFocus() {
334 viewer
.getTable().setFocus();
337 /** Programmatically configure the context menu */
338 protected void contextMenuAboutToShow(IMenuManager menuManager
) {
339 IWorkbenchWindow window
= DistPlugin
.getDefault().getWorkbench()
340 .getActiveWorkbenchWindow();
342 // Mark as category base
343 Object firstElement
= ((IStructuredSelection
) viewer
.getSelection())
345 Node currSelected
= (Node
) firstElement
;
347 DistWkspEditorInput input
= (DistWkspEditorInput
) getEditorInput();
349 Map
<String
, String
> params
= new HashMap
<String
, String
>();
350 params
.put(OpenGenerateBinariesWizard
.PARAM_REPO_NODE_PATH
,
351 input
.getRepoNodePath());
353 params
.put(OpenGenerateBinariesWizard
.PARAM_MODULE_PATH
,
354 currSelected
.getPath());
355 } catch (RepositoryException e
) {
356 throw new SlcException("Unable to get path for " + currSelected
, e
);
358 params
.put(OpenGenerateBinariesWizard
.PARAM_WORKSPACE_NAME
,
359 input
.getWorkspaceName());
361 CommandUtils
.refreshParametrizedCommand(menuManager
, window
,
362 OpenGenerateBinariesWizard
.ID
,
363 OpenGenerateBinariesWizard
.DEFAULT_LABEL
,
364 OpenGenerateBinariesWizard
.DEFAULT_ICON
, true, params
);
366 // boolean isRelevant = false;
368 // isRelevant = currSelected.isNodeType(SlcTypes.SLC_CATEGORY);
369 // boolean canEdit = currSelected.canAddMixin(SlcTypes.SLC_CATEGORY);
371 // } catch (RepositoryException e) {
372 // throw new SlcException("unable to check type of node "
373 // + firstElement, e);
376 // if (isRelevant) {// Remove
377 // CommandUtils.refreshCommand(menuManager, window,
378 // MarkAsRelevantCategory.ID,
379 // MarkAsRelevantCategory.DEFAULT_REMOVE_LABEL,
380 // MarkAsRelevantCategory.DEFAULT_REMOVE_ICON, true);
382 // CommandUtils.refreshCommand(menuManager, window,
383 // MarkAsRelevantCategory.ID,
384 // MarkAsRelevantCategory.DEFAULT_LABEL,
385 // MarkAsRelevantCategory.DEFAULT_ICON, true);
389 private SelectionAdapter
getSelectionAdapter(final int index
) {
390 SelectionAdapter selectionAdapter
= new SelectionAdapter() {
392 public void widgetSelected(SelectionEvent e
) {
393 Table table
= viewer
.getTable();
394 comparator
.setColumn(index
);
395 int dir
= table
.getSortDirection();
396 if (table
.getSortColumn() == table
.getColumn(index
)) {
397 dir
= dir
== SWT
.UP ? SWT
.DOWN
: SWT
.UP
;
401 table
.setSortDirection(dir
);
402 table
.setSortColumn(table
.getColumn(index
));
406 return selectionAdapter
;
410 private class DistributionsContentProvider
implements
411 IStructuredContentProvider
{
412 // we keep a cache of the Nodes in the content provider to be able to
413 // manage long request
414 private List
<Node
> nodes
;
416 public void dispose() {
419 // We expect a list of nodes as a new input
420 @SuppressWarnings("unchecked")
421 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
422 nodes
= (List
<Node
>) newInput
;
425 public Object
[] getElements(Object arg0
) {
426 return nodes
.toArray();
430 private class DoubleClickListener
implements IDoubleClickListener
{
432 public void doubleClick(DoubleClickEvent event
) {
433 Object obj
= ((IStructuredSelection
) event
.getSelection())
435 if (obj
instanceof Node
) {
436 Node node
= (Node
) obj
;
438 if (node
.isNodeType(SlcTypes
.SLC_ARTIFACT
)) {
439 DistWkspEditorInput dwip
= (DistWkspEditorInput
) getEditorInput();
440 Map
<String
, String
> params
= new HashMap
<String
, String
>();
441 params
.put(OpenModuleEditor
.PARAM_REPO_NODE_PATH
,
442 dwip
.getRepoNodePath());
443 params
.put(OpenModuleEditor
.PARAM_REPO_URI
,
445 params
.put(OpenModuleEditor
.PARAM_WORKSPACE_NAME
,
446 dwip
.getWorkspaceName());
447 String path
= node
.getPath();
448 params
.put(OpenModuleEditor
.PARAM_MODULE_PATH
, path
);
449 CommandUtils
.callCommand(OpenModuleEditor
.ID
, params
);
451 } catch (RepositoryException re
) {
452 throw new SlcException("Cannot get path for node " + node
453 + " while setting parameters for "
454 + "command OpenModuleEditor", re
);
461 class CategoryObserver
extends AsyncUiEventListener
{
463 public CategoryObserver(Display display
) {
468 protected Boolean
willProcessInUiThread(List
<Event
> events
)
469 throws RepositoryException
{
470 for (Event event
: events
) {
471 String path
= event
.getPath();
472 if (JcrUtils
.lastPathElement(path
).equals(
473 DistConstants
.JCR_MIXIN_TYPES
))
479 protected void onEventInUiThread(List
<Event
> events
)
480 throws RepositoryException
{
481 if (getLog().isTraceEnabled())
482 getLog().trace("Refresh table");
488 public void setActive(boolean active
) {
489 super.setActive(active
);