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

(-)src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java (-40 / +544 lines)
Lines 18-28 Link Here
18
package org.apache.poi.xssf.usermodel;
18
package org.apache.poi.xssf.usermodel;
19
19
20
import java.io.IOException;
20
import java.io.IOException;
21
import java.io.InputStream;
21
import java.io.OutputStream;
22
import java.io.OutputStream;
22
import java.io.InputStream;
23
import java.util.ArrayList;
23
import java.util.*;
24
import java.util.Arrays;
25
import java.util.HashMap;
26
import java.util.Iterator;
27
import java.util.List;
28
import java.util.Map;
29
import java.util.TreeMap;
30
24
import javax.xml.namespace.QName;
31
import javax.xml.namespace.QName;
25
32
33
import org.apache.poi.POIXMLDocumentPart;
34
import org.apache.poi.POIXMLException;
26
import org.apache.poi.hssf.util.PaneInformation;
35
import org.apache.poi.hssf.util.PaneInformation;
27
import org.apache.poi.ss.usermodel.CellStyle;
36
import org.apache.poi.ss.usermodel.CellStyle;
28
import org.apache.poi.ss.usermodel.Footer;
37
import org.apache.poi.ss.usermodel.Footer;
Lines 31-50 Link Here
31
import org.apache.poi.ss.usermodel.Sheet;
40
import org.apache.poi.ss.usermodel.Sheet;
32
import org.apache.poi.ss.util.CellRangeAddress;
41
import org.apache.poi.ss.util.CellRangeAddress;
33
import org.apache.poi.ss.util.CellReference;
42
import org.apache.poi.ss.util.CellReference;
43
import org.apache.poi.util.POILogFactory;
44
import org.apache.poi.util.POILogger;
34
import org.apache.poi.xssf.model.CommentsTable;
45
import org.apache.poi.xssf.model.CommentsTable;
35
import org.apache.poi.xssf.usermodel.helpers.ColumnHelper;
46
import org.apache.poi.xssf.usermodel.helpers.ColumnHelper;
36
import org.apache.poi.POIXMLDocumentPart;
47
import org.apache.xmlbeans.XmlException;
37
import org.apache.poi.POIXMLException;
38
import org.apache.poi.util.POILogger;
39
import org.apache.poi.util.POILogFactory;
40
import org.apache.xmlbeans.XmlOptions;
48
import org.apache.xmlbeans.XmlOptions;
41
import org.apache.xmlbeans.XmlException;
49
import org.openxml4j.exceptions.InvalidFormatException;
42
import org.openxml4j.opc.PackagePart;
50
import org.openxml4j.opc.PackagePart;
43
import org.openxml4j.opc.PackageRelationship;
51
import org.openxml4j.opc.PackageRelationship;
44
import org.openxml4j.opc.PackageRelationshipCollection;
52
import org.openxml4j.opc.PackageRelationshipCollection;
45
import org.openxml4j.exceptions.InvalidFormatException;
46
import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
47
import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId;
53
import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId;
54
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBreak;
55
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol;
56
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols;
57
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDrawing;
58
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTHeaderFooter;
59
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTHyperlink;
60
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMergeCell;
61
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMergeCells;
62
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTOutlinePr;
63
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageBreak;
64
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageMargins;
65
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageSetUpPr;
66
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPane;
67
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPrintOptions;
68
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow;
69
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSelection;
70
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheet;
71
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetData;
72
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetFormatPr;
73
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetPr;
74
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetView;
75
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetViews;
76
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
77
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPane;
78
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPaneState;
79
import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorksheetDocument;
48
80
49
81
50
/**
82
/**
Lines 320-325 Link Here
320
     * Creates a split (freezepane). Any existing freezepane or split pane is overwritten.
352
     * Creates a split (freezepane). Any existing freezepane or split pane is overwritten.
321
     * @param colSplit	  Horizonatal position of split.
353
     * @param colSplit	  Horizonatal position of split.
322
     * @param rowSplit	  Vertical position of split.
354
     * @param rowSplit	  Vertical position of split.
355
     */
356
    public void createFreezePane(int colSplit, int rowSplit) {
357
        createFreezePane( colSplit, rowSplit, colSplit, rowSplit );
358
    } 
359
360
    
361
    /**
362
     * Creates a split (freezepane). Any existing freezepane or split pane is overwritten.
363
     * @param colSplit	  Horizonatal position of split.
364
     * @param rowSplit	  Vertical position of split.
323
     * @param topRow		Top row visible in bottom pane
365
     * @param topRow		Top row visible in bottom pane
324
     * @param leftmostColumn   Left column visible in right pane.
366
     * @param leftmostColumn   Left column visible in right pane.
325
     */
367
     */
Lines 344-358 Link Here
344
        CTSelection sel = ctView.addNewSelection();
386
        CTSelection sel = ctView.addNewSelection();
345
        sel.setPane(pane.getActivePane());
387
        sel.setPane(pane.getActivePane());
346
    }
388
    }
389
  
347
390
348
    /**
349
     * Creates a split (freezepane). Any existing freezepane or split pane is overwritten.
350
     * @param colSplit	  Horizonatal position of split.
351
     * @param rowSplit	  Vertical position of split.
352
     */
353
    public void createFreezePane(int colSplit, int rowSplit) {
354
        createFreezePane( colSplit, rowSplit, colSplit, rowSplit );
355
    }
