]> git.argeo.org Git - lgpl/argeo-commons.git/blob - AbstractPageViewer.java
31d54c00c302bdcf9d197e7806b8982b0d188670
[lgpl/argeo-commons.git] / AbstractPageViewer.java
1 package org.argeo.cms.viewers;
2
3 import java.util.Observable;
4 import java.util.Observer;
5
6 import javax.jcr.Node;
7 import javax.jcr.RepositoryException;
8 import javax.jcr.Session;
9
10 import org.apache.commons.logging.Log;
11 import org.apache.commons.logging.LogFactory;
12 import org.argeo.cms.CmsException;
13 import org.argeo.cms.ui.CmsEditable;
14 import org.argeo.cms.widgets.ScrolledPage;
15 import org.eclipse.jface.viewers.ContentViewer;
16 import org.eclipse.jface.viewers.ISelection;
17 import org.eclipse.jface.viewers.StructuredSelection;
18 import org.eclipse.swt.SWT;
19 import org.eclipse.swt.events.FocusEvent;
20 import org.eclipse.swt.events.FocusListener;
21 import org.eclipse.swt.events.MouseAdapter;
22 import org.eclipse.swt.events.MouseListener;
23 import org.eclipse.swt.widgets.Composite;
24 import org.eclipse.swt.widgets.Control;
25 import org.eclipse.swt.widgets.Widget;
26 import org.xml.sax.SAXParseException;
27
28 /** Base class for viewers related to a page */
29 public abstract class AbstractPageViewer extends ContentViewer implements
30 Observer {
31 private static final long serialVersionUID = 5438688173410341485L;
32
33 private final static Log log = LogFactory.getLog(AbstractPageViewer.class);
34
35 private final boolean readOnly;
36 /** The basis for the layouts, typically a ScrolledPage. */
37 private final Composite page;
38 private final CmsEditable cmsEditable;
39
40 private MouseListener mouseListener;
41 private FocusListener focusListener;
42
43 private EditablePart edited;
44 private ISelection selection = StructuredSelection.EMPTY;
45
46 protected AbstractPageViewer(Section parent, int style,
47 CmsEditable cmsEditable) {
48 // read only at UI level
49 readOnly = SWT.READ_ONLY == (style & SWT.READ_ONLY);
50
51 this.cmsEditable = cmsEditable == null ? CmsEditable.NON_EDITABLE
52 : cmsEditable;
53 if (this.cmsEditable instanceof Observable)
54 ((Observable) this.cmsEditable).addObserver(this);
55
56 if (cmsEditable.canEdit()) {
57 mouseListener = createMouseListener();
58 focusListener = createFocusListener();
59 }
60 page = findPage(parent);
61 }
62
63 /**
64 * Can be called to simplify the called to isModelInitialized() and
65 * initModel()
66 */
67 protected void initModelIfNeeded(Node node) {
68 try {
69 if (!isModelInitialized(node))
70 if (getCmsEditable().canEdit()) {
71 initModel(node);
72 node.getSession().save();
73 }
74 } catch (Exception e) {
75 throw new CmsException("Cannot initialize model", e);
76 }
77 }
78
79 /** Called if user can edit and model is not initialized */
80 protected Boolean isModelInitialized(Node node) throws RepositoryException {
81 return true;
82 }
83
84 /** Called if user can edit and model is not initialized */
85 protected void initModel(Node node) throws RepositoryException {
86 }
87
88 /** Create (retrieve) the MouseListener to use. */
89 protected MouseListener createMouseListener() {
90 return new MouseAdapter() {
91 private static final long serialVersionUID = 1L;
92 };
93 }
94
95 /** Create (retrieve) the FocusListener to use. */
96 protected FocusListener createFocusListener() {
97 return new FocusListener() {
98 private static final long serialVersionUID = 1L;
99
100 @Override
101 public void focusLost(FocusEvent event) {
102 }
103
104 @Override
105 public void focusGained(FocusEvent event) {
106 }
107 };
108 }
109
110 protected Composite findPage(Composite composite) {
111 if (composite instanceof ScrolledPage) {
112 return (ScrolledPage) composite;
113 } else {
114 if (composite.getParent() == null)
115 return composite;
116 return findPage(composite.getParent());
117 }
118 }
119
120 @Override
121 public void update(Observable o, Object arg) {
122 if (o == cmsEditable)
123 editingStateChanged(cmsEditable);
124 }
125
126 /** To be overridden in order to provide the actual refresh */
127 protected void refresh(Control control) throws RepositoryException {
128 }
129
130 /** To be overridden.Save the edited part. */
131 protected void save(EditablePart part) throws RepositoryException {
132 }
133
134 /** Prepare the edited part */
135 protected void prepare(EditablePart part, Object caretPosition) {
136 }
137
138 /** Notified when the editing state changed. Does nothing, to be overridden */
139 protected void editingStateChanged(CmsEditable cmsEditable) {
140 }
141
142 @Override
143 public void refresh() {
144 try {
145 if (cmsEditable.canEdit() && !readOnly)
146 mouseListener = createMouseListener();
147 else
148 mouseListener = null;
149 refresh(getControl());
150 layout(getControl());
151 } catch (RepositoryException e) {
152 throw new CmsException("Cannot refresh", e);
153 }
154 }
155
156 @Override
157 public void setSelection(ISelection selection, boolean reveal) {
158 this.selection = selection;
159 }
160
161 protected void updateContent(EditablePart part) throws RepositoryException {
162 }
163
164 // LOW LEVEL EDITION
165 protected void edit(EditablePart part, Object caretPosition) {
166 try {
167 if (edited == part)
168 return;
169
170 if (edited != null && edited != part) {
171 EditablePart previouslyEdited = edited;
172 try {
173 stopEditing(true);
174 } catch (Exception e) {
175 notifyEditionException(e);
176 edit(previouslyEdited, caretPosition);
177 return;
178 }
179 }
180
181 part.startEditing();
182 updateContent(part);
183 prepare(part, caretPosition);
184 edited = part;
185 layout(part.getControl());
186 } catch (RepositoryException e) {
187 throw new CmsException("Cannot edit " + part, e);
188 }
189 }
190
191 private void stopEditing(Boolean save) throws RepositoryException {
192 if (edited instanceof Widget && ((Widget) edited).isDisposed()) {
193 edited = null;
194 return;
195 }
196
197 assert edited != null;
198 if (edited == null) {
199 if (log.isTraceEnabled())
200 log.warn("Told to stop editing while not editing anything");
201 return;
202 }
203
204 if (save)
205 save(edited);
206
207 edited.stopEditing();
208 updateContent(edited);
209 layout(((EditablePart) edited).getControl());
210 edited = null;
211 }
212
213 // METHODS AVAILABLE TO EXTENDING CLASSES
214 protected void saveEdit() {
215 try {
216 if (edited != null)
217 stopEditing(true);
218 } catch (RepositoryException e) {
219 throw new CmsException("Cannot stop editing", e);
220 }
221 }
222
223 protected void cancelEdit() {
224 try {
225 if (edited != null)
226 stopEditing(false);
227 } catch (RepositoryException e) {
228 throw new CmsException("Cannot cancel editing", e);
229 }
230 }
231
232 /** Layout this controls from the related base page. */
233 public void layout(Control... controls) {
234 page.layout(controls);
235 }
236
237 /**
238 * Find the first {@link EditablePart} in the parents hierarchy of this
239 * control
240 */
241 protected EditablePart findDataParent(Control parent) {
242 if (parent instanceof EditablePart) {
243 return (EditablePart) parent;
244 }
245 if (parent.getParent() != null)
246 return findDataParent(parent.getParent());
247 else
248 throw new CmsException("No data parent found");
249 }
250
251 // UTILITIES
252 /** Check whether the edited part is in a proper state */
253 protected void checkEdited() {
254 if (edited == null || (edited instanceof Widget)
255 && ((Widget) edited).isDisposed())
256 throw new CmsException(
257 "Edited should not be null or disposed at this stage");
258 }
259
260 /** Persist all changes. */
261 protected void persistChanges(Session session) throws RepositoryException {
262 session.save();
263 session.refresh(false);
264 // TODO notify that changes have been persisted
265 }
266
267 /** Convenience method using a Node in order to save the underlying session. */
268 protected void persistChanges(Node anyNode) throws RepositoryException {
269 persistChanges(anyNode.getSession());
270 }
271
272 /** Notify edition exception */
273 protected void notifyEditionException(Throwable e) {
274 Throwable eToLog = e;
275 if (e instanceof IllegalArgumentException)
276 if (e.getCause() instanceof SAXParseException)
277 eToLog = e.getCause();
278 log.error(eToLog.getMessage());
279 if (log.isTraceEnabled())
280 log.trace("Full stack of " + eToLog.getMessage(), e);
281 // TODO Light error notification popup
282 }
283
284 // GETTERS / SETTERS
285 public boolean isReadOnly() {
286 return readOnly;
287 }
288
289 protected EditablePart getEdited() {
290 return edited;
291 }
292
293 public MouseListener getMouseListener() {
294 return mouseListener;
295 }
296
297 public FocusListener getFocusListener() {
298 return focusListener;
299 }
300
301 public CmsEditable getCmsEditable() {
302 return cmsEditable;
303 }
304
305 @Override
306 public ISelection getSelection() {
307 return selection;
308 }
309 }