001: /*
002: ItsNat Java Web Application Framework
003: Copyright (C) 2007 Innowhere Software Services S.L., Spanish Company
004: Author: Jose Maria Arranz Santamaria
005:
006: This program is free software: you can redistribute it and/or modify
007: it under the terms of the GNU Affero General Public License as published by
008: the Free Software Foundation, either version 3 of the License, or
009: (at your option) any later version. See the GNU Affero General Public
010: License for more details. See the copy of the GNU Affero General Public License
011: included in this program. If not, see <http://www.gnu.org/licenses/>.
012: */
013:
014: package org.itsnat.impl.comp;
015:
016: import org.itsnat.comp.ui.ItsNatTextComponentUI;
017: import org.itsnat.core.ItsNatException;
018: import javax.swing.event.DocumentEvent;
019: import javax.swing.text.AbstractDocument;
020: import javax.swing.text.BadLocationException;
021: import javax.swing.text.Document;
022: import org.itsnat.impl.comp.html.ItsNatHTMLFormComponentImpl;
023:
024: /**
025: *
026: * @author jmarranz
027: */
028: public class ItsNatTextBasedSharedImpl {
029:
030: /**
031: * Creates a new instance of ItsNatTextBasedSharedImpl
032: */
033: public ItsNatTextBasedSharedImpl() {
034: }
035:
036: public static void bindDataModel(ItsNatTextComponentInternal comp) {
037: // A partir de ahora los cambios los repercutimos en el DOM por eventos
038: // No se debe cambiar el DOM por otra vía que por el objeto dataModel
039: Document dataModel = comp.getDocument();
040: dataModel.addDocumentListener(comp);
041: }
042:
043: public static void unbindDataModel(ItsNatTextComponentInternal comp) {
044: Document dataModel = comp.getDocument();
045: dataModel.removeDocumentListener(comp);
046: }
047:
048: public static void syncUIWithDataModel(
049: ItsNatTextComponentInternal comp) {
050: ItsNatTextComponentUI compUI = comp.getItsNatTextComponentUI();
051: Document dataModel = comp.getDocument();
052:
053: String str;
054: try {
055: str = dataModel.getText(0, dataModel.getLength());
056: } catch (BadLocationException ex) {
057: throw new ItsNatException(ex);
058: }
059:
060: ItsNatHTMLFormComponentImpl compHTML = (ItsNatHTMLFormComponentImpl) comp; // A día de hoy todos los componentes texto son elementos de formulario HTML, en el futuro ya veremos
061: // Sincronizamos con el DOM
062: boolean wasDisabled = compHTML
063: .disableSendCodeToRequesterIfServerUpdating();
064: try {
065: compUI.setText(str);
066: } finally {
067: if (wasDisabled)
068: compHTML.enableSendCodeToRequester();
069: }
070: }
071:
072: public static void insertUpdate(ItsNatTextComponentInternal comp,
073: DocumentEvent e) {
074: ItsNatTextComponentUI compUI = comp.getItsNatTextComponentUI();
075: // Sincronizamos con el DOM
076: Document dataModel = e.getDocument();
077: int offset = e.getOffset();
078: int len = e.getLength();
079:
080: String str;
081: try {
082: str = dataModel.getText(offset, len);
083: } catch (BadLocationException ex) {
084: throw new ItsNatException(ex);
085: }
086:
087: // Sincronizamos con el DOM
088: ItsNatHTMLFormComponentImpl compHTML = (ItsNatHTMLFormComponentImpl) comp; // A día de hoy todos los componentes texto son elementos de formulario HTML, en el futuro ya veremos
089: boolean wasDisabled = compHTML
090: .disableSendCodeToRequesterIfServerUpdating();
091: try {
092: compUI.insertString(offset, str);
093: } finally {
094: if (wasDisabled)
095: compHTML.enableSendCodeToRequester();
096: }
097: }
098:
099: public static void removeUpdate(ItsNatTextComponentInternal comp,
100: DocumentEvent e) {
101: ItsNatTextComponentUI compUI = comp.getItsNatTextComponentUI();
102: // Sincronizamos con el DOM
103: int offset = e.getOffset();
104: int len = e.getLength();
105:
106: ItsNatHTMLFormComponentImpl compHTML = (ItsNatHTMLFormComponentImpl) comp; // A día de hoy todos los componentes texto son elementos de formulario HTML, en el futuro ya veremos
107: boolean wasDisabled = compHTML
108: .disableSendCodeToRequesterIfServerUpdating();
109: try {
110: compUI.removeString(offset, len);
111: } finally {
112: if (wasDisabled)
113: compHTML.enableSendCodeToRequester();
114: }
115: }
116:
117: public static void changedUpdate(ItsNatTextComponentInternal comp,
118: DocumentEvent e) {
119: // No hacemos nada pues no se gestionan atributos
120: }
121:
122: public static String getText(ItsNatTextComponentInternal comp) {
123: Document dataModel = comp.getDocument();
124: return getText(comp, 0, dataModel.getLength());
125: }
126:
127: public static void setText(ItsNatTextComponentInternal comp,
128: String t) {
129: Document dataModel = comp.getDocument();
130: replaceString(comp, t, 0, dataModel.getLength());
131: }
132:
133: public static String getText(ItsNatTextComponentInternal comp,
134: int offs, int len) {
135: Document dataModel = comp.getDocument();
136: try {
137: return dataModel.getText(offs, len);
138: } catch (BadLocationException ex) {
139: throw new ItsNatException(ex);
140: }
141: }
142:
143: public static void appendString(ItsNatTextComponentInternal comp,
144: String str) {
145: Document dataModel = comp.getDocument();
146: insertString(comp, str, dataModel.getLength());
147: }
148:
149: public static void replaceString(ItsNatTextComponentInternal comp,
150: String str, int start, int end) {
151: if (end < start)
152: throw new ItsNatException("end before start");
153:
154: Document dataModel = comp.getDocument();
155: try {
156: if (dataModel instanceof AbstractDocument) {
157: ((AbstractDocument) dataModel).replace(start, end
158: - start, str, null);
159: } else {
160: dataModel.remove(start, end - start);
161: dataModel.insertString(start, str, null);
162: }
163: } catch (BadLocationException ex) {
164: throw new ItsNatException(ex);
165: }
166: }
167:
168: public static void insertString(ItsNatTextComponentInternal comp,
169: String str, int pos) {
170: Document dataModel = comp.getDocument();
171: try {
172: dataModel.insertString(pos, str, null);
173: } catch (BadLocationException ex) {
174: throw new ItsNatException(ex);
175: }
176: }
177:
178: public static void remove(ItsNatTextComponentInternal comp,
179: int pos, int length) {
180: Document dataModel = comp.getDocument();
181: try {
182: dataModel.remove(pos, length);
183: } catch (BadLocationException ex) {
184: throw new ItsNatException(ex);
185: }
186: }
187:
188: public static void fullChange(ItsNatTextComponentInternal comp,
189: String newValue) {
190: // Llamado por el evento "change"
191: String oldValue = comp.getText();
192:
193: if (oldValue.equals(newValue))
194: return; // No ha habido cambio alguno, evitamos repercutir falsos eventos "change" que al parecer se producen
195:
196: setText(comp, newValue);
197: }
198:
199: public static void incrementalChange(
200: ItsNatTextComponentInternal comp, String newValue) {
201: // Es especialmente útil cuando es llamado por la pulsación de una tecla, dicha
202: // tecla puede ser un cursor que no cambia el texto,
203: // un CTRL-V que pega un trozo de texto, un CTRL-X que quita un trozo, el texto seleccionado que
204: // es cambiado completamente al pegar otro
205: // etc, además no sabemos donde se ha puesto el cursor inicialmente pues puede
206: // ponerse en el medio del texto box por ejemplo. Por tanto no es posible
207: // "añadir" o "quitar" algo a partir de la tecla pues newValue puede ser muy diferente al valor actual no sólo con un caracter cambiado.
208: // Cada vez que se pulsa una tecla (keyup) se trae el valor actual del texto en el control
209: // sin embargo dicho valor no incluye la posible "nueva" letra (el cambio en general) porque el evento keydown
210: // es cancelable por lo que hasta que no se procesa totalmente con éxito no se añade
211: // al control. Pero el valor actual bien puede ser el valor tras una tecla anterior
212: // con lo cual este cambio incremental es interesante porque aunque vayamos con una tecla
213: // de retraso vamos cambiando el valor en el servidor.
214:
215: // Suponemos que una sola parte ha cambiado: o bien eliminada, o bien
216: // insertada o bien substituida
217: // El objetivo es modificar el Document de forma incremental para que
218: // un posible listener sepa qué ha cambiado exactamente
219:
220: String oldValue = comp.getText();
221:
222: // Si oldValue is igual a newValue se detecta
223:
224: int lenOld = oldValue.length();
225: int lenNew = newValue.length();
226: if (lenOld > lenNew) {
227: // Se ha borrado una parte de oldValue
228: int start; // Posición del comienzo de la zona quitada en oldValue
229: for (start = 0; start < lenNew; start++) {
230: if (oldValue.charAt(start) != newValue.charAt(start))
231: break;
232: }
233:
234: int length = lenOld - lenNew;
235: String newValueCalc = oldValue.substring(0, start)
236: + oldValue.substring(start + length);
237: if (newValueCalc.equals(newValue))
238: remove(comp, start, length);
239: else
240: fullChange(comp, newValue); // Ha habido un cambio más complicado
241: } else if (lenOld < lenNew) {
242: // Se ha insertado una parte en oldValue
243: int start; // Posición del comienzo de la zona insertada en oldValue
244: for (start = 0; start < lenOld; start++) {
245: if (oldValue.charAt(start) != newValue.charAt(start))
246: break;
247: }
248: int length = lenNew - lenOld;
249: String strIns = newValue.substring(start, start + length);
250: String newValueCalc = oldValue.substring(0, start) + strIns
251: + oldValue.substring(start);
252: if (newValueCalc.equals(newValue))
253: insertString(comp, strIns, start);
254: else
255: fullChange(comp, newValue); // Ha habido un cambio más complicado
256: } else // Se ha cambiado una parte en oldValue
257: {
258: int start; // Posición del comienzo de la zona insertada en oldValue
259: for (start = 0; start < lenOld; start++) {
260: if (oldValue.charAt(start) != newValue.charAt(start))
261: break;
262: }
263: if (start >= lenOld)
264: return; // Son iguales, no ha cambiado nada
265:
266: int end;
267: for (end = start; end < lenOld; end++) {
268: if (oldValue.charAt(end) == newValue.charAt(end))
269: break;
270: }
271: String strReplace = newValue.substring(start, end);
272: String newValueCalc = oldValue.substring(0, start)
273: + strReplace
274: + oldValue.substring(start + end - start);
275: if (newValueCalc.equals(newValue))
276: replaceString(comp, strReplace, start, end);
277: else
278: fullChange(comp, newValue); // Ha habido un cambio más complicado
279: }
280: }
281: }
|