1 package org
.argeo
.cms
.ui
.viewers
;
3 import java
.security
.AccessControlContext
;
4 import java
.security
.AccessController
;
5 import java
.security
.PrivilegedAction
;
6 import java
.util
.Observable
;
7 import java
.util
.Observer
;
10 import javax
.jcr
.RepositoryException
;
11 import javax
.jcr
.Session
;
12 import javax
.security
.auth
.Subject
;
14 import org
.apache
.commons
.logging
.Log
;
15 import org
.apache
.commons
.logging
.LogFactory
;
16 import org
.argeo
.cms
.CmsException
;
17 import org
.argeo
.cms
.ui
.CmsEditable
;
18 import org
.argeo
.cms
.ui
.widgets
.ScrolledPage
;
19 import org
.argeo
.jcr
.JcrException
;
20 import org
.eclipse
.jface
.viewers
.ContentViewer
;
21 import org
.eclipse
.jface
.viewers
.ISelection
;
22 import org
.eclipse
.jface
.viewers
.StructuredSelection
;
23 import org
.eclipse
.swt
.SWT
;
24 import org
.eclipse
.swt
.events
.FocusEvent
;
25 import org
.eclipse
.swt
.events
.FocusListener
;
26 import org
.eclipse
.swt
.events
.MouseAdapter
;
27 import org
.eclipse
.swt
.events
.MouseListener
;
28 import org
.eclipse
.swt
.widgets
.Composite
;
29 import org
.eclipse
.swt
.widgets
.Control
;
30 import org
.eclipse
.swt
.widgets
.Widget
;
31 import org
.xml
.sax
.SAXParseException
;
33 /** Base class for viewers related to a page */
34 public abstract class AbstractPageViewer
extends ContentViewer
implements Observer
{
35 private static final long serialVersionUID
= 5438688173410341485L;
37 private final static Log log
= LogFactory
.getLog(AbstractPageViewer
.class);
39 private final boolean readOnly
;
40 /** The basis for the layouts, typically a ScrolledPage. */
41 private final Composite page
;
42 private final CmsEditable cmsEditable
;
44 private MouseListener mouseListener
;
45 private FocusListener focusListener
;
47 private EditablePart edited
;
48 private ISelection selection
= StructuredSelection
.EMPTY
;
50 private AccessControlContext accessControlContext
;
52 protected AbstractPageViewer(Section parent
, int style
, CmsEditable cmsEditable
) {
53 // read only at UI level
54 readOnly
= SWT
.READ_ONLY
== (style
& SWT
.READ_ONLY
);
56 this.cmsEditable
= cmsEditable
== null ? CmsEditable
.NON_EDITABLE
: cmsEditable
;
57 if (this.cmsEditable
instanceof Observable
)
58 ((Observable
) this.cmsEditable
).addObserver(this);
60 if (cmsEditable
.canEdit()) {
61 mouseListener
= createMouseListener();
62 focusListener
= createFocusListener();
64 page
= findPage(parent
);
65 accessControlContext
= AccessController
.getContext();
69 * Can be called to simplify the called to isModelInitialized() and initModel()
71 protected void initModelIfNeeded(Node node
) {
73 if (!isModelInitialized(node
))
74 if (getCmsEditable().canEdit()) {
76 node
.getSession().save();
78 } catch (Exception e
) {
79 throw new CmsException("Cannot initialize model", e
);
83 /** Called if user can edit and model is not initialized */
84 protected Boolean
isModelInitialized(Node node
) throws RepositoryException
{
88 /** Called if user can edit and model is not initialized */
89 protected void initModel(Node node
) throws RepositoryException
{
92 /** Create (retrieve) the MouseListener to use. */
93 protected MouseListener
createMouseListener() {
94 return new MouseAdapter() {
95 private static final long serialVersionUID
= 1L;
99 /** Create (retrieve) the FocusListener to use. */
100 protected FocusListener
createFocusListener() {
101 return new FocusListener() {
102 private static final long serialVersionUID
= 1L;
105 public void focusLost(FocusEvent event
) {
109 public void focusGained(FocusEvent event
) {
114 protected Composite
findPage(Composite composite
) {
115 if (composite
instanceof ScrolledPage
) {
116 return (ScrolledPage
) composite
;
118 if (composite
.getParent() == null)
120 return findPage(composite
.getParent());
125 public void update(Observable o
, Object arg
) {
126 if (o
== cmsEditable
)
127 editingStateChanged(cmsEditable
);
130 /** To be overridden in order to provide the actual refresh */
131 protected void refresh(Control control
) throws RepositoryException
{
134 /** To be overridden.Save the edited part. */
135 protected void save(EditablePart part
) throws RepositoryException
{
138 /** Prepare the edited part */
139 protected void prepare(EditablePart part
, Object caretPosition
) {
142 /** Notified when the editing state changed. Does nothing, to be overridden */
143 protected void editingStateChanged(CmsEditable cmsEditable
) {
147 public void refresh() {
148 // TODO check actual context in order to notice a discrepancy
149 Subject viewerSubject
= getViewerSubject();
150 Subject
.doAs(viewerSubject
, (PrivilegedAction
<Void
>) () -> {
152 if (cmsEditable
.canEdit() && !readOnly
)
153 mouseListener
= createMouseListener();
155 mouseListener
= null;
156 refresh(getControl());
157 layout(getControl());
158 } catch (RepositoryException e
) {
159 throw new CmsException("Cannot refresh", e
);
166 public void setSelection(ISelection selection
, boolean reveal
) {
167 this.selection
= selection
;
170 protected void updateContent(EditablePart part
) throws RepositoryException
{
174 protected void edit(EditablePart part
, Object caretPosition
) {
179 if (edited
!= null && edited
!= part
) {
180 EditablePart previouslyEdited
= edited
;
183 } catch (Exception e
) {
184 notifyEditionException(e
);
185 edit(previouslyEdited
, caretPosition
);
192 prepare(part
, caretPosition
);
194 edited
.getControl().addFocusListener(new FocusListener() {
197 public void focusLost(FocusEvent event
) {
202 public void focusGained(FocusEvent event
) {
206 layout(part
.getControl());
207 } catch (RepositoryException e
) {
208 throw new CmsException("Cannot edit " + part
, e
);
212 protected void stopEditing(Boolean save
) {
213 if (edited
instanceof Widget
&& ((Widget
) edited
).isDisposed()) {
218 assert edited
!= null;
219 if (edited
== null) {
220 if (log
.isTraceEnabled())
221 log
.warn("Told to stop editing while not editing anything");
229 edited
.stopEditing();
230 updateContent(edited
);
231 layout(((EditablePart
) edited
).getControl());
232 } catch (RepositoryException e
) {
233 throw new JcrException("Cannot stop editing", e
);
239 // METHODS AVAILABLE TO EXTENDING CLASSES
240 protected void saveEdit() {
245 protected void cancelEdit() {
250 /** Layout this controls from the related base page. */
251 public void layout(Control
... controls
) {
252 page
.layout(controls
);
256 * Find the first {@link EditablePart} in the parents hierarchy of this control
258 protected EditablePart
findDataParent(Control parent
) {
259 if (parent
instanceof EditablePart
) {
260 return (EditablePart
) parent
;
262 if (parent
.getParent() != null)
263 return findDataParent(parent
.getParent());
265 throw new CmsException("No data parent found");
269 /** Check whether the edited part is in a proper state */
270 protected void checkEdited() {
271 if (edited
== null || (edited
instanceof Widget
) && ((Widget
) edited
).isDisposed())
272 throw new CmsException("Edited should not be null or disposed at this stage");
275 /** Persist all changes. */
276 protected void persistChanges(Session session
) throws RepositoryException
{
278 session
.refresh(false);
279 // TODO notify that changes have been persisted
282 /** Convenience method using a Node in order to save the underlying session. */
283 protected void persistChanges(Node anyNode
) throws RepositoryException
{
284 persistChanges(anyNode
.getSession());
287 /** Notify edition exception */
288 protected void notifyEditionException(Throwable e
) {
289 Throwable eToLog
= e
;
290 if (e
instanceof IllegalArgumentException
)
291 if (e
.getCause() instanceof SAXParseException
)
292 eToLog
= e
.getCause();
293 log
.error(eToLog
.getMessage(), eToLog
);
294 // if (log.isTraceEnabled())
295 // log.trace("Full stack of " + eToLog.getMessage(), e);
296 // TODO Light error notification popup
299 protected Subject
getViewerSubject() {
301 if (accessControlContext
!= null) {
302 res
= Subject
.getSubject(accessControlContext
);
305 throw new CmsException("No subject associated with this viewer");
310 public boolean isReadOnly() {
314 protected EditablePart
getEdited() {
318 public MouseListener
getMouseListener() {
319 return mouseListener
;
322 public FocusListener
getFocusListener() {
323 return focusListener
;
326 public CmsEditable
getCmsEditable() {
331 public ISelection
getSelection() {