Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/sc/source/ui/StatisticsDialogs/AnalysisOfVarianceDialog.cxx
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
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/.
8
 *
9
 */
10
11
#include <memory>
12
#include <string_view>
13
14
#include <rangelst.hxx>
15
#include <reffact.hxx>
16
#include <TableFillingAndNavigationTools.hxx>
17
#include <AnalysisOfVarianceDialog.hxx>
18
#include <scresid.hxx>
19
#include <strings.hrc>
20
21
namespace
22
{
23
24
struct StatisticCalculation {
25
    TranslateId aLabelId;
26
    const char* aFormula;
27
    const char* aResultRangeName;
28
};
29
30
StatisticCalculation const lclBasicStatistics[] =
31
{
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       }
38
};
39
40
const TranslateId lclAnovaLabels[] =
41
{
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,
49
    {}
50
};
51
52
constexpr OUString strWildcardRange = u"%RANGE%"_ustr;
53
54
OUString lclCreateMultiParameterFormula(
55
            ScRangeList&        aRangeList, const OUString& aFormulaTemplate,
56
            std::u16string_view aWildcard,  const ScDocument& rDocument,
57
            const ScAddress::Details& aAddressDetails)
58
0
{
59
0
    OUStringBuffer aResult;
60
0
    for (size_t i = 0; i < aRangeList.size(); i++)
61
0
    {
62
0
        OUString aRangeString(aRangeList[i].Format(rDocument, ScRefFlags::RANGE_ABS_3D, aAddressDetails));
63
0
        OUString aFormulaString = aFormulaTemplate.replaceAll(aWildcard, aRangeString);
64
0
        aResult.append(aFormulaString);
65
0
        if(i != aRangeList.size() - 1) // Not Last
66
0
            aResult.append(";");
67
0
    }
68
0
    return aResult.makeStringAndClear();
69
0
}
70
71
void lclMakeSubRangesList(ScRangeList& rRangeList, const ScRange& rInputRange, ScStatisticsInputOutputDialog::GroupedBy aGroupedBy)
72
0
{
73
0
    std::unique_ptr<DataRangeIterator> pIterator;
74
0
    if (aGroupedBy == ScStatisticsInputOutputDialog::BY_COLUMN)
75
0
        pIterator.reset(new DataRangeByColumnIterator(rInputRange));
76
0
    else
77
0
        pIterator.reset(new DataRangeByRowIterator(rInputRange));
78
79
0
    for( ; pIterator->hasNext(); pIterator->next() )
80
0
    {
81
0
        ScRange aRange = pIterator->get();
82
0
        rRangeList.push_back(aRange);
83
0
    }
84
0
}
85
86
}
87
88
ScAnalysisOfVarianceDialog::ScAnalysisOfVarianceDialog(
89
                    SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
90
                    weld::Window* pParent, ScViewData& rViewData )
91
0
    : ScStatisticsInputOutputDialog(
92
0
            pSfxBindings, pChildWindow, pParent, rViewData,
93
0
            u"modules/scalc/ui/analysisofvariancedialog.ui"_ustr,
94
0
            u"AnalysisOfVarianceDialog"_ustr)
95
0
    , meFactor(SINGLE_FACTOR)
96
0
    , mxAlphaField(m_xBuilder->weld_spin_button(u"alpha-spin"_ustr))
97
0
    , mxSingleFactorRadio(m_xBuilder->weld_radio_button(u"radio-single-factor"_ustr))
98
0
    , mxTwoFactorRadio(m_xBuilder->weld_radio_button(u"radio-two-factor"_ustr))
99
0
    , mxRowsPerSampleField(m_xBuilder->weld_spin_button(u"rows-per-sample-spin"_ustr))
