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

(-)src/examples/src/org/apache/poi/xssf/usermodel/examples/Outlining.java (+75 lines)
Line 0 Link Here
1
/* ====================================================================
2
   Licensed to the Apache Software Foundation (ASF) under one or more
3
   contributor license agreements.  See the NOTICE file distributed with
4
   this work for additional information regarding copyright ownership.
5
   The ASF licenses this file to You under the Apache License, Version 2.0
6
   (the "License"); you may not use this file except in compliance with
7
   the License.  You may obtain a copy of the License at
8
9
       http://www.apache.org/licenses/LICENSE-2.0
10
11
   Unless required by applicable law or agreed to in writing, software
12
   distributed under the License is distributed on an "AS IS" BASIS,
13
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
   See the License for the specific language governing permissions and
15
   limitations under the License.
16
==================================================================== */
17
18
package org.apache.poi.xssf.usermodel.examples;
19
20
import java.io.FileOutputStream;
21
22
import org.apache.poi.ss.usermodel.Sheet;
23
import org.apache.poi.ss.usermodel.Workbook;
24
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
25
26
public class Outlining {
27
28
    public static void main(String[]args) throws Exception{
29
	Outlining o=new Outlining();
30
	o.groupRowColumn();
31
	o.collapseExpandRowColumn();
32
    }
33
34
35
    private void groupRowColumn() throws Exception{
36
	Workbook wb = new XSSFWorkbook();
37
	Sheet sheet1 = wb.createSheet("new sheet");
38
39
	sheet1.groupRow( 5, 14 );
40
	sheet1.groupRow( 7, 14 );
41
	sheet1.groupRow( 16, 19 );
42
43
	sheet1.groupColumn( (short)4, (short)7 );
44
	sheet1.groupColumn( (short)9, (short)12 );
45
	sheet1.groupColumn( (short)10, (short)11 );
46
47
	FileOutputStream fileOut = new FileOutputStream("outlining.xlsx");
48
	wb.write(fileOut);
49
	fileOut.close();
50
51
    }
52
53
    private void collapseExpandRowColumn()throws Exception{
54
	Workbook wb2 = new XSSFWorkbook();
55
	Sheet sheet2 = wb2.createSheet("new sheet");
56
	sheet2.groupRow( 5, 14 );
57
	sheet2.groupRow( 7, 14 );
58
	sheet2.groupRow( 16, 19 );
59
60
	sheet2.groupColumn( (short)4, (short)7 );
61
	sheet2.groupColumn( (short)9, (short)12 );
62
	sheet2.groupColumn( (short)10, (short)11 );
63
	
64
	
65
	sheet2.setRowGroupCollapsed( 7, true );
66
	//sheet1.setRowGroupCollapsed(7,false);
67
	
68
	sheet2.setColumnGroupCollapsed( (short)4, true );	
69
	sheet2.setColumnGroupCollapsed( (short)4, false );
70
	
71
	FileOutputStream fileOut = new FileOutputStream("outlining_collapsed.xlsx");
72
	wb2.write(fileOut);
73
	fileOut.close();
74
    }
75
}
(-)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/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java (-45 / +574 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
1287
		.getOutlineLevel(), true);
1288
1289
	// write collapse field
1290
	setColumn((int) (lastColMax + 1), null, 0, null, null, Boolean.TRUE);
1291
1231
    }
1292
    }
1232
1293
1233
    public void setRowGroupCollapsed(int row, boolean collapse) {
1294
    private void setColumn(int targetColumnIx, Short xfIndex, Integer style,
1234
        // TODO Auto-generated method stub
1295
	    Integer level, Boolean hidden, Boolean collapsed) {
1296
	CTCols cols = worksheet.getColsArray(0);
1297
	CTCol ci = null;
1298
	int k = 0;
1299
	for (k = 0; k < cols.sizeOfColArray(); k++) {
1300
	    CTCol tci = cols.getColArray(k);
1301
	    if (tci.getMin() >= targetColumnIx
1302
		    && tci.getMax() <= targetColumnIx) {
1303
		ci = tci;
1304
		break;
1305
	    }
1306
	    if (tci.getMin() > targetColumnIx) {
1307
		// call column infos after k are for later columns
1308
		break; // exit now so k will be the correct insert pos
1309
	    }
1310
	}
1235
1311
1312
	if (ci == null) {
1313
	    // okay so there ISN'T a column info record that covers this column
1314
	    // so lets create one!
1315
	    CTCol nci = CTCol.Factory.newInstance();
1316
	    nci.setMin(targetColumnIx);
1317
	    nci.setMax(targetColumnIx);
1318
	    unsetCollapsed(collapsed, nci);
1319
	    this.columnHelper.addCleanColIntoCols(cols, nci);
1320
	    return;
1321
	}
1322
1323
	boolean styleChanged = style != null
1324
		&& ci.getStyle() != style.intValue();
1325
	boolean levelChanged = level != null
1326
		&& ci.getOutlineLevel() != level.intValue();
1327
	boolean hiddenChanged = hidden != null
1328
		&& ci.getHidden() != hidden.booleanValue();
1329
	boolean collapsedChanged = collapsed != null
1330
		&& ci.getCollapsed() != collapsed.booleanValue();
1331
	boolean columnChanged = levelChanged || hiddenChanged
1332
		|| collapsedChanged || styleChanged;
1333
	if (!columnChanged) {
1334
	    // do nothing...nothing changed.
1335
	    return;
1336
	}
1337
1338
	if (ci.getMin() == targetColumnIx && ci.getMax() == targetColumnIx) {
1339
	    // ColumnInfo ci for a single column, the target column
1340
	    unsetCollapsed(collapsed, ci);
1341
	    return;
1342
	}
1343
1344
	if (ci.getMin() == targetColumnIx || ci.getMax() == targetColumnIx) {
1345
	    // The target column is at either end of the multi-column ColumnInfo
1346
	    // ci
1347
	    // we'll just divide the info and create a new one
1348
	    if (ci.getMin() == targetColumnIx) {
1349
		ci.setMin(targetColumnIx + 1);
1350
	    } else {
1351
		ci.setMax(targetColumnIx - 1);
1352
		k++; // adjust insert pos to insert after
1353
	    }
1354
	    CTCol nci = columnHelper.cloneCol(cols, ci);
1355
	    nci.setMin(targetColumnIx);
1356
	    unsetCollapsed(collapsed, nci);
1357
	    this.columnHelper.addCleanColIntoCols(cols, nci);
1358
1359
	} else {
1360
	    // split to 3 records
1361
	    CTCol ciStart = ci;
1362
	    CTCol ciMid = columnHelper.cloneCol(cols, ci);
1363
	    CTCol ciEnd = columnHelper.cloneCol(cols, ci);
1364
	    int lastcolumn = (int) ci.getMax();
1365
1366
	    ciStart.setMax(targetColumnIx - 1);
1367
1368
	    ciMid.setMin(targetColumnIx);
1369
	    ciMid.setMax(targetColumnIx);
1370
	    unsetCollapsed(collapsed, ciMid);
1371
	    this.columnHelper.addCleanColIntoCols(cols, ciMid);
1372
1373
	    ciEnd.setMin(targetColumnIx + 1);
1374
	    ciEnd.setMax(lastcolumn);
1375
	    this.columnHelper.addCleanColIntoCols(cols, ciEnd);
1376
	}
1236
    }
1377
    }
1237
1378
1379
    private void unsetCollapsed(boolean collapsed, CTCol ci) {
1380
	if (collapsed) {
1381
	    ci.setCollapsed(collapsed);
1382
	} else {
1383
	    ci.unsetCollapsed();
1384
	}
1385
    }
1386
1238
    /**
1387
    /**
1388
     * Sets all adjacent columns of the same outline level to the specified
1389
     * hidden status.
1390
     * 
1391
     * @param pIdx
1392
     *                the col info index of the start of the outline group
1393
     * @return the column index of the last column in the outline group
1394
     */
1395
    private int setGroupHidden(int pIdx, int level, boolean hidden) {
1396
	CTCols cols = worksheet.getColsArray(0);
1397
	int idx = pIdx;
1398
	CTCol columnInfo = cols.getColArray(idx);
1399
	while (idx < cols.sizeOfColArray()) {
1400
	    columnInfo.setHidden(hidden);
1401
	    if (idx + 1 < cols.sizeOfColArray()) {
1402
		CTCol nextColumnInfo = cols.getColArray(idx + 1);
1403
1404
		if (!isAdjacentBefore(columnInfo, nextColumnInfo)) {
1405
		    break;
1406
		}
1407
1408
		if (nextColumnInfo.getOutlineLevel() < level) {
1409
		    break;
1410
		}
1411
		columnInfo = nextColumnInfo;
1412
	    }
1413
	    idx++;
1414
	}
1415
	return (int) columnInfo.getMax();
1416
    }
1417
1418
    private boolean isAdjacentBefore(CTCol col, CTCol other_col) {
1419
	return (col.getMax() == (other_col.getMin() - 1));
1420
    }
1421
1422
    private int findStartOfColumnOutlineGroup(int pIdx) {
1423
	// Find the start of the group.
1424
	CTCols cols = worksheet.getColsArray(0);
1425
	CTCol columnInfo = cols.getColArray(pIdx);
1426
	int level = columnInfo.getOutlineLevel();
1427
	int idx = pIdx;
1428
	while (idx != 0) {
1429
	    CTCol prevColumnInfo = cols.getColArray(idx - 1);
1430
	    if (!isAdjacentBefore(prevColumnInfo, columnInfo)) {
1431
		break;
1432
	    }
1433
	    if (prevColumnInfo.getOutlineLevel() < level) {
1434
		break;
1435
	    }
1436
	    idx--;
1437
	    columnInfo = prevColumnInfo;
1438
	}
1439
	return idx;
1440
    }
1441
1442
    private int findEndOfColumnOutlineGroup(int colInfoIndex) {
1443
	CTCols cols = worksheet.getColsArray(0);
1444
	// Find the end of the group.
1445
	CTCol columnInfo = cols.getColArray(colInfoIndex);
1446
	int level = columnInfo.getOutlineLevel();
1447
	int idx = colInfoIndex;
1448
	while (idx < cols.sizeOfColArray() - 1) {
1449
	    CTCol nextColumnInfo = cols.getColArray(idx + 1);
1450
	    if (!isAdjacentBefore(columnInfo, nextColumnInfo)) {
1451
		break;
1452
	    }
1453
	    if (nextColumnInfo.getOutlineLevel() < level) {
1454
		break;
1455
	    }
1456
	    idx++;
1457
	    columnInfo = nextColumnInfo;
1458
	}
1459
	return idx;
1460
    }
1461
1462
    private void expandColumn(int columnIndex) {
1463
	CTCols cols = worksheet.getColsArray(0);
1464
	CTCol col = columnHelper.getColumn(columnIndex, false);
1465
	int colInfoIx = columnHelper.getIndexOfColumn(cols, col);
1466
1467
	int idx = findColInfoIdx((int) col.getMax(), colInfoIx);
1468
	if (idx == -1) {
1469
	    return;
1470
	}
1471
1472
	// If it is already expanded do nothing.
1473
	if (!isColumnGroupCollapsed(idx)) {
1474
	    return;
1475
	}
1476
1477
	// Find the start/end of the group.
1478
	int startIdx = findStartOfColumnOutlineGroup(idx);
1479
	int endIdx = findEndOfColumnOutlineGroup(idx);
1480
1481
	// expand:
1482
	// colapsed bit must be unset
1483
	// hidden bit gets unset _if_ surrounding groups are expanded you can
1484
	// determine
1485
	// this by looking at the hidden bit of the enclosing group. You will
1486
	// have
1487
	// to look at the start and the end of the current group to determine
1488
	// which
1489
	// is the enclosing group
1490
	// hidden bit only is altered for this outline level. ie. don't
1491
	// uncollapse contained groups
1492
	CTCol columnInfo = cols.getColArray(endIdx);
1493
	if (!isColumnGroupHiddenByParent(idx)) {
1494
	    int outlineLevel = columnInfo.getOutlineLevel();
1495
	    boolean nestedGroup = false;
1496
	    for (int i = startIdx; i <= endIdx; i++) {
1497
		CTCol ci = cols.getColArray(i);
1498
		if (outlineLevel == ci.getOutlineLevel()) {
1499
		    ci.unsetHidden();
1500
		    if (nestedGroup) {
1501
			nestedGroup = false;
1502
			ci.setCollapsed(true);
1503
		    }
1504
		} else {
1505
		    nestedGroup = true;
1506
		}
1507
	    }
1508
	}
1509
	// Write collapse flag (stored in a single col info record after this
1510
	// outline group)
1511
	setColumn((int) columnInfo.getMax() + 1, null, null, null,
1512
		Boolean.FALSE, Boolean.FALSE);
1513
    }
1514
1515
    private boolean isColumnGroupHiddenByParent(int idx) {
1516
	CTCols cols = worksheet.getColsArray(0);
1517
	// Look out outline details of end
1518
	int endLevel = 0;
1519
	boolean endHidden = false;
1520
	int endOfOutlineGroupIdx = findEndOfColumnOutlineGroup(idx);
1521
	if (endOfOutlineGroupIdx < cols.sizeOfColArray()) {
1522
	    CTCol nextInfo = cols.getColArray(endOfOutlineGroupIdx + 1);
1523
	    if (isAdjacentBefore(cols.getColArray(endOfOutlineGroupIdx),
1524
		    nextInfo)) {
1525
		endLevel = nextInfo.getOutlineLevel();
1526
		endHidden = nextInfo.getHidden();
1527
	    }
1528
	}
1529
	// Look out outline details of start
1530
	int startLevel = 0;
1531
	boolean startHidden = false;
1532
	int startOfOutlineGroupIdx = findStartOfColumnOutlineGroup(idx);
1533
	if (startOfOutlineGroupIdx > 0) {
1534
	    CTCol prevInfo = cols.getColArray(startOfOutlineGroupIdx - 1);
1535
1536
	    if (isAdjacentBefore(prevInfo, cols
1537
		    .getColArray(startOfOutlineGroupIdx))) {
1538
		startLevel = prevInfo.getOutlineLevel();
1539
		startHidden = prevInfo.getHidden();
1540
	    }
1541
1542
	}
1543
	if (endLevel > startLevel) {
1544
	    return endHidden;
1545
	}
1546
	return startHidden;
1547
    }
1548
1549
    private int findColInfoIdx(int columnValue, int fromColInfoIdx) {
1550
	CTCols cols = worksheet.getColsArray(0);
1551
1552
	if (columnValue < 0) {
1553
	    throw new IllegalArgumentException(
1554
		    "column parameter out of range: " + columnValue);
1555
	}
1556
	if (fromColInfoIdx < 0) {
1557
	    throw new IllegalArgumentException(
1558
		    "fromIdx parameter out of range: " + fromColInfoIdx);
1559
	}
1560
1561
	for (int k = fromColInfoIdx; k < cols.sizeOfColArray(); k++) {
1562
	    CTCol ci = cols.getColArray(k);
1563
1564
	    if (containsColumn(ci, columnValue)) {
1565
		return k;
1566
	    }
1567
1568
	    if (ci.getMin() > fromColInfoIdx) {
1569
		break;
1570
	    }
1571
1572
	}
1573
	return -1;
1574
    }
1575
1576
    private boolean containsColumn(CTCol col, int columnIndex) {
1577
	return col.getMin() <= columnIndex && columnIndex <= col.getMax();
1578
    }
1579
1580
    /**
1581
     * 'Collapsed' state is stored in a single column col info record
1582
     * immediately after the outline group
1583
     * 
1584
     * @param idx
1585
     * @return a boolean represented if the column is collapsed
1586
     */
1587
    private boolean isColumnGroupCollapsed(int idx) {
1588
	CTCols cols = worksheet.getColsArray(0);
1589
	int endOfOutlineGroupIdx = findEndOfColumnOutlineGroup(idx);
1590
	int nextColInfoIx = endOfOutlineGroupIdx + 1;
1591
	if (nextColInfoIx >= cols.sizeOfColArray()) {
1592
	    return false;
1593
	}
1594
	CTCol nextColInfo = cols.getColArray(nextColInfoIx);
1595
1596
	CTCol col = cols.getColArray(endOfOutlineGroupIdx);
1597
	if (!isAdjacentBefore(col, nextColInfo)) {
1598
	    return false;
1599
	}
1600
1601
	return nextColInfo.getCollapsed();
1602
    }    
1603
1604
    /**
1239
     * Get the visibility state for a given column.
1605
     * Get the visibility state for a given column.
1240
     *
1606
     *
1241
     * @param columnIndex - the column to get (0-based)
1607
     * @param columnIndex - the column to get (0-based)
Lines 1327-1337 Link Here
1327
        opts.setHorizontalCentered(value);
1693
        opts.setHorizontalCentered(value);
1328
    }
1694
    }
1329
1695
1696
1330
    /**
1697
    /**
1331
     * Whether the output is vertically centered on the page.
1698
     * group the row It is possible for collapsed to be false and yet still have
1332
     *
1699
     * the rows in question hidden. This can be achieved by having a lower
1333
     * @param value true to vertically center, false otherwise.
1700
     * outline level collapsed, thus hiding all the child rows. Note that in
1701
     * this case, if the lowest level were expanded, the middle level would
1702
     * remain collapsed.
1703
     * 
1704
     * @param rowIndex -
1705
     *                the row involved
1706
     * @param collapse -
1707
     *                boolean value for collapse
1334
     */
1708
     */
1709
    public void setRowGroupCollapsed(int rowIndex, boolean collapse) {
1710
	if (collapse) {
1711
	    collapseRow(rowIndex);
1712
	} else {
1713
	    expandRow(rowIndex);
1714
	}
1715
    }
1716
1717
    private void collapseRow(int rowIndex) {
1718
	XSSFRow row = getRow(rowIndex - 1);
1719
	if (row != null) {
1720
	    int startRow = findStartOfRowOutlineGroup(rowIndex - 1);
1721
1722
	    // Hide all the columns until the end of the group
1723
	    int lastRow = writeHidden(row, startRow, true);
1724
	    if (getRow(lastRow + 1) != null) {
1725
		getRow(lastRow + 1).getCTRow().setCollapsed(true);
1726
	    } else {
1727
		XSSFRow newRow = createRow(lastRow + 1);
1728
		newRow.getCTRow().setCollapsed(true);
1729
	    }
1730
	}
1731
    }
1732
1733
    private int findStartOfRowOutlineGroup(int rowIndex) {
1734
	// Find the start of the group.
1735
	int level = getRow(rowIndex).getCTRow().getOutlineLevel();
1736
	int currentRow = rowIndex;
1737
	while (getRow(currentRow) != null) {
1738
	    if (getRow(currentRow).getCTRow().getOutlineLevel() < level)
1739
		return currentRow + 1;
1740
	    currentRow--;
1741
	}
1742
	return currentRow + 1;
1743
    }
1744
1745
    private int writeHidden(XSSFRow xRow, int rowIndex, boolean hidden) {
1746
	int level = xRow.getCTRow().getOutlineLevel();
1747
	for (Iterator<Row> it = rowIterator(); it.hasNext();) {
1748
	    xRow = (XSSFRow) it.next();
1749
	    if (xRow.getCTRow().getOutlineLevel() >= level) {
1750
		xRow.getCTRow().setHidden(hidden);
1751
		rowIndex++;
1752
	    }
1753
1754
	}
1755
	return rowIndex;
1756
    }
