1 package org
.argeo
.jcr
.ui
.explorer
.editors
;
3 import java
.text
.DateFormat
;
4 import java
.text
.SimpleDateFormat
;
5 import java
.util
.ArrayList
;
6 import java
.util
.Calendar
;
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
;
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
;
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
52 public class NodeVersionHistoryPage
extends FormPage
implements
53 JcrExplorerConstants
{
54 // private final static Log log = LogFactory
55 // .getLog(NodeVersionHistoryPage.class);
58 protected DateFormat timeFormatter
= new SimpleDateFormat(DATE_TIME_FORMAT
);
61 private Node currentNode
;
63 // this page UI components
64 private FullVersioningTreeContentProvider nodeContentProvider
;
65 private TreeViewer nodesViewer
;
66 private FormToolkit tk
;
68 public NodeVersionHistoryPage(FormEditor editor
, String title
,
70 super(editor
, "NodeVersionHistoryPage", title
);
71 this.currentNode
= currentNode
;
74 protected void createFormContent(IManagedForm managedForm
) {
75 ScrolledForm form
= managedForm
.getForm();
76 form
.setText(JcrExplorerPlugin
77 .getMessage("nodeVersionHistoryPageTitle"));
78 tk
= managedForm
.getToolkit();
79 GridLayout twt
= new GridLayout(1, false);
80 twt
.marginWidth
= twt
.marginHeight
= 5;
81 Composite body
= form
.getBody();
85 if (!currentNode
.isNodeType(NodeType
.MIX_VERSIONABLE
)) {
86 tk
.createLabel(body
, JcrExplorerPlugin
87 .getMessage("warningUnversionableNode"));
89 createHistorySection(form
.getBody());
90 createTreeSection(form
.getBody());
92 } catch (RepositoryException e
) {
93 throw new ArgeoException(
94 "Unexpected error while checking if node is versionable", e
);
98 protected void createTreeSection(Composite parent
) {
99 // Section Layout & MetaData
100 Section section
= tk
.createSection(parent
, Section
.TWISTIE
);
101 section
.setLayoutData(new GridData(GridData
.FILL_BOTH
));
102 section
.setText(JcrExplorerPlugin
.getMessage("versionTreeSectionTitle"));
105 Composite body
= tk
.createComposite(section
, SWT
.FILL
);
106 // WARNING : 2 following lines are compulsory or body won't be
108 body
.setLayout(new GridLayout());
109 section
.setClient(body
);
111 body
.setLayoutData(new GridData(GridData
.FILL_BOTH
));
112 section
.setExpanded(true);
114 nodeContentProvider
= new FullVersioningTreeContentProvider();
115 nodesViewer
= createNodeViewer(body
, nodeContentProvider
);
116 nodesViewer
.setInput(currentNode
);
119 protected TreeViewer
createNodeViewer(Composite parent
,
120 final ITreeContentProvider nodeContentProvider
) {
122 final TreeViewer tmpNodeViewer
= new TreeViewer(parent
, SWT
.MULTI
);
124 tmpNodeViewer
.getTree().setLayoutData(
125 new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
127 tmpNodeViewer
.setContentProvider(nodeContentProvider
);
128 tmpNodeViewer
.setLabelProvider(new VersionLabelProvider());
130 .addDoubleClickListener(new GenericNodeDoubleClickListener(
132 return tmpNodeViewer
;
135 protected void createHistorySection(Composite parent
) {
138 Section section
= tk
.createSection(parent
, Section
.TWISTIE
);
139 section
.setLayoutData(new GridData(TableWrapData
.FILL_GRAB
));
140 TableWrapLayout twt
= new TableWrapLayout();
141 section
.setLayout(twt
);
143 // Set title of the section
144 section
.setText(JcrExplorerPlugin
145 .getMessage("versionHistorySectionTitle"));
147 final Text styledText
= tk
.createText(section
, "", SWT
.FULL_SELECTION
148 | SWT
.BORDER
| SWT
.MULTI
| SWT
.WRAP
| SWT
.V_SCROLL
);
149 styledText
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
150 section
.setClient(styledText
);
151 refreshHistory(styledText
);
152 styledText
.setEditable(false);
153 section
.setExpanded(false);
155 AbstractFormPart part
= new AbstractFormPart() {
156 public void commit(boolean onSave
) {
159 public void refresh() {
161 refreshHistory(styledText
);
164 getManagedForm().addPart(part
);
167 protected void refreshHistory(Text styledText
) {
169 List
<VersionDiff
> lst
= listHistoryDiff();
170 StringBuffer main
= new StringBuffer("");
172 for (int i
= lst
.size() - 1; i
>= 0; i
--) {
174 main
.append("Creation (");
176 main
.append("Update " + i
+ " (");
178 if (lst
.get(i
).getUserId() != null)
179 main
.append("UserId : " + lst
.get(i
).getUserId());
181 if (lst
.get(i
).getUserId() != null
182 && lst
.get(i
).getUpdateTime() != null)
185 if (lst
.get(i
).getUpdateTime() != null)
186 main
.append("Date : "
187 + timeFormatter
.format(lst
.get(i
).getUpdateTime()
188 .getTime()) + ")\n");
190 StringBuffer buf
= new StringBuffer("");
191 Map
<String
, PropertyDiff
> diffs
= lst
.get(i
).getDiffs();
192 for (String prop
: diffs
.keySet()) {
193 PropertyDiff pd
= diffs
.get(prop
);
194 // String propName = pd.getRelPath();
195 Value refValue
= pd
.getReferenceValue();
196 Value newValue
= pd
.getNewValue();
197 String refValueStr
= "";
198 String newValueStr
= "";
200 if (refValue
!= null) {
201 if (refValue
.getType() == PropertyType
.DATE
) {
202 refValueStr
= timeFormatter
.format(refValue
203 .getDate().getTime());
205 refValueStr
= refValue
.getString();
207 if (newValue
!= null) {
208 if (newValue
.getType() == PropertyType
.DATE
) {
209 newValueStr
= timeFormatter
.format(newValue
210 .getDate().getTime());
212 newValueStr
= newValue
.getString();
215 if (pd
.getType() == PropertyDiff
.MODIFIED
) {
216 buf
.append(prop
).append(": ");
217 buf
.append(refValueStr
);
219 buf
.append(newValueStr
);
221 } else if (pd
.getType() == PropertyDiff
.ADDED
222 && !"".equals(newValueStr
)) {
223 // we don't list property that have been added with an
224 // empty string as value
225 buf
.append(prop
).append(": ");
227 buf
.append(newValueStr
);
229 } else if (pd
.getType() == PropertyDiff
.REMOVED
) {
230 buf
.append(prop
).append(": ");
232 buf
.append(refValueStr
);
239 styledText
.setText(main
.toString());
240 } catch (RepositoryException e
) {
241 throw new ArgeoException("Cannot generate history for node", e
);
246 public List
<VersionDiff
> listHistoryDiff() {
248 List
<VersionDiff
> res
= new ArrayList
<VersionDiff
>();
249 VersionManager versionManager
= currentNode
.getSession()
250 .getWorkspace().getVersionManager();
251 VersionHistory versionHistory
= versionManager
252 .getVersionHistory(currentNode
.getPath());
254 VersionIterator vit
= versionHistory
.getAllLinearVersions();
255 while (vit
.hasNext()) {
256 Version version
= vit
.nextVersion();
257 Node node
= version
.getFrozenNode();
258 Version predecessor
= null;
260 predecessor
= version
.getLinearPredecessor();
261 } catch (Exception e
) {
262 // no predecessor seems to throw an exception even if it
265 if (predecessor
== null) {// original
267 Map
<String
, PropertyDiff
> diffs
= JcrUtils
.diffProperties(
268 predecessor
.getFrozenNode(), node
);
269 if (!diffs
.isEmpty()) {
270 String lastUserName
= null;
271 Calendar lastUpdate
= null;
274 .isNodeType(NodeType
.MIX_LAST_MODIFIED
)) {
275 lastUserName
= node
.getProperty(
276 Property
.JCR_LAST_MODIFIED_BY
)
278 lastUpdate
= node
.getProperty(
279 Property
.JCR_LAST_MODIFIED
).getDate();
281 lastUpdate
= version
.getProperty(
282 Property
.JCR_CREATED
).getDate();
284 } catch (Exception e
) {
285 // Silent that info is optional
287 VersionDiff vd
= new VersionDiff(lastUserName
,
294 } catch (RepositoryException e
) {
295 throw new ArgeoException("Cannot generate history for node ");
301 public void setActive(boolean active
) {
302 super.setActive(active
);