tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / StatisticsDialogs / AnalysisOfVarianceDialog.cxx
blobacfab698b6011aff1499dddb6de29c926b5ae9bb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
9 */
11 #include <memory>
12 #include <string_view>
14 #include <rangelst.hxx>
15 #include <reffact.hxx>
16 #include <TableFillingAndNavigationTools.hxx>
17 #include <AnalysisOfVarianceDialog.hxx>
18 #include <scresid.hxx>
19 #include <strings.hrc>
21 namespace
24 struct StatisticCalculation {
25 TranslateId aLabelId;
26 const char* aFormula;
27 const char* aResultRangeName;
30 StatisticCalculation const lclBasicStatistics[] =
32 { STR_ANOVA_LABEL_GROUPS, nullptr, nullptr },
33 { STRID_CALC_COUNT, "=COUNT(%RANGE%)", "COUNT_RANGE" },
34 { STRID_CALC_SUM, "=SUM(%RANGE%)", "SUM_RANGE" },
35 { STRID_CALC_MEAN, "=AVERAGE(%RANGE%)", "MEAN_RANGE" },
36 { STRID_CALC_VARIANCE, "=VAR(%RANGE%)", "VAR_RANGE" },
37 { {}, nullptr, nullptr }
40 const TranslateId lclAnovaLabels[] =
42 STR_ANOVA_LABEL_SOURCE_OF_VARIATION,
43 STR_ANOVA_LABEL_SS,
44 STR_ANOVA_LABEL_DF,
45 STR_ANOVA_LABEL_MS,
46 STR_ANOVA_LABEL_F,
47 STR_ANOVA_LABEL_P_VALUE,
48 STR_ANOVA_LABEL_F_CRITICAL,
52 constexpr OUString strWildcardRange = u"%RANGE%"_ustr;
54 OUString lclCreateMultiParameterFormula(
55 ScRangeList& aRangeList, const OUString& aFormulaTemplate,
56 std::u16string_view aWildcard, const ScDocument& rDocument,
57 const ScAddress::Details& aAddressDetails)
59 OUStringBuffer aResult;
60 for (size_t i = 0; i < aRangeList.size(); i++)
62 OUString aRangeString(aRangeList[i].Format(rDocument, ScRefFlags::RANGE_ABS_3D, aAddressDetails));
63 OUString aFormulaString = aFormulaTemplate.replaceAll(aWildcard, aRangeString);
64 aResult.append(aFormulaString);
65 if(i != aRangeList.size() - 1) // Not Last
66 aResult.append(";");
68 return aResult.makeStringAndClear();
71 void lclMakeSubRangesList(ScRangeList& rRangeList, const ScRange& rInputRange, ScStatisticsInputOutputDialog::GroupedBy aGroupedBy)
73 std::unique_ptr<DataRangeIterator> pIterator;
74 if (aGroupedBy == ScStatisticsInputOutputDialog::BY_COLUMN)
75 pIterator.reset(new DataRangeByColumnIterator(rInputRange));
76 else
77 pIterator.reset(new DataRangeByRowIterator(rInputRange));
79 for( ; pIterator->hasNext(); pIterator->next() )
81 ScRange aRange = pIterator->get();
82 rRangeList.push_back(aRange);
88 ScAnalysisOfVarianceDialog::ScAnalysisOfVarianceDialog(
89 SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
90 weld::Window* pParent, ScViewData& rViewData )
91 : ScStatisticsInputOutputDialog(
92 pSfxBindings, pChildWindow, pParent, rViewData,
93 u"modules/scalc/ui/analysisofvariancedialog.ui"_ustr,
94 u"AnalysisOfVarianceDialog"_ustr)
95 , meFactor(SINGLE_FACTOR)
96 , mxAlphaField(m_xBuilder->weld_spin_button(u"alpha-spin"_ustr))
97 , mxSingleFactorRadio(m_xBuilder->weld_radio_button(u"radio-single-factor"_ustr))
98 , mxTwoFactorRadio(m_xBuilder->weld_radio_button(u"radio-two-factor"_ustr))
99 , mxRowsPerSampleField(m_xBuilder->weld_spin_button(u"rows-per-sample-spin"_ustr))
101 mxSingleFactorRadio->connect_toggled( LINK( this, ScAnalysisOfVarianceDialog, FactorChanged ) );
102 mxTwoFactorRadio->connect_toggled( LINK( this, ScAnalysisOfVarianceDialog, FactorChanged ) );
104 mxSingleFactorRadio->set_active(true);
105 mxTwoFactorRadio->set_active(false);
107 FactorChanged();
110 ScAnalysisOfVarianceDialog::~ScAnalysisOfVarianceDialog()
114 void ScAnalysisOfVarianceDialog::Close()
116 DoClose( ScAnalysisOfVarianceDialogWrapper::GetChildWindowId() );
119 TranslateId ScAnalysisOfVarianceDialog::GetUndoNameId()
121 return STR_ANALYSIS_OF_VARIANCE_UNDO_NAME;
124 IMPL_LINK_NOARG( ScAnalysisOfVarianceDialog, FactorChanged, weld::Toggleable&, void )
126 FactorChanged();
129 void ScAnalysisOfVarianceDialog::FactorChanged()
131 if (mxSingleFactorRadio->get_active())
133 mxGroupByRowsRadio->set_sensitive(true);
134 mxGroupByColumnsRadio->set_sensitive(true);
135 mxRowsPerSampleField->set_sensitive(false);
136 meFactor = SINGLE_FACTOR;
138 else if (mxTwoFactorRadio->get_active())
140 mxGroupByRowsRadio->set_sensitive(false);
141 mxGroupByColumnsRadio->set_sensitive(false);
142 mxRowsPerSampleField->set_sensitive(false); // Rows per sample not yet implemented
143 meFactor = TWO_FACTOR;
147 void ScAnalysisOfVarianceDialog::RowColumn(ScRangeList& rRangeList, AddressWalkerWriter& aOutput, FormulaTemplate& aTemplate,
148 const OUString& sFormula, GroupedBy aGroupedBy, ScRange* pResultRange)
150 if (pResultRange != nullptr)
151 pResultRange->aStart = aOutput.current();
152 if (!sFormula.isEmpty())
154 for (size_t i = 0; i < rRangeList.size(); i++)
156 ScRange const & rRange = rRangeList[i];
157 aTemplate.setTemplate(sFormula);
158 aTemplate.applyRange(strWildcardRange, rRange);
159 aOutput.writeFormula(aTemplate.getTemplate());
160 if (pResultRange != nullptr)
161 pResultRange->aEnd = aOutput.current();
162 aOutput.nextRow();
165 else
167 TranslateId pLabelId = (aGroupedBy == BY_COLUMN) ? STR_COLUMN_LABEL_TEMPLATE : STR_ROW_LABEL_TEMPLATE;
168 OUString aLabelTemplate(ScResId(pLabelId));
170 for (size_t i = 0; i < rRangeList.size(); i++)
172 aTemplate.setTemplate(aLabelTemplate);
173 aTemplate.applyNumber(u"%NUMBER%", i + 1);
174 aOutput.writeString(aTemplate.getTemplate());
175 if (pResultRange != nullptr)
176 pResultRange->aEnd = aOutput.current();
177 aOutput.nextRow();
182 void ScAnalysisOfVarianceDialog::AnovaSingleFactor(AddressWalkerWriter& output, FormulaTemplate& aTemplate)
184 output.writeBoldString(ScResId(STR_ANOVA_SINGLE_FACTOR_LABEL));
185 output.newLine();
187 double aAlphaValue = mxAlphaField->get_value() / 100.0;
188 output.writeString(ScResId(STR_LABEL_ALPHA));
189 output.nextColumn();
190 output.writeValue(aAlphaValue);
191 aTemplate.autoReplaceAddress(u"%ALPHA%"_ustr, output.current());
192 output.newLine();
193 output.newLine();
195 // Write labels
196 for(sal_Int32 i = 0; lclBasicStatistics[i].aLabelId; i++)
198 output.writeString(ScResId(lclBasicStatistics[i].aLabelId));
199 output.nextColumn();
201 output.newLine();
203 // Collect aRangeList
204 ScRangeList aRangeList;
205 lclMakeSubRangesList(aRangeList, mInputRange, mGroupedBy);
207 output.push();
209 // Write values
210 for(sal_Int32 i = 0; lclBasicStatistics[i].aLabelId; i++)
212 output.resetRow();
213 ScRange aResultRange;
214 OUString sFormula = OUString::createFromAscii(lclBasicStatistics[i].aFormula);
215 RowColumn(aRangeList, output, aTemplate, sFormula, mGroupedBy, &aResultRange);
216 output.nextColumn();
217 if (lclBasicStatistics[i].aResultRangeName != nullptr)
219 OUString sResultRangeName = OUString::createFromAscii(lclBasicStatistics[i].aResultRangeName);
220 aTemplate.autoReplaceRange("%" + sResultRangeName + "%", aResultRange);
224 output.nextRow(); // Blank row
226 // Write ANOVA labels
227 output.resetColumn();
228 for(sal_Int32 i = 0; lclAnovaLabels[i]; i++)
230 output.writeString(ScResId(lclAnovaLabels[i]));
231 output.nextColumn();
233 output.nextRow();
235 aTemplate.autoReplaceRange(u"%FIRST_COLUMN%"_ustr, aRangeList[0]);
237 // Between Groups
239 // Label
240 output.resetColumn();
241 output.writeString(ScResId(STR_ANOVA_LABEL_BETWEEN_GROUPS));
242 output.nextColumn();
244 // Sum of Squares
245 aTemplate.setTemplate("=SUMPRODUCT(%SUM_RANGE%;%MEAN_RANGE%)-SUM(%SUM_RANGE%)^2/SUM(%COUNT_RANGE%)");
246 aTemplate.autoReplaceAddress(u"%BETWEEN_SS%"_ustr, output.current());
247 output.writeFormula(aTemplate.getTemplate());
248 output.nextColumn();
250 // Degree of freedom
251 aTemplate.setTemplate("=COUNT(%SUM_RANGE%)-1");
252 aTemplate.autoReplaceAddress(u"%BETWEEN_DF%"_ustr, output.current());
253 output.writeFormula(aTemplate.getTemplate());
254 output.nextColumn();
256 // MS
257 aTemplate.setTemplate("=%BETWEEN_SS% / %BETWEEN_DF%");
258 aTemplate.autoReplaceAddress(u"%BETWEEN_MS%"_ustr, output.current());
259 output.writeFormula(aTemplate.getTemplate());
260 output.nextColumn();
262 // F
263 aTemplate.setTemplate("=%BETWEEN_MS% / %WITHIN_MS%");
264 aTemplate.applyAddress(u"%WITHIN_MS%", output.current(-1, 1));
265 aTemplate.autoReplaceAddress(u"%F_VAL%"_ustr, output.current());
266 output.writeFormula(aTemplate.getTemplate());
267 output.nextColumn();
269 // P-value
270 aTemplate.setTemplate("=FDIST(%F_VAL%; %BETWEEN_DF%; %WITHIN_DF%");
271 aTemplate.applyAddress(u"%WITHIN_DF%", output.current(-3, 1));
272 output.writeFormula(aTemplate.getTemplate());
273 output.nextColumn();
275 // F critical
276 aTemplate.setTemplate("=FINV(%ALPHA%; %BETWEEN_DF%; %WITHIN_DF%");
277 aTemplate.applyAddress(u"%WITHIN_DF%", output.current(-4, 1));
278 output.writeFormula(aTemplate.getTemplate());
280 output.nextRow();
282 // Within Groups
284 // Label
285 output.resetColumn();
286 output.writeString(ScResId(STR_ANOVA_LABEL_WITHIN_GROUPS));
287 output.nextColumn();
289 // Sum of Squares
290 OUString aSSPart = lclCreateMultiParameterFormula(aRangeList, u"DEVSQ(%RANGE%)"_ustr, strWildcardRange, mDocument, mAddressDetails);
291 aTemplate.setTemplate("=SUM(%RANGE%)");
292 aTemplate.applyString(strWildcardRange, aSSPart);
293 aTemplate.autoReplaceAddress(u"%WITHIN_SS%"_ustr, output.current());
294 output.writeFormula(aTemplate.getTemplate());
295 output.nextColumn();
297 // Degree of freedom
298 aTemplate.setTemplate("=SUM(%COUNT_RANGE%)-COUNT(%COUNT_RANGE%)");
299 aTemplate.autoReplaceAddress(u"%WITHIN_DF%"_ustr, output.current());
300 output.writeFormula(aTemplate.getTemplate());
301 output.nextColumn();
303 // MS
304 aTemplate.setTemplate("=%WITHIN_SS% / %WITHIN_DF%");
305 output.writeFormula(aTemplate.getTemplate());
307 output.nextRow();
309 // Total
311 // Label
312 output.resetColumn();
313 output.writeString(ScResId(STR_ANOVA_LABEL_TOTAL));
314 output.nextColumn();
316 // Sum of Squares
317 aTemplate.setTemplate("=DEVSQ(%RANGE_LIST%)");
318 aTemplate.applyRangeList(u"%RANGE_LIST%", aRangeList, ';');
319 output.writeFormula(aTemplate.getTemplate());
320 output.nextColumn();
322 // Degree of freedom
323 aTemplate.setTemplate("=SUM(%COUNT_RANGE%) - 1");
324 output.writeFormula(aTemplate.getTemplate());
326 output.nextRow();
329 void ScAnalysisOfVarianceDialog::AnovaTwoFactor(AddressWalkerWriter& output, FormulaTemplate& aTemplate)
331 output.writeBoldString(ScResId(STR_ANOVA_TWO_FACTOR_LABEL));
332 output.newLine();
334 double aAlphaValue = mxAlphaField->get_value() / 100.0;
335 output.writeString("Alpha");
336 output.nextColumn();
337 output.writeValue(aAlphaValue);
338 aTemplate.autoReplaceAddress(u"%ALPHA%"_ustr, output.current());
339 output.newLine();
340 output.newLine();
342 // Write labels
343 for(sal_Int32 i = 0; lclBasicStatistics[i].aLabelId; i++)
345 output.writeString(ScResId(lclBasicStatistics[i].aLabelId));
346 output.nextColumn();
348 output.newLine();
350 ScRangeList aColumnRangeList;
351 ScRangeList aRowRangeList;
353 lclMakeSubRangesList(aColumnRangeList, mInputRange, BY_COLUMN);
354 lclMakeSubRangesList(aRowRangeList, mInputRange, BY_ROW);
356 // Write ColumnX values
357 output.push();
358 for(sal_Int32 i = 0; lclBasicStatistics[i].aLabelId; i++)
360 output.resetRow();
361 ScRange aResultRange;
362 OUString sFormula = OUString::createFromAscii(lclBasicStatistics[i].aFormula);
363 RowColumn(aColumnRangeList, output, aTemplate, sFormula, BY_COLUMN, &aResultRange);
364 if (lclBasicStatistics[i].aResultRangeName != nullptr)
366 OUString sResultRangeName = OUString::createFromAscii(lclBasicStatistics[i].aResultRangeName);
367 aTemplate.autoReplaceRange("%" + sResultRangeName + "_COLUMN%", aResultRange);
369 output.nextColumn();
371 output.newLine();
373 // Write RowX values
374 output.push();
375 for(sal_Int32 i = 0; lclBasicStatistics[i].aLabelId; i++)
377 output.resetRow();
378 ScRange aResultRange;
379 OUString sFormula = OUString::createFromAscii(lclBasicStatistics[i].aFormula);
380 RowColumn(aRowRangeList, output, aTemplate, sFormula, BY_ROW, &aResultRange);
382 if (lclBasicStatistics[i].aResultRangeName != nullptr)
384 OUString sResultRangeName = OUString::createFromAscii(lclBasicStatistics[i].aResultRangeName);
385 aTemplate.autoReplaceRange("%" + sResultRangeName + "_ROW%", aResultRange);
387 output.nextColumn();
389 output.newLine();
391 // Write ANOVA labels
392 for(sal_Int32 i = 0; lclAnovaLabels[i]; i++)
394 output.writeString(ScResId(lclAnovaLabels[i]));
395 output.nextColumn();
397 output.nextRow();
399 // Setup auto-replace strings
400 aTemplate.autoReplaceRange(strWildcardRange, mInputRange);
401 aTemplate.autoReplaceRange(u"%FIRST_COLUMN%"_ustr, aColumnRangeList[0]);
402 aTemplate.autoReplaceRange(u"%FIRST_ROW%"_ustr, aRowRangeList[0]);
404 // Rows
406 // Label
407 output.resetColumn();
408 output.writeString("Rows");
409 output.nextColumn();
411 // Sum of Squares
412 aTemplate.setTemplate("=SUMPRODUCT(%SUM_RANGE_ROW%;%MEAN_RANGE_ROW%) - SUM(%RANGE%)^2 / COUNT(%RANGE%)");
413 aTemplate.autoReplaceAddress(u"%ROW_SS%"_ustr, output.current());
414 output.writeFormula(aTemplate.getTemplate());
415 output.nextColumn();
417 // Degree of freedom
418 aTemplate.setTemplate("=MAX(%COUNT_RANGE_COLUMN%) - 1");
419 aTemplate.autoReplaceAddress(u"%ROW_DF%"_ustr, output.current());
420 output.writeFormula(aTemplate.getTemplate());
421 output.nextColumn();
423 // MS
424 aTemplate.setTemplate("=%ROW_SS% / %ROW_DF%");
425 aTemplate.autoReplaceAddress(u"%MS_ROW%"_ustr, output.current());
426 output.writeFormula(aTemplate.getTemplate());
427 output.nextColumn();
429 // F
430 aTemplate.setTemplate("=%MS_ROW% / %MS_ERROR%");
431 aTemplate.applyAddress(u"%MS_ERROR%", output.current(-1, 2));
432 aTemplate.autoReplaceAddress(u"%F_ROW%"_ustr, output.current());
433 output.writeFormula(aTemplate.getTemplate());
434 output.nextColumn();
436 // P-value
437 aTemplate.setTemplate("=FDIST(%F_ROW%; %ROW_DF%; %ERROR_DF%");
438 aTemplate.applyAddress(u"%ERROR_DF%", output.current(-3, 2));
439 output.writeFormula(aTemplate.getTemplate());
440 output.nextColumn();
442 // F critical
443 aTemplate.setTemplate("=FINV(%ALPHA%; %ROW_DF%; %ERROR_DF%");
444 aTemplate.applyAddress(u"%ERROR_DF%", output.current(-4, 2));
445 output.writeFormula(aTemplate.getTemplate());
446 output.nextColumn();
448 output.nextRow();
450 // Columns
452 // Label
453 output.resetColumn();
454 output.writeString("Columns");
455 output.nextColumn();
457 // Sum of Squares
458 aTemplate.setTemplate("=SUMPRODUCT(%SUM_RANGE_COLUMN%;%MEAN_RANGE_COLUMN%) - SUM(%RANGE%)^2 / COUNT(%RANGE%)");
459 aTemplate.autoReplaceAddress(u"%COLUMN_SS%"_ustr, output.current());
460 output.writeFormula(aTemplate.getTemplate());
461 output.nextColumn();
463 // Degree of freedom
464 aTemplate.setTemplate("=MAX(%COUNT_RANGE_ROW%) - 1");
465 aTemplate.autoReplaceAddress(u"%COLUMN_DF%"_ustr, output.current());
466 output.writeFormula(aTemplate.getTemplate());
467 output.nextColumn();
469 // MS
470 aTemplate.setTemplate("=%COLUMN_SS% / %COLUMN_DF%");
471 aTemplate.autoReplaceAddress(u"%MS_COLUMN%"_ustr, output.current());
472 output.writeFormula(aTemplate.getTemplate());
473 output.nextColumn();
475 // F
476 aTemplate.setTemplate("=%MS_COLUMN% / %MS_ERROR%");
477 aTemplate.applyAddress(u"%MS_ERROR%", output.current(-1, 1));
478 aTemplate.autoReplaceAddress(u"%F_COLUMN%"_ustr, output.current());
479 output.writeFormula(aTemplate.getTemplate());
480 output.nextColumn();
482 // P-value
483 aTemplate.setTemplate("=FDIST(%F_COLUMN%; %COLUMN_DF%; %ERROR_DF%");
484 aTemplate.applyAddress(u"%ERROR_DF%", output.current(-3, 1));
485 output.writeFormula(aTemplate.getTemplate());
486 output.nextColumn();
488 // F critical
489 aTemplate.setTemplate("=FINV(%ALPHA%; %COLUMN_DF%; %ERROR_DF%");
490 aTemplate.applyAddress(u"%ERROR_DF%", output.current(-4, 1));
491 output.writeFormula(aTemplate.getTemplate());
492 output.nextColumn();
494 output.nextRow();
496 // Error
498 // Label
499 output.resetColumn();
500 output.writeString("Error");
501 output.nextColumn();
503 // Sum of Squares
504 aTemplate.setTemplate("=SUMSQ(%RANGE%)+SUM(%RANGE%)^2/COUNT(%RANGE%) - (SUMPRODUCT(%SUM_RANGE_ROW%;%MEAN_RANGE_ROW%) + SUMPRODUCT(%SUM_RANGE_COLUMN%;%MEAN_RANGE_COLUMN%))");
505 aTemplate.autoReplaceAddress(u"%ERROR_SS%"_ustr, output.current());
506 output.writeFormula(aTemplate.getTemplate());
507 output.nextColumn();
509 // Degree of freedom
510 aTemplate.setTemplate("=%TOTAL_DF% - %ROW_DF% - %COLUMN_DF%");
511 aTemplate.applyAddress(u"%TOTAL_DF%", output.current(0,1));
512 aTemplate.autoReplaceAddress(u"%ERROR_DF%"_ustr, output.current());
513 output.writeFormula(aTemplate.getTemplate());
514 output.nextColumn();
516 // MS
517 aTemplate.setTemplate("=%ERROR_SS% / %ERROR_DF%");
518 output.writeFormula(aTemplate.getTemplate());
520 output.nextRow();
522 // Total
524 // Label
525 output.resetColumn();
526 output.writeString("Total");
527 output.nextColumn();
529 // Sum of Squares
530 aTemplate.setTemplate("=SUM(%ROW_SS%;%COLUMN_SS%;%ERROR_SS%)");
531 output.writeFormula(aTemplate.getTemplate());
532 output.nextColumn();
534 // Degree of freedom
535 aTemplate.setTemplate("=COUNT(%RANGE%)-1");
536 output.writeFormula(aTemplate.getTemplate());
537 output.nextColumn();
541 ScRange ScAnalysisOfVarianceDialog::ApplyOutput(ScDocShell* pDocShell)
543 AddressWalkerWriter output(mOutputAddress, pDocShell, mDocument,
544 formula::FormulaGrammar::mergeToGrammar(formula::FormulaGrammar::GRAM_ENGLISH, mAddressDetails.eConv));
545 FormulaTemplate aTemplate(&mDocument);
547 if (meFactor == SINGLE_FACTOR)
549 AnovaSingleFactor(output, aTemplate);
551 else if (meFactor == TWO_FACTOR)
553 AnovaTwoFactor(output, aTemplate);
556 return ScRange(output.mMinimumAddress, output.mMaximumAddress);
559 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */