View | Details | Raw Unified | Return to bug 58443
Collapse All | Expand All

(-)src/java/org/apache/poi/ss/util/CellRangeAddressBase.java (+32 lines)
Lines 17-23 Link Here
17
17
18
package org.apache.poi.ss.util;
18
package org.apache.poi.ss.util;
19
19
20
import java.awt.Rectangle;
21
20
import org.apache.poi.ss.SpreadsheetVersion;
22
import org.apache.poi.ss.SpreadsheetVersion;
23
import org.apache.poi.util.Internal;
21
24
22
25
23
/**
26
/**
Lines 123-128 Link Here
123
		return _firstRow <= rowInd && rowInd <= _lastRow &&
126
		return _firstRow <= rowInd && rowInd <= _lastRow &&
124
				_firstCol <= colInd && colInd <= _lastCol;
127
				_firstCol <= colInd && colInd <= _lastCol;
125
	}
128
	}
129
	
130
	/**
131
	 * Determines whether or not this CellRangeAddress and the specified CellRangeAddress intersect.
132
	 *
133
	 * @param other
134
	 * @return
135
	 */
136
	public boolean intersects(CellRangeAddress other) {
137
		// see java.awt.Rectangle.intersects
138
	    // http://stackoverflow.com/questions/13390333/two-rectangles-intersection
139
	    return getRectangle().intersects(other.getRectangle());
140
	}
141
	
142
	@Internal
143
	protected Rectangle getRectangle() {
144
        int firstRow = Math.min(_firstRow, _lastRow);
145
        int lastRow = Math.max(_firstRow,  _lastRow);
146
        int firstCol = Math.min(_firstCol, _lastCol);
147
        int lastCol = Math.max(_firstCol, _lastCol);
148
        if (isFullColumnRange()) {
149
            firstRow = 0;
150
            lastRow = Integer.MAX_VALUE;
151
        }
152
        if (isFullRowRange()) {
153
            firstCol = 0;
154
            lastCol = Integer.MAX_VALUE;
155
        }
156
        return new Rectangle(firstRow, firstCol, lastRow-firstRow+1, lastCol-firstCol+1);
157
	}
126
158
127
	/**
159
	/**
128
	 * @param firstCol column number for the upper left hand corner
160
	 * @param firstCol column number for the upper left hand corner
(-)src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java (-11 / +9 lines)
Lines 674-690 Link Here
674
    }
674
    }
675
675
676
    /**
676
    /**
677
     * @deprecated (Aug-2008) use <tt>CellRangeAddress</tt> instead of <tt>Region</tt>
678
     */
679
    public int addMergedRegion(org.apache.poi.ss.util.Region region) {
680
        return _sheet.addMergedRegion(region.getRowFrom(),
681
                region.getColumnFrom(),
682
                //(short) region.getRowTo(),
683
                region.getRowTo(),
684
                region.getColumnTo());
685
    }
686
687
    /**
688
     * adds a merged region of cells (hence those cells form one)
677
     * adds a merged region of cells (hence those cells form one)
689
     *
678
     *
690
     * @param region (rowfrom/colfrom-rowto/colto) to merge
679
     * @param region (rowfrom/colfrom-rowto/colto) to merge
Lines 696-701 Link Here
696
        // throw IllegalStateException if the argument CellRangeAddress intersects with
685
        // throw IllegalStateException if the argument CellRangeAddress intersects with
697
        // a multi-cell array formula defined in this sheet
686
        // a multi-cell array formula defined in this sheet
698
        validateArrayFormulas(region);
687
        validateArrayFormulas(region);
688
        
689
        // Throw IllegalStateException if the argument CellRangeAddress intersects with
690
        // a merged region already in this sheet
691
        for (final CellRangeAddress existingRegion : getMergedRegions()) {
692
            if (existingRegion.intersects(region)) {
693
                throw new IllegalStateException("Cannot add merged region " + region.formatAsString() +
694
                        " to sheet because it overlaps with an existing merged region (" + existingRegion.formatAsString() + ").");
695
            }
696
        }
699
697
700
        return _sheet.addMergedRegion(region.getFirstRow(),
698
        return _sheet.addMergedRegion(region.getFirstRow(),
701
                region.getFirstColumn(),
699
                region.getFirstColumn(),
(-)src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java (+11 lines)
Lines 325-330 Link Here
325
     *
325
     *
326
     * @param region (rowfrom/colfrom-rowto/colto) to merge
326
     * @param region (rowfrom/colfrom-rowto/colto) to merge
327
     * @return index of this region
327
     * @return index of this region
328
     * @throws IllegalStateException if region intersects with a multi-cell array formula
329
     * @throws IllegalStateException if region intersects with an existing region on this sheet
328
     */
330
     */
329
    @Override
331
    @Override
330
    public int addMergedRegion(CellRangeAddress region) {
332
    public int addMergedRegion(CellRangeAddress region) {
Lines 333-338 Link Here
333
        // throw IllegalStateException if the argument CellRangeAddress intersects with
335
        // throw IllegalStateException if the argument CellRangeAddress intersects with
334
        // a multi-cell array formula defined in this sheet
336
        // a multi-cell array formula defined in this sheet
335
        validateArrayFormulas(region);
337
        validateArrayFormulas(region);
338
        
339
        // Throw IllegalStateException if the argument CellRangeAddress intersects with
340
        // a merged region already in this sheet 
341
        for (final CellRangeAddress existingRegion: getMergedRegions()) {
342
            if (existingRegion.intersects(region)) {
343
                throw new IllegalStateException("Cannot add merged region " + region.formatAsString() +
344
                        " to sheet because it overlaps with an existing merged region (" + existingRegion.formatAsString() + ").");
345
            }
346
        }
336
347
337
        CTMergeCells ctMergeCells = worksheet.isSetMergeCells() ? worksheet.getMergeCells() : worksheet.addNewMergeCells();
348
        CTMergeCells ctMergeCells = worksheet.isSetMergeCells() ? worksheet.getMergeCells() : worksheet.addNewMergeCells();
338
        CTMergeCell ctMergeCell = ctMergeCells.addNewMergeCell();
349
        CTMergeCell ctMergeCell = ctMergeCells.addNewMergeCell();
(-)src/testcases/org/apache/poi/hssf/usermodel/TestWorkbook.java (-3 / +2 lines)
Lines 575-581 Link Here
575
        assertTrue("file exists",file.exists());
575
        assertTrue("file exists",file.exists());
576
    }
576
    }
577
577
578
    @SuppressWarnings("deprecation")
579
    public void testAddMergedRegionWithRegion() {
578
    public void testAddMergedRegionWithRegion() {
580
        HSSFWorkbook     wb   = new HSSFWorkbook();
579
        HSSFWorkbook     wb   = new HSSFWorkbook();
581
        HSSFSheet        s    = wb.createSheet();
580
        HSSFSheet        s    = wb.createSheet();
Lines 592-599 Link Here
592
                c.setCellValue(new HSSFRichTextString("TEST"));
591
                c.setCellValue(new HSSFRichTextString("TEST"));
593
            }
592
            }
594
        }
593
        }
595
        s.addMergedRegion(new Region(0, (short)0, 10, (short)10));
594
        s.addMergedRegion(new CellRangeAddress(0, 10, 0, 10));
596
        s.addMergedRegion(new Region(30, (short)5, 40, (short)15));
595
        s.addMergedRegion(new CellRangeAddress(30, 40, 5, 15));
597
        sanityChecker.checkHSSFWorkbook(wb);
596
        sanityChecker.checkHSSFWorkbook(wb);
598
        wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
597
        wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
599
598
(-)src/testcases/org/apache/poi/ss/usermodel/BaseTestBugzillaIssues.java (-1 / +1 lines)
Lines 143-149 Link Here
143
       Sheet template = wb.getSheetAt(0);
143
       Sheet template = wb.getSheetAt(0);
144
144
145
       template.addMergedRegion(new CellRangeAddress(0, 1, 0, 2));
145
       template.addMergedRegion(new CellRangeAddress(0, 1, 0, 2));
146
       template.addMergedRegion(new CellRangeAddress(1, 2, 0, 2));
146
       template.addMergedRegion(new CellRangeAddress(2, 3, 0, 2));
147
147
148
       Sheet clone = wb.cloneSheet(0);
148
       Sheet clone = wb.cloneSheet(0);
149
       int originalMerged = template.getNumMergedRegions();
149
       int originalMerged = template.getNumMergedRegions();
(-)src/testcases/org/apache/poi/ss/usermodel/BaseTestSheet.java (-2 / +42 lines)
Lines 287-292 Link Here
287
        }
287
        }
288
        assertEquals(1, sheet.getNumMergedRegions());
288
        assertEquals(1, sheet.getNumMergedRegions());
289
    }
289
    }
290
    
291
    /**
292
     * Dissallow creating wholly or partially overlapping merged regions
293
     * as this results in a corrupted workbook
294
     */
295
    @Test
296
    public void addOverlappingMergedRegions() {
297
        final Workbook wb = _testDataProvider.createWorkbook();
298
        final Sheet sheet = wb.createSheet();
299
        
300
        final CellRangeAddress baseRegion = new CellRangeAddress(0, 1, 0, 1);
301
        sheet.addMergedRegion(baseRegion);
302
        
303
        try {
304
            final CellRangeAddress duplicateRegion = new CellRangeAddress(0, 1, 0, 1);
305
            sheet.addMergedRegion(duplicateRegion);
306
            fail("Should not be able to add a merged region if sheet already contains the same merged region");
307
        } catch (final IllegalStateException e) { } //expected
308
        
309
        try {
310
            final CellRangeAddress partiallyOverlappingRegion = new CellRangeAddress(1, 2, 1, 2);
311
            sheet.addMergedRegion(partiallyOverlappingRegion);
312
            fail("Should not be able to add a merged region if it partially overlaps with an existing merged region");
313
        } catch (final IllegalStateException e) { } //expected
314
        
315
        try {
316
            final CellRangeAddress subsetRegion = new CellRangeAddress(0, 1, 0, 0);
317
            sheet.addMergedRegion(subsetRegion);
318
            fail("Should not be able to add a merged region if it is a formal subset of an existing merged region");
319
        } catch (final IllegalStateException e) { } //expected
320
        
321
        try {
322
            final CellRangeAddress supersetRegion = new CellRangeAddress(0, 2, 0, 2);
323
            sheet.addMergedRegion(supersetRegion);
324
            fail("Should not be able to add a merged region if it is a formal superset of an existing merged region");
325
        } catch (final IllegalStateException e) { } //expected
326
        
327
        final CellRangeAddress disjointRegion = new CellRangeAddress(10, 11, 10, 11);
328
        sheet.addMergedRegion(disjointRegion); //allowed
329
    }
