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