View Javadoc
1   package org.argeo.suite.e4.parts;
2   
3   import static org.argeo.eclipse.ui.EclipseUiUtils.notEmpty;
4   
5   import java.util.List;
6   
7   import javax.annotation.PostConstruct;
8   import javax.annotation.PreDestroy;
9   import javax.inject.Inject;
10  import javax.jcr.NodeIterator;
11  import javax.jcr.Repository;
12  import javax.jcr.RepositoryException;
13  import javax.jcr.Session;
14  import javax.jcr.observation.Event;
15  import javax.jcr.observation.EventIterator;
16  import javax.jcr.observation.EventListener;
17  import javax.jcr.query.Query;
18  import javax.jcr.query.QueryResult;
19  
20  import org.apache.commons.logging.Log;
21  import org.apache.commons.logging.LogFactory;
22  import org.argeo.activities.ActivitiesService;
23  import org.argeo.cms.util.CmsUtils;
24  import org.argeo.connect.ConnectException;
25  import org.argeo.connect.ConnectTypes;
26  import org.argeo.connect.resources.ResourcesService;
27  import org.argeo.connect.ui.ConnectUiConstants;
28  import org.argeo.connect.ui.Refreshable;
29  import org.argeo.connect.ui.SystemWorkbenchService;
30  import org.argeo.connect.ui.util.BasicNodeListContentProvider;
31  import org.argeo.connect.ui.util.JcrViewerDClickListener;
32  import org.argeo.connect.ui.widgets.DelayedText;
33  import org.argeo.connect.util.ConnectJcrUtils;
34  import org.argeo.connect.util.XPathUtils;
35  import org.argeo.eclipse.ui.EclipseUiUtils;
36  import org.argeo.jcr.JcrUtils;
37  import org.argeo.people.PeopleService;
38  import org.eclipse.e4.ui.di.Focus;
39  import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
40  import org.eclipse.jface.layout.TableColumnLayout;
41  import org.eclipse.jface.viewers.ColumnWeightData;
42  import org.eclipse.jface.viewers.ILabelProvider;
43  import org.eclipse.jface.viewers.ISelectionChangedListener;
44  import org.eclipse.jface.viewers.IStructuredSelection;
45  import org.eclipse.jface.viewers.SelectionChangedEvent;
46  import org.eclipse.jface.viewers.StructuredSelection;
47  import org.eclipse.jface.viewers.TableViewer;
48  import org.eclipse.swt.SWT;
49  import org.eclipse.swt.events.KeyEvent;
50  import org.eclipse.swt.events.KeyListener;
51  import org.eclipse.swt.events.ModifyEvent;
52  import org.eclipse.swt.events.ModifyListener;
53  import org.eclipse.swt.layout.GridData;
54  import org.eclipse.swt.layout.GridLayout;
55  import org.eclipse.swt.widgets.Composite;
56  import org.eclipse.swt.widgets.Table;
57  import org.eclipse.swt.widgets.TableColumn;
58  import org.eclipse.swt.widgets.Text;
59  
60  /** A table with a quick search field. */
61  public class QuickSearchView implements Refreshable {
62  	private final static Log log = LogFactory.getLog(QuickSearchView.class);
63  	// public static final String ID = AsUiPlugin.PLUGIN_ID + ".quickSearchView";
64  
65  	/* DEPENDENCY INJECTION */
66  	@Inject
67  	private Repository repository;
68  	@Inject
69  	private ResourcesService resourcesService;
70  	@Inject
71  	private ActivitiesService activitiesService;
72  	@Inject
73  	private PeopleService peopleService;
74  	@Inject
75  	private SystemWorkbenchService systemWorkbenchService;
76  
77  	@Inject
78  	private ESelectionService selectionService;
79  
80  	// This page widgets
81  	private TableViewer entityViewer;
82  	private Text filterTxt;
83  
84  	private Session session;
85  
86  	// @Override
87  	// public void init(IViewSite site) throws PartInitException {
88  	// super.init(site);
89  	// }
90  
91  	@PostConstruct
92  	public void createPartControl(Composite parent) {
93  		session = ConnectJcrUtils.login(repository);
94  		// MainLayout
95  		parent.setLayout(new GridLayout());
96  		addFilterPanel(parent);
97  		entityViewer = createListPart(parent, new EntitySingleColumnLabelProvider(resourcesService, activitiesService,
98  				peopleService, systemWorkbenchService));
99  		refreshFilteredList();
100 
101 		try {
102 			// new String[] { ConnectTypes.CONNECT_ENTITY }
103 			session.getWorkspace().getObservationManager().addEventListener(new EventListener() {
104 
105 				@Override
106 				public void onEvent(EventIterator events) {
107 					parent.getDisplay().asyncExec(() -> refreshFilteredList());
108 				}
109 			}, Event.PROPERTY_CHANGED | Event.NODE_ADDED | Event.NODE_REMOVED | Event.PROPERTY_ADDED, "/", true, null,
110 					null, false);
111 		} catch (RepositoryException e) {
112 			throw new ConnectException("Cannot add JCR observer", e);
113 		}
114 
115 	}
116 
117 	private void addFilterPanel(Composite parent) {
118 		// Use a delayed text: the query won't be done until the user stop
119 		// typing for 800ms
120 		int style = SWT.BORDER | SWT.SEARCH | SWT.ICON_CANCEL;
121 		DelayedText delayedText = new DelayedText(parent, style, ConnectUiConstants.SEARCH_TEXT_DELAY);
122 		filterTxt = delayedText.getText();
123 		filterTxt.setLayoutData(EclipseUiUtils.fillWidth());
124 
125 		// final ServerPushSession pushSession = new ServerPushSession();
126 		delayedText.addDelayedModifyListener(null, new ModifyListener() {
127 			private static final long serialVersionUID = 5003010530960334977L;
128 
129 			public void modifyText(ModifyEvent event) {
130 				delayedText.getText().getDisplay().asyncExec(new Runnable() {
131 					@Override
132 					public void run() {
133 						refreshFilteredList();
134 					}
135 				});
136 				// pushSession.stop();
137 			}
138 		});
139 
140 		// Jump to the first item of the list using the down arrow
141 		filterTxt.addKeyListener(new KeyListener() {
142 			private static final long serialVersionUID = -4523394262771183968L;
143 
144 			@Override
145 			public void keyReleased(KeyEvent e) {
146 			}
147 
148 			@Override
149 			public void keyPressed(KeyEvent e) {
150 				// boolean shiftPressed = (e.stateMask & SWT.SHIFT) != 0;
151 				// boolean altPressed = (e.stateMask & SWT.ALT) != 0;
152 				if (e.keyCode == SWT.ARROW_DOWN || e.keyCode == SWT.TAB) {
153 					Object first = entityViewer.getElementAt(0);
154 					if (first != null) {
155 						entityViewer.getTable().setFocus();
156 						entityViewer.setSelection(new StructuredSelection(first), true);
157 					}
158 					e.doit = false;
159 				}
160 			}
161 		});
162 	}
163 
164 	protected TableViewer createListPart(Composite parent, ILabelProvider labelProvider) {
165 		parent.setLayout(new GridLayout());
166 
167 		Composite tableComposite = new Composite(parent, SWT.NONE);
168 		GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_VERTICAL
169 				| GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL);
170 		tableComposite.setLayoutData(gd);
171 
172 		TableViewer v = new TableViewer(tableComposite);
173 		v.setLabelProvider(labelProvider);
174 
175 		TableColumn singleColumn = new TableColumn(v.getTable(), SWT.V_SCROLL);
176 		TableColumnLayout tableColumnLayout = new TableColumnLayout();
177 		tableColumnLayout.setColumnData(singleColumn, new ColumnWeightData(85));
178 		tableComposite.setLayout(tableColumnLayout);
179 
180 		// Corresponding table & style
181 		Table table = v.getTable();
182 		table.setLinesVisible(true);
183 		table.setHeaderVisible(false);
184 		CmsUtils.markup(table);
185 		CmsUtils.setItemHeight(table, 26);
186 
187 		v.setContentProvider(new BasicNodeListContentProvider());
188 		v.addDoubleClickListener(new JcrViewerDClickListener(systemWorkbenchService));
189 		v.addSelectionChangedListener(new ISelectionChangedListener() {
190 			public void selectionChanged(SelectionChangedEvent event) {
191 				IStructuredSelection selection = (IStructuredSelection) event.getSelection();
192 				List<?> lst = selection.toList();
193 				if (lst != null && !lst.isEmpty())
194 					selectionService.setSelection(selection.toList());
195 				else
196 					selectionService.setSelection(null);
197 			}
198 		});
199 		return v;
200 	}
201 
202 	@PreDestroy
203 	public void dispose() {
204 		JcrUtils.logoutQuietly(session);
205 	}
206 
207 	@Focus
208 	public void setFocus() {
209 		refreshFilteredList();
210 		filterTxt.setFocus();
211 	}
212 
213 	@Override
214 	public void forceRefresh(Object object) {
215 		refreshFilteredList();
216 	}
217 
218 	protected void refreshFilteredList() {
219 		try {
220 			String filter = filterTxt.getText();
221 			// Prevents the query on the full repository
222 			// if (isEmpty(filter)) {
223 			// entityViewer.setInput(null);
224 			// return;
225 			// }
226 
227 			// XPATH Query
228 			String xpathQueryStr = "//element(*, " + ConnectTypes.CONNECT_ENTITY + ")";
229 			String xpathFilter = XPathUtils.getFreeTextConstraint(filter);
230 			if (notEmpty(xpathFilter))
231 				xpathQueryStr += "[" + xpathFilter + "]";
232 
233 			// boolean doOrder = orderResultsBtn != null
234 			// && !(orderResultsBtn.isDisposed())
235 			// && orderResultsBtn.getSelection();
236 			// if (doOrder) {
237 			// xpathQueryStr += " order by jcr:title";
238 			// }
239 
240 			long begin = System.currentTimeMillis();
241 			// session.refresh(false);
242 			Query xpathQuery = XPathUtils.createQuery(session, xpathQueryStr);
243 
244 			xpathQuery.setLimit(ConnectUiConstants.SEARCH_DEFAULT_LIMIT);
245 			QueryResult result = xpathQuery.execute();
246 
247 			NodeIterator nit = result.getNodes();
248 			entityViewer.setInput(JcrUtils.nodeIteratorToList(nit));
249 			if (log.isTraceEnabled()) {
250 				long end = System.currentTimeMillis();
251 				log.trace("Quick Search - Found: " + nit.getSize() + " in " + (end - begin)
252 						+ " ms by executing XPath query (" + xpathQueryStr + ").");
253 			}
254 		} catch (RepositoryException e) {
255 			throw new ConnectException("Unable to list entities", e);
256 		}
257 	}
258 
259 	// public void setRepository(Repository repository) {
260 	// this.repository = repository;
261 	// }
262 	//
263 	// public void setResourcesService(ResourcesService resourcesService) {
264 	// this.resourcesService = resourcesService;
265 	// }
266 	//
267 	// public void setActivitiesService(ActivitiesService activitiesService) {
268 	// this.activitiesService = activitiesService;
269 	// }
270 	//
271 	// public void setPeopleService(PeopleService peopleService) {
272 	// this.peopleService = peopleService;
273 	// }
274 	//
275 	// public void setSystemWorkbenchService(SystemWorkbenchService
276 	// systemWorkbenchService) {
277 	// this.systemWorkbenchService = systemWorkbenchService;
278 	// }
279 }