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

(-)src/java/org/apache/poi/hssf/usermodel/HSSFCell.java (-1 / +1 lines)
Lines 969-975 Link Here
969
     * @return CellValueRecordInterface representing the cell via the low level api.
969
     * @return CellValueRecordInterface representing the cell via the low level api.
970
     */
970
     */
971
971
972
    protected CellValueRecordInterface getCellValueRecord()
972
    public CellValueRecordInterface getCellValueRecord()
973
    {
973
    {
974
        return _record;
974
        return _record;
975
    }
975
    }
(-)src/java/org/apache/poi/ss/formula/CompleteFormulaShifter.java (+227 lines)
Line 0 Link Here
1
package org.apache.poi.ss.formula;
2
3
import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
4
import org.apache.poi.hssf.usermodel.HSSFCell;
5
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
6
import org.apache.poi.hssf.util.CellReference;
7
import org.apache.poi.ss.SpreadsheetVersion;
8
import org.apache.poi.ss.formula.FormulaParseException;
9
import org.apache.poi.ss.formula.FormulaParser;
10
import org.apache.poi.ss.formula.FormulaRenderer;
11
import org.apache.poi.ss.formula.FormulaShifter;
12
import org.apache.poi.ss.formula.FormulaType;
13
import org.apache.poi.ss.formula.ptg.Area3DPtg;
14
import org.apache.poi.ss.formula.ptg.Area3DPxg;
15
import org.apache.poi.ss.formula.ptg.AreaPtg;
16
import org.apache.poi.ss.formula.ptg.Ptg;
17
import org.apache.poi.ss.formula.ptg.Ref3DPtg;
18
import org.apache.poi.ss.formula.ptg.Ref3DPxg;
19
import org.apache.poi.ss.formula.ptg.RefPtg;
20
import org.apache.poi.ss.usermodel.Cell;
21
import org.apache.poi.ss.usermodel.CellType;
22
import org.apache.poi.ss.usermodel.Row;
23
import org.apache.poi.ss.usermodel.Sheet;
24
import org.apache.poi.ss.usermodel.Workbook;
25
import org.apache.poi.xssf.usermodel.XSSFEvaluationWorkbook;
26
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
27
28
/***
29
 * Wrapper around FormulaShifter, with added functionality. Takes formula string as input (instead of Ptg[]), so it makes better automation.
30
 * Works with both rows and columns.
31
 * @author Dragan Jovanović (zmau3012 @ skype)
32
 *
33
 */
