1 2 /* ==================================================================== 3 * The Apache Software License, Version 1.1 4 * 5 * Copyright (c) 2002 The Apache Software Foundation. All rights 6 * reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 20 * 3. The end-user documentation included with the redistribution, 21 * if any, must include the following acknowledgment: 22 * "This product includes software developed by the 23 * Apache Software Foundation (http://www.apache.org/)." 24 * Alternately, this acknowledgment may appear in the software itself, 25 * if and wherever such third-party acknowledgments normally appear. 26 * 27 * 4. The names "Apache" and "Apache Software Foundation" and 28 * "Apache POI" must not be used to endorse or promote products 29 * derived from this software without prior written permission. For 30 * written permission, please contact apache@apache.org. 31 * 32 * 5. Products derived from this software may not be called "Apache", 33 * "Apache POI", nor may "Apache" appear in their name, without 34 * prior written permission of the Apache Software Foundation. 35 * 36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 39 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 42 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 43 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 44 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 45 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 46 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 47 * SUCH DAMAGE. 48 * ==================================================================== 49 * 50 * This software consists of voluntary contributions made by many 51 * individuals on behalf of the Apache Software Foundation. For more 52 * information on the Apache Software Foundation, please see 53 * <http://www.apache.org/>. 54 */ 55 56 package org.apache.poi.hssf.record; 57 58 import java.util.ArrayList; 59 60 import org.apache.poi.util.LittleEndian; 61 62 /** 63 * Title: Merged Cells Record<P> 64 * Description: Optional record defining a square area of cells to "merged" into 65 * one cell. <P> 66 * REFERENCE: NONE (UNDOCUMENTED PRESENTLY) <P> 67 * @author Andrew C. Oliver (acoliver at apache dot org) 68 * @version 2.0-pre 69 */ 70 71 public class MergeCellsRecord 72 extends Record 73 { 74 public final static short sid = 0xe5; 75 private short field_1_num_areas; 76 private ArrayList field_2_regions; 77 78 public MergeCellsRecord() 79 { 80 } 81 82 /** 83 * Constructs a MergedCellsRecord and sets its fields appropriately 84 * 85 * @param sid id must be 0xe5 or an exception will be throw upon validation 86 * @param size the size of the data area of the record 87 * @param data data of the record (should not contain sid/len) 88 */ 89 90 public MergeCellsRecord(short sid, short size, byte [] data) 91 { 92 super(sid, size, data); 93 } 94 95 /** 96 * Constructs a MergedCellsRecord and sets its fields appropriately 97 * 98 * @param sid id must be 0xe5 or an exception will be throw upon validation 99 * @param size the size of the data area of the record 100 * @param data data of the record (should not contain sid/len) 101 * @param offset the offset of the record's data 102 */ 103 104 public MergeCellsRecord(short sid, short size, byte [] data, int offset) 105 { 106 super(sid, size, data, offset); 107 } 108 109 protected void fillFields(byte [] data, short size, int offset) 110 { 111 field_1_num_areas = LittleEndian.getShort(data, 0 + offset); 112 field_2_regions = new ArrayList(field_1_num_areas + 10); 113 int pos = 2; 114 115 for (int k = 0; k < field_1_num_areas; k++) 116 { 117 MergedRegion region = 118 new MergedRegiongetShortLittleEndian .getShort(data, pos + offset), LittleEndian 119 .getShort(data, pos + 2 + offset), LittleEndian 120 .getShort(data, pos + 4 + offset), LittleEndian 121 .getShort(data, pos + 6 + offset)); 122 123 pos += 8; 124 field_2_regions.add(region); 125 } 126 } 127 128 /** 129 * get the number of merged areas. If this drops down to 0 you should just go 130 * ahead and delete the record. 131 * @return number of areas 132 */ 133 134 public short getNumAreas() 135 { 136 return field_1_num_areas; 137 } 138 139 /** 140 * set the number of merged areas. You do not need to call this if you use addArea, 141 * it will be incremented automatically or decremented when an area is removed. If 142 * you are setting this to 0 then you are a terrible person. Just remove the record. 143 * (just kidding about you being a terrible person..hehe) 144 * 145 * @param numareas number of areas 146 */ 147 148 public void setNumAreas(short numareas) 149 { 150 field_1_num_areas = numareas; 151 } 152 153 /** 154 * Add an area to consider a merged cell. The index returned is only gauranteed to 155 * be correct provided you do not add ahead of or remove ahead of it (in which case 156 * you should increment or decrement appropriately....in other words its an arrayList) 157 * 158 * @param rowfrom - the upper left hand corner's row 159 * @param colfrom - the upper left hand corner's col 160 * @param rowto - the lower right hand corner's row 161 * @param colto - the lower right hand corner's col 162 * @return new index of said area (don't depend on it if you add/remove) 163 */ 164 165 //public int addArea(short rowfrom, short colfrom, short rowto, short colto) 166 public int addArea(int rowfrom, short colfrom, int rowto, short colto) 167 { 168 if (field_2_regions == null) 169 { 170 field_2_regions = new ArrayList(10); 171 } 172 MergedRegion region = new MergedRegion(rowfrom, rowto, colfrom, 173 colto); 174 175 field_2_regions.add(region); 176 field_1_num_areas++; 177 return field_2_regions.size() - 1; 178 } 179 180 /** 181 * essentially unmerge the cells in the "area" stored at the passed in index 182 * @param area index 183 */ 184 185 public void removeAreaAt(int area) 186 { 187 field_2_regions.remove(area); 188 field_1_num_areas--; 189 } 190 191 /** 192 * return the MergedRegion at the given index. 193 * 194 * @return MergedRegion representing the area that is Merged (r1,c1 - r2,c2) 195 */ 196 197 public MergedRegion getAreaAt(int index) 198 { 199 return ( MergedRegion ) field_2_regions.get(index); 200 } 201 202 public int getRecordSize() 203 { 204 int retValue; 205 206 retValue = 6 + (8 * field_2_regions.size()); 207 return retValue; 208 } 209 210 public short getSid() 211 { 212 return sid; 213 } 214 215 public int serialize(int offset, byte [] data) 216 { 217 int recordsize = getRecordSize(); 218 int pos = 6; 219 220 LittleEndian.putShort(data, offset + 0, sid); 221 LittleEndian.putShort(data, offset + 2, ( short ) (recordsize - 4)); 222 LittleEndian.putShort(data, offset + 4, getNumAreas()); 223 for (int k = 0; k < getNumAreas(); k++) 224 { 225 MergedRegion region = getAreaAt(k); 226 227 //LittleEndian.putShort(data, offset + pos, region.row_from); 228 LittleEndian.putShort(data, offset + pos, ( short ) region.row_from); 229 pos += 2; 230 //LittleEndian.putShort(data, offset + pos, region.row_to); 231 LittleEndian.putShort(data, offset + pos, ( short ) region.row_to); 232 pos += 2; 233 LittleEndian.putShort(data, offset + pos, region.col_from); 234 pos += 2; 235 LittleEndian.putShort(data, offset + pos, region.col_to); 236 pos += 2; 237 } 238 return recordsize; 239 } 240 241 public String toString() 242 { 243 StringBuffer retval = new StringBuffer(); 244 245 retval.append("[MERGEDCELLS]").append("\n"); 246 retval.append(" .sid =").append(sid).append("\n"); 247 retval.append(" .numregions =").append(field_1_num_areas) 248 .append("\n"); 249 for (int k = 0; k < field_1_num_areas; k++) 250 { 251 MergedRegion region = ( MergedRegion ) field_2_regions.get(k); 252 253 retval.append(" .rowfrom =").append(region.row_from) 254 .append("\n"); 255 retval.append(" .colfrom =").append(region.col_from) 256 .append("\n"); 257 retval.append(" .rowto =").append(region.row_to) 258 .append("\n"); 259 retval.append(" .colto =").append(region.col_to) 260 .append("\n"); 261 } 262 retval.append("[MERGEDCELLS]").append("\n"); 263 return retval.toString(); 264 } 265 266 protected void validateSid(short id) 267 { 268 if (id != sid) 269 { 270 throw new RecordFormatException("NOT A MERGEDCELLS RECORD!! " 271 + id); 272 } 273 } 274 275 /** 276 * this is a low level representation of a MergedRegion of cells. It is an 277 * inner class because we do not want it used without reference to this class. 278 * 279 */ 280 281 public class MergedRegion 282 { 283 284 /** 285 * create a merged region all in one stroke. 286 */ 287 288 //public MergedRegion(short row_from, short row_to, short col_from, 289 public MergedRegion(int row_from, int row_to, short col_from, 290 short col_to) 291 { 292 this.row_from = row_from; 293 this.row_to = row_to; 294 this.col_from = col_from; 295 this.col_to = col_to; 296 } 297 298 /** 299 * upper lefthand corner row 300 */ 301 302 //public short row_from; 303 public int row_from; 304 305 /** 306 * lower right hand corner row 307 */ 308 309 //public short row_to; 310 public int row_to; 311 312 /** 313 * upper right hand corner col 314 */ 315 316 public short col_from; 317 318 /** 319 * lower right hand corner col 320 */ 321 322 public short col_to; 323 } 324 } 325