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