1 package org
.argeo
.cms
.swt
.acr
;
3 import java
.security
.PrivilegedAction
;
5 import javax
.security
.auth
.Subject
;
7 import org
.argeo
.api
.acr
.Content
;
8 import org
.argeo
.api
.acr
.ContentSession
;
9 import org
.argeo
.api
.acr
.spi
.ProvidedContent
;
10 import org
.argeo
.api
.cms
.CmsLog
;
11 import org
.argeo
.api
.cms
.ux
.CmsEditable
;
12 import org
.argeo
.cms
.auth
.CurrentUser
;
13 import org
.argeo
.cms
.swt
.SwtEditablePart
;
14 import org
.argeo
.cms
.swt
.widgets
.ScrolledPage
;
15 import org
.eclipse
.swt
.SWT
;
16 import org
.eclipse
.swt
.events
.FocusEvent
;
17 import org
.eclipse
.swt
.events
.FocusListener
;
18 import org
.eclipse
.swt
.events
.MouseAdapter
;
19 import org
.eclipse
.swt
.events
.MouseListener
;
20 import org
.eclipse
.swt
.widgets
.Composite
;
21 import org
.eclipse
.swt
.widgets
.Control
;
22 import org
.eclipse
.swt
.widgets
.Widget
;
23 import org
.xml
.sax
.SAXParseException
;
25 /** Base class for viewers related to a page */
26 public abstract class AbstractPageViewer
{
28 private final static CmsLog log
= CmsLog
.getLog(AbstractPageViewer
.class);
30 private final boolean readOnly
;
31 /** The basis for the layouts, typically a ScrolledPage. */
32 private final Composite page
;
33 private final CmsEditable cmsEditable
;
35 private MouseListener mouseListener
;
36 private FocusListener focusListener
;
38 private SwtEditablePart edited
;
39 // private ISelection selection = StructuredSelection.EMPTY;
41 private Subject viewerSubject
;
43 protected AbstractPageViewer(Composite parent
, int style
, CmsEditable cmsEditable
) {
44 // read only at UI level
45 readOnly
= SWT
.READ_ONLY
== (style
& SWT
.READ_ONLY
);
47 this.cmsEditable
= cmsEditable
== null ? CmsEditable
.NON_EDITABLE
: cmsEditable
;
48 // if (this.cmsEditable instanceof Observable)
49 // ((Observable) this.cmsEditable).addObserver(this);
51 if (cmsEditable
.canEdit()) {
52 mouseListener
= createMouseListener();
53 focusListener
= createFocusListener();
55 page
= findPage(parent
);
56 // accessControlContext = AccessController.getContext();
57 viewerSubject
= CurrentUser
.getCmsSession().getSubject();
60 public abstract Control
getControl();
63 // * Can be called to simplify the called to isModelInitialized() and initModel()
65 // protected void initModelIfNeeded(Node node) {
67 // if (!isModelInitialized(node))
68 // if (getCmsEditable().canEdit()) {
70 // node.getSession().save();
72 // } catch (RepositoryException e) {
73 // throw new JcrException("Cannot initialize model", e);
77 // /** Called if user can edit and model is not initialized */
78 // protected Boolean isModelInitialized(Node node) throws RepositoryException {
82 // /** Called if user can edit and model is not initialized */
83 // protected void initModel(Node node) throws RepositoryException {
86 /** Create (retrieve) the MouseListener to use. */
87 protected MouseListener
createMouseListener() {
88 return new MouseAdapter() {
89 private static final long serialVersionUID
= 1L;
93 /** Create (retrieve) the FocusListener to use. */
94 protected FocusListener
createFocusListener() {
95 return new FocusListener() {
96 private static final long serialVersionUID
= 1L;
99 public void focusLost(FocusEvent event
) {
103 public void focusGained(FocusEvent event
) {
108 protected Composite
findPage(Composite composite
) {
109 if (composite
instanceof ScrolledPage
) {
110 return (ScrolledPage
) composite
;
112 if (composite
.getParent() == null)
114 return findPage(composite
.getParent());
118 public void layoutPage() {
120 page
.layout(true, true);
123 protected void showControl(Control control
) {
124 if (page
!= null && (page
instanceof ScrolledPage
))
125 ((ScrolledPage
) page
).showControl(control
);
129 // public void update(Observable o, Object arg) {
130 // if (o == cmsEditable)
131 // editingStateChanged(cmsEditable);
134 /** To be overridden in order to provide the actual refresh */
135 protected void refresh(Control control
) {
138 /** To be overridden.Save the edited part. */
139 protected void save(SwtEditablePart part
) {
142 /** Prepare the edited part */
143 protected void prepare(SwtEditablePart part
, Object caretPosition
) {
146 /** Notified when the editing state changed. Does nothing, to be overridden */
147 protected void editingStateChanged(CmsEditable cmsEditable
) {
150 public void refresh() {
151 // TODO check actual context in order to notice a discrepancy
152 Subject viewerSubject
= getViewerSubject();
153 Subject
.doAs(viewerSubject
, (PrivilegedAction
<Void
>) () -> {
154 if (cmsEditable
.canEdit() && !readOnly
)
155 mouseListener
= createMouseListener();
157 mouseListener
= null;
158 refresh(getControl());
159 // layout(getControl());
160 if (!getControl().isDisposed())
167 // public void setSelection(ISelection selection, boolean reveal) {
168 // this.selection = selection;
171 protected void updateContent(SwtEditablePart part
) {
175 protected void edit(SwtEditablePart part
, Object caretPosition
) {
179 if (edited
!= null && edited
!= part
) {
180 SwtEditablePart previouslyEdited
= edited
;
183 } catch (Exception e
) {
184 notifyEditionException(e
);
185 edit(previouslyEdited
, caretPosition
);
193 prepare(part
, caretPosition
);
194 edited
.getControl().addFocusListener(new FocusListener() {
195 private static final long serialVersionUID
= 6883521812717097017L;
198 public void focusLost(FocusEvent event
) {
203 public void focusGained(FocusEvent event
) {
207 layout(part
.getControl());
208 showControl(part
.getControl());
211 protected void stopEditing(Boolean save
) {
212 if (edited
instanceof Widget
&& ((Widget
) edited
).isDisposed()) {
217 assert edited
!= null;
218 if (edited
== null) {
219 if (log
.isTraceEnabled())
220 log
.warn("Told to stop editing while not editing anything");
228 edited
.stopEditing();
229 SwtEditablePart editablePart
= edited
;
230 Control control
= ((SwtEditablePart
) edited
).getControl();
232 // TODO make edited state management more robust
233 updateContent(editablePart
);
240 // METHODS AVAILABLE TO EXTENDING CLASSES
241 protected void saveEdit() {
246 protected void cancelEdit() {
251 /** Layout this controls from the related base page. */
252 public void layout(Control
... controls
) {
253 page
.layout(controls
);
257 * Find the first {@link SwtEditablePart} in the parents hierarchy of this
260 protected SwtEditablePart
findDataParent(Control parent
) {
261 if (parent
instanceof SwtEditablePart
) {
262 return (SwtEditablePart
) parent
;
264 if (parent
.getParent() != null)
265 return findDataParent(parent
.getParent());
267 throw new IllegalStateException("No data parent found");
271 /** Check whether the edited part is in a proper state */
272 protected void checkEdited() {
273 if (edited
== null || (edited
instanceof Widget
) && ((Widget
) edited
).isDisposed())
274 throw new IllegalStateException("Edited should not be null or disposed at this stage");
277 /** Persist all changes. */
278 protected void persistChanges(ContentSession session
) {
280 // session.refresh(false);
281 // TODO notify that changes have been persisted
284 /** Convenience method using a Node in order to save the underlying session. */
285 protected void persistChanges(Content anyNode
) {
286 persistChanges(((ProvidedContent
) anyNode
).getSession());
289 /** Notify edition exception */
290 protected void notifyEditionException(Throwable e
) {
291 Throwable eToLog
= e
;
292 if (e
instanceof IllegalArgumentException
)
293 if (e
.getCause() instanceof SAXParseException
)
294 eToLog
= e
.getCause();
295 log
.error(eToLog
.getMessage(), eToLog
);
296 // if (log.isTraceEnabled())
297 // log.trace("Full stack of " + eToLog.getMessage(), e);
298 // TODO Light error notification popup
301 protected Subject
getViewerSubject() {
302 return viewerSubject
;
303 // Subject res = null;
304 // if (accessControlContext != null) {
305 // res = Subject.getSubject(accessControlContext);
308 // throw new IllegalStateException("No subject associated with this viewer");
313 public boolean isReadOnly() {
317 protected SwtEditablePart
getEdited() {
321 public MouseListener
getMouseListener() {
322 return mouseListener
;
325 public FocusListener
getFocusListener() {
326 return focusListener
;
329 public CmsEditable
getCmsEditable() {
334 // public ISelection getSelection() {