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