100
0
{
101
0
    mxSingleFactorRadio->connect_toggled( LINK( this, ScAnalysisOfVarianceDialog, FactorChanged ) );
102
0
    mxTwoFactorRadio->connect_toggled( LINK( this, ScAnalysisOfVarianceDialog, FactorChanged ) );
103
104
0
    mxSingleFactorRadio->set_active(true);
105
0
    mxTwoFactorRadio->set_active(false);
106
107
0
    FactorChanged();
108
0
}
109
110
ScAnalysisOfVarianceDialog::~ScAnalysisOfVarianceDialog()
111
0
{
112
0
}
113
114
void ScAnalysisOfVarianceDialog::Close()
115
0
{
116
0
    DoClose( ScAnalysisOfVarianceDialogWrapper::GetChildWindowId() );
117
0
}
118
119
TranslateId ScAnalysisOfVarianceDialog::GetUndoNameId()
120
0
{
121
0
    return STR_ANALYSIS_OF_VARIANCE_UNDO_NAME;
122
0
}
123
124
IMPL_LINK_NOARG( ScAnalysisOfVarianceDialog, FactorChanged, weld::Toggleable&, void )
125
0
{
126
0
    FactorChanged();
127
0
}
128
129
void ScAnalysisOfVarianceDialog::FactorChanged()
130
0
{
131
0
    if (mxSingleFactorRadio->get_active())
132
0
    {
133
0
        mxGroupByRowsRadio->set_sensitive(true);
134
0
        mxGroupByColumnsRadio->set_sensitive(true);
135
0
        mxRowsPerSampleField->set_sensitive(false);
136
0
        meFactor = SINGLE_FACTOR;
137
0
    }
138
0
    else if (mxTwoFactorRadio->get_active())
139
0
    {
140
0
        mxGroupByRowsRadio->set_sensitive(false);
141
0
        mxGroupByColumnsRadio->set_sensitive(false);
142
0
        mxRowsPerSampleField->set_sensitive(false); // Rows per sample not yet implemented
143
0
        meFactor = TWO_FACTOR;
144
0
    }
145
0
}
146
147
void ScAnalysisOfVarianceDialog::RowColumn(ScRangeList& rRangeList, AddressWalkerWriter& aOutput, FormulaTemplate& aTemplate,
148
                                           const OUString& sFormula, GroupedBy aGroupedBy, ScRange* pResultRange)