34
public class CompleteFormulaShifter {
35
	private FormulaShifter formulaShifter;
36
	private SpreadsheetVersion spreadSheetVersion;
37
	private Sheet shiftingSheet;
38
	private boolean rowModeElseColumn; 
39
40
	public static CompleteFormulaShifter createForItemShift(Sheet sheet, boolean rowModeElseColumn, int firstShiftItemIndex, int lastShiftItemIndex, int shiftStep){
41
		CompleteFormulaShifter instance = new CompleteFormulaShifter(sheet, rowModeElseColumn);
42
		instance.configureForItemShifting(firstShiftItemIndex, lastShiftItemIndex, shiftStep);
43
		return instance; 
44
	}
45
	public static CompleteFormulaShifter createForItemCopy(Sheet sheet, boolean rowModeElseColumn, int firstShiftItemIndex, int lastShiftItemIndex, int shiftStep){
46
		CompleteFormulaShifter instance = new CompleteFormulaShifter(sheet, rowModeElseColumn);
47
		instance.configureForItemCopiing(firstShiftItemIndex, lastShiftItemIndex, shiftStep);
48
		return instance; 
49
	}
50
51
	public CompleteFormulaShifter(Sheet shiftingSheet, boolean rowModeElseColumn){
52
		this.shiftingSheet = shiftingSheet;
53
		this.spreadSheetVersion = getSpreadsheetVersion(shiftingSheet);
54
		this.rowModeElseColumn = rowModeElseColumn;
55
	}
56
57
	public void configureForItemShifting(int firstShiftItemIndex, int lastShiftItemIndex, int shiftStep){
58
		formulaShifter = FormulaShifter.createForRowShift(shiftingSheet.getWorkbook().getSheetIndex(shiftingSheet), shiftingSheet.getSheetName(), 
59
	    		firstShiftItemIndex, lastShiftItemIndex, shiftStep, spreadSheetVersion);
60
	}
61
	public void configureForItemCopiing(int firstShiftRowIndex, int lastShiftItemIndex, int shiftStep){
62
		formulaShifter = FormulaShifter.createForRowCopy(shiftingSheet.getWorkbook().getSheetIndex(shiftingSheet), shiftingSheet.getSheetName(), 
63
	    		firstShiftRowIndex, lastShiftItemIndex, shiftStep, spreadSheetVersion);
64
	}
65
	public void processFormulasOnOtherSheets(){
66
		Workbook wb = shiftingSheet.getWorkbook();
67
		int sheetIndex = 0;
68
		while(sheetIndex < wb.getNumberOfSheets()){
69
			Sheet aSheet = wb.getSheetAt(sheetIndex++);
70
			if(!aSheet.getSheetName().equals(shiftingSheet.getSheetName())){
71
				shiftAllFormulas(aSheet);
72
			}
73
		}
74
	}
75
76
	private void shiftAllFormulas(Sheet aSheet){
77
		for(int rowNo = 0; rowNo < aSheet.getPhysicalNumberOfRows(); rowNo++)
78
		{	
79
			Row row = aSheet.getRow(rowNo);
80
		    for (int i = 0; i <= row.getPhysicalNumberOfCells(); i++){
81
		    	org.apache.poi.ss.usermodel.Cell currentCell = row.getCell(i);
82
		    	if(currentCell != null){
83
		    		if(currentCell.getCellTypeEnum() == CellType.FORMULA)
84
		    			shiftFormula(currentCell); 
85
		    	}
86
		    }
87
		}
88
	}
89
	
90
	public void shiftFormula(Cell cell) {
91
		switch (spreadSheetVersion) {
92
			case EXCEL2007:
93
				int currentSheetIndex = getSheetIndex(cell.getSheet());
94
				String shiftedFormula = getShiftedFormulaForXSSF(cell.toString(), currentSheetIndex); 
95
				cell.setCellFormula(shiftedFormula);
96
			break;
97
			case EXCEL97:
98
				shiftFormulaForHSSF((HSSFCell)cell);
99
			break;
100
		}
101
	}
102
	
103
	// original code in org.apache.poi.xssf.usermodel.helpers.XSSFRowShifter.shiftFormula()
104
	/** Recalculates formula, for EXCEL2007 spreadsheets 
105
	 * @param formula string representing formula
106
	 * */
107
    public String getShiftedFormulaForXSSF(String formula, int currentSheetIndex) {
108
    	boolean adjustSucceeded;
109
    	Workbook wb = shiftingSheet.getWorkbook();
110
    	XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create((XSSFWorkbook) wb);
111
        try {
112
            Ptg[] ptgs = FormulaParser.parse(formula, fpb, FormulaType.CELL, currentSheetIndex);
113
            String shiftedFmla = null;
114
            if(rowModeElseColumn)
115
            	adjustSucceeded = formulaShifter.adjustFormula(ptgs, currentSheetIndex);
116
            else {
117
	        	Ptg[] transponedPtgs = transpose(ptgs);
118
	        	adjustSucceeded = formulaShifter.adjustFormula(transponedPtgs, currentSheetIndex); 
119
	        	if (adjustSucceeded) 
120
	        		ptgs = transpose(transponedPtgs);
121
            }
122
            if(adjustSucceeded){
123
	            shiftedFmla = FormulaRenderer.toFormulaString(fpb, ptgs);
124
	                // dont use logger here, because of transfer to POI project
125
	                //System.out.println(String.format("original : %s; shifted : %s", formula, shiftedFmla));
126
	            return shiftedFmla;
127
            }
128
            else return formula; // better return some error msg ?
129
        } catch (FormulaParseException fpe) {
130
            // Log, but don't change, rather than breaking; uncomment this in  POI context
131
            //logger.log(POILogger.WARN, "Error shifting formula on row ", row.getRowNum(), fpe);
132
            return formula;
133
        }
134
    }
135
    
136
    // original code in org.apache.poi.hssf.record.aggregates.ValueRecordsAggregate.updateFormulasAfterRowShift()
137
	/** Recalculates formula, for EXCEL97 spreadsheets 
138
	 * @param formula string representing formula
139
	 * */
140
    void shiftFormulaForHSSF(HSSFCell cell) {
141
    	boolean adjustSucceeded;
142
        int sheetIndex = getSheetIndex(cell.getSheet());
143
        FormulaRecordAggregate fra = (FormulaRecordAggregate)cell.getCellValueRecord();
144
        Ptg[] ptgs = fra.getFormulaTokens(); 
145
        if(rowModeElseColumn)
146
        	adjustSucceeded = formulaShifter.adjustFormula(ptgs, sheetIndex);
147
        else {
148
        	Ptg[] transposedPtgs = transpose(ptgs);
149
        	adjustSucceeded = formulaShifter.adjustFormula(transposedPtgs, sheetIndex);
150
        	if (adjustSucceeded)
151
        		ptgs = transpose(transposedPtgs);
152
        }
153
        fra.setParsedExpression(ptgs);
154
    }
155
    
156
    private Ptg[] transpose(Ptg[] original){
157
        Ptg[] transposed = new Ptg[original.length];
158
        int index = 0;
159
        for (Ptg ptg : original) {
160
            String ptgType = ptg.getClass().getSimpleName();  
161
        	if(ptgType.equals("Ref3DPtg")){  //3D means (sheetNo, col, row) reference, for example Sheet1!B3; xls version  
162
            	int oldColumnIndex = ((Ref3DPtg) ptg).getColumn();
163
            	((Ref3DPtg) ptg).setColumn(((Ref3DPtg) ptg).getRow());
164
            	((Ref3DPtg) ptg).setRow(oldColumnIndex);
165
            	transposed[index] = ptg;
166
        	} else if(ptgType.equals("Ref3DPxg")){  //3D means (sheetNo, col, row) reference, for example Sheet1!B3; xlsx version  
167
    	        int oldColumnIndex = ((Ref3DPxg) ptg).getColumn();
168
            	((Ref3DPxg) ptg).setColumn(((Ref3DPxg) ptg).getRow());
169
            	((Ref3DPxg) ptg).setRow(oldColumnIndex);
170
            	transposed[index] = ptg;
171
        	} else if(ptgType.equals("AreaPtg")){  // region for aggregate function, for example A1:B3 or Sheet1!B3:Sheet1!C3
172
		        	int oldFirstColumnIndex = ((AreaPtg) ptg).getFirstColumn();
173
		        	((AreaPtg) ptg).setFirstColumn(((AreaPtg) ptg).getFirstRow());
174
		        	((AreaPtg) ptg).setFirstRow(oldFirstColumnIndex);
175
		        	int oldLastColumnIndex = ((AreaPtg) ptg).getLastColumn();
176
		        	((AreaPtg) ptg).setLastColumn(((AreaPtg) ptg).getLastRow());
177
		        	((AreaPtg) ptg).setLastRow(oldLastColumnIndex);
178
		        	transposed[index] = ptg;
179
        	}
180
        	 else if(ptgType.equals("Area3DPtg")){ //for example SUM(Sheet1!B3:C3); xls version 
181
		        	int oldFirstColumnIndex = ((Area3DPtg) ptg).getFirstColumn();
182
		        	((Area3DPtg) ptg).setFirstColumn(((Area3DPtg) ptg).getFirstRow());
183
		        	((Area3DPtg) ptg).setFirstRow(oldFirstColumnIndex);
184
		        	int oldLastColumnIndex = ((Area3DPtg) ptg).getLastColumn();
185
		        	((Area3DPtg) ptg).setLastColumn(((Area3DPtg) ptg).getLastRow());
186
		        	((Area3DPtg) ptg).setLastRow(oldLastColumnIndex);
187
		        	transposed[index] = ptg;
188
        	 }
189
        	 else if(ptgType.equals("Area3DPxg")){ //for example SUM(Sheet1!B3:C3); xlsx version 
190
        	         int oldFirstColumnIndex = ((Area3DPxg) ptg).getFirstColumn();
191
		        	((Area3DPxg) ptg).setFirstColumn(((Area3DPxg) ptg).getFirstRow());
192
		        	((Area3DPxg) ptg).setFirstRow(oldFirstColumnIndex);
193
		        	int oldLastColumnIndex = ((Area3DPxg) ptg).getLastColumn();
194
		        	((Area3DPxg) ptg).setLastColumn(((Area3DPxg) ptg).getLastRow());
195
		        	((Area3DPxg) ptg).setLastRow(oldLastColumnIndex);
196
		        	transposed[index] = ptg;
197
        	 }	else if(ptgType.equals("RefPtg")){  // common simple reference, like A2 
198
	                RefPtg transponedCellRefToken = new RefPtg(transpose(ptg.toFormulaString()));
199
	                transposed[index] = transponedCellRefToken;
200
        	 }
201
        	 else // operators like + or SUM, for example
202
	            	transposed[index] = ptg;
203
            index++;
204
        }
205
        return transposed;
206
    }
207
208
    public static String transpose(String cellreference){
209
    	CellReference original = new CellReference(cellreference);
210
    	// transpose, calling public CellReference(int *pRow*, int *pCol*) !!!!
211
    	CellReference transposed = new CellReference(original.getCol(), original.getRow(), original.isColAbsolute(), original.isRowAbsolute());  
212
    	return transposed.formatAsString();
213
    }
214
    
215
	private int getSheetIndex(Sheet sheet){
216
		return sheet.getWorkbook().getSheetIndex(sheet);
217
	}
218
219
	public static SpreadsheetVersion getSpreadsheetVersion(Sheet sheet){
220
		if(sheet.getWorkbook() instanceof XSSFWorkbook)
221
			return SpreadsheetVersion.EXCEL2007;
222
		else if(sheet.getWorkbook() instanceof HSSFWorkbook)
223
			return SpreadsheetVersion.EXCEL97;
224
		else return null;
225
	}
226
	
227
}
(-)src/java/org/apache/poi/ss/formula/FormulaShifter.java (-1 / +1 lines)
Lines 40-46 Link Here
40
 */
40
 */
41
public final class FormulaShifter {
41
public final class FormulaShifter {
42
42
43
    private static enum ShiftMode {
43
    public static enum ShiftMode {
44
        RowMove,
44
        RowMove,
45
        RowCopy,
45
        RowCopy,
46
        SheetMove,
46
        SheetMove,

Return to bug 61474