View Javadoc
1   package org.argeo.connect.ui.parts;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   
6   import javax.jcr.Node;
7   import javax.jcr.NodeIterator;
8   import javax.jcr.RepositoryException;
9   import javax.jcr.Session;
10  import javax.jcr.query.Query;
11  import javax.jcr.query.QueryResult;
12  
13  import org.argeo.cms.util.CmsUtils;
14  import org.argeo.connect.ConnectException;
15  import org.argeo.connect.ConnectTypes;
16  import org.argeo.connect.ui.AppWorkbenchService;
17  import org.argeo.connect.ui.ConnectColumnDefinition;
18  import org.argeo.connect.ui.ConnectUiConstants;
19  import org.argeo.connect.ui.util.TitleIconHtmlLP;
20  import org.argeo.connect.ui.widgets.DelayedText;
21  import org.argeo.connect.util.XPathUtils;
22  import org.argeo.eclipse.ui.EclipseUiUtils;
23  import org.argeo.eclipse.ui.specific.EclipseUiSpecificUtils;
24  import org.argeo.eclipse.ui.utils.ViewerUtils;
25  import org.argeo.jcr.JcrUtils;
26  import org.eclipse.jface.layout.TableColumnLayout;
27  import org.eclipse.jface.viewers.ColumnWeightData;
28  import org.eclipse.jface.viewers.ILazyContentProvider;
29  import org.eclipse.jface.viewers.TableViewer;
30  import org.eclipse.jface.viewers.TableViewerColumn;
31  import org.eclipse.jface.viewers.Viewer;
32  import org.eclipse.rap.rwt.service.ServerPushSession;
33  import org.eclipse.swt.SWT;
34  import org.eclipse.swt.events.ModifyEvent;
35  import org.eclipse.swt.events.ModifyListener;
36  import org.eclipse.swt.events.SelectionAdapter;
37  import org.eclipse.swt.events.SelectionEvent;
38  import org.eclipse.swt.events.TraverseEvent;
39  import org.eclipse.swt.events.TraverseListener;
40  import org.eclipse.swt.layout.GridData;
41  import org.eclipse.swt.layout.GridLayout;
42  import org.eclipse.swt.widgets.Button;
43  import org.eclipse.swt.widgets.Composite;
44  import org.eclipse.swt.widgets.Table;
45  import org.eclipse.swt.widgets.Text;
46  
47  /** Almost canonical implementation of a table that display entities */
48  public class FilterEntitiesVirtualTable extends Composite {
49  	private static final long serialVersionUID = 1262369448445021926L;
50  
51  	// Context
52  	private Session session;
53  	private AppWorkbenchService appWorkbenchService;
54  
55  	// UI Objects
56  	private TableViewer entityViewer;
57  	private Text filterTxt;
58  	private int tableStyle;
59  
60  	// Defaults
61  	private String nodeType = ConnectTypes.CONNECT_ENTITY;
62  
63  	public FilterEntitiesVirtualTable(Composite parent, int style, Session session,
64  			AppWorkbenchService systemWorkbenchService, String nodeType) {
65  		this(parent, style, session, systemWorkbenchService, nodeType, false);
66  	}
67  
68  	/**
69  	 * If lazy flag is set, the populate method must be explicitly called:
70  	 * Enable further configuration of the table before display, like typically
71  	 * definition of other column
72  	 */
73  	public FilterEntitiesVirtualTable(Composite parent, int style, Session session,
74  			AppWorkbenchService appWorkbenchService, String nodeType, boolean lazy) {
75  		super(parent, SWT.NONE);
76  		this.session = session;
77  		this.appWorkbenchService = appWorkbenchService;
78  		this.tableStyle = style;
79  		if (EclipseUiUtils.notEmpty(nodeType))
80  			this.nodeType = nodeType;
81  		if (!lazy)
82  			populate();
83  	}
84  
85  	protected void populate() {
86  		Composite parent = this;
87  		GridLayout layout = EclipseUiUtils.noSpaceGridLayout();
88  		layout.verticalSpacing = 5;
89  		this.setLayout(layout);
90  		createFilterPart(parent);
91  		createTableViewer(parent);
92  		this.layout();
93  		EclipseUiSpecificUtils.enableToolTipSupport(entityViewer);
94  
95  		if (!appWorkbenchService.lazyLoadLists())
96  			refreshFilteredList();
97  	}
98  
99  	protected int getTableHeight() {
100 		return SWT.DEFAULT;
101 	}
102 
103 	private void createTableViewer(final Composite parent) {
104 		Composite listCmp = new Composite(parent, SWT.NO_FOCUS);
105 		GridData gd = EclipseUiUtils.fillAll();
106 		listCmp.setLayoutData(gd);
107 
108 		entityViewer = new TableViewer(listCmp, SWT.VIRTUAL | tableStyle);
109 		Table table = entityViewer.getTable();
110 		table.setLinesVisible(true);
111 		table.setHeaderVisible(true);
112 		CmsUtils.markup(table);
113 		CmsUtils.setItemHeight(table, 26);
114 		TableColumnLayout tableColumnLayout = new TableColumnLayout();
115 		TableViewerColumn column;
116 
117 		for (ConnectColumnDefinition colDef : getColumnsDef()) {
118 			column = ViewerUtils.createTableViewerColumn(entityViewer, colDef.getHeaderLabel(), SWT.NONE,
119 					colDef.getColumnSize());
120 			column.setLabelProvider(colDef.getColumnLabelProvider());
121 			tableColumnLayout.setColumnData(column.getColumn(),
122 					new ColumnWeightData(colDef.getColumnSize(), colDef.getColumnSize(), true));
123 		}
124 		listCmp.setLayout(tableColumnLayout);
125 		entityViewer.setContentProvider(new MyLazyCP(entityViewer));
126 	}
127 
128 	private class MyLazyCP implements ILazyContentProvider {
129 		private static final long serialVersionUID = 1L;
130 		private TableViewer viewer;
131 		private Object[] elements;
132 
133 		public MyLazyCP(TableViewer viewer) {
134 			this.viewer = viewer;
135 		}
136 
137 		public void dispose() {
138 		}
139 
140 		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
141 			// IMPORTANT: don't forget this: an exception will be thrown if a
142 			// selected object is not part of the results anymore.
143 			viewer.setSelection(null);
144 			this.elements = (Object[]) newInput;
145 		}
146 
147 		public void updateElement(int index) {
148 			viewer.replace(elements[index], index);
149 		}
150 	}
151 
152 	protected List<ConnectColumnDefinition> getColumnsDef() {
153 		List<ConnectColumnDefinition> colDefs;
154 		colDefs = new ArrayList<ConnectColumnDefinition>();
155 		colDefs.add(new ConnectColumnDefinition("Name", new TitleIconHtmlLP(appWorkbenchService), 300));
156 		return colDefs;
157 	}
158 
159 	/** Returns the User table viewer, typically to add doubleclick listener */
160 	public TableViewer getTableViewer() {
161 		return entityViewer;
162 	}
163 
164 	/* MANAGE FILTER */
165 	private void createFilterPart(Composite parent) {
166 		Composite filterCmp = new Composite(parent, SWT.NO_FOCUS);
167 		GridLayout layout = EclipseUiUtils.noSpaceGridLayout(new GridLayout(2, false));
168 		layout.horizontalSpacing = 5;
169 		filterCmp.setLayout(layout);
170 		filterCmp.setLayoutData(EclipseUiUtils.fillWidth());
171 
172 		int style = SWT.BORDER | SWT.SEARCH | SWT.ICON_SEARCH | SWT.ICON_CANCEL;
173 		Button okBtn = new Button(filterCmp, SWT.FLAT);
174 		okBtn.setText("Find");
175 		boolean isDyn = appWorkbenchService.queryWhenTyping();
176 //		if (isDyn)
177 //			filterTxt = new DelayedText(filterCmp, style, ConnectUiConstants.SEARCH_TEXT_DELAY);
178 //		else
179 //			filterTxt = new Text(filterCmp, style);
180 //		filterTxt.setLayoutData(EclipseUiUtils.fillWidth());
181 //
182 //
183 //		if (isDyn) {
184 //			final ServerPushSession pushSession = new ServerPushSession();
185 //			((DelayedText) filterTxt).addDelayedModifyListener(pushSession, new ModifyListener() {
186 //				private static final long serialVersionUID = 5003010530960334977L;
187 //
188 //				public void modifyText(ModifyEvent event) {
189 //					filterTxt.getDisplay().asyncExec(new Runnable() {
190 //						@Override
191 //						public void run() {
192 //							refreshFilteredList();
193 //						}
194 //					});
195 //					pushSession.stop();
196 //				}
197 //			});
198 //		}
199 		if (isDyn) {
200 			final DelayedText delayedText = new DelayedText(parent, style, ConnectUiConstants.SEARCH_TEXT_DELAY);
201 			final ServerPushSession pushSession = new ServerPushSession();
202 			(delayedText).addDelayedModifyListener(pushSession, new ModifyListener() {
203 				private static final long serialVersionUID = 5003010530960334977L;
204 
205 				public void modifyText(ModifyEvent event) {
206 					delayedText.getText().getDisplay().asyncExec(new Runnable() {
207 						@Override
208 						public void run() {
209 							refreshFilteredList();
210 						}
211 					});
212 					pushSession.stop();
213 				}
214 			});
215 			filterTxt = delayedText.getText();
216 		}else {
217 			filterTxt = new Text(parent, style);
218 		}
219 		filterTxt.setLayoutData(EclipseUiUtils.fillWidth());
220 
221 		filterTxt.addTraverseListener(new TraverseListener() {
222 			private static final long serialVersionUID = 3946973977865345010L;
223 
224 			@Override
225 			public void keyTraversed(TraverseEvent e) {
226 				if (e.keyCode == SWT.CR) {
227 					refreshFilteredList();
228 				}
229 			}
230 		});
231 
232 		okBtn.addSelectionListener(new SelectionAdapter() {
233 			private static final long serialVersionUID = 4305076157959928315L;
234 
235 			@Override
236 			public void widgetSelected(SelectionEvent e) {
237 				refreshFilteredList();
238 			}
239 		});
240 	}
241 
242 	private void refreshFilteredList() {
243 		List<Node> nodes;
244 		try {
245 			nodes = JcrUtils.nodeIteratorToList(listFilteredElements(session, filterTxt.getText()));
246 			entityViewer.setInput(nodes.toArray());
247 			entityViewer.setItemCount(nodes.size());
248 			entityViewer.refresh();
249 		} catch (RepositoryException e) {
250 			throw new ConnectException(
251 					"Unable to refresh filtered list of " + nodeType + " with filter " + filterTxt.getText(), e);
252 		}
253 	}
254 
255 	/**
256 	 * Build repository request: caller might overwrite in order to display a
257 	 * subset
258 	 */
259 	protected NodeIterator listFilteredElements(Session session, String filter) throws RepositoryException {
260 		String xpathQueryStr = "//element(*, " + nodeType + ")";
261 		String attrQuery = XPathUtils.getFreeTextConstraint(filter);
262 		if (EclipseUiUtils.notEmpty(attrQuery))
263 			xpathQueryStr += "[" + attrQuery + "]";
264 		Query xpathQuery = XPathUtils.createQuery(session, xpathQueryStr);
265 		xpathQuery.setLimit(ConnectUiConstants.SEARCH_DEFAULT_LIMIT);
266 		QueryResult result = xpathQuery.execute();
267 		return result.getNodes();
268 
269 		// QueryManager queryManager = session.getWorkspace().getQueryManager();
270 		// QueryObjectModelFactory factory = queryManager.getQOMFactory();
271 		// Selector source = factory.selector(nodeType, nodeType);
272 		// Constraint defaultC = null;
273 		// // Build constraints based the textArea filter content
274 		// if (filter != null && !"".equals(filter.trim())) {
275 		// // Parse the String
276 		// String[] strs = filter.trim().split(" ");
277 		// for (String token : strs) {
278 		// StaticOperand so = factory.literal(session.getValueFactory()
279 		// .createValue("*" + token + "*"));
280 		// Constraint currC = factory.fullTextSearch(
281 		// source.getSelectorName(), null, so);
282 		// if (defaultC == null)
283 		// defaultC = currC;
284 		// else
285 		// defaultC = factory.and(defaultC, currC);
286 		// }
287 		// }
288 
289 		// // Entity should normally always be a mix:title
290 		// Ordering order = factory.ascending(factory.propertyValue(
291 		// source.getSelectorName(), Property.JCR_TITLE));
292 		// Ordering[] orderings = { order };
293 		// QueryObjectModel query = factory.createQuery(source, defaultC,
294 		// orderings, null);
295 		// QueryObjectModel query = factory.createQuery(source, defaultC, null,
296 		// null);
297 		// query.setLimit(PeopleConstants.QUERY_DEFAULT_LIMIT);
298 		// QueryResult result = query.execute();
299 		// return result.getNodes();
300 	}
301 }