1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
11 #include <sfx2/dispatch.hxx>
12 #include <svl/zforlist.hxx>
13 #include <svl/undo.hxx>
15 #include "formulacell.hxx"
16 #include "rangelst.hxx"
17 #include "scitems.hxx"
19 #include "document.hxx"
20 #include "uiitems.hxx"
21 #include "reffact.hxx"
22 #include "strload.hxx"
23 #include "docfunc.hxx"
24 #include "StatisticsDialogs.hrc"
25 #include "TableFillingAndNavigationTools.hxx"
27 #include "AnalysisOfVarianceDialog.hxx"
32 struct StatisticCalculation
{
35 const char* aResultRangeName
;
38 static StatisticCalculation lclBasicStatistics
[] =
40 { STR_ANOVA_LABEL_GROUPS
, NULL
, NULL
},
41 { STRID_CALC_COUNT
, "=COUNT(%RANGE%)", "COUNT_RANGE" },
42 { STRID_CALC_SUM
, "=SUM(%RANGE%)", "SUM_RANGE" },
43 { STRID_CALC_MEAN
, "=AVERAGE(%RANGE%)", "MEAN_RANGE" },
44 { STRID_CALC_VARIANCE
, "=VAR(%RANGE%)", "VAR_RANGE" },
48 static sal_Int16 lclAnovaLabels
[] =
50 STR_ANOVA_LABEL_SOURCE_OF_VARIATION
,
55 STR_ANOVA_LABEL_P_VALUE
,
56 STR_ANOVA_LABEL_F_CRITICAL
,
60 static const char strWildcardRange
[] = "%RANGE%";
61 static const char strWildcardNumber
[] = "%NUMBER%";
63 OUString
lclCreateMultiParameterFormula(
64 ScRangeList
& aRangeList
, const OUString
& aFormulaTemplate
,
65 const OUString
& aWildcard
, ScDocument
* pDocument
,
66 ScAddress::Details
& aAddressDetails
)
69 for (size_t i
= 0; i
< aRangeList
.size(); i
++)
71 OUString
aRangeString(aRangeList
[i
]->Format(SCR_ABS
, pDocument
, aAddressDetails
));
72 OUString aFormulaString
= aFormulaTemplate
.replaceAll(aWildcard
, aRangeString
);
73 aResult
+= aFormulaString
;
74 if(i
!= aRangeList
.size() - 1) // Not Last
80 void lclMakeSubRangesList(ScRangeList
& rRangeList
, ScRange
& rInputRange
, ScStatisticsInputOutputDialog::GroupedBy aGroupedBy
)
82 boost::scoped_ptr
<DataRangeIterator
> pIterator
;
83 if (aGroupedBy
== ScStatisticsInputOutputDialog::BY_COLUMN
)
84 pIterator
.reset(new DataRangeByColumnIterator(rInputRange
));
86 pIterator
.reset(new DataRangeByRowIterator(rInputRange
));
88 for( ; pIterator
->hasNext(); pIterator
->next() )
90 ScRange aRange
= pIterator
->get();
91 rRangeList
.Append(aRange
);
97 ScAnalysisOfVarianceDialog::ScAnalysisOfVarianceDialog(
98 SfxBindings
* pSfxBindings
, SfxChildWindow
* pChildWindow
,
99 vcl::Window
* pParent
, ScViewData
* pViewData
) :
100 ScStatisticsInputOutputDialog(
101 pSfxBindings
, pChildWindow
, pParent
, pViewData
,
102 "AnalysisOfVarianceDialog", "modules/scalc/ui/analysisofvariancedialog.ui" ),
103 meFactor(SINGLE_FACTOR
)
105 get(mpAlphaField
, "alpha-spin");
106 get(mpSingleFactorRadio
, "radio-single-factor");
107 get(mpTwoFactorRadio
, "radio-two-factor");
108 get(mpRowsPerSampleField
, "rows-per-sample-spin");
110 mpSingleFactorRadio
->SetToggleHdl( LINK( this, ScAnalysisOfVarianceDialog
, FactorChanged
) );
111 mpTwoFactorRadio
->SetToggleHdl( LINK( this, ScAnalysisOfVarianceDialog
, FactorChanged
) );
113 mpSingleFactorRadio
->Check(true);
114 mpTwoFactorRadio
->Check(false);
119 ScAnalysisOfVarianceDialog::~ScAnalysisOfVarianceDialog()
124 void ScAnalysisOfVarianceDialog::dispose()
126 mpAlphaField
.clear();
127 mpSingleFactorRadio
.clear();
128 mpTwoFactorRadio
.clear();
129 mpRowsPerSampleField
.clear();
130 ScStatisticsInputOutputDialog::dispose();
133 bool ScAnalysisOfVarianceDialog::Close()
135 return DoClose( ScAnalysisOfVarianceDialogWrapper::GetChildWindowId() );
138 sal_Int16
ScAnalysisOfVarianceDialog::GetUndoNameId()
140 return STR_ANALYSIS_OF_VARIANCE_UNDO_NAME
;
143 IMPL_LINK_NOARG( ScAnalysisOfVarianceDialog
, FactorChanged
)
145 if (mpSingleFactorRadio
->IsChecked())
147 mpGroupByRowsRadio
->Enable(true);
148 mpGroupByColumnsRadio
->Enable(true);
149 mpRowsPerSampleField
->Enable(false);
150 meFactor
= SINGLE_FACTOR
;
152 else if (mpTwoFactorRadio
->IsChecked())
154 mpGroupByRowsRadio
->Enable(false);
155 mpGroupByColumnsRadio
->Enable(false);
156 mpRowsPerSampleField
->Enable(false); // Rows per sample not yet implemented
157 meFactor
= TWO_FACTOR
;
163 void ScAnalysisOfVarianceDialog::RowColumn(ScRangeList
& rRangeList
, AddressWalkerWriter
& aOutput
, FormulaTemplate
& aTemplate
,
164 OUString
& sFormula
, GroupedBy aGroupedBy
, ScRange
* pResultRange
)
166 if (pResultRange
!= NULL
)
167 pResultRange
->aStart
= aOutput
.current();
168 if (!sFormula
.isEmpty())
170 for (size_t i
= 0; i
< rRangeList
.size(); i
++)
172 ScRange
* pRange
= rRangeList
[i
];
173 aTemplate
.setTemplate(sFormula
);
174 aTemplate
.applyRange(strWildcardRange
, *pRange
);
175 aOutput
.writeFormula(aTemplate
.getTemplate());
176 if (pResultRange
!= NULL
)
177 pResultRange
->aEnd
= aOutput
.current();
183 sal_Int16 aLabelId
= (aGroupedBy
== BY_COLUMN
) ? STR_COLUMN_LABEL_TEMPLATE
: STR_ROW_LABEL_TEMPLATE
;
184 OUString
aLabelTemplate(SC_STRLOAD(RID_STATISTICS_DLGS
, aLabelId
));
186 for (size_t i
= 0; i
< rRangeList
.size(); i
++)
188 aTemplate
.setTemplate(aLabelTemplate
);
189 aTemplate
.applyNumber(strWildcardNumber
, i
+ 1);
190 aOutput
.writeString(aTemplate
.getTemplate());
191 if (pResultRange
!= NULL
)
192 pResultRange
->aEnd
= aOutput
.current();
198 void ScAnalysisOfVarianceDialog::AnovaSingleFactor(AddressWalkerWriter
& output
, FormulaTemplate
& aTemplate
)
200 output
.writeBoldString(SC_STRLOAD(RID_STATISTICS_DLGS
, STR_ANOVA_SINGLE_FACTOR_LABEL
));
203 double aAlphaValue
= mpAlphaField
->GetValue() / 100.0;
204 output
.writeString(SC_STRLOAD(RID_STATISTICS_DLGS
, STR_LABEL_ALPHA
));
206 output
.writeValue(aAlphaValue
);
207 aTemplate
.autoReplaceAddress("%ALPHA%", output
.current());
212 for(sal_Int32 i
= 0; lclBasicStatistics
[i
].aLabelId
!= 0; i
++)
214 output
.writeString(SC_STRLOAD(RID_STATISTICS_DLGS
, lclBasicStatistics
[i
].aLabelId
));
219 // Collect aRangeList
220 ScRangeList aRangeList
;
221 lclMakeSubRangesList(aRangeList
, mInputRange
, mGroupedBy
);
226 for(sal_Int32 i
= 0; lclBasicStatistics
[i
].aLabelId
!= 0; i
++)
229 ScRange aResultRange
;
230 OUString sFormula
= OUString::createFromAscii(lclBasicStatistics
[i
].aFormula
);
231 RowColumn(aRangeList
, output
, aTemplate
, sFormula
, mGroupedBy
, &aResultRange
);
233 if (lclBasicStatistics
[i
].aResultRangeName
!= NULL
)
235 OUString sResultRangeName
= OUString::createFromAscii(lclBasicStatistics
[i
].aResultRangeName
);
236 aTemplate
.autoReplaceRange("%" + sResultRangeName
+ "%", aResultRange
);
240 output
.nextRow(); // Blank row
242 // Write ANOVA labels
243 output
.resetColumn();
244 for(sal_Int32 i
= 0; lclAnovaLabels
[i
] != 0; i
++)
246 output
.writeString(SC_STRLOAD(RID_STATISTICS_DLGS
, lclAnovaLabels
[i
]));
251 aTemplate
.autoReplaceRange("%FIRST_COLUMN%", *aRangeList
[0]);
256 output
.resetColumn();
257 output
.writeString(SC_STRLOAD(RID_STATISTICS_DLGS
, STR_ANOVA_LABEL_BETWEEN_GROUPS
));
262 aTemplate
.setTemplate("=SUMPRODUCT(%SUM_RANGE%;%MEAN_RANGE%)-SUM(%SUM_RANGE%)^2/SUM(%COUNT_RANGE%)");
263 aTemplate
.autoReplaceAddress("%BETWEEN_SS%", output
.current());
264 output
.writeFormula(aTemplate
.getTemplate());
268 aTemplate
.setTemplate("=COUNT(%SUM_RANGE%)-1");
269 aTemplate
.autoReplaceAddress("%BETWEEN_DF%", output
.current());
270 output
.writeFormula(aTemplate
.getTemplate());
274 aTemplate
.setTemplate("=%BETWEEN_SS% / %BETWEEN_DF%");
275 aTemplate
.autoReplaceAddress("%BETWEEN_MS%", output
.current());
276 output
.writeFormula(aTemplate
.getTemplate());
280 aTemplate
.setTemplate("=%BETWEEN_MS% / %WITHIN_MS%");
281 aTemplate
.applyAddress("%WITHIN_MS%", output
.current(-1, 1));
282 aTemplate
.autoReplaceAddress("%F_VAL%", output
.current());
283 output
.writeFormula(aTemplate
.getTemplate());
287 aTemplate
.setTemplate("=FDIST(%F_VAL%; %BETWEEN_DF%; %WITHIN_DF%");
288 aTemplate
.applyAddress("%WITHIN_DF%", output
.current(-3, 1));
289 output
.writeFormula(aTemplate
.getTemplate());
293 aTemplate
.setTemplate("=FINV(%ALPHA%; %BETWEEN_DF%; %WITHIN_DF%");
294 aTemplate
.applyAddress("%WITHIN_DF%", output
.current(-4, 1));
295 output
.writeFormula(aTemplate
.getTemplate());
302 output
.resetColumn();
303 output
.writeString(SC_STRLOAD(RID_STATISTICS_DLGS
, STR_ANOVA_LABEL_WITHIN_GROUPS
));
307 OUString aSSPart
= lclCreateMultiParameterFormula(aRangeList
, OUString("DEVSQ(%RANGE%)"), strWildcardRange
, mDocument
, mAddressDetails
);
308 aTemplate
.setTemplate("=SUM(%RANGE%)");
309 aTemplate
.applyString(strWildcardRange
, aSSPart
);
310 aTemplate
.autoReplaceAddress("%WITHIN_SS%", output
.current());
311 output
.writeFormula(aTemplate
.getTemplate());
315 aTemplate
.setTemplate("=SUM(%COUNT_RANGE%)-COUNT(%COUNT_RANGE%)");
316 aTemplate
.autoReplaceAddress("%WITHIN_DF%", output
.current());
317 output
.writeFormula(aTemplate
.getTemplate());
321 aTemplate
.setTemplate("=%WITHIN_SS% / %WITHIN_DF%");
322 output
.writeFormula(aTemplate
.getTemplate());
329 output
.resetColumn();
330 output
.writeString(SC_STRLOAD(RID_STATISTICS_DLGS
, STR_ANOVA_LABEL_TOTAL
));
334 aTemplate
.setTemplate("=DEVSQ(%RANGE_LIST%)");
335 aTemplate
.applyRangeList("%RANGE_LIST%", aRangeList
);
336 output
.writeFormula(aTemplate
.getTemplate());
340 aTemplate
.setTemplate("=SUM(%COUNT_RANGE%) - 1");
341 output
.writeFormula(aTemplate
.getTemplate());
346 void ScAnalysisOfVarianceDialog::AnovaTwoFactor(AddressWalkerWriter
& output
, FormulaTemplate
& aTemplate
)
348 output
.writeBoldString(SC_STRLOAD(RID_STATISTICS_DLGS
, STR_ANOVA_TWO_FACTOR_LABEL
));
351 double aAlphaValue
= mpAlphaField
->GetValue() / 100.0;
352 output
.writeString("Alpha");
354 output
.writeValue(aAlphaValue
);
355 aTemplate
.autoReplaceAddress("%ALPHA%", output
.current());
360 for(sal_Int32 i
= 0; lclBasicStatistics
[i
].aLabelId
!= 0; i
++)
362 output
.writeString(SC_STRLOAD(RID_STATISTICS_DLGS
, lclBasicStatistics
[i
].aLabelId
));
367 ScRangeList aColumnRangeList
;
368 ScRangeList aRowRangeList
;
370 lclMakeSubRangesList(aColumnRangeList
, mInputRange
, BY_COLUMN
);
371 lclMakeSubRangesList(aRowRangeList
, mInputRange
, BY_ROW
);
373 // Write ColumnX values
375 for(sal_Int32 i
= 0; lclBasicStatistics
[i
].aLabelId
!= 0; i
++)
378 ScRange aResultRange
;
379 OUString sFormula
= OUString::createFromAscii(lclBasicStatistics
[i
].aFormula
);
380 RowColumn(aColumnRangeList
, output
, aTemplate
, sFormula
, BY_COLUMN
, &aResultRange
);
381 if (lclBasicStatistics
[i
].aResultRangeName
!= NULL
)
383 OUString sResultRangeName
= OUString::createFromAscii(lclBasicStatistics
[i
].aResultRangeName
);
384 aTemplate
.autoReplaceRange("%" + sResultRangeName
+ "_COLUMN%", aResultRange
);
392 for(sal_Int32 i
= 0; lclBasicStatistics
[i
].aLabelId
!= 0; i
++)
395 ScRange aResultRange
;
396 OUString sFormula
= OUString::createFromAscii(lclBasicStatistics
[i
].aFormula
);
397 RowColumn(aRowRangeList
, output
, aTemplate
, sFormula
, BY_ROW
, &aResultRange
);
399 if (lclBasicStatistics
[i
].aResultRangeName
!= NULL
)
401 OUString sResultRangeName
= OUString::createFromAscii(lclBasicStatistics
[i
].aResultRangeName
);
402 aTemplate
.autoReplaceRange("%" + sResultRangeName
+ "_ROW%", aResultRange
);
408 // Write ANOVA labels
409 for(sal_Int32 i
= 0; lclAnovaLabels
[i
] != 0; i
++)
411 output
.writeString(SC_STRLOAD(RID_STATISTICS_DLGS
, lclAnovaLabels
[i
]));
416 // Setup auto-replace strings
417 aTemplate
.autoReplaceRange(strWildcardRange
, mInputRange
);
418 aTemplate
.autoReplaceRange("%FIRST_COLUMN%", *aColumnRangeList
[0]);
419 aTemplate
.autoReplaceRange("%FIRST_ROW%", *aRowRangeList
[0]);
424 output
.resetColumn();
425 output
.writeString("Rows");
429 aTemplate
.setTemplate("=SUMPRODUCT(%SUM_RANGE_ROW%;%MEAN_RANGE_ROW%) - SUM(%RANGE%)^2 / COUNT(%RANGE%)");
430 aTemplate
.autoReplaceAddress("%ROW_SS%", output
.current());
431 output
.writeFormula(aTemplate
.getTemplate());
435 aTemplate
.setTemplate("=MAX(%COUNT_RANGE_COLUMN%) - 1");
436 aTemplate
.autoReplaceAddress("%ROW_DF%", output
.current());
437 output
.writeFormula(aTemplate
.getTemplate());
441 aTemplate
.setTemplate("=%ROW_SS% / %ROW_DF%");
442 aTemplate
.autoReplaceAddress("%MS_ROW%", output
.current());
443 output
.writeFormula(aTemplate
.getTemplate());
447 aTemplate
.setTemplate("=%MS_ROW% / %MS_ERROR%");
448 aTemplate
.applyAddress("%MS_ERROR%", output
.current(-1, 2));
449 aTemplate
.autoReplaceAddress("%F_ROW%", output
.current());
450 output
.writeFormula(aTemplate
.getTemplate());
454 aTemplate
.setTemplate("=FDIST(%F_ROW%; %ROW_DF%; %ERROR_DF%");
455 aTemplate
.applyAddress("%ERROR_DF%", output
.current(-3, 2));
456 output
.writeFormula(aTemplate
.getTemplate());
460 aTemplate
.setTemplate("=FINV(%ALPHA%; %ROW_DF%; %ERROR_DF%");
461 aTemplate
.applyAddress("%ERROR_DF%", output
.current(-4, 2));
462 output
.writeFormula(aTemplate
.getTemplate());
470 output
.resetColumn();
471 output
.writeString("Columns");
475 aTemplate
.setTemplate("=SUMPRODUCT(%SUM_RANGE_COLUMN%;%MEAN_RANGE_COLUMN%) - SUM(%RANGE%)^2 / COUNT(%RANGE%)");
476 aTemplate
.autoReplaceAddress("%COLUMN_SS%", output
.current());
477 output
.writeFormula(aTemplate
.getTemplate());
481 aTemplate
.setTemplate("=MAX(%COUNT_RANGE_ROW%) - 1");
482 aTemplate
.autoReplaceAddress("%COLUMN_DF%", output
.current());
483 output
.writeFormula(aTemplate
.getTemplate());
487 aTemplate
.setTemplate("=%COLUMN_SS% / %COLUMN_DF%");
488 aTemplate
.autoReplaceAddress("%MS_COLUMN%", output
.current());
489 output
.writeFormula(aTemplate
.getTemplate());
493 aTemplate
.setTemplate("=%MS_COLUMN% / %MS_ERROR%");
494 aTemplate
.applyAddress("%MS_ERROR%", output
.current(-1, 1));
495 aTemplate
.autoReplaceAddress("%F_COLUMN%", output
.current());
496 output
.writeFormula(aTemplate
.getTemplate());
500 aTemplate
.setTemplate("=FDIST(%F_COLUMN%; %COLUMN_DF%; %ERROR_DF%");
501 aTemplate
.applyAddress("%ERROR_DF%", output
.current(-3, 1));
502 output
.writeFormula(aTemplate
.getTemplate());
506 aTemplate
.setTemplate("=FINV(%ALPHA%; %COLUMN_DF%; %ERROR_DF%");
507 aTemplate
.applyAddress("%ERROR_DF%", output
.current(-4, 1));
508 output
.writeFormula(aTemplate
.getTemplate());
516 output
.resetColumn();
517 output
.writeString("Error");
521 aTemplate
.setTemplate("=SUMSQ(%RANGE%)+SUM(%RANGE%)^2/COUNT(%RANGE%) - (SUMPRODUCT(%SUM_RANGE_ROW%;%MEAN_RANGE_ROW%) + SUMPRODUCT(%SUM_RANGE_COLUMN%;%MEAN_RANGE_COLUMN%))");
522 aTemplate
.autoReplaceAddress("%ERROR_SS%", output
.current());
523 output
.writeFormula(aTemplate
.getTemplate());
527 aTemplate
.setTemplate("=%TOTAL_DF% - %ROW_DF% - %COLUMN_DF%");
528 aTemplate
.applyAddress("%TOTAL_DF%", output
.current(0,1,0));
529 aTemplate
.autoReplaceAddress("%ERROR_DF%", output
.current());
530 output
.writeFormula(aTemplate
.getTemplate());
534 aTemplate
.setTemplate("=%ERROR_SS% / %ERROR_DF%");
535 output
.writeFormula(aTemplate
.getTemplate());
542 output
.resetColumn();
543 output
.writeString("Total");
547 aTemplate
.setTemplate("=SUM(%ROW_SS%;%COLUMN_SS%;%ERROR_SS%)");
548 output
.writeFormula(aTemplate
.getTemplate());
552 aTemplate
.setTemplate("=COUNT(%RANGE%)-1");
553 output
.writeFormula(aTemplate
.getTemplate());
558 ScRange
ScAnalysisOfVarianceDialog::ApplyOutput(ScDocShell
* pDocShell
)
560 AddressWalkerWriter
output(mOutputAddress
, pDocShell
, mDocument
,
561 formula::FormulaGrammar::mergeToGrammar(formula::FormulaGrammar::GRAM_ENGLISH
, mAddressDetails
.eConv
));
562 FormulaTemplate
aTemplate(mDocument
);
564 if (meFactor
== SINGLE_FACTOR
)
566 AnovaSingleFactor(output
, aTemplate
);
568 else if (meFactor
== TWO_FACTOR
)
570 AnovaTwoFactor(output
, aTemplate
);
573 return ScRange(output
.mMinimumAddress
, output
.mMaximumAddress
);
576 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */