View Javadoc
1   package org.argeo.connect.ui.parts;
2   
3   import java.text.DateFormat;
4   import java.text.ParseException;
5   import java.text.SimpleDateFormat;
6   import java.util.Calendar;
7   import java.util.Date;
8   import java.util.GregorianCalendar;
9   
10  import javax.jcr.Node;
11  import javax.jcr.PropertyType;
12  import javax.jcr.RepositoryException;
13  
14  import org.argeo.cms.ui.eclipse.forms.AbstractFormPart;
15  import org.argeo.cms.util.CmsUtils;
16  import org.argeo.connect.ConnectConstants;
17  import org.argeo.connect.ConnectException;
18  import org.argeo.connect.ui.ConnectEditor;
19  import org.argeo.connect.ui.ConnectImages;
20  import org.argeo.connect.ui.ConnectUiStyles;
21  import org.argeo.connect.ui.ConnectUiUtils;
22  import org.argeo.connect.util.ConnectJcrUtils;
23  import org.argeo.eclipse.ui.EclipseUiUtils;
24  import org.eclipse.swt.SWT;
25  import org.eclipse.swt.events.FocusEvent;
26  import org.eclipse.swt.events.FocusListener;
27  import org.eclipse.swt.events.MouseEvent;
28  import org.eclipse.swt.events.MouseListener;
29  import org.eclipse.swt.events.SelectionAdapter;
30  import org.eclipse.swt.events.SelectionEvent;
31  import org.eclipse.swt.events.ShellAdapter;
32  import org.eclipse.swt.events.ShellEvent;
33  import org.eclipse.swt.layout.GridData;
34  import org.eclipse.swt.layout.GridLayout;
35  import org.eclipse.swt.widgets.Button;
36  import org.eclipse.swt.widgets.Composite;
37  import org.eclipse.swt.widgets.Control;
38  import org.eclipse.swt.widgets.DateTime;
39  import org.eclipse.swt.widgets.Shell;
40  import org.eclipse.swt.widgets.Text;
41  
42  /** A composite to put in a form to manage a date with a pop-up calendar */
43  public class DateTextPart extends Composite {
44  	private static final long serialVersionUID = 7651166365139278532L;
45  
46  	// Context
47  	private Node node;
48  	private String propName;
49  
50  	// UI Objects
51  	private final ConnectEditor editor;
52  	private AbstractFormPart formPart;
53  	private Text dateTxt;
54  	private Button openCalBtn;
55  
56  	private DateFormat dateFormat = new SimpleDateFormat(ConnectConstants.DEFAULT_SHORT_DATE_FORMAT);
57  
58  	/**
59  	 * 
60  	 * @param parent
61  	 * @param style
62  	 * @param toolkit
63  	 * @param formPart
64  	 *            if null at creation time, use setFormPart to enable life cycle
65  	 *            management afterwards
66  	 * @param node
67  	 * @param propName
68  	 */
69  	public DateTextPart(ConnectEditor editor, Composite parent, int style, AbstractFormPart formPart, Node node,
70  			String propName) {
71  		super(parent, style);
72  		this.editor = editor;
73  		this.formPart = formPart;
74  		this.node = node;
75  		this.propName = propName;
76  		populate(this);
77  	}
78  
79  	/**
80  	 * Generally, the form part is null when the control is created, use this to set
81  	 * initialised formPart afterwards.
82  	 */
83  	public void setFormPart(AbstractFormPart formPart) {
84  		this.formPart = formPart;
85  	}
86  
87  	public void setText(Calendar cal) {
88  		String newValueStr = "";
89  		if (cal != null)
90  			newValueStr = dateFormat.format(cal.getTime());
91  		if (!newValueStr.equals(dateTxt.getText()))
92  			dateTxt.setText(newValueStr);
93  	}
94  
95  	public void refresh() {
96  		Calendar cal = null;
97  		try {
98  			if (node.hasProperty(propName))
99  				cal = node.getProperty(propName).getDate();
100 			dateTxt.setEnabled(editor.isEditing());
101 			openCalBtn.setEnabled(editor.isEditing());
102 		} catch (RepositoryException e) {
103 			throw new ConnectException("Unable to refresh " + propName + " date property for " + node, e);
104 		}
105 		setText(cal);
106 	}
107 
108 	private void populate(Composite dateComposite) {
109 		GridLayout gl = ConnectUiUtils.noSpaceGridLayout(2);
110 		gl.horizontalSpacing = 5;
111 		dateComposite.setLayout(gl);
112 		dateTxt = new Text(dateComposite, SWT.BORDER);
113 		dateTxt.setMessage(ConnectConstants.DEFAULT_SHORT_DATE_FORMAT);
114 		CmsUtils.style(dateTxt, ConnectUiStyles.FORCE_BORDER);
115 		dateTxt.setLayoutData(new GridData(150, SWT.DEFAULT));
116 		dateTxt.setToolTipText(
117 				"Enter a date with form \"" + ConnectConstants.DEFAULT_SHORT_DATE_FORMAT + "\" or use the calendar");
118 		openCalBtn = new Button(dateComposite, SWT.FLAT);
119 		openCalBtn.setAlignment(SWT.CENTER);
120 		openCalBtn.setImage(ConnectImages.CALENDAR);
121 		// CmsUtils.style(openCalBtn, ConnectUiStyles.OPEN_CALENDAR_BTN);
122 		// openCalBtn.setLayoutData(new GridData(16, 16));
123 
124 		openCalBtn.addSelectionListener(new SelectionAdapter() {
125 			private static final long serialVersionUID = 1L;
126 
127 			public void widgetSelected(SelectionEvent event) {
128 				CalendarPopup popup = new CalendarPopup(dateTxt);
129 				popup.open();
130 			}
131 		});
132 
133 		dateTxt.addFocusListener(new FocusListener() {
134 			private static final long serialVersionUID = 1L;
135 
136 			@Override
137 			public void focusLost(FocusEvent event) {
138 				try {
139 					Calendar newVal = parseDate(false);
140 					if (newVal != null) {
141 						if (ConnectJcrUtils.setJcrProperty(node, propName, PropertyType.DATE, newVal))
142 							formPart.markDirty();
143 					} else if (node.hasProperty(propName)) {
144 						node.getProperty(propName).remove();
145 						formPart.markDirty();
146 					}
147 				} catch (RepositoryException e) {
148 					throw new ConnectException("Unable to update " + propName + " date property for " + node, e);
149 				}
150 			}
151 
152 			@Override
153 			public void focusGained(FocusEvent event) {
154 			}
155 		});
156 	}
157 
158 	private Calendar parseDate(boolean openWrongFormatError) {
159 		String dateStr = dateTxt.getText();
160 
161 		if (EclipseUiUtils.notEmpty(dateStr)) {
162 			try {
163 				Date date = dateFormat.parse(dateStr);
164 				Calendar cal = new GregorianCalendar();
165 				cal.setTime(date);
166 				return cal;
167 			} catch (ParseException pe) {
168 				// Silent. Manage error popup?
169 				refresh();
170 				try {
171 					if (node.hasProperty(propName))
172 						return node.getProperty(propName).getDate();
173 				} catch (RepositoryException re) {
174 					throw new ConnectException("Unable to reset text to old value after parsing of invalid value for "
175 							+ propName + " of " + node, re);
176 				}
177 			}
178 		}
179 		return null;
180 	}
181 
182 	private class CalendarPopup extends Shell {
183 		private static final long serialVersionUID = 1L;
184 		private Calendar currCal = null;
185 		private DateTime dateTimeCtl;
186 
187 		public CalendarPopup(Control source) {
188 			super(source.getDisplay(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
189 			currCal = parseDate(false);
190 
191 			populate();
192 
193 			// Add border and shadow style
194 			CmsUtils.style(CalendarPopup.this, ConnectUiStyles.POPUP_SHELL);
195 
196 			pack();
197 			layout();
198 			setLocation(source.toDisplay((source.getLocation().x - 2), (source.getSize().y) + 3));
199 
200 			addShellListener(new ShellAdapter() {
201 				private static final long serialVersionUID = 5178980294808435833L;
202 
203 				@Override
204 				public void shellDeactivated(ShellEvent e) {
205 					close();
206 					dispose();
207 				}
208 
209 			});
210 			open();
211 		}
212 
213 		private void setProperty() {
214 			Calendar cal = new GregorianCalendar();
215 			cal.set(dateTimeCtl.getYear(), dateTimeCtl.getMonth(), dateTimeCtl.getDay(), 12, 0);
216 			dateTxt.setText(dateFormat.format(cal.getTime()));
217 			if (ConnectJcrUtils.setJcrProperty(node, propName, PropertyType.DATE, cal))
218 				formPart.markDirty();
219 		}
220 
221 		protected void populate() {
222 			setLayout(EclipseUiUtils.noSpaceGridLayout());
223 
224 			dateTimeCtl = new DateTime(this, SWT.CALENDAR);
225 			dateTimeCtl.setLayoutData(EclipseUiUtils.fillAll());
226 			if (currCal != null)
227 				dateTimeCtl.setDate(currCal.get(Calendar.YEAR), currCal.get(Calendar.MONTH),
228 						currCal.get(Calendar.DAY_OF_MONTH));
229 
230 			dateTimeCtl.addSelectionListener(new SelectionAdapter() {
231 				private static final long serialVersionUID = -8414377364434281112L;
232 
233 				@Override
234 				public void widgetSelected(SelectionEvent e) {
235 					setProperty();
236 				}
237 			});
238 
239 			dateTimeCtl.addMouseListener(new MouseListener() {
240 				private static final long serialVersionUID = 1L;
241 
242 				@Override
243 				public void mouseUp(MouseEvent e) {
244 				}
245 
246 				@Override
247 				public void mouseDown(MouseEvent e) {
248 				}
249 
250 				@Override
251 				public void mouseDoubleClick(MouseEvent e) {
252 					setProperty();
253 					close();
254 					dispose();
255 				}
256 			});
257 		}
258 	}
259 }