1 package org.argeo.connect.e4.resources.parts;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 import javax.annotation.PostConstruct;
7 import javax.annotation.PreDestroy;
8 import javax.inject.Inject;
9 import javax.jcr.Node;
10 import javax.jcr.Property;
11 import javax.jcr.Repository;
12 import javax.jcr.RepositoryException;
13 import javax.jcr.Session;
14 import javax.jcr.query.Query;
15 import javax.jcr.query.Row;
16 import javax.jcr.query.RowIterator;
17
18 import org.apache.commons.logging.Log;
19 import org.apache.commons.logging.LogFactory;
20 import org.argeo.cms.auth.CurrentUser;
21 import org.argeo.cms.ui.eclipse.forms.FormToolkit;
22 import org.argeo.cms.util.CmsUtils;
23 import org.argeo.connect.ConnectConstants;
24 import org.argeo.connect.ConnectException;
25 import org.argeo.connect.ConnectTypes;
26 import org.argeo.connect.SystemAppService;
27 import org.argeo.connect.e4.ConnectE4Constants;
28 import org.argeo.connect.resources.ResourcesNames;
29 import org.argeo.connect.resources.ResourcesRole;
30 import org.argeo.connect.resources.ResourcesService;
31 import org.argeo.connect.resources.core.TagUtils;
32 import org.argeo.connect.ui.AppWorkbenchService;
33 import org.argeo.connect.ui.ConnectColumnDefinition;
34 import org.argeo.connect.ui.ConnectUiConstants;
35 import org.argeo.connect.ui.IJcrTableViewer;
36 import org.argeo.connect.ui.Refreshable;
37 import org.argeo.connect.ui.SystemWorkbenchService;
38 import org.argeo.connect.ui.util.HtmlListRwtAdapter;
39 import org.argeo.connect.ui.util.JcrRowLabelProvider;
40 import org.argeo.connect.ui.util.JcrViewerDClickListener;
41 import org.argeo.connect.ui.util.MainNodeTypeLabelProvider;
42 import org.argeo.connect.ui.util.TagLabelProvider;
43 import org.argeo.connect.ui.util.TitleIconRowLP;
44 import org.argeo.connect.ui.util.VirtualJcrTableViewer;
45 import org.argeo.connect.util.ConnectJcrUtils;
46 import org.argeo.connect.util.XPathUtils;
47 import org.argeo.eclipse.ui.EclipseUiUtils;
48 import org.argeo.jcr.JcrUtils;
49 import org.eclipse.e4.ui.di.Focus;
50 import org.eclipse.e4.ui.model.application.ui.basic.MPart;
51 import org.eclipse.jface.viewers.ColumnLabelProvider;
52 import org.eclipse.jface.viewers.ILazyContentProvider;
53 import org.eclipse.jface.viewers.TableViewer;
54 import org.eclipse.jface.viewers.Viewer;
55 import org.eclipse.jface.wizard.WizardDialog;
56 import org.eclipse.rap.rwt.RWT;
57 import org.eclipse.rap.rwt.client.service.BrowserNavigation;
58 import org.eclipse.swt.SWT;
59 import org.eclipse.swt.events.ModifyEvent;
60 import org.eclipse.swt.events.ModifyListener;
61 import org.eclipse.swt.events.SelectionAdapter;
62 import org.eclipse.swt.events.SelectionEvent;
63 import org.eclipse.swt.layout.GridData;
64 import org.eclipse.swt.layout.GridLayout;
65 import org.eclipse.swt.widgets.Composite;
66 import org.eclipse.swt.widgets.Label;
67 import org.eclipse.swt.widgets.Link;
68 import org.eclipse.swt.widgets.Text;
69
70
71 public class TagEditor implements Refreshable, IJcrTableViewer {
72 private final static Log log = LogFactory.getLog(TagEditor.class);
73
74
75
76 @Inject
77 private Repository repository;
78 @Inject
79 private ResourcesService resourcesService;
80 @Inject
81 private SystemAppService systemAppService;
82 @Inject
83 private SystemWorkbenchService systemWorkbenchService;
84 @Inject
85 private MPart mPart;
86
87
88 private Row[] rows;
89 protected FormToolkit toolkit;
90 private List<ConnectColumnDefinition> colDefs;
91 private TableViewer membersViewer;
92 private Text filterTxt;
93 private Label titleROLbl;
94 private ColumnLabelProvider groupTitleLP;
95
96
97 private Session session;
98 private Node node;
99 private String partName;
100
101
102 private BrowserNavigation browserNavigation;
103
104
105 public void init(String entityId) {
106
107
108
109
110 session = ConnectJcrUtils.login(repository);
111 node = ConnectJcrUtils.getNodeByIdentifier(session, entityId);
112
113 colDefs = new ArrayList<ConnectColumnDefinition>();
114 colDefs.add(new ConnectColumnDefinition("Display Name",
115 new TitleIconRowLP(systemWorkbenchService, null, Property.JCR_TITLE), 300));
116 colDefs.add(new ConnectColumnDefinition("Other tags",
117 new OtherTagsLabelProvider(resourcesService, systemWorkbenchService, node, null), 300));
118 }
119
120 protected void afterNameUpdate(String name) {
121 if (EclipseUiUtils.isEmpty(name))
122 name = ConnectJcrUtils.get(node, Property.JCR_TITLE);
123 if (EclipseUiUtils.notEmpty(name)) {
124 setPartName(name);
125
126
127 }
128 if (titleROLbl != null && !titleROLbl.isDisposed())
129 titleROLbl.setText(groupTitleLP.getText(node));
130 }
131
132 protected void setPartName(String name) {
133 this.partName = name;
134 mPart.setLabel(name);
135 }
136
137
138
139 protected boolean enableBatchUpdate() {
140 return false;
141 }
142
143
144 @PostConstruct
145 public void createPartControl(Composite parent) {
146 String entityId = mPart.getPersistedState().get(ConnectE4Constants.ENTITY_ID);
147 init(entityId);
148
149 toolkit = new FormToolkit(parent.getDisplay());
150
151
152
153 Composite main = new Composite(parent, SWT.NONE);
154 createMainLayout(main);
155 afterNameUpdate(null);
156
157 browserNavigation = RWT.getClient().getService(BrowserNavigation.class);
158 }
159
160 protected void createMainLayout(Composite parent) {
161 parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
162
163 Composite header = toolkit.createComposite(parent, SWT.NO_FOCUS);
164 header.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
165 populateHeader(header);
166
167 Composite body = toolkit.createComposite(parent, SWT.NO_FOCUS);
168 body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
169 createMembersList(body, getNode());
170 }
171
172 protected void populateHeader(final Composite parent) {
173 parent.setLayout(new GridLayout(2, false));
174 titleROLbl = toolkit.createLabel(parent, "", SWT.WRAP);
175 CmsUtils.markup(titleROLbl);
176 groupTitleLP = new TagLabelProvider(resourcesService, ConnectUiConstants.LIST_TYPE_OVERVIEW_TITLE);
177 titleROLbl.setText(groupTitleLP.getText(getNode()));
178 titleROLbl.setLayoutData(EclipseUiUtils.fillWidth());
179
180 Link editTitleLink = null;
181 if (CurrentUser.isInRole(ResourcesRole.editor.dn())) {
182 editTitleLink = new Link(parent, SWT.NONE);
183 editTitleLink.setText("<a>Edit Tag</a>");
184 } else
185 toolkit.createLabel(parent, "");
186
187 if (editTitleLink != null) {
188 editTitleLink.addSelectionListener(new SelectionAdapter() {
189 private static final long serialVersionUID = 1L;
190
191 @Override
192 public void widgetSelected(final SelectionEvent event) {
193 EditTagWizard wizard = new EditTagWizard(resourcesService, systemWorkbenchService, getNode(),
194 ConnectConstants.RESOURCE_TAG, ResourcesNames.CONNECT_TAGS);
195 WizardDialog dialog = new WizardDialog(titleROLbl.getShell(), wizard);
196
197
198 dialog.open();
199 }
200 });
201 }
202 }
203
204
205 @Override
206 public Row[] getElements(String extractId) {
207 return rows;
208 }
209
210 @Override
211 public List<ConnectColumnDefinition> getColumnDefinition(String extractId) {
212 List<ConnectColumnDefinition> columns = new ArrayList<ConnectColumnDefinition>();
213 columns.add(new ConnectColumnDefinition("Type", new MainNodeTypeLabelProvider(systemAppService)));
214 columns.add(new ConnectColumnDefinition("Name", new JcrRowLabelProvider(Property.JCR_TITLE)));
215 columns.add(new ConnectColumnDefinition("Tags", new JcrRowLabelProvider(ResourcesNames.CONNECT_TAGS)));
216 columns.add(new ConnectColumnDefinition("Notes", new JcrRowLabelProvider(Property.JCR_DESCRIPTION)));
217 return columns;
218 }
219
220 public void createMembersList(Composite parent, final Node entity) {
221 parent.setLayout(new GridLayout());
222
223
224 filterTxt = createFilterText(parent);
225 filterTxt.setLayoutData(EclipseUiUtils.fillWidth());
226
227
228 Composite tableComp = toolkit.createComposite(parent);
229 tableComp.setLayoutData(EclipseUiUtils.fillAll());
230
231 membersViewer = createTableViewer(tableComp);
232 membersViewer.setContentProvider(new MyLazyContentProvider(membersViewer));
233 refreshFilteredList();
234
235
236 JcrViewerDClickListener ndcl = new JcrViewerDClickListener();
237 membersViewer.addDoubleClickListener(ndcl);
238 }
239
240 private Text createFilterText(Composite parent) {
241 Text filterTxt = toolkit.createText(parent, "", SWT.BORDER | SWT.SEARCH | SWT.ICON_SEARCH | SWT.ICON_CANCEL);
242 filterTxt.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
243 filterTxt.addModifyListener(new ModifyListener() {
244 private static final long serialVersionUID = 5003010530960334977L;
245
246 public void modifyText(ModifyEvent event) {
247 refreshFilteredList();
248 }
249 });
250 return filterTxt;
251 }
252
253
254 protected void refreshFilteredList() {
255 long begin = System.currentTimeMillis();
256 try {
257
258 Node tagParent = TagUtils.retrieveTagParentFromTag(node);
259 String parentPath = tagParent.getProperty(ResourcesNames.RESOURCES_TAGGABLE_PARENT_PATH).getString();
260 String xpathQueryStr = XPathUtils.descendantFrom(parentPath) + "//element(*, "
261 + ConnectTypes.CONNECT_TAGGABLE + ")";
262
263 String filter = filterTxt.getText();
264 String currVal = ConnectJcrUtils.get(getNode(), Property.JCR_TITLE);
265 String freeTxtCond = XPathUtils.getFreeTextConstraint(filter);
266 String mlNamecond = XPathUtils.getPropertyEquals(ResourcesNames.CONNECT_TAGS, currVal);
267 String conditions = XPathUtils.localAnd(freeTxtCond, mlNamecond);
268 if (EclipseUiUtils.notEmpty(conditions))
269 xpathQueryStr += "[" + conditions + "]";
270 Query xpathQuery = XPathUtils.createQuery(session, xpathQueryStr);
271 RowIterator xPathRit = xpathQuery.execute().getRows();
272 Row[] rows = ConnectJcrUtils.rowIteratorToArray(xPathRit);
273 setViewerInput(rows);
274 if (log.isDebugEnabled()) {
275 long end = System.currentTimeMillis();
276 log.debug("Found: " + xPathRit.getSize() + " members for tag " + getNode() + " in " + (end - begin)
277 + " ms by executing XPath query (" + xpathQueryStr + ").");
278 }
279 } catch (RepositoryException e) {
280 throw new ConnectException("Unable to list entities with static filter for tag " + getNode(), e);
281 }
282 }
283
284 private TableViewer createTableViewer(Composite parent) {
285 parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
286 VirtualJcrTableViewer tableCmp = new VirtualJcrTableViewer(parent, SWT.MULTI, colDefs, enableBatchUpdate());
287 TableViewer tableViewer = tableCmp.getTableViewer();
288 tableViewer.getTable().setHeaderVisible(false);
289 tableCmp.setLayoutData(EclipseUiUtils.fillAll());
290 tableViewer.getTable().addSelectionListener(new HtmlListRwtAdapter(systemWorkbenchService));
291 return tableViewer;
292 }
293
294
295 protected void setViewerInput(Row[] rows) {
296 this.rows = rows;
297 membersViewer.setInput(rows);
298
299 membersViewer.setItemCount(rows.length);
300 membersViewer.refresh();
301 }
302
303 private class MyLazyContentProvider implements ILazyContentProvider {
304 private static final long serialVersionUID = 1L;
305 private TableViewer viewer;
306 private Row[] elements;
307
308 public MyLazyContentProvider(TableViewer viewer) {
309 this.viewer = viewer;
310 }
311
312 public void dispose() {
313 }
314
315 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
316
317
318 viewer.setSelection(null);
319 this.elements = (Row[]) newInput;
320 }
321
322 public void updateElement(int index) {
323 viewer.replace(elements[index], index);
324 }
325 }
326
327 @Override
328 public void forceRefresh(Object object) {
329 afterNameUpdate(null);
330 refreshFilteredList();
331 }
332
333
334 protected Node getNode() {
335 return node;
336 }
337
338 protected ResourcesService getResourcesService() {
339 return resourcesService;
340 }
341
342 protected AppWorkbenchService getAppWorkbenchService() {
343 return systemWorkbenchService;
344 }
345
346
347 protected boolean canSave() {
348 return false;
349 }
350
351 @PreDestroy
352 public void dispose() {
353 JcrUtils.logoutQuietly(session);
354 browserNavigation.pushState("~", null);
355 }
356
357 @Focus
358 public void setFocus() {
359 try {
360 browserNavigation.pushState(node.getPath(), partName);
361 } catch (RepositoryException e) {
362 log.error("Cannot set client state", e);
363 }
364 }
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383 }