]> git.argeo.org Git - gpl/argeo-suite.git/blob - argeo/suite/ui/RecentItems.java
Prepare next development cycle
[gpl/argeo-suite.git] / argeo / suite / ui / RecentItems.java
1 package org.argeo.suite.ui;
2
3 import static org.argeo.eclipse.ui.EclipseUiUtils.notEmpty;
4
5 import java.util.List;
6 import java.util.Map;
7
8 import javax.jcr.Node;
9 import javax.jcr.NodeIterator;
10 import javax.jcr.RepositoryException;
11 import javax.jcr.Session;
12 import javax.jcr.observation.Event;
13 import javax.jcr.observation.EventIterator;
14 import javax.jcr.observation.EventListener;
15 import javax.jcr.query.Query;
16 import javax.jcr.query.QueryResult;
17
18 import org.argeo.cms.ui.CmsTheme;
19 import org.argeo.cms.ui.CmsUiProvider;
20 import org.argeo.cms.ui.CmsView;
21 import org.argeo.cms.ui.util.CmsUiUtils;
22 import org.argeo.eclipse.ui.EclipseUiUtils;
23 import org.argeo.entity.EntityType;
24 import org.argeo.jcr.Jcr;
25 import org.argeo.jcr.JcrUtils;
26 import org.argeo.suite.ui.widgets.DelayedText;
27 import org.argeo.suite.util.XPathUtils;
28 import org.eclipse.jface.layout.TableColumnLayout;
29 import org.eclipse.jface.viewers.ColumnLabelProvider;
30 import org.eclipse.jface.viewers.ColumnWeightData;
31 import org.eclipse.jface.viewers.DoubleClickEvent;
32 import org.eclipse.jface.viewers.IDoubleClickListener;
33 import org.eclipse.jface.viewers.ILabelProvider;
34 import org.eclipse.jface.viewers.ISelectionChangedListener;
35 import org.eclipse.jface.viewers.IStructuredContentProvider;
36 import org.eclipse.jface.viewers.SelectionChangedEvent;
37 import org.eclipse.jface.viewers.TableViewer;
38 import org.eclipse.jface.viewers.Viewer;
39 import org.eclipse.swt.SWT;
40 import org.eclipse.swt.events.KeyEvent;
41 import org.eclipse.swt.events.KeyListener;
42 import org.eclipse.swt.events.ModifyEvent;
43 import org.eclipse.swt.events.ModifyListener;
44 import org.eclipse.swt.layout.GridData;
45 import org.eclipse.swt.layout.GridLayout;
46 import org.eclipse.swt.widgets.Composite;
47 import org.eclipse.swt.widgets.Control;
48 import org.eclipse.swt.widgets.Table;
49 import org.eclipse.swt.widgets.TableColumn;
50 import org.eclipse.swt.widgets.Text;
51 import org.eclipse.swt.widgets.ToolBar;
52 import org.eclipse.swt.widgets.ToolItem;
53
54 /** List recent items. */
55 public class RecentItems implements CmsUiProvider {
56 private final static int SEARCH_TEXT_DELAY = 800;
57 private final static int SEARCH_DEFAULT_LIMIT = 100;
58
59 private CmsTheme theme;
60
61 private String entityType;
62
63 static enum Property {
64 entityTypes;
65 }
66
67 @Override
68 public Control createUi(Composite parent, Node context) throws RepositoryException {
69 theme = CmsTheme.getCmsTheme(parent);
70 parent.setLayout(new GridLayout());
71 // parent.setLayout(CmsUiUtils.noSpaceGridLayout());
72 parent.setLayout(new GridLayout());
73
74 // Composite top = new Composite(parent, SWT.BORDER);
75 // CmsUiUtils.style(top, SuiteStyle.recentItems);
76 // top.setLayoutData(CmsUiUtils.fillWidth());
77 // top.setLayout(CmsUiUtils.noSpaceGridLayout(2));
78 // Label lbl = new Label(top, SWT.FLAT);
79 // lbl.setLayoutData(CmsUiUtils.fillWidth());
80 // lbl.setText(SuiteMsg.recentItems.lead());
81 // CmsUiUtils.style(lbl, SuiteStyle.recentItems);
82 //
83 // ToolBar topToolBar = new ToolBar(top, SWT.NONE);
84 // ToolItem addItem = new ToolItem(topToolBar, SWT.FLAT);
85 //// CmsUiUtils.style(addItem, SuiteStyle.recentItems);
86 // addItem.setImage(SuiteIcon.add.getSmallIcon(theme));
87
88 if (context == null)
89 return null;
90 SingleEntityViewer entityViewer = new SingleEntityViewer(parent, SWT.NONE, context.getSession());
91 entityViewer.createUi();
92 entityViewer.getViewer().getTable().setLayoutData(CmsUiUtils.fillAll());
93
94 Composite bottom = new Composite(parent, SWT.NONE);
95 bottom.setLayoutData(CmsUiUtils.fillWidth());
96 bottom.setLayout(CmsUiUtils.noSpaceGridLayout());
97 ToolBar bottomToolBar = new ToolBar(bottom, SWT.NONE);
98 bottomToolBar.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
99 ToolItem deleteItem = new ToolItem(bottomToolBar, SWT.FLAT);
100 deleteItem.setEnabled(false);
101 // CmsUiUtils.style(deleteItem, SuiteStyle.recentItems);
102 deleteItem.setImage(SuiteIcon.delete.getSmallIcon(theme));
103 ToolItem addItem = new ToolItem(bottomToolBar, SWT.FLAT);
104 addItem.setImage(SuiteIcon.add.getSmallIcon(theme));
105 entityViewer.getViewer().addDoubleClickListener(new IDoubleClickListener() {
106
107 @Override
108 public void doubleClick(DoubleClickEvent event) {
109 Node node = (Node) entityViewer.getViewer().getStructuredSelection().getFirstElement();
110 if (node != null)
111 CmsView.getCmsView(parent).sendEvent(SuiteEvent.openNewPart.topic(),
112 SuiteEvent.eventProperties(node));
113
114 }
115 });
116 entityViewer.getViewer().addSelectionChangedListener(new ISelectionChangedListener() {
117 public void selectionChanged(SelectionChangedEvent event) {
118 Node node = (Node) entityViewer.getViewer().getStructuredSelection().getFirstElement();
119 if (node != null) {
120 CmsView.getCmsView(parent).sendEvent(SuiteEvent.refreshPart.topic(),
121 SuiteEvent.eventProperties(node));
122 deleteItem.setEnabled(true);
123 } else {
124 deleteItem.setEnabled(false);
125 }
126 }
127 });
128
129 return entityViewer.filterTxt;
130
131 }
132
133 public void init(Map<String, String> properties) {
134 // TODO manage multiple entities
135 entityType = properties.get(Property.entityTypes.name());
136 }
137
138 class SingleEntityViewer {
139 Composite parent;
140 Text filterTxt;
141 TableViewer viewer;
142 Session session;
143
144 public SingleEntityViewer(Composite parent, int style, Session session) {
145 this.parent = parent;
146 this.session = session;
147 }
148
149 public void createUi() {
150 // MainLayout
151 addFilterPanel(parent);
152 viewer = createListPart(parent, new SingleEntityLabelProvider());
153 refreshFilteredList();
154
155 try {
156 String[] nodeTypes = entityType != null && entityType.contains(":") ? new String[] { entityType }
157 : null;
158 session.getWorkspace().getObservationManager().addEventListener(new EventListener() {
159
160 @Override
161 public void onEvent(EventIterator events) {
162 parent.getDisplay().asyncExec(() -> refreshFilteredList());
163 }
164 }, Event.PROPERTY_CHANGED | Event.NODE_ADDED | Event.NODE_REMOVED | Event.PROPERTY_ADDED, "/", true,
165 null, nodeTypes, false);
166 } catch (RepositoryException e) {
167 throw new IllegalStateException("Cannot add JCR observer", e);
168 }
169
170 }
171
172 private void addFilterPanel(Composite parent) {
173 // Use a delayed text: the query won't be done until the user stop
174 // typing for 800ms
175 int style = SWT.BORDER | SWT.SEARCH | SWT.ICON_CANCEL;
176 DelayedText delayedText = new DelayedText(parent, style, SEARCH_TEXT_DELAY);
177 filterTxt = delayedText.getText();
178 filterTxt.setLayoutData(EclipseUiUtils.fillWidth());
179
180 // final ServerPushSession pushSession = new ServerPushSession();
181 delayedText.addDelayedModifyListener(null, new ModifyListener() {
182 private static final long serialVersionUID = 5003010530960334977L;
183
184 public void modifyText(ModifyEvent event) {
185 delayedText.getText().getDisplay().asyncExec(new Runnable() {
186 @Override
187 public void run() {
188 refreshFilteredList();
189 }
190 });
191 // pushSession.stop();
192 }
193 });
194
195 // Jump to the first item of the list using the down arrow
196 filterTxt.addKeyListener(new KeyListener() {
197 private static final long serialVersionUID = -4523394262771183968L;
198
199 @Override
200 public void keyReleased(KeyEvent e) {
201 }
202
203 @Override
204 public void keyPressed(KeyEvent e) {
205 // boolean shiftPressed = (e.stateMask & SWT.SHIFT) != 0;
206 // boolean altPressed = (e.stateMask & SWT.ALT) != 0;
207 if (e.keyCode == SWT.ARROW_DOWN || e.keyCode == SWT.TAB) {
208 // Object first = entityViewer.getElementAt(0);
209 // if (first != null) {
210 // entityViewer.getTable().setFocus();
211 // entityViewer.setSelection(new StructuredSelection(first), true);
212 // }
213 e.doit = false;
214 }
215 }
216 });
217
218 parent.addDisposeListener((e) -> {
219 delayedText.close();
220 });
221 }
222
223 protected TableViewer createListPart(Composite parent, ILabelProvider labelProvider) {
224 // parent.setLayout(new GridLayout());
225 // parent.setLayout(CmsUiUtils.noSpaceGridLayout());
226
227 Composite tableComposite = new Composite(parent, SWT.NONE);
228 GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_VERTICAL
229 | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL);
230 tableComposite.setLayoutData(gd);
231
232 TableViewer viewer = new TableViewer(tableComposite, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
233 viewer.setLabelProvider(labelProvider);
234
235 TableColumn singleColumn = new TableColumn(viewer.getTable(), SWT.V_SCROLL);
236 TableColumnLayout tableColumnLayout = new TableColumnLayout();
237 tableColumnLayout.setColumnData(singleColumn, new ColumnWeightData(85));
238 tableComposite.setLayout(tableColumnLayout);
239
240 // Corresponding table & style
241 Table table = viewer.getTable();
242 // Listener[] mouseDownListeners = table.getListeners(SWT.MouseDown);
243 // for (Listener listener : table.getListeners(SWT.MouseDown))
244 // table.removeListener(SWT.MouseDown, listener);
245 // for (Listener listener : table.getListeners(SWT.MouseUp))
246 // table.removeListener(SWT.MouseUp, listener);
247 // for (Listener listener : table.getListeners(SWT.MouseDoubleClick))
248 // table.removeListener(SWT.MouseDoubleClick, listener);
249 //
250 // table.addMouseListener(new MouseListener() {
251 //
252 // @Override
253 // public void mouseUp(MouseEvent e) {
254 // System.out.println("Mouse up: "+e);
255 // }
256 //
257 // @Override
258 // public void mouseDown(MouseEvent e) {
259 // System.out.println("Mouse down: "+e);
260 // }
261 //
262 // @Override
263 // public void mouseDoubleClick(MouseEvent e) {
264 // System.out.println("Mouse double: "+e);
265 //
266 // }
267 // });
268 table.setLinesVisible(true);
269 table.setHeaderVisible(false);
270 // CmsUiUtils.markup(table);
271 // CmsUiUtils.setItemHeight(table, 26);
272
273 viewer.setContentProvider(new BasicNodeListContentProvider());
274 return viewer;
275 }
276
277 // public boolean setFocus() {
278 // refreshFilteredList();
279 // return parent.setFocus();
280 // }
281
282 public void forceRefresh(Object object) {
283 refreshFilteredList();
284 }
285
286 protected void refreshFilteredList() {
287 try {
288 String filter = filterTxt.getText();
289 // Prevents the query on the full repository
290 // if (isEmpty(filter)) {
291 // entityViewer.setInput(null);
292 // return;
293 // }
294
295 // XPATH Query
296 String xpathQueryStr;
297 if (entityType != null) {
298 int indexColumn = entityType.indexOf(':');
299 if (indexColumn > 0) {// JCR node type
300 xpathQueryStr = "//element(*, " + entityType + ") order by @jcr:created descending";
301 } else {
302 xpathQueryStr = entityType.contains(":") ? "//element(*, " + entityType + ")"
303 : "//element(*, " + EntityType.entity.get() + ")[@entity:type='" + entityType + "']";
304 }
305 } else {
306 xpathQueryStr = "//element(*, " + EntityType.entity.get() + ")";
307 }
308 // String xpathQueryStr = "//element(*, " + ConnectTypes.CONNECT_ENTITY + ")";
309 String xpathFilter = XPathUtils.getFreeTextConstraint(filter);
310 if (notEmpty(xpathFilter))
311 xpathQueryStr += "[" + xpathFilter + "]";
312
313 // long begin = System.currentTimeMillis();
314 // session.refresh(false);
315 Query xpathQuery = XPathUtils.createQuery(session, xpathQueryStr);
316
317 xpathQuery.setLimit(SEARCH_DEFAULT_LIMIT);
318 QueryResult result = xpathQuery.execute();
319
320 NodeIterator nit = result.getNodes();
321 viewer.setInput(JcrUtils.nodeIteratorToList(nit));
322 // if (log.isTraceEnabled()) {
323 // long end = System.currentTimeMillis();
324 // log.trace("Quick Search - Found: " + nit.getSize() + " in " + (end - begin)
325 // + " ms by executing XPath query (" + xpathQueryStr + ").");
326 // }
327 } catch (RepositoryException e) {
328 throw new IllegalStateException("Unable to list entities", e);
329 }
330 }
331
332 public TableViewer getViewer() {
333 return viewer;
334 }
335
336 class SingleEntityLabelProvider extends ColumnLabelProvider {
337 private static final long serialVersionUID = -2209337675781795677L;
338
339 @Override
340 public String getText(Object element) {
341 return Jcr.getTitle((Node) element);
342 }
343
344 }
345
346 class BasicNodeListContentProvider implements IStructuredContentProvider {
347 private static final long serialVersionUID = 1L;
348 // keep a cache of the Nodes in the content provider to be able to
349 // manage long request
350 private List<Node> nodes;
351
352 public void dispose() {
353 }
354
355 /** Expects a list of nodes as a new input */
356 @SuppressWarnings("unchecked")
357 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
358 nodes = (List<Node>) newInput;
359 }
360
361 public Object[] getElements(Object arg0) {
362 return nodes.toArray();
363 }
364 }
365 }
366 }