1757
1758
    private void expandRow(int rowNumber) {
1759
	int idx = rowNumber;
1760
	if (idx == -1)
1761
	    return;
1762
	XSSFRow row = getRow(rowNumber - 1);
1763
	// If it is already expanded do nothing.
1764
	if (!row.getCTRow().isSetHidden())
1765
	    return;
1766
1767
	// Find the start of the group.
1768
	int startIdx = findStartOfRowOutlineGroup(idx - 1);
1769
1770
	// Find the end of the group.
1771
	int endIdx = findEndOfRowOutlineGroup(idx - 1);
1772
1773
	// expand:
1774
	// collapsed must be unset
1775
	// hidden bit gets unset _if_ surrounding groups are expanded you can
1776
	// determine
1777
	// this by looking at the hidden bit of the enclosing group. You will
1778
	// have
1779
	// to look at the start and the end of the current group to determine
1780
	// which
1781
	// is the enclosing group
1782
	// hidden bit only is altered for this outline level. ie. don't
1783
	// un-collapse contained groups
1784
	if (!isRowGroupHiddenByParent(idx - 1)) {
1785
	    for (int i = startIdx; i < endIdx; i++) {
1786
		if (row.getCTRow().getOutlineLevel() == getRow(i).getCTRow()
1787
			.getOutlineLevel()) {
1788
		    getRow(i).getCTRow().unsetHidden();
1789
		} else if (!isRowGroupCollapsed(i)) {
1790
		    getRow(i).getCTRow().unsetHidden();
1791
		}
1792
	    }
1793
	}
1794
	// Write collapse field
1795
	getRow(endIdx + 1).getCTRow().unsetCollapsed();
1796
    }
1797
1798
    public int findEndOfRowOutlineGroup(int row) {
1799
	int level = getRow(row).getCTRow().getOutlineLevel();
1800
	int currentRow;
1801
	for (currentRow = row; currentRow < getLastRowNum(); currentRow++) {
1802
	    if (getRow(currentRow) == null
1803
		    || getRow(currentRow).getCTRow().getOutlineLevel() < level) {
1804
		break;
1805
	    }
1806
	}
1807
	return currentRow;
1808
    }
1809
1810
    private boolean isRowGroupHiddenByParent(int row) {
1811
	// Look out outline details of end
1812
	int endLevel;
1813
	boolean endHidden;
1814
	int endOfOutlineGroupIdx = findEndOfRowOutlineGroup(row);
1815
	if (getRow(endOfOutlineGroupIdx + 1) == null) {
1816
	    endLevel = 0;
1817
	    endHidden = false;
1818
	} else {
1819
	    endLevel = (int) (getRow(endOfOutlineGroupIdx + 1).getCTRow()
1820
		    .getOutlineLevel());
1821
	    endHidden = getRow(endOfOutlineGroupIdx + 1).getCTRow().getHidden();
1822
	}
1823
1824
	// Look out outline details of start
1825
	int startLevel;
1826
	boolean startHidden;
1827
	int startOfOutlineGroupIdx = findStartOfRowOutlineGroup(row);
1828
	if (startOfOutlineGroupIdx - 1 < 0
1829
		|| getRow(startOfOutlineGroupIdx - 1) == null) {
1830
	    startLevel = 0;
1831
	    startHidden = false;
1832
	} else {
1833
	    startLevel = getRow(startOfOutlineGroupIdx - 1).getCTRow()
1834
		    .getOutlineLevel();
1835
	    startHidden = getRow(startOfOutlineGroupIdx - 1).getCTRow()
1836
		    .getHidden();
1837
	}
1838
	if (endLevel > startLevel) {
1839
	    return endHidden;
1840
	} else {
1841
	    return startHidden;
1842
	}
1843
    }
1844
1845
    private boolean isRowGroupCollapsed(int row) {
1846
	int collapseRow = findEndOfRowOutlineGroup(row) + 1;
1847
	if (getRow(collapseRow) == null)
1848
	    return false;
1849
	else
1850
	    return getRow(collapseRow).getCTRow().getCollapsed();
1851
    }
1852
1853
    
1335
    public void setVerticallyCenter(boolean value) {
1854
    public void setVerticallyCenter(boolean value) {
1336
        CTPrintOptions opts = worksheet.isSetPrintOptions() ?
1855
        CTPrintOptions opts = worksheet.isSetPrintOptions() ?
1337
                worksheet.getPrintOptions() : worksheet.addNewPrintOptions();
1856
                worksheet.getPrintOptions() : worksheet.addNewPrintOptions();
Lines 1339-1350 Link Here
1339
    }
1858
    }