290
330
291
    /**
331
    /**
292
     * When removing one merged region, it would break
332
     * When removing one merged region, it would break
Lines 298-310 Link Here
298
        Sheet sheet = wb.createSheet();
338
        Sheet sheet = wb.createSheet();
299
        CellRangeAddress region = new CellRangeAddress(0, 1, 0, 1);
339
        CellRangeAddress region = new CellRangeAddress(0, 1, 0, 1);
300
        sheet.addMergedRegion(region);
340
        sheet.addMergedRegion(region);
301
        region = new CellRangeAddress(1, 2, 0, 1);
341
        region = new CellRangeAddress(2, 3, 0, 1);
302
        sheet.addMergedRegion(region);
342
        sheet.addMergedRegion(region);
303
343
304
        sheet.removeMergedRegion(0);
344
        sheet.removeMergedRegion(0);
305
345
306
        region = sheet.getMergedRegion(0);
346
        region = sheet.getMergedRegion(0);
307
        assertEquals("Left over region should be starting at row 1", 1, region.getFirstRow());
347
        assertEquals("Left over region should be starting at row 2", 2, region.getFirstRow());
308
348
309
        sheet.removeMergedRegion(0);
349
        sheet.removeMergedRegion(0);
310
350
(-)src/testcases/org/apache/poi/ss/usermodel/BaseTestWorkbook.java (-6 / +6 lines)
Lines 447-453 Link Here
447
        sheet.createRow(0).createCell(0).setCellValue("Test");
447
        sheet.createRow(0).createCell(0).setCellValue("Test");
448
        sheet.createRow(1).createCell(0).setCellValue(36.6);
448
        sheet.createRow(1).createCell(0).setCellValue(36.6);
449
        sheet.addMergedRegion(new CellRangeAddress(0, 1, 0, 2));
449
        sheet.addMergedRegion(new CellRangeAddress(0, 1, 0, 2));
450
        sheet.addMergedRegion(new CellRangeAddress(1, 2, 0, 2));
450
        sheet.addMergedRegion(new CellRangeAddress(2, 3, 0, 2));
451
        assertTrue(sheet.isSelected());
451
        assertTrue(sheet.isSelected());
452
452
453
        Sheet clonedSheet = book.cloneSheet(0);
453
        Sheet clonedSheet = book.cloneSheet(0);
Lines 456-471 Link Here
456
        assertEquals(2, clonedSheet.getNumMergedRegions());
456
        assertEquals(2, clonedSheet.getNumMergedRegions());
457
        assertFalse(clonedSheet.isSelected());
457
        assertFalse(clonedSheet.isSelected());
458
458
459
        //cloned sheet is a deep copy, adding rows in the original does not affect the clone
459
        //cloned sheet is a deep copy, adding rows or merged regions in the original does not affect the clone
460
        sheet.createRow(2).createCell(0).setCellValue(1);
460
        sheet.createRow(2).createCell(0).setCellValue(1);
461
        sheet.addMergedRegion(new CellRangeAddress(0, 2, 0, 2));
461
        sheet.addMergedRegion(new CellRangeAddress(4, 5, 0, 2));
462
        assertEquals(2, clonedSheet.getPhysicalNumberOfRows());
462
        assertEquals(2, clonedSheet.getPhysicalNumberOfRows());
463
        assertEquals(2, clonedSheet.getPhysicalNumberOfRows());
463
        assertEquals(2, clonedSheet.getNumMergedRegions());
464
464
465
        clonedSheet.createRow(2).createCell(0).setCellValue(1);
465
        clonedSheet.createRow(2).createCell(0).setCellValue(1);
466
        clonedSheet.addMergedRegion(new CellRangeAddress(0, 2, 0, 2));
466
        clonedSheet.addMergedRegion(new CellRangeAddress(6, 7, 0, 2));
467
        assertEquals(3, clonedSheet.getPhysicalNumberOfRows());
467
        assertEquals(3, clonedSheet.getPhysicalNumberOfRows());
468
        assertEquals(3, clonedSheet.getPhysicalNumberOfRows());
468
        assertEquals(3, clonedSheet.getNumMergedRegions());
469
469
470
    }
470
    }
471
471
(-)src/testcases/org/apache/poi/ss/util/TestCellRangeAddress.java (+30 lines)
Lines 17-22 Link Here
17
17
18
package org.apache.poi.ss.util;
18
package org.apache.poi.ss.util;
19
19
20
import static org.junit.Assert.fail;
21
20
import java.io.ByteArrayOutputStream;
22
import java.io.ByteArrayOutputStream;
21
import java.io.IOException;
23
import java.io.IOException;
22
24
Lines 190-193 Link Here
190
        ref = new CellRangeAddress(-1, -1, -1, -1);
192
        ref = new CellRangeAddress(-1, -1, -1, -1);
191
        assertEquals(":", ref.formatAsString());
193
        assertEquals(":", ref.formatAsString());
192
    }
194
    }
195
    
196
    public void testIntersects() {
197
        final CellRangeAddress baseRegion = new CellRangeAddress(0, 1, 0, 1);
198
        
199
        final CellRangeAddress duplicateRegion = new CellRangeAddress(0, 1, 0, 1);
200
        assertIntersects(baseRegion, duplicateRegion);
201
        
202
        final CellRangeAddress partiallyOverlappingRegion = new CellRangeAddress(1, 2, 1, 2);
203
        assertIntersects(baseRegion, partiallyOverlappingRegion);
204
        
205
        final CellRangeAddress subsetRegion = new CellRangeAddress(0, 1, 0, 0);
206
        assertIntersects(baseRegion, subsetRegion);
207
    
208
        final CellRangeAddress supersetRegion = new CellRangeAddress(0, 2, 0, 2);
209
        assertIntersects(baseRegion, supersetRegion);
210
        
211
        final CellRangeAddress disjointRegion = new CellRangeAddress(10, 11, 10, 11);
212
        assertNotIntersects(baseRegion, disjointRegion);
213
    }
214
    
215
    private static void assertIntersects(CellRangeAddress regionA, CellRangeAddress regionB) {
216
        assertTrue(regionA.intersects(regionB));
217
        assertTrue(regionB.intersects(regionA));
218
    }
219
    private static void assertNotIntersects(CellRangeAddress regionA, CellRangeAddress regionB) {
220
        assertFalse(regionA.intersects(regionB));
221
        assertFalse(regionB.intersects(regionA));
222
    }
193
}
223
}

Return to bug 58443