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 { 167 if (field_2_regions == null) 168 { 169 field_2_regions = new ArrayList(10); 170 } 171 MergedRegion region = new MergedRegion(rowfrom, rowto, colfrom, 172 colto); 173 174 field_2_regions.add(region); 175 field_1_num_areas++; 176 return field_2_regions.size() - 1; 177 } 178 179 /** 180 * essentially unmerge the cells in the "area" stored at the passed in index 181 * @param area index 182 */ 183 184 public void removeAreaAt(int area) 185 { 186 field_2_regions.remove(area); 187 field_1_num_areas--; 188 } 189 190 /** 191 * return the MergedRegion at the given index. 192 * 193 * @return MergedRegion representing the area that is Merged (r1,c1 - r2,c2) 194 */ 195 196 public MergedRegion getAreaAt(int index) 197 { 198 return ( MergedRegion ) field_2_regions.get(index); 199 } 200 201 public int getRecordSize() 202 { 203 int retValue; 204 205 retValue = 6 + (8 * field_2_regions.size()); 206 return retValue; 207 } 208 209 public short getSid() 210 { 211 return sid; 212 } 213 214 public int serialize(int offset, byte [] data) 215 { 216 int recordsize = getRecordSize(); 217 int pos = 6; 218 219 LittleEndian.putShort(data, offset + 0, sid); 220 LittleEndian.putShort(data, offset + 2, ( short ) (recordsize - 4)); 221 LittleEndian.putShort(data, offset + 4, getNumAreas()); 222 for (int k = 0; k < getNumAreas(); k++) 223 { 224 MergedRegion region = getAreaAt(k); 225 226 LittleEndian.putShort(data, offset + pos, region.row_from); 227 pos += 2; 228 LittleEndian.putShort(data, offset + pos, region.row_to); 229 pos += 2; 230 LittleEndian.putShort(data, offset + pos, region.col_from); 231 pos += 2; 232 LittleEndian.putShort(data, offset + pos, region.col_to); 233 pos += 2; 234 } 235 return recordsize; 236 } 237 238 public String toString() 239 { 240 StringBuffer retval = new StringBuffer(); 241 242 retval.append("[MERGEDCELLS]").append("\n"); 243 retval.append(" .sid =").append(sid).append("\n"); 244 retval.append(" .numregions =").append(field_1_num_areas) 245 .append("\n"); 246 for (int k = 0; k < field_1_num_areas; k++) 247 { 248 MergedRegion region = ( MergedRegion ) field_2_regions.get(k); 249 250 retval.append(" .rowfrom =").append(region.row_from) 251 .append("\n"); 252 retval.append(" .colfrom =").append(region.col_from) 253 .append("\n"); 254 retval.append(" .rowto =").append(region.row_to) 255 .append("\n"); 256 retval.append(" .colto =").append(region.col_to) 257 .append("\n"); 258 } 259 retval.append("[MERGEDCELLS]").append("\n"); 260 return retval.toString(); 261 } 262 263 protected void validateSid(short id) 264 { 265 if (id != sid) 266 { 267 throw new RecordFormatException("NOT A MERGEDCELLS RECORD!! " 268 + id); 269 } 270 } 271 272 /** 273 * this is a low level representation of a MergedRegion of cells. It is an 274 * inner class because we do not want it used without reference to this class. 275 * 276 */ 277 278 public class MergedRegion 279 { 280 281 /** 282 * create a merged region all in one stroke. 283 */ 284 285 public MergedRegion(short row_from, short row_to, short col_from, 286 short col_to) 287 { 288 this.row_from = row_from; 289 this.row_to = row_to; 290 this.col_from = col_from; 291 this.col_to = col_to; 292 } 293 294 /** 295 * upper lefthand corner row 296 */ 297 298 public short row_from; 299 300 /** 301 * lower right hand corner row 302 */ 303 304 public short row_to; 305 306 /** 307 * upper right hand corner col 308 */ 309 310 public short col_from; 311 312 /** 313 * lower right hand corner col 314 */ 315 316 public short col_to; 317 } 318 } 319