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