356
391
357
    /**
392
    /**
358
     * Creates a new comment for this sheet. You still
393
     * Creates a new comment for this sheet. You still
Lines 388-407 Link Here
388
     * @param leftmostColumn   Left column visible in right pane.
423
     * @param leftmostColumn   Left column visible in right pane.
389
     * @param activePane	Active pane.  One of: PANE_LOWER_RIGHT,
424
     * @param activePane	Active pane.  One of: PANE_LOWER_RIGHT,
390
     *					  PANE_UPPER_RIGHT, PANE_LOWER_LEFT, PANE_UPPER_LEFT
425
     *					  PANE_UPPER_RIGHT, PANE_LOWER_LEFT, PANE_UPPER_LEFT
391
     * @see #PANE_LOWER_LEFT
426
     * @see org.apache.poi.ss.usermodel.Sheet#PANE_LOWER_LEFT
392
     * @see #PANE_LOWER_RIGHT
427
     * @see org.apache.poi.ss.usermodel.Sheet#PANE_LOWER_RIGHT
393
     * @see #PANE_UPPER_LEFT
428
     * @see org.apache.poi.ss.usermodel.Sheet#PANE_UPPER_LEFT
394
     * @see #PANE_UPPER_RIGHT
429
     * @see org.apache.poi.ss.usermodel.Sheet#PANE_UPPER_RIGHT
395
     */
430
     */
396
    public void createSplitPane(int xSplitPos, int ySplitPos, int leftmostColumn, int topRow, int activePane) {
431
    public void createSplitPane(int xSplitPos, int ySplitPos, int leftmostColumn, int topRow, int activePane) {
397
        createFreezePane(xSplitPos, ySplitPos, leftmostColumn, topRow);
432
        createFreezePane(xSplitPos, ySplitPos, leftmostColumn, topRow);
398
        getPane().setActivePane(STPane.Enum.forInt(activePane));
433
        getPane().setState(STPaneState.SPLIT);
399
    }
434
        getPane().setActivePane(STPane.Enum.forInt(activePane));        
400
435
    }    
436
    
401
    public XSSFComment getCellComment(int row, int column) {
437
    public XSSFComment getCellComment(int row, int column) {
402
        if (sheetComments == null) return null;
438
        if (sheetComments == null) return null;
403
        else return sheetComments.findCellComment(row, column);
439
        else return sheetComments.findCellComment(row, column);
404
    }
440
    }
441
    
405
442
406
    public XSSFHyperlink getHyperlink(int row, int column) {
443
    public XSSFHyperlink getHyperlink(int row, int column) {
407
        String ref = new CellReference(row, column).formatAsString();
444
        String ref = new CellReference(row, column).formatAsString();
Lines 1226-1241 Link Here
1226
    }
1263
    }
1227
1264
1228
    public void setColumnGroupCollapsed(short columnNumber, boolean collapsed) {
1265
    public void setColumnGroupCollapsed(short columnNumber, boolean collapsed) {
1229
        // TODO Auto-generated method stub
1266
	if (collapsed) {
1267
	    collapseColumn(columnNumber);
1268
	} else {
1269
	    expandColumn(columnNumber);
1270
	}
1271
    }
1230
1272
1273
    private void collapseColumn(short columnNumber){
1274
	CTCols cols=worksheet.getColsArray(0);
1275
	CTCol col=columnHelper.getColumn(columnNumber, false);
1276
	int colInfoIx = columnHelper.getIndexOfColumn(cols, col);
1277
	if (colInfoIx == -1) {
1278
	    return;
1279
	}
1280
	// Find the start of the group.
1281
	int groupStartColInfoIx = findStartOfColumnOutlineGroup(colInfoIx);
1282
1283
	CTCol columnInfo = cols.getColArray(groupStartColInfoIx);
1284
1285
	// Hide all the columns until the end of the group
1286
	int lastColMax = setGroupHidden(groupStartColInfoIx, columnInfo.getOutlineLevel(), true);
1287
1288
	//write collapse field	
1289
	setColumn((int)(lastColMax + 1), null,0, null, null, Boolean.TRUE);
1290
1231
    }
1291
    }
