1 package org.argeo.connect.ui.parts;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 import javax.jcr.Node;
7 import javax.jcr.Property;
8 import javax.jcr.RepositoryException;
9 import javax.jcr.Session;
10 import javax.jcr.Value;
11 import javax.jcr.nodetype.NodeType;
12 import javax.jcr.version.VersionManager;
13
14 import org.argeo.cms.ui.dialogs.CmsMessageDialog;
15 import org.argeo.cms.ui.eclipse.forms.AbstractFormPart;
16 import org.argeo.cms.ui.eclipse.forms.FormToolkit;
17 import org.argeo.cms.util.CmsUtils;
18 import org.argeo.connect.ConnectException;
19 import org.argeo.connect.resources.ResourcesNames;
20 import org.argeo.connect.resources.ResourcesService;
21 import org.argeo.connect.ui.ConnectEditor;
22 import org.argeo.connect.ui.ConnectImages;
23 import org.argeo.connect.ui.ConnectUiStyles;
24 import org.argeo.connect.ui.ConnectUiUtils;
25 import org.argeo.connect.ui.SystemWorkbenchService;
26 import org.argeo.connect.ui.widgets.TagLikeDropDown;
27 import org.argeo.connect.util.ConnectJcrUtils;
28 import org.argeo.eclipse.ui.EclipseUiUtils;
29 import org.argeo.jcr.JcrUtils;
30 import org.argeo.people.ui.PeopleMsg;
31 import org.eclipse.jface.dialogs.MessageDialog;
32 import org.eclipse.swt.SWT;
33 import org.eclipse.swt.events.SelectionAdapter;
34 import org.eclipse.swt.events.SelectionEvent;
35 import org.eclipse.swt.events.TraverseEvent;
36 import org.eclipse.swt.events.TraverseListener;
37 import org.eclipse.swt.layout.GridData;
38 import org.eclipse.swt.layout.RowData;
39 import org.eclipse.swt.layout.RowLayout;
40 import org.eclipse.swt.widgets.Button;
41 import org.eclipse.swt.widgets.Composite;
42 import org.eclipse.swt.widgets.Label;
43 import org.eclipse.swt.widgets.Link;
44 import org.eclipse.swt.widgets.Shell;
45 import org.eclipse.swt.widgets.Text;
46
47
48
49
50
51
52
53 public class TagLikeListPart extends Composite {
54 private static final long serialVersionUID = -312141685147619814L;
55
56
57
58 private final ConnectEditor editor;
59 private final FormToolkit toolkit;
60 private final String newTagMsg;
61
62
63 private final ResourcesService resourcesService;
64 private final SystemWorkbenchService systemWorkbenchService;
65 private final Node taggable;
66 private final Node tagParent;
67 private final String tagId;
68 private final String taggablePropName;
69
70
71 private final Session session;
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 public TagLikeListPart(ConnectEditor editor, Composite parent, int style, ResourcesService resourcesService,
89 SystemWorkbenchService systemWorkbenchService, String tagId, Node taggable, String taggablePropName,
90 String newTagMsg) {
91 super(parent, style);
92 this.editor = editor;
93 this.toolkit = editor.getFormToolkit();
94 this.resourcesService = resourcesService;
95 this.systemWorkbenchService = systemWorkbenchService;
96 this.tagId = tagId;
97 this.taggable = taggable;
98 this.taggablePropName = taggablePropName;
99 this.newTagMsg = newTagMsg;
100
101
102 session = ConnectJcrUtils.getSession(taggable);
103 tagParent = resourcesService.getTagLikeResourceParent(session, tagId);
104
105 RowLayout rl = new RowLayout(SWT.HORIZONTAL);
106 rl.wrap = true;
107 rl.marginLeft = rl.marginTop = rl.marginBottom = 0;
108 rl.marginRight = 8;
109 this.setLayout(rl);
110
111 AbstractFormPart tagFormPart = new TagFormPart(this);
112 tagFormPart.initialize(editor.getManagedForm());
113 editor.getManagedForm().addPart(tagFormPart);
114 }
115
116 private class TagFormPart extends AbstractFormPart {
117 private Composite parentCmp;
118
119 public TagFormPart(Composite parent) {
120 this.parentCmp = parent;
121 }
122
123 @Override
124 public void commit(boolean onSave) {
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151 super.commit(onSave);
152 }
153
154 public void refresh() {
155 super.refresh();
156 EclipseUiUtils.clear(parentCmp);
157
158 boolean isCO = editor.isEditing();
159
160 try {
161 if (taggable.hasProperty(taggablePropName)) {
162 Value[] values = taggable.getProperty(taggablePropName).getValues();
163 for (final Value value : values) {
164 final String tagValue = value.getString();
165
166 Composite tagCmp = toolkit.createComposite(parentCmp, SWT.NO_FOCUS);
167 tagCmp.setLayout(ConnectUiUtils.noSpaceGridLayout(2));
168
169
170
171 Link link = new Link(tagCmp, SWT.NONE);
172
173
174 CmsUtils.markup(link);
175 CmsUtils.style(link, ConnectUiStyles.ENTITY_HEADER);
176 link.setText(getLinkText(taggablePropName, tagValue));
177 link.addSelectionListener(new SelectionAdapter() {
178 private static final long serialVersionUID = 1L;
179
180 @Override
181 public void widgetSelected(final SelectionEvent event) {
182 Node tag = resourcesService.getRegisteredTag(tagParent, tagValue);
183
184
185
186
187
188
189
190
191
192
193
194 systemWorkbenchService.openEntityEditor(tag);
195
196
197
198
199
200
201 }
202 });
203
204 if (isCO) {
205 addDeleteButton(TagFormPart.this, tagCmp, value);
206 }
207 }
208 }
209 if (isCO) {
210 final Text tagTxt = toolkit.createText(parentCmp, "", SWT.BORDER);
211 tagTxt.setMessage(newTagMsg);
212 RowData rd = new RowData(120, SWT.DEFAULT);
213 tagTxt.setLayoutData(rd);
214
215 final TagLikeDropDown tagDD = new TagLikeDropDown(taggable.getSession(), resourcesService, tagId,
216 tagTxt);
217
218 tagTxt.addTraverseListener(new TraverseListener() {
219 private static final long serialVersionUID = 1L;
220
221 public void keyTraversed(TraverseEvent e) {
222 if (e.keyCode == SWT.CR) {
223 String newTag = tagDD.getText();
224 addTag(tagTxt.getShell(), TagFormPart.this, newTag);
225 e.doit = false;
226
227
228
229 }
230 }
231 });
232
233 tagTxt.getParent().layout();
234
235 Button okBtn = toolkit.createButton(parentCmp, "OK", SWT.BORDER | SWT.PUSH | SWT.BOTTOM);
236 rd = new RowData(SWT.DEFAULT, tagTxt.getSize().y - 2);
237 okBtn.setLayoutData(rd);
238
239 okBtn.addSelectionListener(new SelectionAdapter() {
240 private static final long serialVersionUID = 2780819012423622369L;
241
242 @Override
243 public void widgetSelected(SelectionEvent e) {
244 String newTag = tagDD.getText();
245 if (EclipseUiUtils.isEmpty(newTag))
246 return;
247 else
248 addTag(parentCmp.getShell(), TagFormPart.this, newTag);
249 }
250 });
251
252 }
253 parentCmp.layout(false);
254 parentCmp.getParent().getParent().layout();
255
256 } catch (RepositoryException re) {
257 throw new ConnectException("Error while refreshing tag like list for " + taggable, re);
258 }
259 }
260 }
261
262 protected String getLinkText(String taggablePropName, String value) {
263 if (taggablePropName.equals(ResourcesNames.CONNECT_TAGS))
264 return " <a>#" + value + "</a>";
265 else
266 return " <a>" + value + "</a>";
267 }
268
269 private void addDeleteButton(final AbstractFormPart part, Composite parent, final Value value) {
270 final Button deleteBtn = new Button(parent, SWT.FLAT);
271 deleteBtn.setImage(ConnectImages.DELETE_SMALL);
272
273
274
275 deleteBtn.addSelectionListener(new SelectionAdapter() {
276 private static final long serialVersionUID = 1L;
277
278 @Override
279 public void widgetSelected(final SelectionEvent event) {
280 try {
281 String tagToRemove = value.getString();
282 List<String> tags = new ArrayList<String>();
283 Value[] values = taggable.getProperty(taggablePropName).getValues();
284 for (int i = 0; i < values.length; i++) {
285 String curr = values[i].getString();
286 if (!tagToRemove.equals(curr))
287 tags.add(curr);
288 }
289 taggable.setProperty(taggablePropName, tags.toArray(new String[tags.size()]));
290 part.refresh();
291 part.markDirty();
292 } catch (RepositoryException e) {
293 throw new ConnectException("unable to initialise deletion", e);
294 }
295 }
296 });
297 }
298
299 private Node registerNewTag(String newTag) {
300
301
302
303
304
305 Session tagSession = null;
306 try {
307 Session session = taggable.getSession();
308 tagSession = session.getRepository().login();
309 Node registered = resourcesService.registerTag(tagSession, tagId, newTag);
310 tagSession.save();
311 if (registered.isNodeType(NodeType.MIX_VERSIONABLE)) {
312 VersionManager manager = session.getWorkspace().getVersionManager();
313 manager.checkpoint(registered.getPath());
314 }
315 session.refresh(true);
316 Node newTagNode = session.getNode(registered.getPath());
317 return newTagNode;
318 } catch (RepositoryException re) {
319 throw new ConnectException("Unable to set " + taggablePropName + " on " + taggable, re);
320 } finally {
321 JcrUtils.logoutQuietly(tagSession);
322 }
323 }
324
325 private void addTag(Shell shell, final AbstractFormPart part, String newTag) {
326 String msg = null;
327
328 try {
329 Session session = taggable.getSession();
330
331 Node registered = resourcesService.getRegisteredTag(tagParent, newTag);
332
333 if (registered == null) {
334 if (resourcesService.canCreateTag(session)) {
335
336
337
338 msg = PeopleMsg.confirmNewTag.format(new String[] { newTag });
339
340 if (CmsMessageDialog.openConfirm(msg)) {
341 registered = registerNewTag(newTag);
342 } else
343 return;
344 } else {
345
346
347
348
349 msg = PeopleMsg.cannotCreateTag.format(new String[] { newTag });
350 CmsMessageDialog.openWarning(msg);
351
352 return;
353 }
354 }
355
356 Value[] values;
357 String[] valuesStr;
358 if (taggable.hasProperty(taggablePropName)) {
359 values = taggable.getProperty(taggablePropName).getValues();
360
361
362 for (Value tag : values) {
363 String curTagUpperCase = tag.getString().toUpperCase().trim();
364 if (newTag.toUpperCase().trim().equals(curTagUpperCase)) {
365 msg = "\"" + ConnectJcrUtils.get(taggable, Property.JCR_TITLE) + "\" is already linked with \""
366 + tag.getString() + "\". Nothing has been done.";
367 MessageDialog.openError(shell, "Duplicate link", msg);
368 return;
369 }
370 }
371
372 valuesStr = new String[values.length + 1];
373 int i;
374 for (i = 0; i < values.length; i++) {
375 valuesStr[i] = values[i].getString();
376 }
377 valuesStr[i] = newTag;
378 } else {
379 valuesStr = new String[1];
380 valuesStr[0] = newTag;
381 }
382 taggable.setProperty(taggablePropName, valuesStr);
383 part.refresh();
384 part.markDirty();
385 } catch (RepositoryException re) {
386 throw new ConnectException("Unable to set " + taggablePropName + " on " + taggable, re);
387 }
388 }
389 }