View Javadoc
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.NodeIterator;
11  import javax.jcr.Property;
12  import javax.jcr.Repository;
13  import javax.jcr.RepositoryException;
14  import javax.jcr.Session;
15  import javax.jcr.nodetype.NodeType;
16  import javax.jcr.query.Query;
17  
18  import org.argeo.cms.auth.CurrentUser;
19  import org.argeo.connect.ConnectException;
20  import org.argeo.connect.resources.ResourcesNames;
21  import org.argeo.connect.resources.ResourcesRole;
22  import org.argeo.connect.resources.ResourcesService;
23  import org.argeo.connect.ui.ConnectColumnDefinition;
24  import org.argeo.connect.ui.ConnectUiSnippets;
25  import org.argeo.connect.ui.Refreshable;
26  import org.argeo.connect.ui.SystemWorkbenchService;
27  import org.argeo.connect.ui.parts.AskTitleDescriptionDialog;
28  import org.argeo.connect.ui.util.JcrHtmlLabelProvider;
29  import org.argeo.connect.ui.util.JcrViewerDClickListener;
30  import org.argeo.connect.ui.util.VirtualJcrTableViewer;
31  import org.argeo.connect.util.ConnectJcrUtils;
32  import org.argeo.connect.util.XPathUtils;
33  import org.argeo.eclipse.ui.EclipseUiUtils;
34  import org.argeo.jcr.JcrUtils;
35  import org.eclipse.e4.ui.di.Focus;
36  import org.eclipse.jface.dialogs.Dialog;
37  import org.eclipse.jface.dialogs.MessageDialog;
38  import org.eclipse.jface.viewers.ColumnLabelProvider;
39  import org.eclipse.jface.viewers.TableViewer;
40  import org.eclipse.jface.wizard.Wizard;
41  import org.eclipse.jface.wizard.WizardDialog;
42  import org.eclipse.rap.rwt.RWT;
43  import org.eclipse.swt.SWT;
44  import org.eclipse.swt.events.ModifyEvent;
45  import org.eclipse.swt.events.ModifyListener;
46  import org.eclipse.swt.events.SelectionAdapter;
47  import org.eclipse.swt.events.SelectionEvent;
48  import org.eclipse.swt.layout.GridLayout;
49  import org.eclipse.swt.widgets.Button;
50  import org.eclipse.swt.widgets.Composite;
51  import org.eclipse.swt.widgets.Text;
52  
53  /**
54   * Display a list for all values of a given tag like resource (Typically a tag
55   * or a mailing list).
56   */
57  public class SearchTagsEditor implements Refreshable {
58  
59  //	public final static String ID = ConnectUiPlugin.PLUGIN_ID + ".searchTagsEditor";
60  
61  	/* DEPENDENCY INJECTION */
62  	@Inject
63  	private Repository repository;
64  	@Inject
65  	private ResourcesService resourcesService;
66  	@Inject
67  	private SystemWorkbenchService systemWorkbenchService;
68  
69  	// Context
70  	private Session session;
71  	private Node tagParent;
72  	private String tagId;
73  	private String tagInstanceType;
74  	private String propertyName;
75  
76  	// UI Objects
77  	private List<ConnectColumnDefinition> colDefs = new ArrayList<ConnectColumnDefinition>();
78  	private TableViewer tableViewer;
79  	private Text filterTxt;
80  
81  	public void init() {
82  //		setSite(site);
83  //		setInput(input);
84  //		String label = ((SearchNodeEditorInput) getEditorInput()).getName();
85  //		setPartName(label);
86  
87  		tagInstanceType = null;// ((SearchNodeEditorInput) getEditorInput()).getNodeType();
88  		session = ConnectJcrUtils.login(repository);
89  		tagParent = resourcesService.getTagLikeResourceParent(session, tagInstanceType);
90  		tagId = ConnectJcrUtils.get(tagParent, ResourcesNames.RESOURCES_TAG_ID);
91  
92  		colDefs.add(new ConnectColumnDefinition("Title", new JcrHtmlLabelProvider(Property.JCR_TITLE), 300));
93  		colDefs.add(new ConnectColumnDefinition("Member count", new CountMemberLP(), 85));
94  		if (canEdit())
95  			colDefs.add(new ConnectColumnDefinition("", new EditLabelProvider(), 80));
96  	}
97  
98  	// MAIN LAYOUT
99  	@PostConstruct
100 	public void createPartControl(Composite parent) {
101 		init();
102 		parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
103 		// the generic free search part
104 		Composite searchCmp = new Composite(parent, SWT.NO_FOCUS);
105 		populateSearchPanel(searchCmp);
106 		searchCmp.setLayoutData(EclipseUiUtils.fillWidth());
107 
108 		// The table itself
109 		Composite tableCmp = new Composite(parent, SWT.NO_FOCUS);
110 		createListPart(tableCmp);
111 		tableCmp.setLayoutData(EclipseUiUtils.fillAll());
112 		refreshStaticFilteredList();
113 	}
114 
115 	// Header
116 	protected void populateSearchPanel(Composite parent) {
117 		parent.setLayout(new GridLayout(2, false));
118 		filterTxt = new Text(parent, SWT.BORDER | SWT.SEARCH | SWT.ICON_SEARCH | SWT.ICON_CANCEL);
119 		filterTxt.setLayoutData(EclipseUiUtils.fillWidth());
120 		filterTxt.addModifyListener(new ModifyListener() {
121 			private static final long serialVersionUID = 5003010530960334977L;
122 
123 			public void modifyText(ModifyEvent event) {
124 				refreshStaticFilteredList();
125 			}
126 		});
127 
128 		Button addBtn = new Button(parent, SWT.PUSH);
129 		addBtn.setText("Create new...");
130 		addBtn.addSelectionListener(new SelectionAdapter() {
131 			private static final long serialVersionUID = -1990521824772413097L;
132 
133 			@Override
134 			public void widgetSelected(SelectionEvent e) {
135 				AskTitleDescriptionDialog dialog = new AskTitleDescriptionDialog(e.display.getActiveShell(), "Create");
136 				if (Dialog.OK == dialog.open()) {
137 					try {
138 						Node tag = resourcesService.registerTag(session, tagId, dialog.getTitle());
139 						String desc = dialog.getDescription();
140 						if (EclipseUiUtils.notEmpty(desc))
141 							tag.setProperty(Property.JCR_DESCRIPTION, desc);
142 						if (tag.isNodeType(NodeType.MIX_VERSIONABLE))
143 							ConnectJcrUtils.saveAndPublish(tag, true);
144 						else
145 							session.save();
146 						refreshStaticFilteredList();
147 					} catch (RepositoryException re) {
148 						throw new ConnectException("Unable to create new " + propertyName, re);
149 					}
150 				}
151 			}
152 		});
153 	}
154 
155 	protected void createListPart(Composite parent) {
156 		parent.setLayout(new GridLayout());
157 		VirtualJcrTableViewer tableCmp = new VirtualJcrTableViewer(parent, SWT.MULTI, colDefs);
158 		tableViewer = tableCmp.getTableViewer();
159 		tableCmp.setLayoutData(EclipseUiUtils.fillAll());
160 		tableViewer.addDoubleClickListener(new JcrViewerDClickListener());
161 		tableViewer.getTable().addSelectionListener(new HtmlRwtAdapter());
162 	}
163 
164 	/** Refresh the table viewer based on the free text search field */
165 	protected void refreshStaticFilteredList() {
166 		try {
167 			String queryStr = XPathUtils.descendantFrom(tagParent.getPath()) + "//element(*, " + tagInstanceType + ")";
168 			String attrQuery = XPathUtils.getFreeTextConstraint(filterTxt.getText());
169 			if (EclipseUiUtils.notEmpty(attrQuery))
170 				queryStr += "[" + attrQuery + "]";
171 			// always order ?
172 			queryStr += " order by @" + Property.JCR_TITLE;
173 			Query query = XPathUtils.createQuery(session, queryStr);
174 			NodeIterator nit = query.execute().getNodes();
175 			Node[] nodes = ConnectJcrUtils.nodeIteratorToArray(nit);
176 			setViewerInput(nodes);
177 		} catch (RepositoryException e) {
178 			throw new ConnectException("Unable to list " + tagInstanceType, e);
179 		}
180 	}
181 
182 	/** Use this method to update the result table */
183 	protected void setViewerInput(Object[] elements) {
184 		tableViewer.setInput(elements);
185 		// we must explicitly set the items count
186 		tableViewer.setItemCount(elements.length);
187 		tableViewer.refresh();
188 	}
189 
190 	protected class CountMemberLP extends ColumnLabelProvider {
191 		private static final long serialVersionUID = 1L;
192 
193 		@Override
194 		public String getText(Object element) {
195 			Node currNode = ConnectJcrUtils.getNodeFromElement(element, null);
196 			long count = resourcesService.countMembers(currNode);
197 			return "" + count;
198 		}
199 	}
200 
201 	protected class EditLabelProvider extends ColumnLabelProvider {
202 		private static final long serialVersionUID = 1L;
203 
204 		@Override
205 		public String getText(Object element) {
206 			Node currNode = ConnectJcrUtils.getNodeFromElement(element, null);
207 			try {
208 				String jcrId = currNode.getIdentifier();
209 				StringBuilder builder = new StringBuilder();
210 				if (canEdit())
211 					builder.append(ConnectUiSnippets.getRWTLink("edit/" + jcrId, "Edit")).append(" ");
212 				// builder.append("<a " + PeopleRapConstants.PEOPLE_STYLE_LINK +
213 				// " href=\"edit/" + jcrId
214 				// + "\" target=\"_rwt\"></a> ");
215 				if (canDelete(currNode))
216 					builder.append(ConnectUiSnippets.getRWTLink("delete/" + jcrId, "Delete"));
217 				return builder.toString();
218 			} catch (RepositoryException re) {
219 				throw new ConnectException("Unable to create edit/remove link for " + currNode, re);
220 			}
221 		}
222 	}
223 
224 	private boolean canEdit() {
225 		return CurrentUser.isInRole(ResourcesRole.editor.dn());
226 	}
227 
228 	private boolean canDelete(Node currNode) {
229 		long currCount = resourcesService.countMembers(currNode);
230 		return canEdit() && currCount == 0;
231 	}
232 
233 	private class HtmlRwtAdapter extends SelectionAdapter {
234 		private static final long serialVersionUID = 1L;
235 
236 		public void widgetSelected(SelectionEvent event) {
237 			if (event.detail == RWT.HYPERLINK) {
238 				String string = event.text;
239 				String[] token = string.split("/");
240 				try {
241 					Node node = session.getNodeByIdentifier(token[1]);
242 
243 					if ("edit".equals(token[0])) {
244 						Wizard wizard = new EditTagWizard(resourcesService, systemWorkbenchService, node, tagId,
245 								propertyName);
246 						WizardDialog dialog = new WizardDialog(event.display.getActiveShell(), wizard);
247 						int result = dialog.open();
248 						if (result == WizardDialog.OK) {
249 							refreshStaticFilteredList();
250 						}
251 					} else {
252 						if (canDelete(node)) { // Superstition
253 							String msg = "Are you sure you want to delete \""
254 									+ ConnectJcrUtils.get(node, Property.JCR_TITLE) + "\" ?";
255 							if (MessageDialog.openConfirm(event.display.getActiveShell(), "Confirm deletion", msg)) {
256 								ConnectJcrUtils.checkCOStatusBeforeUpdate(node);
257 								session.removeItem(node.getPath());
258 								session.save();
259 								refreshStaticFilteredList();
260 							}
261 						}
262 					}
263 				} catch (RepositoryException re) {
264 					throw new ConnectException("unable to retrieve Node with ID " + token[1], re);
265 				}
266 			}
267 		}
268 	}
269 
270 	@Override
271 	public void forceRefresh(Object object) {
272 		refreshStaticFilteredList();
273 	}
274 
275 	@Focus
276 	public void setFocus() {
277 		filterTxt.setFocus();
278 	}
279 
280 	@PreDestroy
281 	public void dispose() {
282 		JcrUtils.logoutQuietly(session);
283 	}
284 
285 	/* DEPENDENCY INJECTION */
286 //	public void setRepository(Repository repository) {
287 //		this.repository = repository;
288 //	}
289 //
290 //	public void setResourcesService(ResourcesService resourcesService) {
291 //		this.resourcesService = resourcesService;
292 //	}
293 //
294 //	public void setSystemWorkbenchService(SystemWorkbenchService systemWorkbenchService) {
295 //		this.systemWorkbenchService = systemWorkbenchService;
296 //	}
297 }