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.html;
015:
016: import org.itsnat.core.event.CustomParamTransport;
017: import org.itsnat.comp.html.ItsNatHTMLSelectMult;
018: import org.itsnat.comp.ui.ItsNatComponentUI;
019: import org.itsnat.comp.ui.ItsNatListMultSelUI;
020: import org.itsnat.impl.comp.ItsNatListMultSelSharedImpl;
021: import org.itsnat.impl.comp.ItsNatListMultSelInternal;
022: import org.itsnat.impl.comp.ListSelectionModelMgrImpl;
023: import org.itsnat.impl.comp.html.ui.ItsNatHTMLSelectMultUIImpl;
024: import java.util.List;
025: import javax.swing.DefaultListModel;
026: import javax.swing.DefaultListSelectionModel;
027: import javax.swing.ListModel;
028: import javax.swing.ListSelectionModel;
029: import javax.swing.event.ListDataEvent;
030: import javax.swing.event.ListSelectionEvent;
031: import javax.swing.event.ListSelectionListener;
032: import org.itsnat.core.event.ParamTransport;
033: import org.itsnat.core.NameValue;
034: import org.itsnat.core.event.DOMEvent;
035: import org.w3c.dom.events.Event;
036: import org.w3c.dom.html.HTMLSelectElement;
037:
038: /**
039: * Parecido a JList
040: *
041: * @author jmarranz
042: */
043: public class ItsNatHTMLSelectMultImpl extends ItsNatHTMLSelectImpl
044: implements ItsNatHTMLSelectMult, ItsNatListMultSelInternal,
045: ListSelectionListener {
046: protected ListSelectionModelMgrImpl selModelMgr;
047:
048: /**
049: * Creates a new instance of ItsNatHTMLSelectMultImpl
050: */
051: public ItsNatHTMLSelectMultImpl(HTMLSelectElement element,
052: NameValue[] artifacts,
053: ItsNatHTMLComponentManagerImpl componentMgr) {
054: super (element, artifacts, componentMgr);
055:
056: // Aunque pongamos en <select> con multiple="multiple"
057: // el selection model puede estar en modo de selección única
058: // y funcionará pues el componente quitará el actual al ser cambiado por otro
059: // No imponemos multiple="multiple" así podríamos en teoría asociar al tipo de select que queramos
060: // getHTMLSelectElement().setMultiple(true); // Para asegurarnos
061:
062: init();
063: }
064:
065: public void setDefaultModels() {
066: super .setDefaultModels();
067:
068: // Después de la iniciación del data model
069: setListSelectionModel(new DefaultListSelectionModel());
070: }
071:
072: public void unbindModels() {
073: unsetListSelectionModel();
074:
075: super .unbindModels();
076: }
077:
078: public void unsetListSelectionModel() {
079: if (selModelMgr != null) {
080: selModelMgr.getListSelectionModel()
081: .removeListSelectionListener(this );
082: selModelMgr.dispose();
083: }
084: // No anulamos el selModelMgr para que se pueda recuperar el ListSelectionModel después de un dispose
085: }
086:
087: protected ParamTransport[] getParamTransports(String type) {
088: if (type.equals("change")) {
089: // En selección múltiple el selectedIndex sirve de muy poco (o nada) por ejemplo
090: // cuando se selecciona/deselecciona con la tecla CTRL o SHIFT pulsada
091: // La mejor manera es traerse el estado de todos los elementos
092: CustomParamTransport selectedIndexes = new CustomParamTransport(
093: "selectedIndexes",
094: "itsNatDoc.getSelectedHTMLSelect(this.getCurrentTarget())");
095: return new ParamTransport[] { selectedIndexes };
096: } else
097: return null;
098: }
099:
100: public void handleEventOnChange(Event evt) {
101: // Ejecutado como respuesta al evento "change" en el SELECT en el navegador
102: // El <select multiple="multiple"> permite múltiple selección
103: // En selección múltiple no sabemos cuales fueron seleccionados/quitados
104: // por eso nos bajamos una foto del estado actual del componente
105: // esto no garantiza que quede así pues el ListSelectionModel tiene
106: // la última palabra según el modo de selección, a partir de la detección
107: // de los cambios habidos obtendremos el estado final
108:
109: // NO hacemos setServerUpdatingFromClient(true) porque necesitamos
110: // que el servidor propague al cliente los que verdaderamente han de quedar seleccionados
111: // que puede diferir de lo que hay en el cliente cuando se genera el evento
112:
113: DOMEvent itsNatEvent = (DOMEvent) evt;
114: String indexesStr = (String) itsNatEvent
115: .getExtraParam("selectedIndexes");
116:
117: int[] indices;
118: if (indexesStr.length() > 0) // El split(",") ante una cadena vacía también genera un item erroneamente
119: {
120: String[] indexesStrArr = indexesStr.split(",");
121: indices = new int[indexesStrArr.length];
122: for (int i = 0; i < indexesStrArr.length; i++) {
123: indices[i] = Integer.parseInt(indexesStrArr[i]);
124: }
125: } else
126: indices = new int[0];
127:
128: selModelMgr.setSelectedIndices(indices);
129: }
130:
131: public ItsNatListMultSelUI getItsNatListMultSelUI() {
132: return (ItsNatListMultSelUI) compUI;
133: }
134:
135: public Object createDefaultModelInternal() {
136: return createDefaultListModel();
137: }
138:
139: public ListModel createDefaultListModel() {
140: return new DefaultListModel();
141: }
142:
143: public ItsNatListMultSelUI createDefaultItsNatHTMLSelectMultUI() {
144: return new ItsNatHTMLSelectMultUIImpl(this );
145: }
146:
147: public ItsNatComponentUI createDefaultItsNatComponentUI() {
148: return createDefaultItsNatHTMLSelectMultUI();
149: }
150:
151: public ListModel getListModel() {
152: return (ListModel) dataModel;
153: }
154:
155: public void setListModel(ListModel dataModel) {
156: setDataModel(dataModel);
157: }
158:
159: public void setListData(Object[] listData) {
160: ItsNatListMultSelSharedImpl.setListData(this , listData);
161: }
162:
163: public void setListData(List listData) {
164: ItsNatListMultSelSharedImpl.setListData(this , listData);
165: }
166:
167: public ListSelectionModelMgrImpl getListSelectionModelMgr() {
168: return selModelMgr;
169: }
170:
171: public ListSelectionModel getListSelectionModel() {
172: if (selModelMgr == null)
173: return null;
174: return selModelMgr.getListSelectionModel();
175: }
176:
177: public void setListSelectionModel(ListSelectionModel selectionModel) {
178: unsetListSelectionModel();
179:
180: this .selModelMgr = ItsNatListMultSelSharedImpl
181: .setSelectionModel(this , selectionModel);
182:
183: // A partir de ahora los cambios en la selección se notificarán al DOM
184: // pues hemos de cambiar el atributo selected
185: selectionModel.addListSelectionListener(this );
186: }
187:
188: public void valueChanged(ListSelectionEvent e) {
189: // Ha habido un cambio en la selección a través del SelectionModel
190: // necesitamos sincronizar el DOM de acuerdo al mismo, pues el DOM
191: // es el que manifiesta visualmente la selección
192: // No llamamos a disableSendCodeToRequesterIfServerUpdating()/enableSendCodeToRequester
193: // porque es el servidor y no el cliente el que decide qué elementos al final estarán seleccionados
194: // por lo que no hay el caso de actualización del servidor respecto al cliente sin más
195: // puede haber redundancia (re-seleccionar algunos elmentos en el cliente ya seleccionados) pero se asume.
196: ListSelectionModel selModel = (ListSelectionModel) e
197: .getSource();
198: if (selModel.getValueIsAdjusting())
199: return;
200:
201: int first = e.getFirstIndex();
202: int last = e.getLastIndex();
203:
204: ItsNatListMultSelUI compUI = getItsNatListMultSelUI();
205:
206: for (int i = first; i <= last; i++) {
207: boolean selected = selModel.isSelectedIndex(i);
208: compUI.setSelectedIndex(i, selected);
209: }
210: }
211:
212: public int getSelectedIndex() {
213: return getListSelectionModel().getMinSelectionIndex();
214: }
215:
216: public void setSelectedIndex(int index) {
217: getListSelectionModel().setSelectionInterval(index, index);
218: }
219:
220: public int[] getSelectedIndices() {
221: return selModelMgr.getSelectedIndices();
222: }
223:
224: public void setSelectedIndices(int[] indices) {
225: selModelMgr.setSelectedIndices(indices);
226: }
227:
228: public void contentsChanged(ListDataEvent e) {
229: super .contentsChanged(e);
230:
231: ItsNatListMultSelSharedImpl.contentsChanged(this , e);
232: }
233:
234: public void syncWithDataModel() {
235: super .syncWithDataModel();
236:
237: ItsNatListMultSelSharedImpl.syncSelModelWithDataModel(this );
238: }
239:
240: public void insertElementAtInternal(int index, Object anObject) {
241: super .insertElementAtInternal(index, anObject);
242:
243: selModelMgr.insertElementUpdateModel(index);
244: }
245:
246: public void removeElementRangeInternal(int fromIndex, int toIndex) {
247: selModelMgr.removeRangeUpdateModel(fromIndex, toIndex);
248:
249: super .removeElementRangeInternal(fromIndex, toIndex);
250: }
251:
252: public void removeAllElementsInternal() {
253: if (selModelMgr != null) // Es null en el proceso de carga, es normal
254: selModelMgr.removeAllUpdateModel();
255:
256: super .removeAllElementsInternal();
257: }
258:
259: public boolean isCombo() {
260: return false;
261: }
262: }
|