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