]> git.argeo.org Git - lgpl/argeo-commons.git/blob - server/plugins/org.argeo.jcr.ui.explorer/src/main/java/org/argeo/jcr/ui/explorer/editors/NodeVersionHistoryPage.java
Some refactoring of the model and of command handling.
[lgpl/argeo-commons.git] / server / plugins / org.argeo.jcr.ui.explorer / src / main / java / org / argeo / jcr / ui / explorer / editors / NodeVersionHistoryPage.java
1 package org.argeo.jcr.ui.explorer.editors;
2
3 import java.text.DateFormat;
4 import java.text.SimpleDateFormat;
5 import java.util.ArrayList;
6 import java.util.Calendar;
7 import java.util.List;
8 import java.util.Map;
9
10 import javax.jcr.Node;
11 import javax.jcr.Property;
12 import javax.jcr.PropertyType;
13 import javax.jcr.RepositoryException;
14 import javax.jcr.Value;
15 import javax.jcr.nodetype.NodeType;
16 import javax.jcr.version.Version;
17 import javax.jcr.version.VersionHistory;
18 import javax.jcr.version.VersionIterator;
19 import javax.jcr.version.VersionManager;
20
21 import org.argeo.ArgeoException;
22 import org.argeo.jcr.JcrUtils;
23 import org.argeo.jcr.PropertyDiff;
24 import org.argeo.jcr.VersionDiff;
25 import org.argeo.jcr.ui.explorer.JcrExplorerConstants;
26 import org.argeo.jcr.ui.explorer.JcrExplorerPlugin;
27 import org.argeo.jcr.ui.explorer.providers.FullVersioningTreeContentProvider;
28 import org.argeo.jcr.ui.explorer.providers.VersionLabelProvider;
29 import org.argeo.jcr.ui.explorer.utils.GenericNodeDoubleClickListener;
30 import org.eclipse.jface.viewers.ITreeContentProvider;
31 import org.eclipse.jface.viewers.TreeViewer;
32 import org.eclipse.swt.SWT;
33 import org.eclipse.swt.layout.GridData;
34 import org.eclipse.swt.layout.GridLayout;
35 import org.eclipse.swt.widgets.Composite;
36 import org.eclipse.swt.widgets.Text;
37 import org.eclipse.ui.forms.AbstractFormPart;
38 import org.eclipse.ui.forms.IManagedForm;
39 import org.eclipse.ui.forms.editor.FormEditor;
40 import org.eclipse.ui.forms.editor.FormPage;
41 import org.eclipse.ui.forms.widgets.FormToolkit;
42 import org.eclipse.ui.forms.widgets.ScrolledForm;
43 import org.eclipse.ui.forms.widgets.Section;
44 import org.eclipse.ui.forms.widgets.TableWrapData;
45 import org.eclipse.ui.forms.widgets.TableWrapLayout;
46
47 /**
48 * Offers two main sections : one to display a text area with a summary of all
49 * variations between a version and its predecessor and one tree view that
50 * enable browsing
51 * */
52 public class NodeVersionHistoryPage extends FormPage implements
53 JcrExplorerConstants {
54 // private final static Log log = LogFactory
55 // .getLog(NodeVersionHistoryPage.class);
56
57 // Utils
58 protected DateFormat timeFormatter = new SimpleDateFormat(DATE_TIME_FORMAT);
59
60 // business objects
61 private Node currentNode;
62
63 // this page UI components
64 private FullVersioningTreeContentProvider nodeContentProvider;
65 private TreeViewer nodesViewer;
66 private FormToolkit tk;
67
68 public NodeVersionHistoryPage(FormEditor editor, String title,
69 Node currentNode) {
70 super(editor, "NodeVersionHistoryPage", title);
71 this.currentNode = currentNode;
72 }
73
74 protected void createFormContent(IManagedForm managedForm) {
75 ScrolledForm form = managedForm.getForm();
76 tk = managedForm.getToolkit();
77 GridLayout twt = new GridLayout(1, false);
78 twt.marginWidth = twt.marginHeight = 5;
79 Composite body = form.getBody();
80 body.setLayout(twt);
81
82 try {
83 if (!currentNode.isNodeType(NodeType.MIX_VERSIONABLE)) {
84 tk.createLabel(body, JcrExplorerPlugin
85 .getMessage("warningUnversionableNode"));
86 } else {
87 createHistorySection(form.getBody());
88 createTreeSection(form.getBody());
89 }
90 } catch (RepositoryException e) {
91 throw new ArgeoException(
92 "Unexpected error while checking if node is versionable", e);
93 }
94 }
95
96 protected void createTreeSection(Composite parent) {
97 // Section Layout & MetaData
98 Section section = tk.createSection(parent, Section.TWISTIE);
99 section.setLayoutData(new GridData(GridData.FILL_BOTH));
100 section.setText(JcrExplorerPlugin.getMessage("versionTreeSectionTitle"));
101
102 // Section Body
103 Composite body = tk.createComposite(section, SWT.FILL);
104 // WARNING : 2 following lines are compulsory or body won't be
105 // displayed.
106 body.setLayout(new GridLayout());
107 section.setClient(body);
108
109 body.setLayoutData(new GridData(GridData.FILL_BOTH));
110 section.setExpanded(true);
111
112 nodeContentProvider = new FullVersioningTreeContentProvider();
113 nodesViewer = createNodeViewer(body, nodeContentProvider);
114 nodesViewer.setInput(currentNode);
115 }
116
117 protected TreeViewer createNodeViewer(Composite parent,
118 final ITreeContentProvider nodeContentProvider) {
119
120 final TreeViewer tmpNodeViewer = new TreeViewer(parent, SWT.MULTI);
121
122 tmpNodeViewer.getTree().setLayoutData(
123 new GridData(SWT.FILL, SWT.FILL, true, true));
124
125 tmpNodeViewer.setContentProvider(nodeContentProvider);
126 tmpNodeViewer.setLabelProvider(new VersionLabelProvider());
127 tmpNodeViewer
128 .addDoubleClickListener(new GenericNodeDoubleClickListener(
129 tmpNodeViewer));
130 return tmpNodeViewer;
131 }
132
133 protected void createHistorySection(Composite parent) {
134
135 // Section Layout
136 Section section = tk.createSection(parent, Section.TWISTIE);
137 section.setLayoutData(new GridData(TableWrapData.FILL_GRAB));
138 TableWrapLayout twt = new TableWrapLayout();
139 section.setLayout(twt);
140
141 // Set title of the section
142 section.setText(JcrExplorerPlugin
143 .getMessage("versionHistorySectionTitle"));
144
145 final Text styledText = tk.createText(section, "", SWT.FULL_SELECTION
146 | SWT.BORDER | SWT.MULTI | SWT.WRAP | SWT.V_SCROLL);
147 styledText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
148 section.setClient(styledText);
149 refreshHistory(styledText);
150 styledText.setEditable(false);
151 section.setExpanded(false);
152
153 AbstractFormPart part = new AbstractFormPart() {
154 public void commit(boolean onSave) {
155 }
156
157 public void refresh() {
158 super.refresh();
159 refreshHistory(styledText);
160 }
161 };
162 getManagedForm().addPart(part);
163 }
164
165 protected void refreshHistory(Text styledText) {
166 try {
167 List<VersionDiff> lst = listHistoryDiff();
168 StringBuffer main = new StringBuffer("");
169
170 for (int i = lst.size() - 1; i >= 0; i--) {
171 if (i == 0)
172 main.append("Creation (");
173 else
174 main.append("Update " + i + " (");
175
176 if (lst.get(i).getUserId() != null)
177 main.append("UserId : " + lst.get(i).getUserId());
178
179 if (lst.get(i).getUserId() != null
180 && lst.get(i).getUpdateTime() != null)
181 main.append(", ");
182
183 if (lst.get(i).getUpdateTime() != null)
184 main.append("Date : "
185 + timeFormatter.format(lst.get(i).getUpdateTime()
186 .getTime()) + ")\n");
187
188 StringBuffer buf = new StringBuffer("");
189 Map<String, PropertyDiff> diffs = lst.get(i).getDiffs();
190 for (String prop : diffs.keySet()) {
191 PropertyDiff pd = diffs.get(prop);
192 // String propName = pd.getRelPath();
193 Value refValue = pd.getReferenceValue();
194 Value newValue = pd.getNewValue();
195 String refValueStr = "";
196 String newValueStr = "";
197
198 if (refValue != null) {
199 if (refValue.getType() == PropertyType.DATE) {
200 refValueStr = timeFormatter.format(refValue
201 .getDate().getTime());
202 } else
203 refValueStr = refValue.getString();
204 }
205 if (newValue != null) {
206 if (newValue.getType() == PropertyType.DATE) {
207 newValueStr = timeFormatter.format(newValue
208 .getDate().getTime());
209 } else
210 newValueStr = newValue.getString();
211 }
212
213 if (pd.getType() == PropertyDiff.MODIFIED) {
214 buf.append(prop).append(": ");
215 buf.append(refValueStr);
216 buf.append(" > ");
217 buf.append(newValueStr);
218 buf.append("\n");
219 } else if (pd.getType() == PropertyDiff.ADDED
220 && !"".equals(newValueStr)) {
221 // we don't list property that have been added with an
222 // empty string as value
223 buf.append(prop).append(": ");
224 buf.append(" + ");
225 buf.append(newValueStr);
226 buf.append("\n");
227 } else if (pd.getType() == PropertyDiff.REMOVED) {
228 buf.append(prop).append(": ");
229 buf.append(" - ");
230 buf.append(refValueStr);
231 buf.append("\n");
232 }
233 }
234 buf.append("\n");
235 main.append(buf);
236 }
237 styledText.setText(main.toString());
238 } catch (RepositoryException e) {
239 throw new ArgeoException("Cannot generate history for node", e);
240 }
241
242 }
243
244 public List<VersionDiff> listHistoryDiff() {
245 try {
246 List<VersionDiff> res = new ArrayList<VersionDiff>();
247 VersionManager versionManager = currentNode.getSession()
248 .getWorkspace().getVersionManager();
249 VersionHistory versionHistory = versionManager
250 .getVersionHistory(currentNode.getPath());
251
252 VersionIterator vit = versionHistory.getAllLinearVersions();
253 while (vit.hasNext()) {
254 Version version = vit.nextVersion();
255 Node node = version.getFrozenNode();
256 Version predecessor = null;
257 try {
258 predecessor = version.getLinearPredecessor();
259 } catch (Exception e) {
260 // no predecessor seems to throw an exception even if it
261 // shouldn't...
262 }
263 if (predecessor == null) {// original
264 } else {
265 Map<String, PropertyDiff> diffs = JcrUtils.diffProperties(
266 predecessor.getFrozenNode(), node);
267 if (!diffs.isEmpty()) {
268 String lastUserName = null;
269 Calendar lastUpdate = null;
270 try {
271 if (currentNode
272 .isNodeType(NodeType.MIX_LAST_MODIFIED)) {
273 lastUserName = node.getProperty(
274 Property.JCR_LAST_MODIFIED_BY)
275 .getString();
276 lastUpdate = node.getProperty(
277 Property.JCR_LAST_MODIFIED).getDate();
278 } else
279 lastUpdate = version.getProperty(
280 Property.JCR_CREATED).getDate();
281
282 } catch (Exception e) {
283 // Silent that info is optional
284 }
285 VersionDiff vd = new VersionDiff(lastUserName,
286 lastUpdate, diffs);
287 res.add(vd);
288 }
289 }
290 }
291 return res;
292 } catch (RepositoryException e) {
293 throw new ArgeoException("Cannot generate history for node ");
294 }
295
296 }
297
298 @Override
299 public void setActive(boolean active) {
300 super.setActive(active);
301 }
302 }