]> git.argeo.org Git - lgpl/argeo-commons.git/blob - swt/org.argeo.cms.swt/src/org/argeo/cms/swt/acr/AbstractPageViewer.java
Add account-related RFC 2307bis LDAP objects and attributes
[lgpl/argeo-commons.git] / swt / org.argeo.cms.swt / src / org / argeo / cms / swt / acr / AbstractPageViewer.java
1 package org.argeo.cms.swt.acr;
2
3 import java.security.PrivilegedAction;
4
5 import javax.security.auth.Subject;
6
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;
24
25 /** Base class for viewers related to a page */
26 public abstract class AbstractPageViewer {
27
28 private final static CmsLog log = CmsLog.getLog(AbstractPageViewer.class);
29
30 private final boolean readOnly;
31 /** The basis for the layouts, typically a ScrolledPage. */
32 private final Composite page;
33 private final CmsEditable cmsEditable;
34
35 private MouseListener mouseListener;
36 private FocusListener focusListener;
37
38 private SwtEditablePart edited;
39 // private ISelection selection = StructuredSelection.EMPTY;
40
41 private Subject viewerSubject;
42
43 protected AbstractPageViewer(Composite parent, int style, CmsEditable cmsEditable) {
44 // read only at UI level
45 readOnly = SWT.READ_ONLY == (style & SWT.READ_ONLY);
46
47 this.cmsEditable = cmsEditable == null ? CmsEditable.NON_EDITABLE : cmsEditable;
48 // if (this.cmsEditable instanceof Observable)
49 // ((Observable) this.cmsEditable).addObserver(this);
50
51 if (cmsEditable.canEdit()) {
52 mouseListener = createMouseListener();
53 focusListener = createFocusListener();
54 }
55 page = findPage(parent);
56 // accessControlContext = AccessController.getContext();
57 viewerSubject = CurrentUser.getCmsSession().getSubject();
58 }
59
60 public abstract Control getControl();
61
62 // /**
63 // * Can be called to simplify the called to isModelInitialized() and initModel()
64 // */
65 // protected void initModelIfNeeded(Node node) {
66 // try {
67 // if (!isModelInitialized(node))
68 // if (getCmsEditable().canEdit()) {
69 // initModel(node);
70 // node.getSession().save();
71 // }
72 // } catch (RepositoryException e) {
73 // throw new JcrException("Cannot initialize model", e);
74 // }
75 // }
76 //
77 // /** Called if user can edit and model is not initialized */
78 // protected Boolean isModelInitialized(Node node) throws RepositoryException {
79 // return true;
80 // }
81 //
82 // /** Called if user can edit and model is not initialized */
83 // protected void initModel(Node node) throws RepositoryException {
84 // }
85
86 /** Create (retrieve) the MouseListener to use. */
87 protected MouseListener createMouseListener() {
88 return new MouseAdapter() {
89 private static final long serialVersionUID = 1L;
90 };
91 }
92
93 /** Create (retrieve) the FocusListener to use. */
94 protected FocusListener createFocusListener() {
95 return new FocusListener() {
96 private static final long serialVersionUID = 1L;
97
98 @Override
99 public void focusLost(FocusEvent event) {
100 }
101
102 @Override
103 public void focusGained(FocusEvent event) {
104 }
105 };
106 }
107
108 protected Composite findPage(Composite composite) {
109 if (composite instanceof ScrolledPage) {
110 return (ScrolledPage) composite;
111 } else {
112 if (composite.getParent() == null)
113 return composite;
114 return findPage(composite.getParent());
115 }
116 }
117
118 public void layoutPage() {
119 if (page != null)
120 page.layout(true, true);
121 }
122
123 protected void showControl(Control control) {
124 if (page != null && (page instanceof ScrolledPage))
125 ((ScrolledPage) page).showControl(control);
126 }
127
128 // @Override
129 // public void update(Observable o, Object arg) {
130 // if (o == cmsEditable)
131 // editingStateChanged(cmsEditable);
132 // }
133
134 /** To be overridden in order to provide the actual refresh */
135 protected void refresh(Control control) {
136 }
137
138 /** To be overridden.Save the edited part. */
139 protected void save(SwtEditablePart part) {
140 }
141
142 /** Prepare the edited part */
143 protected void prepare(SwtEditablePart part, Object caretPosition) {
144 }
145
146 /** Notified when the editing state changed. Does nothing, to be overridden */
147 protected void editingStateChanged(CmsEditable cmsEditable) {
148 }
149
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();
156 else
157 mouseListener = null;
158 refresh(getControl());
159 // layout(getControl());
160 if (!getControl().isDisposed())
161 layoutPage();
162 return null;
163 });
164 }
165
166 // @Override
167 // public void setSelection(ISelection selection, boolean reveal) {
168 // this.selection = selection;
169 // }
170
171 protected void updateContent(SwtEditablePart part) {
172 }
173
174 // LOW LEVEL EDITION
175 protected void edit(SwtEditablePart part, Object caretPosition) {
176 if (edited == part)
177 return;
178
179 if (edited != null && edited != part) {
180 SwtEditablePart previouslyEdited = edited;
181 try {
182 stopEditing(true);
183 } catch (Exception e) {
184 notifyEditionException(e);
185 edit(previouslyEdited, caretPosition);
186 return;
187 }
188 }
189
190 part.startEditing();
191 edited = part;
192 updateContent(part);
193 prepare(part, caretPosition);
194 edited.getControl().addFocusListener(new FocusListener() {
195 private static final long serialVersionUID = 6883521812717097017L;
196
197 @Override
198 public void focusLost(FocusEvent event) {
199 stopEditing(true);
200 }
201
202 @Override
203 public void focusGained(FocusEvent event) {
204 }
205 });
206
207 layout(part.getControl());
208 showControl(part.getControl());
209 }
210
211 protected void stopEditing(Boolean save) {
212 if (edited instanceof Widget && ((Widget) edited).isDisposed()) {
213 edited = null;
214 return;
215 }
216
217 assert edited != null;
218 if (edited == null) {
219 if (log.isTraceEnabled())
220 log.warn("Told to stop editing while not editing anything");
221 return;
222 }
223
224 try {
225 if (save)
226 save(edited);
227
228 edited.stopEditing();
229 SwtEditablePart editablePart = edited;
230 Control control = ((SwtEditablePart) edited).getControl();
231 edited = null;
232 // TODO make edited state management more robust
233 updateContent(editablePart);
234 layout(control);
235 } finally {
236 edited = null;
237 }
238 }
239
240 // METHODS AVAILABLE TO EXTENDING CLASSES
241 protected void saveEdit() {
242 if (edited != null)
243 stopEditing(true);
244 }
245
246 protected void cancelEdit() {
247 if (edited != null)
248 stopEditing(false);
249 }
250
251 /** Layout this controls from the related base page. */
252 public void layout(Control... controls) {
253 page.layout(controls);
254 }
255
256 /**
257 * Find the first {@link SwtEditablePart} in the parents hierarchy of this
258 * control
259 */
260 protected SwtEditablePart findDataParent(Control parent) {
261 if (parent instanceof SwtEditablePart) {
262 return (SwtEditablePart) parent;
263 }
264 if (parent.getParent() != null)
265 return findDataParent(parent.getParent());
266 else
267 throw new IllegalStateException("No data parent found");
268 }
269
270 // UTILITIES
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");
275 }
276
277 /** Persist all changes. */
278 protected void persistChanges(ContentSession session) {
279 // session.save();
280 // session.refresh(false);
281 // TODO notify that changes have been persisted
282 }
283
284 /** Convenience method using a Node in order to save the underlying session. */
285 protected void persistChanges(Content anyNode) {
286 persistChanges(((ProvidedContent) anyNode).getSession());
287 }
288
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
299 }
300
301 protected Subject getViewerSubject() {
302 return viewerSubject;
303 // Subject res = null;
304 // if (accessControlContext != null) {
305 // res = Subject.getSubject(accessControlContext);
306 // }
307 // if (res == null)
308 // throw new IllegalStateException("No subject associated with this viewer");
309 // return res;
310 }
311
312 // GETTERS / SETTERS
313 public boolean isReadOnly() {
314 return readOnly;
315 }
316
317 protected SwtEditablePart getEdited() {
318 return edited;
319 }
320
321 public MouseListener getMouseListener() {
322 return mouseListener;
323 }
324
325 public FocusListener getFocusListener() {
326 return focusListener;
327 }
328
329 public CmsEditable getCmsEditable() {
330 return cmsEditable;
331 }
332
333 // @Override
334 // public ISelection getSelection() {
335 // return selection;
336 // }
337 }