001 /* 002 * Copyright (c) 2009 The openGion Project. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of 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, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 013 * either express or implied. See the License for the specific language 014 * governing permissions and limitations under the License. 015 */ 016 package org.opengion.hayabusa.db; 017 018 import org.opengion.hayabusa.common.HybsSystem; 019 import org.opengion.fukurou.util.LogWriter; 020 import org.opengion.fukurou.util.StringUtil; 021 022 import java.util.List; 023 import java.util.ArrayList; 024 025 /** 026 * DBTableModelを継承した TableModelのソート機?の実?ラスです? 027 * 028 * ViewFormのヘッ??リンクをクリ?すると、その?につ?再ソートします? 029 * これは、データベ?スではなく?メモリのDBTableModelにソート用のModel? 030 * 用意し、そのModelの行番号のみをソートし、行変換を行います? 031 * ソートを利用するかど?は、シス?パラメータ の、VIEW_USE_TABLE_SORTER 属?で 032 * ?します?(? シス?パラメータ では、false 設? 033 * ヘッ??部に表示するリンクは、command=VIEW&h_sortColumns=XXXXX で、カラ?を指定します? 034 * ※ h_sortColumns 部は、HybsSystemにて定義します?で?のJSPでは使用しな?下さ?? 035 * 036 * DBTableModel インターフェースは?データベ?スの検索結果(Resultset)をラ??する 037 * インターフェースとして使用して下さ?? 038 * 039 * @og.rev 3.5.4.7 (2004/02/06) 新規登録 040 * @og.group ??ブル管? 041 * 042 * @version 4.0 043 * @author Kazuhiko Hasegawa 044 * @since JDK5.0, 045 */ 046 public class DBTableModelSorter extends DBTableModelImpl { 047 private int[] indexes; 048 private int sortingColumn ; 049 private boolean ascending = true; 050 private int lastColumNo = -1; 051 private boolean isNumberType = false; // 3.5.6.3 (2004/07/12) 052 053 /** 054 * DBTableModel を設定し、このオブジェクトを初期化します? 055 * 056 * @param model DBTableModelオブジェク? 057 */ 058 public void setModel( final DBTableModel model ) { 059 DBTableModelImpl impl = (DBTableModelImpl)model; 060 dbColumns = impl.dbColumns; 061 names = impl.names; 062 data = impl.data; 063 rowHeader = impl.rowHeader; 064 columnMap = impl.columnMap; 065 overflow = impl.overflow; 066 numberOfColumns = impl.numberOfColumns; 067 068 // 3.5.5.5 (2004/04/23) 整合?キー(オブジェクト?作?時刻)追? 069 consistencyKey = impl.consistencyKey; 070 071 lastColumNo = -1; 072 reallocateIndexes(); 073 } 074 075 /** 076 * 行番号イン?クスを?期化します? 077 * 行番号をそのまま??番に設定します? 078 * 079 */ 080 private void reallocateIndexes() { 081 int rowCount = super.getRowCount(); 082 indexes = new int[rowCount]; 083 084 for(int row = 0; row < rowCount; row++) { 085 indexes[row] = row; 086 } 087 } 088 089 /** 090 * 同?ラ?号に対する、行1と行2?値の大小を比?ます? 091 * 比?に、そのカラ?、NUMBERタイプ?場合?、Double に変換後?数字として 092 * 比?ます?それ以外?場合?、文字?の比? row1の値.compareTo(s2) )の 093 * 値を返します? 094 * 095 * row1の値 < row2の値 : ? 096 * row1の値 > row2の値 : 正 097 * row1の値 == row2の値 : 0 098 * 099 * @og.rev 3.5.6.3 (2004/07/12) isNumberType 属?を使用する? 100 * 101 * @param row1 比??の行番号 102 * @param row2 比??の行番号 103 * @param column 比?るカラ?号 104 * 105 * @return 比?果[?0/正] 106 */ 107 private int compareRowsByColumn( final int row1, final int row2, final int column ) { 108 109 String s1 = super.getValue(row1, column); 110 String s2 = super.getValue(row2, column); 111 112 if( isNumberType ) { 113 // 3.5.6.3 (2004/07/12) 数字型で ゼロ??時?処? 114 if( s1.length() == 0 || s2.length() == 0 ) { 115 return ( s1.length() - s2.length() ); 116 } 117 118 double d1 = StringUtil.parseDouble( s1 ); 119 double d2 = StringUtil.parseDouble( s2 ); 120 121 // 注意:引き算をすると、桁あふれする可能性があるため?比?る? 122 if(d1 < d2) { return -1; } 123 else if(d1 > d2) { return 1; } 124 else { return 0; } 125 } 126 else { 127 return s1.compareTo(s2); 128 } 129 } 130 131 /** 132 * ???カラ?sortingColumn)に対する、行1と行2?値の大小を比?ます? 133 * 比????、compareRowsByColumn( int,int,int ) を使用します? 134 * ascending フラグ[true:??/false:降?] にしたがって、結果を反転します? 135 * 136 * ascending == true の? ascending == false の? 137 * row1の値 < row2の値 : ? 正 138 * row1の値 > row2の値 : 正 ? 139 * row1の値 == row2の値 : 0 0 140 * 141 * @param row1 比??の行番号 142 * @param row2 比??の行番号 143 * 144 * @return 比?果[?0/正] 145 * @see #compareRowsByColumn( int,int,int ) 146 */ 147 private int compare( final int row1, final int row2 ) { 148 int result = compareRowsByColumn(row1, row2, sortingColumn); 149 150 if(result != 0) { 151 return ascending ? result : -result; 152 } 153 return 0; 154 } 155 156 /** 157 * ソートする?部??タが不整合を起こして?かチェ?します? 158 * ?行番号と、テーブルオブジェクト?件数を比?ます? 159 * 160 * @og.rev 3.5.6.3 (2004/07/12) チェ?エラー時にアベンドせずに再設定する? 161 */ 162 private void checkModel() { 163 if(indexes.length != super.getRowCount()) { 164 String errMsg = "?行番号と、テーブルオブジェクト?件数が不??です? " + HybsSystem.CR 165 + "Index Length=[" + indexes.length + "] , Table Row Count=[" + super.getRowCount() + "]"; 166 LogWriter.log( errMsg ); 167 reallocateIndexes(); 168 } 169 } 170 171 /** 172 * ソート???トップメソ?です? 173 * 174 */ 175 private void sort() { 176 checkModel(); 177 178 reallocateIndexes(); 179 shuttlesort(indexes.clone(), indexes, 0, indexes.length); 180 181 int rowCount = indexes.length; 182 183 List<String[]> newData = new ArrayList<String[]>( rowCount ); 184 List<DBRowHeader> newRowHeader = new ArrayList<DBRowHeader>( rowCount ); 185 186 for( int row=0; row<rowCount; row++ ) { 187 newData.add( row,data.get( indexes[row] ) ); 188 newRowHeader.add( row,rowHeader.get( indexes[row] ) ); 189 } 190 data = newData; 191 rowHeader = newRowHeader; 192 } 193 194 /** 195 * シャトルソートを行います? 196 * 197 * @param from ソート?配? 198 * @param to ソート?配? 199 * @param low ?(下? 200 * @param high ?(上? 201 */ 202 private void shuttlesort( final int[] from, final int[] to, final int low, final int high ) { 203 if(high - low < 2) { 204 return; 205 } 206 int middle = (low + high) >>> 1; // widely publicized the bug pattern. 207 shuttlesort(to, from, low, middle); 208 shuttlesort(to, from, middle, high); 209 210 int pp = low; 211 int qq = middle; 212 213 if(high - low >= 4 && compare(from[middle-1], from[middle]) <= 0) { 214 for(int i = low; i < high; i++) { 215 to[i] = from[i]; 216 } 217 return; 218 } 219 220 for(int i = low; i < high; i++) { 221 if(qq >= high || (pp < middle && compare(from[pp], from[qq]) <= 0)) { 222 to[i] = from[pp++]; 223 } 224 else { 225 to[i] = from[qq++]; 226 } 227 } 228 } 229 230 /** 231 * カラ?ソート?トップメソ?です? 232 * ?ォルトで、??ートを行います? 233 * ?にソートしたカラ?同??カラ??された場合???と降?? 234 * 反転させて、?度ソートを行います?(シャトルソー? 235 * 236 * @param column カラ?号 237 */ 238 public void sortByColumn( final int column ) { 239 if( lastColumNo == column ) { 240 ascending = !ascending ; 241 } 242 else { 243 ascending = true; 244 } 245 sortByColumn( column,ascending ); 246 } 247 248 /** 249 * カラ?ソート?トップメソ?です? 250 * ascending フラグ[true:??/false:降?]を指定します? 251 * 252 * @og.rev 3.5.6.3 (2004/07/12) isNumberType 属?を設定する? 253 * @og.rev 4.0.0.0 (2005/01/31) getColumnClassName ??BColumから取得する? 254 * 255 * @param column カラ?号 256 * @param ascending ソート?方向[true:??/false:降?] 257 */ 258 public void sortByColumn( final int column, final boolean ascending ) { 259 this.ascending = ascending; 260 sortingColumn = column; 261 isNumberType = "NUMBER".equals( getDBColumn(sortingColumn).getClassName() ); 262 sort(); 263 lastColumNo = column; 264 } 265 266 /** 267 * ソート?方???:true/降?:false)を取得します? 268 * 269 * @return ソート?方?[true:??/false:降?] 270 */ 271 public boolean isAscending() { 272 return ascending; 273 } 274 }