1340
1859
1341
    /**
1860
    /**
1342
     * Sets the zoom magnication for the sheet.  The zoom is expressed as a
1861
     * Sets the zoom magnication for the sheet. The zoom is expressed as a
1343
     * fraction.  For example to express a zoom of 75% use 3 for the numerator
1862
     * fraction. For example to express a zoom of 75% use 3 for the numerator
1344
     * and 4 for the denominator.
1863
     * and 4 for the denominator.
1345
     *
1864
     * 
1346
     * @param numerator	 The numerator for the zoom magnification.
1865
     * @param numerator
1347
     * @param denominator   The denominator for the zoom magnification.
1866
     *                The numerator for the zoom magnification.
1867
     * @param denominator
1868
     *                The denominator for the zoom magnification.
1348
     * @see #setZoom(int)
1869
     * @see #setZoom(int)
1349
     */
1870
     */
1350
    public void setZoom(int numerator, int denominator) {
1871
    public void setZoom(int numerator, int denominator) {
Lines 1416-1422 Link Here
1416
            if (!copyRowHeight) {
1937
            if (!copyRowHeight) {
1417
                row.setHeight((short)-1);
1938
                row.setHeight((short)-1);
1418
            }
1939
            }
1419
1420
            if (resetOriginalRowHeight && getDefaultRowHeight() >= 0) {
1940
            if (resetOriginalRowHeight && getDefaultRowHeight() >= 0) {
1421
                row.setHeight(getDefaultRowHeight());
1941
                row.setHeight(getDefaultRowHeight());
1422
            }
1942
            }
Lines 1425-1430 Link Here
1425
            }
1945
            }
1426
            else if (row.getRowNum() >= startRow && row.getRowNum() <= endRow) {
1946
            else if (row.getRowNum() >= startRow && row.getRowNum() <= endRow) {
1427
                row.setRowNum(row.getRowNum() + n);
1947
                row.setRowNum(row.getRowNum() + n);
1948
1949
         	modifyCellReference((XSSFRow)row);
1950
1428
                if (row.getFirstCellNum() > -1) {
1951
                if (row.getFirstCellNum() > -1) {
1429
                    modifyCellReference((XSSFRow) row);
1952
                    modifyCellReference((XSSFRow) row);
1430
                }
1953
                }
Lines 1437-1451 Link Here
1437
    }
1960
    }
1438
1961
1439
1962
1440
    private void modifyCellReference(XSSFRow row) {
1963
    private void modifyCellReference(XSSFRow row){
1441
        for (int i = row.getFirstCellNum(); i <= row.getLastCellNum(); i++) {
1964
	int firstCellNum=row.getFirstCellNum();
1442
            XSSFCell c = row.getCell(i);
1965
	//a row could have no cell
1443
            if (c != null) {
1966
	if(firstCellNum != -1){
1444
                c.modifyCellReference(row);
1967
	    for(int i=firstCellNum;i<=row.getLastCellNum();i++){
1445
            }
1968
		XSSFCell c=(XSSFCell)row.getCell(i);
1446
        }
1969
		if(c!=null){
1970
		    c.modifyCellReference(row);
1971
		}
1972
	    }
1973
	}
1447
    }
1974
    }
1448
1975
    
1976
    
1449
    /**
1977
    /**
1450
     * Location of the top left visible cell Location of the top left visible cell in the bottom right
1978
     * 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).
1979
     * pane (when in Left-to-Right mode).
Lines 1456-1462 Link Here
1456
    public void showInPane(short toprow, short leftcol) {
1984
    public void showInPane(short toprow, short leftcol) {
1457
        CellReference cellReference = new CellReference(toprow, leftcol);
1985
        CellReference cellReference = new CellReference(toprow, leftcol);
1458
        String cellRef = cellReference.formatAsString();
1986
        String cellRef = cellReference.formatAsString();
1459
        getSheetTypeSheetView().setTopLeftCell(cellRef);
1987
    //    getSheetTypeSheetView().setTopLeftCell(cellRef);
1988
        getPane().setTopLeftCell(cellRef);
1460
    }
1989
    }
1461
1990
1462
    public void ungroupColumn(short fromColumn, short toColumn) {
1991
    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();

Return to bug 46161