001 /* 002 * Copyright 2002-2006 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 005 * use this file except in compliance with the License. You may obtain a copy of 006 * the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 013 * License for the specific language governing permissions and limitations under 014 * the License. 015 */ 016 package org.springframework.richclient.list; 017 018 import javax.swing.ListSelectionModel; 019 import javax.swing.event.ListSelectionEvent; 020 import javax.swing.event.ListSelectionListener; 021 022 import org.springframework.binding.value.support.AbstractValueModel; 023 024 /** 025 * Class to adapt the selection model of a list into a value model. This allows 026 * it to be used in conjunction with various Guard implementations. 027 * 028 * @author Larry Streepy 029 * @see ListSingleSelectionGuard 030 * @see ListMultipleSelectionGuard 031 */ 032 public class ListSelectionValueModelAdapter extends AbstractValueModel implements ListSelectionListener { 033 034 private ListSelectionModel model; 035 private int[] currentSelection = new int[0]; 036 private boolean skipSelectionModelUpdate = false; 037 038 /** 039 * Constructor. 040 * 041 * @param model selection model to adapt 042 */ 043 public ListSelectionValueModelAdapter( ListSelectionModel model ) { 044 this.model = model; 045 this.model.addListSelectionListener(this); 046 } 047 048 /* 049 * (non-Javadoc) 050 * 051 * @see javax.swing.event.ListSelectionListener#valueChanged(javax.swing.event.ListSelectionEvent) 052 */ 053 public void valueChanged( ListSelectionEvent e ) { 054 if( !e.getValueIsAdjusting() ) { 055 056 // We need to install this new value into the value model, but 057 // we don't want to propogate it back down to the adapted selection 058 // model (since we are responding to a change in that model). 059 skipSelectionModelUpdate = true; 060 setValue(getSelectedRows()); 061 skipSelectionModelUpdate = false; 062 } 063 } 064 065 /* 066 * (non-Javadoc) 067 * 068 * @see org.springframework.binding.value.ValueModel#getValue() 069 */ 070 public Object getValue() { 071 return currentSelection; 072 } 073 074 /** 075 * Set the selection value. 076 * 077 * @param newValue must be an integer array (int[]) 078 */ 079 public void setValue( Object newValue ) { 080 int[] newSelection = (int[]) newValue; 081 082 if( hasChanged(currentSelection, newSelection) ) { 083 084 int[] oldValue = currentSelection; 085 currentSelection = newSelection; 086 fireValueChange(oldValue, currentSelection); 087 088 if( !skipSelectionModelUpdate) { 089 // Don't want notifications while we do this 090 model.removeListSelectionListener(this); 091 092 // Install the selection on the adapted model 093 model.clearSelection(); 094 095 int i = 0; 096 int len = newSelection.length; 097 while( i < len ) { 098 int start = newSelection[i]; 099 while( i < len - 1 && newSelection[i] == newSelection[i + 1] - 1 ) { 100 i++; 101 } 102 int end = newSelection[i]; 103 model.addSelectionInterval(start, end); 104 i++; 105 } 106 107 // Reinstall listener 108 model.addListSelectionListener(this); 109 } 110 } 111 } 112 113 /** 114 * See if two arrays are different. 115 */ 116 private boolean hasChanged( int[] oldValue, int[] newValue ) { 117 if( oldValue.length == newValue.length ) { 118 for( int i = 0; i < newValue.length; i++ ) { 119 if( oldValue[i] != newValue[i] ) { 120 return true; 121 } 122 } 123 return false; 124 } 125 return true; 126 } 127 128 /** 129 * Returns the indices of all selected rows in the model. 130 * 131 * @return an array of integers containing the indices of all selected rows, 132 * or an empty array if no row is selected 133 */ 134 private int[] getSelectedRows() { 135 int iMin = model.getMinSelectionIndex(); 136 int iMax = model.getMaxSelectionIndex(); 137 138 if( (iMin == -1) || (iMax == -1) ) { 139 return new int[0]; 140 } 141 142 int[] rvTmp = new int[1 + (iMax - iMin)]; 143 int n = 0; 144 for( int i = iMin; i <= iMax; i++ ) { 145 if( model.isSelectedIndex(i) ) { 146 rvTmp[n++] = i; 147 } 148 } 149 int[] rv = new int[n]; 150 System.arraycopy(rvTmp, 0, rv, 0, n); 151 return rv; 152 } 153 }