149
0
{
150
0
    if (pResultRange != nullptr)
151
0
        pResultRange->aStart = aOutput.current();
152
0
    if (!sFormula.isEmpty())
153
0
    {
154
0
        for (size_t i = 0; i < rRangeList.size(); i++)
155
0
        {
156
0
            ScRange const & rRange = rRangeList[i];
157
0
            aTemplate.setTemplate(sFormula);
158
0
            aTemplate.applyRange(strWildcardRange, rRange);
159
0
            aOutput.writeFormula(aTemplate.getTemplate());
160
0
            if (pResultRange != nullptr)
161
0
                pResultRange->aEnd = aOutput.current();
162
0
            aOutput.nextRow();
163
0
        }
164
0
    }
165
0
    else
166
0
    {
167
0
        TranslateId pLabelId = (aGroupedBy == BY_COLUMN) ? STR_COLUMN_LABEL_TEMPLATE : STR_ROW_LABEL_TEMPLATE;
168
0
        OUString aLabelTemplate(ScResId(pLabelId));
169
170
0
        for (size_t i = 0; i < rRangeList.size(); i++)
171
0
        {
172
0
            aTemplate.setTemplate(aLabelTemplate);
173
0
            aTemplate.applyNumber(u"%NUMBER%", i + 1);
174
0
            aOutput.writeString(aTemplate.getTemplate());
175
0
            if (pResultRange != nullptr)
176
0
                pResultRange->aEnd = aOutput.current();
177
0
            aOutput.nextRow();
178
0
        }
179
0
    }
180
0
}
181
182
void ScAnalysisOfVarianceDialog::AnovaSingleFactor(AddressWalkerWriter& output, FormulaTemplate& aTemplate)
183
0
{
184
0
    output.writeBoldString(ScResId(STR_ANOVA_SINGLE_FACTOR_LABEL));
185
0
    output.newLine();
186
187
0
    double aAlphaValue = mxAlphaField->get_value() / 100.0;
188
0
    output.writeString(ScResId(STR_LABEL_ALPHA));
189
0
    output.nextColumn();
190
0
    output.writeValue(aAlphaValue);
191
0
    aTemplate.autoReplaceAddress(u"%ALPHA%"_ustr, output.current());
192
0
    output.newLine();
193
0
    output.newLine();
194
195
    // Write labels
196
0
    for(sal_Int32 i = 0; lclBasicStatistics[i].aLabelId; i++)
197
0
    {
198
0
        output.writeString(ScResId(lclBasicStatistics[i].aLabelId));
199
0
        output.nextColumn();
200
0
    }
201
0
    output.newLine();
202
203
    // Collect aRangeList
204
0
    ScRangeList aRangeList;
205
0
    lclMakeSubRangesList(aRangeList, mInputRange, mGroupedBy);
206
207
0
    output.push();
208
209
    // Write values
210
0
    for(sal_Int32 i = 0; lclBasicStatistics[i].aLabelId; i++)
211
0
    {
212
0
        output.resetRow();
213
0
        ScRange aResultRange;
214
0
        OUString sFormula = OUString::createFromAscii(lclBasicStatistics[i].aFormula);
215
0
        RowColumn(aRangeList, output, aTemplate, sFormula, mGroupedBy, &aResultRange);
216
0
        output.nextColumn();
217
0
        if (lclBasicStatistics[i].aResultRangeName != nullptr)
218
0
        {
219
0
            OUString sResultRangeName = OUString::createFromAscii(lclBasicStatistics[i].aResultRangeName);
220
0
            aTemplate.autoReplaceRange("%" + sResultRangeName + "%", aResultRange);
221
0
        }
222
0
    }
223
224
0
    output.nextRow(); // Blank row
225
226
    // Write ANOVA labels
227
0
    output.resetColumn();
228
0
    for(sal_Int32 i = 0; lclAnovaLabels[i]; i++)
229
0
    {
230
0
        output.writeString(ScResId(lclAnovaLabels[i]));
231
0
        output.nextColumn();
232
0
    }
233
0
    output.nextRow();
234
235
0
    aTemplate.autoReplaceRange(u"%FIRST_COLUMN%"_ustr, aRangeList[0]);
236
237
    // Between Groups
238
0
    {
239
        // Label
240
0
        output.resetColumn();
241
0
        output.writeString(ScResId(STR_ANOVA_LABEL_BETWEEN_GROUPS));
242
0
        output.nextColumn();
243
244
        // Sum of Squares
245
0
        aTemplate.setTemplate("=SUMPRODUCT(%SUM_RANGE%;%MEAN_RANGE%)-SUM(%SUM_RANGE%)^2/SUM(%COUNT_RANGE%)");
246
0
        aTemplate.autoReplaceAddress(u"%BETWEEN_SS%"_ustr, output.current());
247
0
        output.writeFormula(aTemplate.getTemplate());
248
0
        output.nextColumn();
249
250
        // Degree of freedom
251
0
        aTemplate.setTemplate("=COUNT(%SUM_RANGE%)-1");
252
0
        aTemplate.autoReplaceAddress(u"%BETWEEN_DF%"_ustr, output.current());
253
0
        output.writeFormula(aTemplate.getTemplate());
254
0
        output.nextColumn();
255
256
        // MS
257
0
        aTemplate.setTemplate("=%BETWEEN_SS% / %BETWEEN_DF%");
258
0
        aTemplate.autoReplaceAddress(u"%BETWEEN_MS%"_ustr, output.current());
259
0
        output.writeFormula(aTemplate.getTemplate());
260
0
        output.nextColumn();
261
262
        // F
263
0
        aTemplate.setTemplate("=%BETWEEN_MS% / %WITHIN_MS%");
264
0
        aTemplate.applyAddress(u"%WITHIN_MS%",  output.current(-1, 1));
265
0
        aTemplate.autoReplaceAddress(u"%F_VAL%"_ustr, output.current());
266
0
        output.writeFormula(aTemplate.getTemplate());
267
0
        output.nextColumn();
268
269
        // P-value
270
0
        aTemplate.setTemplate("=FDIST(%F_VAL%; %BETWEEN_DF%; %WITHIN_DF%");
271
0
        aTemplate.applyAddress(u"%WITHIN_DF%",   output.current(-3, 1));
272
0
        output.writeFormula(aTemplate.getTemplate());
273
0
        output.nextColumn();
274
275
        // F critical
276
0
        aTemplate.setTemplate("=FINV(%ALPHA%; %BETWEEN_DF%; %WITHIN_DF%");
277
0
        aTemplate.applyAddress(u"%WITHIN_DF%",  output.current(-4, 1));
278
0
        output.writeFormula(aTemplate.getTemplate());
279
0
    }
280
0
    output.nextRow();
281
282
    // Within Groups
283
0
    {
284
        // Label
285
0
        output.resetColumn();
286
0
        output.writeString(ScResId(STR_ANOVA_LABEL_WITHIN_GROUPS));
287
0
        output.nextColumn();
288
289
        // Sum of Squares
290
0
        OUString aSSPart = lclCreateMultiParameterFormula(aRangeList, u"DEVSQ(%RANGE%)"_ustr, strWildcardRange, mDocument, mAddressDetails);
291
0
        aTemplate.setTemplate("=SUM(%RANGE%)");
292
0
        aTemplate.applyString(strWildcardRange, aSSPart);
293
0
        aTemplate.autoReplaceAddress(u"%WITHIN_SS%"_ustr, output.current());
294
0
        output.writeFormula(aTemplate.getTemplate());
295
0
        output.nextColumn();
296
297
        // Degree of freedom
298
0
        aTemplate.setTemplate("=SUM(%COUNT_RANGE%)-COUNT(%COUNT_RANGE%)");
299
0
        aTemplate.autoReplaceAddress(u"%WITHIN_DF%"_ustr, output.current());
300
0
        output.writeFormula(aTemplate.getTemplate());
301
0
        output.nextColumn();
302
303
        // MS
304
0
        aTemplate.setTemplate("=%WITHIN_SS% / %WITHIN_DF%");
305
0
        output.writeFormula(aTemplate.getTemplate());
306
0
    }
307
0
    output.nextRow();
308
309
    // Total
310
0
    {
311
        // Label
312
0
        output.resetColumn();
313
0
        output.writeString(ScResId(STR_ANOVA_LABEL_TOTAL));
314
0
        output.nextColumn();
315
316
        // Sum of Squares
317
0
        aTemplate.setTemplate("=DEVSQ(%RANGE_LIST%)");
318
0
        aTemplate.applyRangeList(u"%RANGE_LIST%", aRangeList, ';');
319
0
        output.writeFormula(aTemplate.getTemplate());
320
0
        output.nextColumn();
321
322
        // Degree of freedom
323
0
        aTemplate.setTemplate("=SUM(%COUNT_RANGE%) - 1");
324
0
        output.writeFormula(aTemplate.getTemplate());
325
0
    }
326
0
    output.nextRow();
327
0
}
328
329
void ScAnalysisOfVarianceDialog::AnovaTwoFactor(AddressWalkerWriter& output, FormulaTemplate& aTemplate)
330
0
{
331
0
    output.writeBoldString(ScResId(STR_ANOVA_TWO_FACTOR_LABEL));
332
0
    output.newLine();
333
334
0
    double aAlphaValue = mxAlphaField->get_value() / 100.0;
335
0
    output.writeString("Alpha");
336
0
    output.nextColumn();
337
0
    output.writeValue(aAlphaValue);
338
0
    aTemplate.autoReplaceAddress(u"%ALPHA%"_ustr, output.current());
339
0
    output.newLine();
340
0
    output.newLine();
341
342
    // Write labels
343
0
    for(sal_Int32 i = 0; lclBasicStatistics[i].aLabelId; i++)
344
0
    {
345
0
        output.writeString(ScResId(lclBasicStatistics[i].aLabelId));
346
0
        output.nextColumn();
347
0
    }
348
0
    output.newLine();
349
350
0
    ScRangeList aColumnRangeList;
351
0
    ScRangeList aRowRangeList;
352
353
0
    lclMakeSubRangesList(aColumnRangeList, mInputRange, BY_COLUMN);
354
0
    lclMakeSubRangesList(aRowRangeList, mInputRange, BY_ROW);
355
356
    // Write ColumnX values
357
0
    output.push();
358
0
    for(sal_Int32 i = 0; lclBasicStatistics[i].aLabelId; i++)
359
0
    {
360
0
        output.resetRow();
361
0
        ScRange aResultRange;
362
0
        OUString sFormula = OUString::createFromAscii(lclBasicStatistics[i].aFormula);
363
0
        RowColumn(aColumnRangeList, output, aTemplate, sFormula, BY_COLUMN, &aResultRange);
364
0
        if (lclBasicStatistics[i].aResultRangeName != nullptr)
365
0
        {
366
0
            OUString sResultRangeName = OUString::createFromAscii(lclBasicStatistics[i].aResultRangeName);
367
0
            aTemplate.autoReplaceRange("%" + sResultRangeName + "_COLUMN%", aResultRange);
368
0
        }
369
0
        output.nextColumn();
370
0
    }
371
0
    output.newLine();
372
373
    // Write RowX values
374
0
    output.push();
375
0
    for(sal_Int32 i = 0; lclBasicStatistics[i].aLabelId; i++)
376
0
    {
377
0
        output.resetRow();
378
0
        ScRange aResultRange;
379
0
        OUString sFormula = OUString::createFromAscii(lclBasicStatistics[i].aFormula);
380
0
        RowColumn(aRowRangeList, output, aTemplate, sFormula, BY_ROW, &aResultRange);
381
382
0
        if (lclBasicStatistics[i].aResultRangeName != nullptr)
383
0
        {
384
0
            OUString sResultRangeName = OUString::createFromAscii(lclBasicStatistics[i].aResultRangeName);
385
0
            aTemplate.autoReplaceRange("%" + sResultRangeName + "_ROW%", aResultRange);
386
0
        }
387
0
        output.nextColumn();
388
0
    }
389
0
    output.newLine();
390
391
    // Write ANOVA labels
392
0
    for(sal_Int32 i = 0; lclAnovaLabels[i]; i++)
393
0
    {
394
0
        output.writeString(ScResId(lclAnovaLabels[i]));
395
0
        output.nextColumn();
396
0
    }
397
0
    output.nextRow();
398
399
    // Setup auto-replace strings
400
0
    aTemplate.autoReplaceRange(strWildcardRange, mInputRange);
401
0
    aTemplate.autoReplaceRange(u"%FIRST_COLUMN%"_ustr, aColumnRangeList[0]);
402
0
    aTemplate.autoReplaceRange(u"%FIRST_ROW%"_ustr,    aRowRangeList[0]);
403
404
    // Rows
405
0
    {
406
        // Label
407
0
        output.resetColumn();
408
0
        output.writeString("Rows");
409
0
        output.nextColumn();
410
411
        // Sum of Squares
412
0
        aTemplate.setTemplate("=SUMPRODUCT(%SUM_RANGE_ROW%;%MEAN_RANGE_ROW%) - SUM(%RANGE%)^2 / COUNT(%RANGE%)");
413
0
        aTemplate.autoReplaceAddress(u"%ROW_SS%"_ustr, output.current());
414
0
        output.writeFormula(aTemplate.getTemplate());
415
0
        output.nextColumn();
416
417
        // Degree of freedom
418
0
        aTemplate.setTemplate("=MAX(%COUNT_RANGE_COLUMN%) - 1");
419
0
        aTemplate.autoReplaceAddress(u"%ROW_DF%"_ustr, output.current());
420
0
        output.writeFormula(aTemplate.getTemplate());
421
0
        output.nextColumn();
422
423
        // MS
424
0
        aTemplate.setTemplate("=%ROW_SS% / %ROW_DF%");
425
0
        aTemplate.autoReplaceAddress(u"%MS_ROW%"_ustr, output.current());
426
0
        output.writeFormula(aTemplate.getTemplate());
427
0
        output.nextColumn();
428
429
        // F
430
0
        aTemplate.setTemplate("=%MS_ROW% / %MS_ERROR%");
431
0
        aTemplate.applyAddress(u"%MS_ERROR%", output.current(-1, 2));
432
0
        aTemplate.autoReplaceAddress(u"%F_ROW%"_ustr, output.current());
433
0
        output.writeFormula(aTemplate.getTemplate());
434
0
        output.nextColumn();
435
436
        // P-value
437
0
        aTemplate.setTemplate("=FDIST(%F_ROW%; %ROW_DF%; %ERROR_DF%");
438
0
        aTemplate.applyAddress(u"%ERROR_DF%",   output.current(-3, 2));
439
0
        output.writeFormula(aTemplate.getTemplate());
440
0
        output.nextColumn();
441
442
        // F critical
443
0
        aTemplate.setTemplate("=FINV(%ALPHA%; %ROW_DF%; %ERROR_DF%");
444
0
        aTemplate.applyAddress(u"%ERROR_DF%",  output.current(-4, 2));
445
0
        output.writeFormula(aTemplate.getTemplate());
446
0
        output.nextColumn();
447
0
    }
448
0
    output.nextRow();
449
450
    // Columns
451
0
    {
452
        // Label
453
0
        output.resetColumn();
454
0
        output.writeString("Columns");
455
0
        output.nextColumn();
456
457
        // Sum of Squares
458
0
        aTemplate.setTemplate("=SUMPRODUCT(%SUM_RANGE_COLUMN%;%MEAN_RANGE_COLUMN%) - SUM(%RANGE%)^2 / COUNT(%RANGE%)");
459
0
        aTemplate.autoReplaceAddress(u"%COLUMN_SS%"_ustr, output.current());
460
0
        output.writeFormula(aTemplate.getTemplate());
461
0
        output.nextColumn();
462
463
        // Degree of freedom
464
0
        aTemplate.setTemplate("=MAX(%COUNT_RANGE_ROW%) - 1");
465
0
        aTemplate.autoReplaceAddress(u"%COLUMN_DF%"_ustr, output.current());
466
0
        output.writeFormula(aTemplate.getTemplate());
467
0
        output.nextColumn();
468
469
        // MS
470
0
        aTemplate.setTemplate("=%COLUMN_SS% / %COLUMN_DF%");
471
0
        aTemplate.autoReplaceAddress(u"%MS_COLUMN%"_ustr, output.current());
472
0
        output.writeFormula(aTemplate.getTemplate());
473
0
        output.nextColumn();
474
475
        // F
476
0
        aTemplate.setTemplate("=%MS_COLUMN% / %MS_ERROR%");
477
0
        aTemplate.applyAddress(u"%MS_ERROR%", output.current(-1, 1));
478
0
        aTemplate.autoReplaceAddress(u"%F_COLUMN%"_ustr, output.current());
479
0
        output.writeFormula(aTemplate.getTemplate());
480
0
        output.nextColumn();
481
482
         // P-value
483
0
        aTemplate.setTemplate("=FDIST(%F_COLUMN%; %COLUMN_DF%; %ERROR_DF%");
484
0
        aTemplate.applyAddress(u"%ERROR_DF%",   output.current(-3, 1));
485
0
        output.writeFormula(aTemplate.getTemplate());
486
0
        output.nextColumn();
487
488
        // F critical
489
0
        aTemplate.setTemplate("=FINV(%ALPHA%; %COLUMN_DF%; %ERROR_DF%");
490
0
        aTemplate.applyAddress(u"%ERROR_DF%",  output.current(-4, 1));
491
0
        output.writeFormula(aTemplate.getTemplate());
492
0
        output.nextColumn();
493
0
    }
494
0
    output.nextRow();
495
496
    // Error
497
0
    {
498
        // Label
499
0
        output.resetColumn();
500
0
        output.writeString("Error");
501
0
        output.nextColumn();
502
503
        // Sum of Squares
504
0
        aTemplate.setTemplate("=SUMSQ(%RANGE%)+SUM(%RANGE%)^2/COUNT(%RANGE%) - (SUMPRODUCT(%SUM_RANGE_ROW%;%MEAN_RANGE_ROW%) + SUMPRODUCT(%SUM_RANGE_COLUMN%;%MEAN_RANGE_COLUMN%))");
505
0
        aTemplate.autoReplaceAddress(u"%ERROR_SS%"_ustr, output.current());
506
0
        output.writeFormula(aTemplate.getTemplate());
507
0
        output.nextColumn();
508
509
        // Degree of freedom
510
0
        aTemplate.setTemplate("=%TOTAL_DF% - %ROW_DF% - %COLUMN_DF%");
511
0
        aTemplate.applyAddress(u"%TOTAL_DF%", output.current(0,1));
512
0
        aTemplate.autoReplaceAddress(u"%ERROR_DF%"_ustr, output.current());
513
0
        output.writeFormula(aTemplate.getTemplate());
514
0
        output.nextColumn();
515
516
        // MS
517
0
        aTemplate.setTemplate("=%ERROR_SS% / %ERROR_DF%");
518
0
        output.writeFormula(aTemplate.getTemplate());
519
0
    }
520
0
    output.nextRow();
521
522
     // Total
523
0
    {
524
        // Label
525
0
        output.resetColumn();
526
0
        output.writeString("Total");
527
0
        output.nextColumn();
528
529
        // Sum of Squares
530
0
        aTemplate.setTemplate("=SUM(%ROW_SS%;%COLUMN_SS%;%ERROR_SS%)");
531
0
        output.writeFormula(aTemplate.getTemplate());
532
0
        output.nextColumn();
533
534
        // Degree of freedom
535
0
        aTemplate.setTemplate("=COUNT(%RANGE%)-1");
536
0
        output.writeFormula(aTemplate.getTemplate());
537
0
        output.nextColumn();
538
0
    }
539
0
}
540
541
ScRange ScAnalysisOfVarianceDialog::ApplyOutput(ScDocShell& rDocShell)
542
0
{
543
0
    AddressWalkerWriter output(mOutputAddress, rDocShell, mDocument,
544
0
        formula::FormulaGrammar::mergeToGrammar(formula::FormulaGrammar::GRAM_ENGLISH, mAddressDetails.eConv));
545
0
    FormulaTemplate aTemplate(&mDocument);
546
547
0
    if (meFactor == SINGLE_FACTOR)
548
0
    {
549
0
        AnovaSingleFactor(output, aTemplate);
550
0
    }
551
0
    else if (meFactor == TWO_FACTOR)
552
0
    {
553
0
        AnovaTwoFactor(output, aTemplate);
554
0
    }
555
556
0
    return ScRange(output.mMinimumAddress, output.mMaximumAddress);
557
0
}
558
559
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */