View Javadoc
1   package org.argeo.people.ui.composites;
2   
3   import static org.argeo.eclipse.ui.jcr.JcrUiUtils.getNodeSelectionAdapter;
4   
5   import java.util.ArrayList;
6   import java.util.List;
7   
8   import javax.jcr.Node;
9   import javax.jcr.NodeIterator;
10  import javax.jcr.Property;
11  import javax.jcr.PropertyType;
12  import javax.jcr.RepositoryException;
13  import javax.jcr.Session;
14  import javax.jcr.query.Query;
15  import javax.jcr.query.QueryResult;
16  
17  import org.argeo.connect.ConnectException;
18  import org.argeo.connect.ConnectTypes;
19  import org.argeo.connect.util.XPathUtils;
20  import org.argeo.eclipse.ui.EclipseUiUtils;
21  import org.argeo.eclipse.ui.jcr.lists.JcrColumnDefinition;
22  import org.argeo.eclipse.ui.jcr.lists.NodeViewerComparator;
23  import org.argeo.eclipse.ui.jcr.lists.SimpleJcrNodeLabelProvider;
24  import org.argeo.eclipse.ui.specific.EclipseUiSpecificUtils;
25  import org.argeo.eclipse.ui.utils.ViewerUtils;
26  import org.argeo.jcr.JcrUtils;
27  import org.argeo.people.ui.PeopleMsg;
28  import org.eclipse.jface.viewers.CheckboxTableViewer;
29  import org.eclipse.jface.viewers.ColumnLabelProvider;
30  import org.eclipse.jface.viewers.IStructuredContentProvider;
31  import org.eclipse.jface.viewers.TableViewer;
32  import org.eclipse.jface.viewers.TableViewerColumn;
33  import org.eclipse.jface.viewers.Viewer;
34  import org.eclipse.swt.SWT;
35  import org.eclipse.swt.events.ModifyEvent;
36  import org.eclipse.swt.events.ModifyListener;
37  import org.eclipse.swt.events.SelectionAdapter;
38  import org.eclipse.swt.events.SelectionEvent;
39  import org.eclipse.swt.layout.GridData;
40  import org.eclipse.swt.layout.GridLayout;
41  import org.eclipse.swt.widgets.Composite;
42  import org.eclipse.swt.widgets.Table;
43  import org.eclipse.swt.widgets.Text;
44  
45  /** Almost canonical implementation of a table that display entities */
46  public class FilteredOrderableEntityTable extends Composite {
47  	// private final static Log log =
48  	// LogFactory.getLog(EntityTableComposite.class);
49  	private static final long serialVersionUID = 1262369448445021926L;
50  
51  	private TableViewer entityViewer;
52  	private Text filterTxt;
53  	private final static String FILTER_HELP_MSG = PeopleMsg.filterHelp.lead();
54  	private Session session;
55  
56  	private int tableStyle;
57  
58  	private boolean hasFilter = false;
59  	private boolean hasSelectionColumn = false;
60  	private List<JcrColumnDefinition> colDefs = new ArrayList<JcrColumnDefinition>();
61  	{ // By default, it displays only title
62  		colDefs.add(new JcrColumnDefinition(null, Property.JCR_TITLE, PropertyType.STRING, PeopleMsg.name.lead(), 300));
63  	};
64  	private String nodeType = ConnectTypes.CONNECT_ENTITY;
65  
66  	public List<JcrColumnDefinition> getColumnsDef() {
67  		return colDefs;
68  	}
69  
70  	// CONSTRUCTORS
71  
72  	/**
73  	 * Default table with no filter and no selection column that only display
74  	 * JCR_TITLES
75  	 * 
76  	 * Default selector is people:entity
77  	 * 
78  	 * @param parent
79  	 * @param style
80  	 *            the style of the table
81  	 * @param session
82  	 */
83  	public FilteredOrderableEntityTable(Composite parent, int style, Session session) {
84  		super(parent, SWT.NONE);
85  		this.tableStyle = style;
86  		this.session = session;
87  		populate();
88  	}
89  
90  	/**
91  	 * Default table that only display JCR_TITLES of an entity table. Caller can
92  	 * choose to add a filter and a selection column
93  	 * 
94  	 * @param parent
95  	 * @param style
96  	 *            the style of the table
97  	 * @param session
98  	 * @param addFilter
99  	 * @param addSelection
100 	 */
101 	public FilteredOrderableEntityTable(Composite parent, int style, Session session, boolean addFilter,
102 			boolean addSelection) {
103 		super(parent, SWT.NONE);
104 		this.tableStyle = style;
105 		this.session = session;
106 		this.hasFilter = addFilter;
107 		this.hasSelectionColumn = addSelection;
108 		populate();
109 	}
110 
111 	/**
112 	 * 
113 	 * @param parent
114 	 * @param style
115 	 *            the style of the table
116 	 * @param session
117 	 * @param colDefs
118 	 */
119 	public FilteredOrderableEntityTable(Composite parent, int style, Session session,
120 			List<JcrColumnDefinition> colDefs) {
121 		super(parent, SWT.NONE);
122 		this.tableStyle = style;
123 		this.session = session;
124 		this.colDefs = colDefs;
125 		populate();
126 	}
127 
128 	/**
129 	 * 
130 	 * if some parameters are null, we use default values instead
131 	 * 
132 	 * @param parent
133 	 * @param style
134 	 *            the style of the table
135 	 * @param session
136 	 * @param colDefs
137 	 * @param addFilter
138 	 * @param addSelection
139 	 */
140 	public FilteredOrderableEntityTable(Composite parent, int style, Session session, String nodeType,
141 			List<JcrColumnDefinition> colDefs, boolean addFilter, boolean addSelection) {
142 		super(parent, SWT.NONE);
143 		this.tableStyle = style;
144 		this.session = session;
145 		if (colDefs != null)
146 			this.colDefs = colDefs;
147 		if (nodeType != null)
148 			this.nodeType = nodeType;
149 		this.hasFilter = addFilter;
150 		this.hasSelectionColumn = addSelection;
151 		populate();
152 	}
153 
154 	protected void populate() {
155 		// initialization
156 		Composite parent = this;
157 		// Main Layout
158 		GridLayout layout = EclipseUiUtils.noSpaceGridLayout();
159 		layout.verticalSpacing = 5;
160 		this.setLayout(layout);
161 		if (hasFilter)
162 			createFilterPart(parent);
163 		entityViewer = createTableViewer(parent);
164 		EclipseUiSpecificUtils.enableToolTipSupport(entityViewer);
165 		entityViewer.setContentProvider(new MyTableContentProvider());
166 		refreshFilteredList();
167 
168 		if (hasFilter)
169 			filterTxt.setFocus();
170 	}
171 
172 	public List<Node> getSelectedEntities() {
173 		if (hasSelectionColumn) {
174 			Object[] elements = ((CheckboxTableViewer) entityViewer).getCheckedElements();
175 
176 			List<Node> result = new ArrayList<Node>();
177 			for (Object obj : elements) {
178 				result.add((Node) obj);
179 			}
180 			return result;
181 		} else
182 			throw new ConnectException("Unvalid request: no selection column  has been created for the current table");
183 	}
184 
185 	/** Returns the User table viewer, typically to add double click listener */
186 	public TableViewer getTableViewer() {
187 		return entityViewer;
188 	}
189 
190 	private TableViewer createTableViewer(final Composite parent) {
191 		if (hasSelectionColumn)
192 			tableStyle = tableStyle | SWT.CHECK;
193 
194 		Table table = new Table(parent, tableStyle);
195 		table.setLayoutData(EclipseUiUtils.fillAll());
196 
197 		TableViewer viewer;
198 		if (hasSelectionColumn)
199 			viewer = new CheckboxTableViewer(table);
200 		else
201 			viewer = new TableViewer(table);
202 
203 		table.setLinesVisible(true);
204 		table.setHeaderVisible(true);
205 
206 		TableViewerColumn column;
207 		int offset = 0;
208 		if (hasSelectionColumn) {
209 			offset = 1;
210 			column = ViewerUtils.createTableViewerColumn(viewer, "", SWT.NONE, 25);
211 			column.setLabelProvider(new ColumnLabelProvider() {
212 				private static final long serialVersionUID = 1L;
213 
214 				@Override
215 				public String getText(Object element) {
216 					return null;
217 				}
218 			});
219 			SelectionAdapter selectionAdapter = new SelectionAdapter() {
220 				private static final long serialVersionUID = 1L;
221 				boolean allSelected = false;
222 
223 				@Override
224 				public void widgetSelected(SelectionEvent e) {
225 					allSelected = !allSelected;
226 					((CheckboxTableViewer) entityViewer).setAllChecked(allSelected);
227 				}
228 			};
229 			column.getColumn().addSelectionListener(selectionAdapter);
230 		}
231 
232 		NodeViewerComparator comparator = new NodeViewerComparator();
233 		int i = offset;
234 		for (JcrColumnDefinition colDef : colDefs) {
235 			column = ViewerUtils.createTableViewerColumn(viewer, colDef.getHeaderLabel(), SWT.NONE,
236 					colDef.getColumnSize());
237 			column.setLabelProvider(new CLProvider(colDef.getPropertyName()));
238 			column.getColumn().addSelectionListener(
239 					getNodeSelectionAdapter(i, colDef.getPropertyType(), colDef.getPropertyName(), comparator, viewer));
240 			i++;
241 		}
242 
243 		// IMPORTANT: initialize comparator before setting it
244 		JcrColumnDefinition firstCol = colDefs.get(0);
245 		comparator.setColumn(firstCol.getPropertyType(), firstCol.getPropertyName());
246 		viewer.setComparator(comparator);
247 
248 		return viewer;
249 	}
250 
251 	private class CLProvider extends SimpleJcrNodeLabelProvider {
252 		private static final long serialVersionUID = 1L;
253 
254 		public CLProvider(String propertyName) {
255 			super(propertyName);
256 		}
257 
258 		public String getToolTipText(Object element) {
259 			return getText(element);
260 		}
261 	}
262 
263 	@Override
264 	public boolean setFocus() {
265 		entityViewer.getTable().setFocus();
266 		return true;
267 	}
268 
269 	@Override
270 	public void dispose() {
271 		super.dispose();
272 	}
273 
274 	public void refresh() {
275 		refreshFilteredList();
276 	}
277 
278 	private class MyTableContentProvider implements IStructuredContentProvider {
279 		private static final long serialVersionUID = 7164029504991808317L;
280 
281 		public Object[] getElements(Object inputElement) {
282 			return (Object[]) inputElement;
283 		}
284 
285 		public void dispose() {
286 		}
287 
288 		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
289 		}
290 	}
291 
292 	/* MANAGE FILTER */
293 	private void createFilterPart(Composite parent) {
294 		// Text Area for the filter
295 		filterTxt = new Text(parent, SWT.BORDER | SWT.SEARCH | SWT.ICON_SEARCH | SWT.ICON_CANCEL);
296 		filterTxt.setMessage(FILTER_HELP_MSG);
297 		filterTxt.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));
298 		filterTxt.addModifyListener(new ModifyListener() {
299 			private static final long serialVersionUID = 1L;
300 
301 			public void modifyText(ModifyEvent event) {
302 				refreshFilteredList();
303 			}
304 		});
305 	}
306 
307 	/**
308 	 * Refresh the list: caller might overwrite in order to display a subset of all
309 	 * nodes
310 	 */
311 	protected void refreshFilteredList() {
312 		List<Node> nodes;
313 		try {
314 			nodes = JcrUtils.nodeIteratorToList(listFilteredElements(session, hasFilter ? filterTxt.getText() : null));
315 			entityViewer.setInput(nodes.toArray());
316 		} catch (RepositoryException e) {
317 			throw new ConnectException("Unable to refresh list", e);
318 		}
319 	}
320 
321 	/**
322 	 * Build repository request : caller might overwrite in order to display a
323 	 * subset
324 	 */
325 	protected NodeIterator listFilteredElements(Session session, String filter) throws RepositoryException {
326 		String xpathQueryStr = "//element(*, " + nodeType + ")";
327 		String attrQuery = XPathUtils.getFreeTextConstraint(filter);
328 		if (EclipseUiUtils.notEmpty(attrQuery))
329 			xpathQueryStr += "[" + attrQuery + "]";
330 		xpathQueryStr += " order by @" + Property.JCR_TITLE;
331 		Query xpathQuery = XPathUtils.createQuery(session, xpathQueryStr);
332 		xpathQuery.setLimit(100);
333 		QueryResult result = xpathQuery.execute();
334 		return result.getNodes();
335 	}
336 }