1232
1292
1233
    public void setRowGroupCollapsed(int row, boolean collapse) {
1234
        // TODO Auto-generated method stub
1235
1293
1294
    private void setColumn(int targetColumnIx, Short xfIndex, Integer style,Integer level, Boolean hidden, Boolean collapsed) {	    
1295
	CTCols cols=worksheet.getColsArray(0);
1296
	CTCol ci = null;
1297
	int k  = 0;
1298
	for (k = 0; k < cols.sizeOfColArray(); k++) {
1299
	    CTCol tci = cols.getColArray(k);
1300
	    if (tci.getMin()>=targetColumnIx && tci.getMax()<=targetColumnIx) {
1301
		ci = tci;
1302
		break;
1303
	    }
1304
	    if (tci.getMin() > targetColumnIx) {
1305
		// call column infos after k are for later columns
1306
		break; // exit now so k will be the correct insert pos
1307
	    }
1308
	}
1309
1310
	if (ci == null) {
1311
	    // okay so there ISN'T a column info record that covers this column so lets create one!
1312
	    CTCol nci = CTCol.Factory.newInstance();
1313
	    nci.setMin(targetColumnIx);
1314
	    nci.setMax(targetColumnIx);
1315
	    unsetCollapsed(collapsed,nci);
1316
	    this.columnHelper.addCleanColIntoCols(cols, nci);
1317
	    return;
1318
	}
1319
1320
	boolean styleChanged = style != null && ci.getStyle() != style.intValue();
1321
	boolean levelChanged = level != null && ci.getOutlineLevel() != level.intValue();
1322
	boolean hiddenChanged = hidden != null && ci.getHidden() != hidden.booleanValue();
1323
	boolean collapsedChanged = collapsed != null && ci.getCollapsed() != collapsed.booleanValue();
1324
	boolean columnChanged =   levelChanged || hiddenChanged || collapsedChanged || styleChanged;
1325
	if (!columnChanged) {
1326
	    // do nothing...nothing changed.
1327
	    return;
1328
	}
1329
1330
	if (ci.getMin() == targetColumnIx && ci.getMax() == targetColumnIx) {
1331
	    // ColumnInfo ci for a single column, the target column
1332
	   unsetCollapsed(collapsed,ci);
1333
	    return;
1334
	}
1335
1336
	if (ci.getMin() == targetColumnIx || ci.getMax() == targetColumnIx) {
1337
	    // The target column is at either end of the multi-column ColumnInfo ci
1338
	    // we'll just divide the info and create a new one
1339
	    if (ci.getMin() == targetColumnIx) {
1340
		ci.setMin(targetColumnIx + 1);
1341
	    } else {
1342
		ci.setMax(targetColumnIx - 1);
1343
		k++; // adjust insert pos to insert after
1344
	    }
1345
	    CTCol nci = columnHelper.cloneCol(cols,ci);
1346
	    nci.setMin(targetColumnIx);
1347
	    unsetCollapsed(collapsed, nci);
1348
	    this.columnHelper.addCleanColIntoCols(cols,nci);
1349
1350
	} 
1351
	else { 
1352
	    //split to 3 records
1353
	    CTCol ciStart = ci;
1354
	    CTCol ciMid = columnHelper.cloneCol(cols,ci);
1355
	    CTCol ciEnd = columnHelper.cloneCol(cols,ci);
1356
	    int lastcolumn = (int)ci.getMax();
1357
1358
	    ciStart.setMax(targetColumnIx - 1);
1359
1360
	    ciMid.setMin(targetColumnIx);
1361
	    ciMid.setMax(targetColumnIx);
1362
	    unsetCollapsed(collapsed, ciMid);
1363
	    this.columnHelper.addCleanColIntoCols(cols,ciMid);
1364
1365
	    ciEnd.setMin(targetColumnIx+1);
1366
	    ciEnd.setMax(lastcolumn);
1367
	    this.columnHelper.addCleanColIntoCols(cols,ciEnd);
1368
	}
1236
    }
1369
    }
1237
1370
1371
    private void unsetCollapsed(boolean collapsed, CTCol ci){
1372
	if(collapsed){
1373
	    ci.setCollapsed(collapsed);
1374
	}
1375
	else{
1376
	    ci.unsetCollapsed();
1377
	}
1378
    }
1379
1238
    /**
1380
    /**
1381
     * Sets all adjacent columns of the same outline level to the specified hidden status.
1382
     * @param pIdx the col info index of the start of the outline group
1383
     * @return the column index of the last column in the outline group
1384
     */
1385
    private int setGroupHidden(int pIdx, int level, boolean hidden) {
1386
	CTCols cols=worksheet.getColsArray(0);
1387
	int idx = pIdx;
1388
	CTCol columnInfo = cols.getColArray(idx);
1389
	while (idx < cols.sizeOfColArray()) {
1390
	    columnInfo.setHidden(hidden);
1391
	    if (idx + 1 < cols.sizeOfColArray()) {
1392
		CTCol nextColumnInfo = cols.getColArray(idx+1);
1393
1394
		if (!isAdjacentBefore(columnInfo,nextColumnInfo)) {
1395
		    break;
1396
		}
1397
1398
		if (nextColumnInfo.getOutlineLevel() < level) {
1399
		    break;
1400
		}
1401
		columnInfo = nextColumnInfo;
1402
	    }
1403
	    idx++;
1404
	}
1405
	return (int)columnInfo.getMax();
1406
    }
1407
1408
1409
    private boolean isAdjacentBefore(CTCol col,CTCol other_col) {
1410
	return (col.getMax() == (other_col.getMin() - 1));
1411
    }
1412
1413
    private int findStartOfColumnOutlineGroup(int pIdx) {
1414
	// Find the start of the group.
1415
	CTCols cols=worksheet.getColsArray(0);
1416
	CTCol columnInfo = cols.getColArray(pIdx);
1417
	int level = columnInfo.getOutlineLevel();
1418
	int idx = pIdx;
1419
	while (idx != 0) {
1420
	    CTCol prevColumnInfo = cols.getColArray(idx - 1);
1421
	    if (!isAdjacentBefore(prevColumnInfo,columnInfo)) {
1422
		break;
1423
	    }
1424
	    if (prevColumnInfo.getOutlineLevel() < level) {
1425
		break;
1426
	    }
1427
	    idx--;
1428
	    columnInfo = prevColumnInfo;
1429
	}
1430
	return idx;
1431
    }
1432
1433
    private int findEndOfColumnOutlineGroup(int colInfoIndex) {
1434
	CTCols cols=worksheet.getColsArray(0);
1435
	// Find the end of the group.
1436
	CTCol columnInfo = cols.getColArray(colInfoIndex);
1437
	int level = columnInfo.getOutlineLevel();
1438
	int idx = colInfoIndex;
1439
	while (idx < cols.sizeOfColArray() - 1) {
1440
	    CTCol nextColumnInfo = cols.getColArray(idx + 1);
1441
	    if (!isAdjacentBefore(columnInfo,nextColumnInfo)) {
1442
		break;
1443
	    }
1444
	    if (nextColumnInfo.getOutlineLevel() < level) {
1445
		break;
1446
	    }
1447
	    idx++;
1448
	    columnInfo = nextColumnInfo;
1449
	}
1450
	return idx;
1451
    }
1452
1453
1454
    private void expandColumn(int columnIndex) {
1455
	CTCols cols=worksheet.getColsArray(0);
1456
	CTCol col= columnHelper.getColumn(columnIndex, false);
1457
	int colInfoIx = columnHelper.getIndexOfColumn(cols, col);
1458
1459
	int idx = findColInfoIdx((int)col.getMax(), colInfoIx);
1460
	if (idx == -1) {
1461
	    return;
1462
	}
1463
1464
	// If it is already expanded do nothing.
1465
	if (!isColumnGroupCollapsed(idx)) {
1466
	    return;
1467
	}
1468
1469
	// Find the start/end of the group.
1470
	int startIdx = findStartOfColumnOutlineGroup(idx);
1471
	int endIdx = findEndOfColumnOutlineGroup(idx);
1472
1473
	// expand:
1474
	// colapsed bit must be unset
1475
	// hidden bit gets unset _if_ surrounding groups are expanded you can determine
1476
	//   this by looking at the hidden bit of the enclosing group.  You will have
1477
	//   to look at the start and the end of the current group to determine which
1478
	//   is the enclosing group
1479
	// hidden bit only is altered for this outline level.  ie.  don't uncollapse contained groups
1480
	CTCol columnInfo = cols.getColArray(endIdx);
1481
	if (!isColumnGroupHiddenByParent(idx)) {
1482
	    int outlineLevel = columnInfo.getOutlineLevel();
1483
	    boolean nestedGroup=false;
1484
	    for (int i = startIdx; i <= endIdx; i++) {
1485
		CTCol ci = cols.getColArray(i);
1486
		if (outlineLevel == ci.getOutlineLevel()){
1487
		    ci.unsetHidden();
1488
		    if(nestedGroup){
1489
			nestedGroup=false;
1490
			ci.setCollapsed(true);
1491
		    }
1492
		}
1493
		else{
1494
		    nestedGroup=true;
1495
		}
1496
	    }
1497
	}
1498
	// Write collapse flag (stored in a single col info record after this outline group)
1499
	setColumn((int)columnInfo.getMax() + 1, null, null, null, Boolean.FALSE, Boolean.FALSE);
1500
    }
1501
1502
    private boolean isColumnGroupHiddenByParent(int idx) {
1503
	CTCols cols=worksheet.getColsArray(0);
1504
	// Look out outline details of end
1505
	int endLevel = 0;
1506
	boolean endHidden = false;
1507
	int endOfOutlineGroupIdx = findEndOfColumnOutlineGroup( idx );
1508
	if (endOfOutlineGroupIdx < cols.sizeOfColArray()) {
1509
	    CTCol nextInfo = cols.getColArray(endOfOutlineGroupIdx + 1);
1510
	    if (isAdjacentBefore(cols.getColArray(endOfOutlineGroupIdx),nextInfo)) {
1511
		endLevel = nextInfo.getOutlineLevel();
1512
		endHidden = nextInfo.getHidden();
1513
	    }
1514
	}
1515
	// Look out outline details of start
1516
	int startLevel = 0;
1517
	boolean startHidden = false;
1518
	int startOfOutlineGroupIdx = findStartOfColumnOutlineGroup( idx );
1519
	if (startOfOutlineGroupIdx > 0) {
1520
	    CTCol prevInfo = cols.getColArray(startOfOutlineGroupIdx - 1);
1521
1522
	    if (isAdjacentBefore(prevInfo,cols.getColArray(startOfOutlineGroupIdx))) {
1523
		startLevel = prevInfo.getOutlineLevel();
1524
		startHidden = prevInfo.getHidden();
1525
	    }
1526
1527
	}
1528
	if (endLevel > startLevel) {
1529
	    return endHidden;
1530
	}
1531
	return startHidden;
1532
    }
1533
1534
1535
1536
    private int findColInfoIdx(int columnValue, int fromColInfoIdx) {
1537
	CTCols cols=worksheet.getColsArray(0);
1538
1539
	if (columnValue < 0) {
1540
	    throw new IllegalArgumentException( "column parameter out of range: " + columnValue );
1541
	}
1542
	if (fromColInfoIdx < 0) {
1543
	    throw new IllegalArgumentException( "fromIdx parameter out of range: " + fromColInfoIdx );
1544
	}
1545
1546
	for (int k = fromColInfoIdx; k < cols.sizeOfColArray(); k++) {
1547
	    CTCol ci = cols.getColArray(k);
1548
1549
	    if (containsColumn(ci,columnValue)) {
1550
		return k;
1551
	    }
1552
1553
	    if (ci.getMin() > fromColInfoIdx) {
1554
		break;
1555
	    }
1556
1557
	}
1558
	return -1;
1559
    }
1560
1561
    private boolean containsColumn(CTCol col,int columnIndex) {
1562
	return col.getMin() <= columnIndex && columnIndex <= col.getMax(); 
1563
    }
1564
1565
    /**
1566
     * 'Collapsed' state is stored in a single column col info record immediately after the outline group
1567
     * @param idx
1568
     * @return a boolean represented if the column is collapsed
1569
     */
1570
    private boolean isColumnGroupCollapsed(int idx) {
1571
	CTCols cols=worksheet.getColsArray(0);
1572
	int endOfOutlineGroupIdx = findEndOfColumnOutlineGroup(idx);
1573
	int nextColInfoIx = endOfOutlineGroupIdx+1;
1574
	if (nextColInfoIx >= cols.sizeOfColArray()) {
1575
	    return false;
1576
	}
1577
	CTCol nextColInfo = cols.getColArray(nextColInfoIx);
1578
1579
	CTCol col=cols.getColArray(endOfOutlineGroupIdx);
1580
	if (!isAdjacentBefore(col,nextColInfo)) {
1581
	    return false;
1582
	}
1583
1584
	return nextColInfo.getCollapsed();
1585
    }    
1586
1587
    /**
1239
     * Get the visibility state for a given column.
1588
     * Get the visibility state for a given column.
1240
     *
1589
     *
1241
     * @param columnIndex - the column to get (0-based)
1590
     * @param columnIndex - the column to get (0-based)
Lines 1327-1337 Link Here
1327
        opts.setHorizontalCentered(value);
1676
        opts.setHorizontalCentered(value);
1328
    }
1677
    }
1329
1678
1679
1330
    /**
1680
    /**
1331
     * Whether the output is vertically centered on the page.
1681
     * group the row
1332
     *
1682
     * It is possible for collapsed to be false and yet still have the rows in question hidden.
1333
     * @param value true to vertically center, false otherwise.
1683
     * This can be achieved by having a lower outline level collapsed, thus hiding all the child rows.
1684
     * Note that in this case, if the lowest level were expanded, the middle level would remain 
1685
     * collapsed.
1686
     * 
1687
     * @param rowIndex - the row involved 
1688
     * @param collapse - boolean value for collapse
1334
     */
1689
     */
1690
    public void setRowGroupCollapsed(int rowIndex, boolean collapse) {
1691
	if(collapse){
1692
	    collapseRow(rowIndex);
1693
	}
1694
	else{
1695
	    expandRow(rowIndex);
1696
	}
1697
    }
1698
1699
    private void collapseRow(int rowIndex){
1700
	XSSFRow row=getRow(rowIndex-1);
1701
	if(row!=null){
1702
	    int startRow=findStartOfRowOutlineGroup(rowIndex-1);
1703
1704
	    // Hide all the columns until the end of the group
1705
	    int lastRow = writeHidden( row, startRow, true );
1706
	    if (getRow(lastRow+1) != null){
1707
		getRow(lastRow+1).getCTRow().setCollapsed(true);
1708
	    }
1709
	    else{
1710
		XSSFRow newRow=createRow(lastRow+1);
1711
		newRow.getCTRow().setCollapsed(true);
1712
	    }
1713
	}
1714
    }
1715
1716
    private int findStartOfRowOutlineGroup(int rowIndex) {
1717
	// Find the start of the group.
1718
	int level = getRow( rowIndex ).getCTRow().getOutlineLevel();
1719
	int currentRow = rowIndex;
1720
	while (getRow( currentRow) != null){
1721
	    if (getRow( currentRow).getCTRow().getOutlineLevel() < level)
1722
		return currentRow+1;
1723
	    currentRow--;
1724
	}
1725
	return currentRow+1;
1726
    }
1727
1728
    private int writeHidden( XSSFRow xRow, int rowIndex, boolean hidden ) {
1729
	int level = xRow.getCTRow().getOutlineLevel();
1730
        for (Iterator<Row> it = rowIterator() ; it.hasNext() ; ) {
1731
	    xRow=(XSSFRow)it.next();
1732
	    if(xRow.getCTRow().getOutlineLevel() >= level){
1733
		xRow.getCTRow().setHidden( hidden );
1734
		rowIndex++;
1735
	    }
1736
1737
	}
1738
	return rowIndex;
1739
    }
1740
1741
    private void expandRow( int rowNumber ) {
1742
	int idx = rowNumber;
1743
	if (idx == -1)
1744
	    return;
1745
	XSSFRow row=getRow(rowNumber-1);
1746
	// If it is already expanded do nothing.
1747
	if (!row.getCTRow().isSetHidden())
1748
	    return;
1749
1750
	// Find the start of the group.
1751
	int startIdx = findStartOfRowOutlineGroup( idx - 1 );
1752
1753
	// Find the end of the group.
1754
	int endIdx = findEndOfRowOutlineGroup( idx -1);
1755
1756
	// expand:
1757
	// collapsed  must be unset
1758
	// hidden bit gets unset _if_ surrounding groups are expanded you can determine
1759
	//   this by looking at the hidden bit of the enclosing group.  You will have
1760
	//   to look at the start and the end of the current group to determine which
1761
	//   is the enclosing group
1762
	// hidden bit only is altered for this outline level.  ie.  don't un-collapse contained groups
1763
	if ( !isRowGroupHiddenByParent( idx -1) ) {
1764
	    for ( int i = startIdx; i < endIdx; i++ ) {        
1765
		if ( row.getCTRow().getOutlineLevel() == getRow( i ).getCTRow().getOutlineLevel() ){
1766
		    getRow( i ).getCTRow().unsetHidden();
1767
		}
1768
		else if (!isRowGroupCollapsed(i)){
1769
		    getRow( i ).getCTRow().unsetHidden();
1770
		}
1771
	    }
1772
	}
1773
	// Write collapse field
1774
	getRow( endIdx + 1 ).getCTRow().unsetCollapsed();
1775
    }
1776
1777
    public int findEndOfRowOutlineGroup( int row ) {
1778
	int level = getRow( row ).getCTRow().getOutlineLevel();
1779
	int currentRow;
1780
	for (currentRow = row; currentRow < getLastRowNum(); currentRow++) {
1781
	    if (getRow(currentRow) == null || getRow(currentRow).getCTRow().getOutlineLevel() < level) {
1782
		break;
1783
	    }
1784
	}
1785
	return currentRow;
1786
    }
1787
    
1788
    private boolean isRowGroupHiddenByParent( int row ) {
1789
        // Look out outline details of end
1790
        int endLevel;
1791
        boolean endHidden;
1792
        int endOfOutlineGroupIdx = findEndOfRowOutlineGroup( row );
1793
        if (getRow( endOfOutlineGroupIdx + 1 ) == null) {
1794
            endLevel = 0;
1795
            endHidden = false;
1796
        }
1797
        else {
1798
            endLevel = (int)(getRow( endOfOutlineGroupIdx + 1).getCTRow().getOutlineLevel());
1799
            endHidden = getRow( endOfOutlineGroupIdx + 1).getCTRow().getHidden();
1800
        }
1801
1802
        // Look out outline details of start
1803
        int startLevel;
1804
        boolean startHidden;
1805
        int startOfOutlineGroupIdx = findStartOfRowOutlineGroup( row );
1806
        if (startOfOutlineGroupIdx - 1 < 0 || getRow(startOfOutlineGroupIdx - 1) == null) {
1807
            startLevel = 0;
1808
            startHidden = false;
1809
        }
1810
        else {
1811
            startLevel = getRow( startOfOutlineGroupIdx - 1).getCTRow().getOutlineLevel();
1812
            startHidden = getRow( startOfOutlineGroupIdx - 1 ).getCTRow().getHidden();
1813
        }
1814
        if (endLevel > startLevel){
1815
            return endHidden;
1816
        }
1817
        else {
1818
            return startHidden;
1819
        }
1820
    }
1821
1822
    private boolean isRowGroupCollapsed( int row ) {
1823
        int collapseRow = findEndOfRowOutlineGroup( row ) + 1;
1824
        if (getRow(collapseRow) == null)
1825
            return false;
1826
        else
1827
            return getRow( collapseRow ).getCTRow().getCollapsed();
1828
    }
1829
1830
    
1335
    public void setVerticallyCenter(boolean value) {
1831
    public void setVerticallyCenter(boolean value) {
1336
        CTPrintOptions opts = worksheet.isSetPrintOptions() ?
1832
        CTPrintOptions opts = worksheet.isSetPrintOptions() ?
1337
                worksheet.getPrintOptions() : worksheet.addNewPrintOptions();
1833
                worksheet.getPrintOptions() : worksheet.addNewPrintOptions();
Lines 1416-1422 Link Here
1416
            if (!copyRowHeight) {
1912
            if (!copyRowHeight) {
1417
                row.setHeight((short)-1);
1913
                row.setHeight((short)-1);
1418
            }
1914
            }
1419
1420
            if (resetOriginalRowHeight && getDefaultRowHeight() >= 0) {
1915
            if (resetOriginalRowHeight && getDefaultRowHeight() >= 0) {
1421
                row.setHeight(getDefaultRowHeight());
1916
                row.setHeight(getDefaultRowHeight());
1422
            }
1917
            }
Lines 1425-1430 Link Here
1425
            }
1920
            }
1426
            else if (row.getRowNum() >= startRow && row.getRowNum() <= endRow) {
1921
            else if (row.getRowNum() >= startRow && row.getRowNum() <= endRow) {
1427
                row.setRowNum(row.getRowNum() + n);
1922
                row.setRowNum(row.getRowNum() + n);
1923
1924
         	modifyCellReference((XSSFRow)row);
1925
1428
                if (row.getFirstCellNum() > -1) {
1926
                if (row.getFirstCellNum() > -1) {
1429
                    modifyCellReference((XSSFRow) row);
1927
                    modifyCellReference((XSSFRow) row);
1430
                }
1928
                }
Lines 1437-1451 Link Here
1437
    }
1935
    }
1438
1936
1439
1937
1440
    private void modifyCellReference(XSSFRow row) {
1938
    private void modifyCellReference(XSSFRow row){
1441
        for (int i = row.getFirstCellNum(); i <= row.getLastCellNum(); i++) {
1939
	int firstCellNum=row.getFirstCellNum();
1442
            XSSFCell c = row.getCell(i);
1940
	//a row could have no cell
1443
            if (c != null) {
1941
	if(firstCellNum != -1){
1444
                c.modifyCellReference(row);
1942
	    for(int i=firstCellNum;i<=row.getLastCellNum();i++){
1445
            }
1943
		XSSFCell c=(XSSFCell)row.getCell(i);
1446
        }
1944
		if(c!=null){
1945
		    c.modifyCellReference(row);
1946
		}
1947
	    }
1948
	}
1447
    }
1949
    }
1448
1950
    
1951
    
1449
    /**
1952
    /**
1450
     * Location of the top left visible cell Location of the top left visible cell in the bottom right
1953
     * Location of the top left visible cell Location of the top left visible cell in the bottom right
1451
     * pane (when in Left-to-Right mode).
1954
     * pane (when in Left-to-Right mode).
Lines 1456-1462 Link Here
1456
    public void showInPane(short toprow, short leftcol) {
1959
    public void showInPane(short toprow, short leftcol) {
1457
        CellReference cellReference = new CellReference(toprow, leftcol);
1960
        CellReference cellReference = new CellReference(toprow, leftcol);
1458
        String cellRef = cellReference.formatAsString();
1961
        String cellRef = cellReference.formatAsString();
1459
        getSheetTypeSheetView().setTopLeftCell(cellRef);
1962
    //    getSheetTypeSheetView().setTopLeftCell(cellRef);
1963
        getPane().setTopLeftCell(cellRef);
1460
    }
1964
    }
1461
1965
1462
    public void ungroupColumn(short fromColumn, short toColumn) {
1966
    public void ungroupColumn(short fromColumn, short toColumn) {
(-)src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java (+124 lines)
Lines 18-23 Link Here
18
package org.apache.poi.xssf.usermodel;
18
package org.apache.poi.xssf.usermodel;
19
19
20
import java.io.File;
20
import java.io.File;
21
import java.io.FileOutputStream;
21
import java.util.Iterator;
22
import java.util.Iterator;
22
import junit.framework.TestCase;
23
import junit.framework.TestCase;
23
import org.apache.poi.ss.usermodel.Cell;
24
import org.apache.poi.ss.usermodel.Cell;
Lines 852-861 Link Here
852
853
853
854
854
    public void testSetColumnGroupCollapsed(){
855
    public void testSetColumnGroupCollapsed(){
856
	Workbook wb = new XSSFWorkbook();
857
	XSSFSheet sheet1 =(XSSFSheet) wb.createSheet();
858
	sheet1.groupColumn( (short)4, (short)7 );
859
	sheet1.groupColumn( (short)9, (short)12 );
860
	sheet1.groupColumn( (short)10, (short)11 );
855
	
861
	
862
	CTCols cols=sheet1.getCTWorksheet().getColsArray(0);
863
	assertEquals(4,cols.sizeOfColArray());
864
865
	// collapse columns - 1
866
	sheet1.setColumnGroupCollapsed( (short)5, true );
867
	assertEquals(5,cols.sizeOfColArray());
868
	assertEquals(true,cols.getColArray(0).isSetHidden());
869
	assertEquals(false,cols.getColArray(0).isSetCollapsed());
870
		
871
	assertEquals(9,cols.getColArray(1).getMin());
872
	assertEquals(false,cols.getColArray(1).getHidden());
873
	//assertEquals(false,cols.getColArray(1).isSetHidden()); ERRORE    why???????
874
	assertEquals(true,cols.getColArray(1).isSetCollapsed());
875
876
	assertEquals(false,cols.getColArray(2).getHidden());
877
//	assertEquals(false,cols.getColArray(2).isSetHidden());  ERRORE
878
	assertEquals(false,cols.getColArray(2).isSetCollapsed());
879
	
880
	
881
	// expande columns - 1
882
	sheet1.setColumnGroupCollapsed( (short)5, false );
883
	
884
	assertEquals(5,cols.sizeOfColArray());
885
	assertEquals(false,cols.getColArray(0).getHidden());
886
	assertEquals(false,cols.getColArray(1).getHidden());
887
	assertEquals(false,cols.getColArray(1).isSetCollapsed());
888
	assertEquals(9,cols.getColArray(1).getMin());
889
	
890
891
	//collapse - 2
892
	sheet1.setColumnGroupCollapsed( (short)9, true );
893
	assertEquals(6,cols.sizeOfColArray());
894
	assertEquals(true,cols.getColArray(1).isSetHidden());
895
	assertEquals(false,cols.getColArray(1).isSetCollapsed());
896
		
897
	assertEquals(10,cols.getColArray(2).getMin());
898
	assertEquals(false,cols.getColArray(5).getHidden());
899
	assertEquals(true,cols.getColArray(5).isSetCollapsed());
900
901
902
	//expand - 2
903
	sheet1.setColumnGroupCollapsed( (short)9, false );
904
	assertEquals(6,cols.sizeOfColArray());
905
	assertEquals(14,cols.getColArray(5).getMin());
906
	
907
	assertEquals(false,cols.getColArray(0).getHidden());
908
	assertEquals(false,cols.getColArray(2).getHidden());
909
	assertEquals(false,cols.getColArray(2).isSetCollapsed());
910
	assertEquals(10,cols.getColArray(2).getMin());
911
	//outline level 2: the line under ==> collapsed==True
912
	assertEquals(2,cols.getColArray(3).getOutlineLevel());
913
	assertEquals(true,cols.getColArray(4).isSetCollapsed());
914
915
	//DOCUMENTARE MEGLIO IL DISCORSO DEL LIVELLO
916
	//collapse - 3
917
	sheet1.setColumnGroupCollapsed( (short)10, true );
918
	assertEquals(6,cols.sizeOfColArray());
919
	assertEquals(true,cols.getColArray(3).getHidden());
920
	assertEquals(false,cols.getColArray(3).isSetCollapsed());
921
	assertEquals(false,cols.getColArray(4).getHidden());
922
	assertEquals(true,cols.getColArray(4).isSetCollapsed());
923
924
	assertEquals(false,cols.getColArray(0).getHidden());
925
	assertEquals(false,cols.getColArray(0).isSetCollapsed());
926
	
927
	
928
	//expand - 3
929
	sheet1.setColumnGroupCollapsed( (short)10, false );
930
	assertEquals(6,cols.sizeOfColArray());
931
	assertEquals(false,cols.getColArray(0).getHidden());
932
	assertEquals(false,cols.getColArray(5).getHidden());
933
	assertEquals(false,cols.getColArray(4).isSetCollapsed());
934
	
935
//write out and give back
936
	// Save and re-load
937
	wb = XSSFTestDataSamples.writeOutAndReadBack(wb);
938
	sheet1 = (XSSFSheet)wb.getSheetAt(0);
939
	assertEquals(6,cols.sizeOfColArray());
940
	assertEquals(false,cols.getColArray(0).getHidden());
941
	assertEquals(false,cols.getColArray(5).getHidden());
942
	assertEquals(false,cols.getColArray(4).isSetCollapsed());
856
    }
943
    }
857
    
944
    
945
    public void testSetRowGroupCollapsed(){
946
	Workbook wb = new XSSFWorkbook();
947
	XSSFSheet sheet1 = (XSSFSheet)wb.createSheet();
858
948
949
	sheet1.groupRow( 5, 14 );
950
	sheet1.groupRow( 7, 14 );
951
	sheet1.groupRow( 16, 19 );
952
	
953
    	assertEquals(14,sheet1.getPhysicalNumberOfRows());	
954
	//collapsed
955
	sheet1.setRowGroupCollapsed( 7, true );	
956
    	
957
	assertEquals(false,sheet1.getRow(6).getCTRow().isSetCollapsed());
958
	assertEquals(true,sheet1.getRow(6).getCTRow().isSetHidden());
959
	assertEquals(true,sheet1.getRow(15).getCTRow().isSetCollapsed());
960
	assertEquals(false,sheet1.getRow(15).getCTRow().isSetHidden());
961
	assertEquals(false,sheet1.getRow(16).getCTRow().isSetCollapsed());
962
	assertEquals(false,sheet1.getRow(16).getCTRow().isSetHidden());
963
		
964
	//expanded
965
	sheet1.setRowGroupCollapsed( 7, false );
966
	assertEquals(false,sheet1.getRow(6).getCTRow().isSetCollapsed());
967
	assertEquals(false,sheet1.getRow(6).getCTRow().isSetHidden());
968
	assertEquals(false,sheet1.getRow(15).getCTRow().isSetCollapsed());
969
	assertEquals(false,sheet1.getRow(15).getCTRow().isSetHidden());
970
971
972
	// Save and re-load
973
	wb = XSSFTestDataSamples.writeOutAndReadBack(wb);
974
	sheet1 = (XSSFSheet)wb.getSheetAt(0);
975
	
976
	assertEquals(false,sheet1.getRow(6).getCTRow().isSetCollapsed());
977
	assertEquals(false,sheet1.getRow(6).getCTRow().isSetHidden());
978
	assertEquals(false,sheet1.getRow(15).getCTRow().isSetCollapsed());
979
	assertEquals(false,sheet1.getRow(15).getCTRow().isSetHidden());
980
	
981
}
982
859
    public void testColumnWidthCompatibility() {
983
    public void testColumnWidthCompatibility() {
860
        Workbook wb1 = new HSSFWorkbook();
984
        Workbook wb1 = new HSSFWorkbook();
861
        Workbook wb2 = new XSSFWorkbook();
985
        Workbook wb2 = new XSSFWorkbook();
(-)src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/ColumnHelper.java (-1 / +4 lines)
Lines 223-231 Link Here
223
    	toCol.setHidden(fromCol.getHidden());
223
    	toCol.setHidden(fromCol.getHidden());
224
    	toCol.setBestFit(fromCol.getBestFit());
224
    	toCol.setBestFit(fromCol.getBestFit());
225
        toCol.setStyle(fromCol.getStyle());
225
        toCol.setStyle(fromCol.getStyle());
226
        if(fromCol.getOutlineLevel()!=0){
226
        if(fromCol.isSetOutlineLevel()){
227
        	toCol.setOutlineLevel(fromCol.getOutlineLevel());
227
        	toCol.setOutlineLevel(fromCol.getOutlineLevel());
228
        }
228
        }
229
        if(fromCol.isSetCollapsed()){
230
            toCol.setCollapsed(true);
231
        }
229
    }
232
    }
230
233
231
    public void setColBestFit(long index, boolean bestFit) {
234
    public void setColBestFit(long index, boolean bestFit) {
(-)src/examples/src/org/apache/poi/xssf/usermodel/examples/Outlining.java (+58 lines)
Line 0 Link Here
1
package org.apache.poi.xssf.usermodel.examples;
2
3
import java.io.FileOutputStream;
4
5
import org.apache.poi.ss.usermodel.Sheet;
6
import org.apache.poi.ss.usermodel.Workbook;
7
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
8
9
public class Outlining {
10
11
    public static void main(String[]args) throws Exception{
12
	Outlining o=new Outlining();
13
	o.groupRowColumn();
14
	o.collapseExpandRowColumn();
15
    }
16
17
18
    private void groupRowColumn() throws Exception{
19
	Workbook wb = new XSSFWorkbook();
20
	Sheet sheet1 = wb.createSheet("new sheet");
21
22
	sheet1.groupRow( 5, 14 );
23
	sheet1.groupRow( 7, 14 );
24
	sheet1.groupRow( 16, 19 );
25
26
	sheet1.groupColumn( (short)4, (short)7 );
27
	sheet1.groupColumn( (short)9, (short)12 );
28
	sheet1.groupColumn( (short)10, (short)11 );
29
30
	FileOutputStream fileOut = new FileOutputStream("outlining.xlsx");
31
	wb.write(fileOut);
32
	fileOut.close();
33
34
    }
35
36
    private void collapseExpandRowColumn()throws Exception{
37
	Workbook wb2 = new XSSFWorkbook();
38
	Sheet sheet2 = wb2.createSheet("new sheet");
39
	sheet2.groupRow( 5, 14 );
40
	sheet2.groupRow( 7, 14 );
41
	sheet2.groupRow( 16, 19 );
42
43
	sheet2.groupColumn( (short)4, (short)7 );
44
	sheet2.groupColumn( (short)9, (short)12 );
45
	sheet2.groupColumn( (short)10, (short)11 );
46
	
47
	
48
	sheet2.setRowGroupCollapsed( 7, true );
49
	//sheet1.setRowGroupCollapsed(7,false);
50
	
51
	sheet2.setColumnGroupCollapsed( (short)4, true );	
52
	sheet2.setColumnGroupCollapsed( (short)4, false );
53
	
54
	FileOutputStream fileOut = new FileOutputStream("outlining_collapsed.xlsx");
55
	wb2.write(fileOut);
56
	fileOut.close();
57
    }
58
}

Return to bug 46161