Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/source/ui/pagedlg/areasdlg.cxx
Line
Count
Source
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
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#include <rangelst.hxx>
21
22
#include <o3tl/string_view.hxx>
23
#include <sfx2/dispatch.hxx>
24
#include <svl/stritem.hxx>
25
#include <vcl/svapp.hxx>
26
#include <vcl/weld.hxx>
27
#include <unotools/charclass.hxx>
28
29
#include <areasdlg.hxx>
30
#include <rangenam.hxx>
31
#include <reffact.hxx>
32
#include <tabvwsh.hxx>
33
#include <docsh.hxx>
34
#include <globstr.hrc>
35
#include <scresid.hxx>
36
#include <compiler.hxx>
37
#include <markdata.hxx>
38
39
// List box positions for print range (PR)
40
enum {
41
    SC_AREASDLG_PR_ENTIRE  = 1,
42
    SC_AREASDLG_PR_USER    = 2,
43
    SC_AREASDLG_PR_SELECT  = 3
44
};
45
46
// List box positions for repeat ranges (RR)
47
enum {
48
    SC_AREASDLG_RR_NONE    = 0,
49
    SC_AREASDLG_RR_USER    = 1,
50
    SC_AREASDLG_RR_OFFSET  = 2
51
};
52
53
namespace
54
{
55
    void ERRORBOX(weld::Window* pParent, TranslateId rId)
56
0
    {
57
0
        std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pParent,
58
0
                                                  VclMessageType::Warning, VclButtonsType::Ok,
59
0
                                                  ScResId(rId)));
60
0
        xBox->run();
61
0
    }
62
}
63
64
// global functions (->at the end of the file):
65
66
static bool lcl_CheckRepeatString( std::u16string_view aStr, const ScDocument& rDoc, bool bIsRow, ScRange* pRange );
67
static void lcl_GetRepeatRangeString( const std::optional<ScRange>& oRange, const ScDocument& rDoc, bool bIsRow, OUString& rStr );
68
69
#if 0
70
// this method is useful when debugging address flags.
71
static void printAddressFlags(ScRefFlags nFlag)
72
{
73
    if ((nFlag & ScRefFlags::COL_ABS      ) == ScRefFlags::COL_ABS      ) printf("ScRefFlags::COL_ABS      \n");
74
    if ((nFlag & ScRefFlags::ROW_ABS      ) == ScRefFlags::ROW_ABS      ) printf("ScRefFlags::ROW_ABS      \n");
75
    if ((nFlag & ScRefFlags::TAB_ABS      ) == ScRefFlags::TAB_ABS      ) printf("ScRefFlags::TAB_ABS      \n");
76
    if ((nFlag & ScRefFlags::TAB_3D       ) == ScRefFlags::TAB_3D       ) printf("ScRefFlags::TAB_3D       \n");
77
    if ((nFlag & ScRefFlags::COL2_ABS     ) == ScRefFlags::COL2_ABS     ) printf("ScRefFlags::COL2_ABS     \n");
78
    if ((nFlag & ScRefFlags::ROW2_ABS     ) == ScRefFlags::ROW2_ABS     ) printf("ScRefFlags::ROW2_ABS     \n");
79
    if ((nFlag & ScRefFlags::TAB2_ABS     ) == ScRefFlags::TAB2_ABS     ) printf("ScRefFlags::TAB2_ABS     \n");
80
    if ((nFlag & ScRefFlags::TAB2_3D      ) == ScRefFlags::TAB2_3D      ) printf("ScRefFlags::TAB2_3D      \n");
81
    if ((nFlag & ScRefFlags::ROW_VALID    ) == ScRefFlags::ROW_VALID    ) printf("ScRefFlags::ROW_VALID    \n");
82
    if ((nFlag & ScRefFlags::COL_VALID    ) == ScRefFlags::COL_VALID    ) printf("ScRefFlags::COL_VALID    \n");
83
    if ((nFlag & ScRefFlags::TAB_VALID    ) == ScRefFlags::TAB_VALID    ) printf("ScRefFlags::TAB_VALID    \n");
84
    if ((nFlag & ScRefFlags::FORCE_DOC    ) == ScRefFlags::FORCE_DOC    ) printf("ScRefFlags::FORCE_DOC    \n");
85
    if ((nFlag & ScRefFlags::ROW2_VALID   ) == ScRefFlags::ROW2_VALID   ) printf("ScRefFlags::ROW2_VALID   \n");
86
    if ((nFlag & ScRefFlags::COL2_VALID   ) == ScRefFlags::COL2_VALID   ) printf("ScRefFlags::COL2_VALID   \n");
87
    if ((nFlag & ScRefFlags::TAB2_VALID   ) == ScRefFlags::TAB2_VALID   ) printf("ScRefFlags::TAB2_VALID   \n");
88
    if ((nFlag & ScRefFlags::VALID        ) == ScRefFlags::VALID        ) printf("ScRefFlags::VALID        \n");
89
    if ((nFlag & ScRefFlags::ADDR_ABS     ) == ScRefFlags::ADDR_ABS     ) printf("ScRefFlags::ADDR_ABS     \n");
90
    if ((nFlag & ScRefFlags::RANGE_ABS    ) == ScRefFlags::RANGE_ABS    ) printf("ScRefFlags::RANGE_ABS    \n");
91
    if ((nFlag & ScRefFlags::ADDR_ABS_3D  ) == ScRefFlags::ADDR_ABS_3D  ) printf("ScRefFlags::ADDR_ABS_3D  \n");
92
    if ((nFlag & ScRefFlags::RANGE_ABS_3D ) == ScRefFlags::RANGE_ABS_3D ) printf("ScRefFlags::RANGE_ABS_3D \n");
93
}
94
#endif
95
96
97
ScPrintAreasDlg::ScPrintAreasDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent, ScViewData& rData)
98
0
    : ScAnyRefDlgController(pB, pCW, pParent, u"modules/scalc/ui/printareasdialog.ui"_ustr, u"PrintAreasDialog"_ustr)
99
0
    , bDlgLostFocus(false)
100
0
    , rViewData(rData)
101
0
    , rDoc(rViewData.GetDocument())
102
0
    , nCurTab(rViewData.CurrentTabForData())
103
0
    , m_xLbPrintArea(m_xBuilder->weld_combo_box(u"lbprintarea"_ustr))
104
0
    , m_xEdPrintArea(new formula::RefEdit(m_xBuilder->weld_entry(u"edprintarea"_ustr)))
105
0
    , m_xRbPrintArea(new formula::RefButton(m_xBuilder->weld_button(u"rbprintarea"_ustr)))
106
0
    , m_xLbRepeatRow(m_xBuilder->weld_combo_box(u"lbrepeatrow"_ustr))
107
0
    , m_xEdRepeatRow(new formula::RefEdit(m_xBuilder->weld_entry(u"edrepeatrow"_ustr)))
108
0
    , m_xRbRepeatRow(new formula::RefButton(m_xBuilder->weld_button(u"rbrepeatrow"_ustr)))
109
0
    , m_xLbRepeatCol(m_xBuilder->weld_combo_box(u"lbrepeatcol"_ustr))
110
0
    , m_xEdRepeatCol(new formula::RefEdit(m_xBuilder->weld_entry(u"edrepeatcol"_ustr)))
111
0
    , m_xRbRepeatCol(new formula::RefButton(m_xBuilder->weld_button(u"rbrepeatcol"_ustr)))
112
0
    , m_xBtnOk(m_xBuilder->weld_button(u"ok"_ustr))
113
0
    , m_xBtnCancel(m_xBuilder->weld_button(u"cancel"_ustr))
114
0
    , m_xPrintFrame(m_xBuilder->weld_frame(u"printframe"_ustr))
115
0
    , m_xRowFrame(m_xBuilder->weld_frame(u"rowframe"_ustr))
116
0
    , m_xColFrame(m_xBuilder->weld_frame(u"colframe"_ustr))
117
0
{
118
0
    m_xEdPrintArea->SetReferences(this, m_xPrintFrame.get());
119
0
    m_pRefInputEdit = m_xEdPrintArea.get();
120
0
    m_xRbPrintArea->SetReferences(this, m_xEdPrintArea.get());
121
122
0
    m_xEdRepeatRow->SetReferences(this, m_xRowFrame.get());
123
0
    m_xRbRepeatRow->SetReferences(this, m_xEdRepeatRow.get());
124
125
0
    m_xEdRepeatCol->SetReferences(this, m_xColFrame.get());
126
0
    m_xRbRepeatCol->SetReferences(this, m_xEdRepeatCol.get());
127
128
0
    Impl_Reset();
129
130
    //@BugID 54702 Enable/Disable only in base class
131
    //SFX_APPWINDOW->Enable();
132
0
}
133
134
ScPrintAreasDlg::~ScPrintAreasDlg()
135
0
{
136
0
}
137
138
void ScPrintAreasDlg::Close()
139
0
{
140
0
    DoClose( ScPrintAreasDlgWrapper::GetChildWindowId() );
141
0
}
142
143
bool ScPrintAreasDlg::IsTableLocked() const
144
0
{
145
    //  Printing areas are per table, therefore it makes no sense,
146
    //  to switch the table during input
147
148
0
    return true;
149
0
}
150
151
void ScPrintAreasDlg::SetReference( const ScRange& rRef, ScDocument& /* rDoc */ )
152
0
{
153
0
    if ( !m_pRefInputEdit )
154
0
        return;
155
156
0
    if ( rRef.aStart != rRef.aEnd )
157
0
        RefInputStart( m_pRefInputEdit );
158
159
0
    OUString  aStr;
160
0
    const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
161
162
0
    if (m_xEdPrintArea.get() == m_pRefInputEdit)
163
0
    {
164
0
        aStr = rRef.Format(rDoc, ScRefFlags::RANGE_ABS, eConv);
165
0
        OUString aVal = m_xEdPrintArea->GetText();
166
0
        Selection aSel = m_xEdPrintArea->GetSelection();
167
0
        aSel.Normalize();
168
0
        aVal = aVal.replaceAt( aSel.Min(), aSel.Len(), aStr );
169
0
        Selection aNewSel( aSel.Min(), aSel.Min()+aStr.getLength() );
170
0
        m_xEdPrintArea->SetRefString( aVal );
171
0
        m_xEdPrintArea->SetSelection( aNewSel );
172
0
    }
173
0
    else
174
0
    {
175
0
        bool bRow = ( m_xEdRepeatRow.get() == m_pRefInputEdit );
176
0
        lcl_GetRepeatRangeString(rRef, rDoc, bRow, aStr);
177
0
        m_pRefInputEdit->SetRefString( aStr );
178
0
    }
179
0
    Impl_ModifyHdl( *m_pRefInputEdit );
180
0
}
181
182
void ScPrintAreasDlg::AddRefEntry()
183
0
{
184
0
    if (m_pRefInputEdit == m_xEdPrintArea.get())
185
0
    {
186
0
        const sal_Unicode sep = ScCompiler::GetNativeSymbolChar(ocSep);
187
0
        OUString aVal = m_xEdPrintArea->GetText() + OUStringChar(sep);
188
0
        m_xEdPrintArea->SetText(aVal);
189
190
0
        sal_Int32 nLen = aVal.getLength();
191
0
        m_xEdPrintArea->SetSelection( Selection( nLen, nLen ) );
192
193
0
        Impl_ModifyHdl( *m_xEdPrintArea );
194
0
    }
195
0
}
196
197
void ScPrintAreasDlg::Deactivate()
198
0
{
199
0
    bDlgLostFocus = true;
200
0
}
201
202
void ScPrintAreasDlg::SetActive()
203
0
{
204
0
    if ( bDlgLostFocus )
205
0
    {
206
0
        bDlgLostFocus = false;
207
208
0
        if ( m_pRefInputEdit )
209
0
        {
210
0
            m_pRefInputEdit->GrabFocus();
211
0
            Impl_ModifyHdl( *m_pRefInputEdit );
212
0
        }
213
0
    }
214
0
    else
215
0
        m_xDialog->grab_focus();
216
217
0
    RefInputDone();
218
0
}
219
220
void ScPrintAreasDlg::Impl_Reset()
221
0
{
222
0
    OUString        aStrRange;
223
0
    std::optional<ScRange> oRepeatColRange = rDoc.GetRepeatColRange( nCurTab );
224
0
    std::optional<ScRange> oRepeatRowRange = rDoc.GetRepeatRowRange( nCurTab );
225
226
0
    m_xEdPrintArea->SetModifyHdl   (LINK( this, ScPrintAreasDlg, Impl_ModifyHdl));
227
0
    m_xEdRepeatRow->SetModifyHdl   (LINK( this, ScPrintAreasDlg, Impl_ModifyHdl));
228
0
    m_xEdRepeatCol->SetModifyHdl   (LINK( this, ScPrintAreasDlg, Impl_ModifyHdl));
229
0
    m_xEdPrintArea->SetGetFocusHdl(LINK( this, ScPrintAreasDlg, Impl_GetEditFocusHdl));
230
0
    m_xEdRepeatRow->SetGetFocusHdl(LINK( this, ScPrintAreasDlg, Impl_GetEditFocusHdl));
231
0
    m_xEdRepeatCol->SetGetFocusHdl(LINK( this, ScPrintAreasDlg, Impl_GetEditFocusHdl));
232
0
    m_xLbPrintArea->connect_focus_in(LINK( this, ScPrintAreasDlg, Impl_GetFocusHdl));
233
0
    m_xLbRepeatRow->connect_focus_in(LINK( this, ScPrintAreasDlg, Impl_GetFocusHdl));
234
0
    m_xLbRepeatCol->connect_focus_in(LINK( this, ScPrintAreasDlg, Impl_GetFocusHdl));
235
0
    m_xLbPrintArea->connect_changed(LINK( this, ScPrintAreasDlg, Impl_SelectHdl));
236
0
    m_xLbRepeatRow->connect_changed(LINK( this, ScPrintAreasDlg, Impl_SelectHdl));
237
0
    m_xLbRepeatCol->connect_changed(LINK( this, ScPrintAreasDlg, Impl_SelectHdl));
238
0
    m_xBtnOk->connect_clicked(LINK( this, ScPrintAreasDlg, Impl_BtnHdl));
239
0
    m_xBtnCancel->connect_clicked(LINK( this, ScPrintAreasDlg, Impl_BtnHdl));
240
241
0
    Impl_FillLists();
242
243
    // printing area
244
245
0
    aStrRange.clear();
246
0
    const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
247
0
    const sal_Unicode sep = ScCompiler::GetNativeSymbolChar(ocSep);
248
0
    sal_uInt16 nRangeCount = rDoc.GetPrintRangeCount( nCurTab );
249
0
    for (sal_uInt16 i=0; i<nRangeCount; i++)
250
0
    {
251
0
        const ScRange* pPrintRange = rDoc.GetPrintRange( nCurTab, i );
252
0
        if (pPrintRange)
253
0
        {
254
0
            if ( !aStrRange.isEmpty() )
255
0
                aStrRange += OUStringChar(sep);
256
0
            aStrRange += pPrintRange->Format(rDoc, ScRefFlags::RANGE_ABS, eConv);
257
0
        }
258
0
    }
259
0
    m_xEdPrintArea->SetText( aStrRange );
260
261
    // repeat row
262
263
0
    lcl_GetRepeatRangeString(oRepeatRowRange, rDoc, true, aStrRange);
264
0
    m_xEdRepeatRow->SetText( aStrRange );
265
266
    // repeat column
267
268
0
    lcl_GetRepeatRangeString(oRepeatColRange, rDoc, false, aStrRange);
269
0
    m_xEdRepeatCol->SetText( aStrRange );
270
271
0
    Impl_ModifyHdl( *m_xEdPrintArea );
272
0
    Impl_ModifyHdl( *m_xEdRepeatRow );
273
0
    Impl_ModifyHdl( *m_xEdRepeatCol );
274
0
    if( rDoc.IsPrintEntireSheet( nCurTab ) )
275
0
        m_xLbPrintArea->set_active(SC_AREASDLG_PR_ENTIRE);
276
277
0
    m_xEdPrintArea->SaveValue();   // save for FillItemSet():
278
0
    m_xEdRepeatRow->SaveValue();
279
0
    m_xEdRepeatCol->SaveValue();
280
0
}
281
282
bool ScPrintAreasDlg::Impl_GetItem( const formula::RefEdit* pEd, SfxStringItem& rItem )
283
0
{
284
0
    OUString  aRangeStr = pEd->GetText();
285
0
    bool bDataChanged = pEd->IsValueChangedFromSaved();
286
287
0
    if ( !aRangeStr.isEmpty() && m_xEdPrintArea.get() != pEd )
288
0
    {
289
0
        ScRange aRange;
290
0
        const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
291
0
        lcl_CheckRepeatString(aRangeStr, rDoc, m_xEdRepeatRow.get() == pEd, &aRange);
292
0
        aRangeStr = aRange.Format(rDoc, ScRefFlags::RANGE_ABS, eConv);
293
0
    }
294
295
0
    rItem.SetValue( aRangeStr );
296
297
0
    return bDataChanged;
298
0
}
299
300
bool ScPrintAreasDlg::Impl_CheckRefStrings()
301
0
{
302
0
    bool        bOk = false;
303
0
    OUString      aStrPrintArea   = m_xEdPrintArea->GetText();
304
0
    OUString      aStrRepeatRow   = m_xEdRepeatRow->GetText();
305
0
    OUString      aStrRepeatCol   = m_xEdRepeatCol->GetText();
306
307
0
    bool bPrintAreaOk = true;
308
0
    if ( !aStrPrintArea.isEmpty() )
309
0
    {
310
0
        const ScRefFlags nValidAddr  = ScRefFlags::VALID | ScRefFlags::ROW_VALID | ScRefFlags::COL_VALID;
311
0
        const ScRefFlags nValidRange = nValidAddr | ScRefFlags::ROW2_VALID | ScRefFlags::COL2_VALID;
312
0
        const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
313
0
        const sal_Unicode sep  = ScCompiler::GetNativeSymbolChar(ocSep);
314
315
0
        ScAddress aAddr;
316
0
        ScRange aRange;
317
0
        for ( sal_Int32 nIdx = 0; nIdx >= 0; )
318
0
        {
319
0
            const OUString aOne = aStrPrintArea.getToken(0, sep, nIdx);
320
0
            ScRefFlags nResult = aRange.Parse( aOne, rDoc, eConv );
321
0
            if ((nResult & nValidRange) != nValidRange)
322
0
            {
323
0
                ScRefFlags nAddrResult = aAddr.Parse( aOne, rDoc, eConv );
324
0
                if ((nAddrResult & nValidAddr) != nValidAddr)
325
0
                {
326
0
                    bPrintAreaOk = false;
327
0
                    break;
328
0
                }
329
0
            }
330
0
        }
331
0
    }
332
333
0
    bool bRepeatRowOk = aStrRepeatRow.isEmpty();
334
0
    if ( !bRepeatRowOk )
335
0
        bRepeatRowOk = lcl_CheckRepeatString(aStrRepeatRow, rDoc, true, nullptr);
336
337
0
    bool bRepeatColOk = aStrRepeatCol.isEmpty();
338
0
    if ( !bRepeatColOk )
339
0
        bRepeatColOk = lcl_CheckRepeatString(aStrRepeatCol, rDoc, false, nullptr);
340
341
    // error messages
342
343
0
    bOk = (bPrintAreaOk && bRepeatRowOk && bRepeatColOk);
344
345
0
    if ( !bOk )
346
0
    {
347
0
        formula::RefEdit* pEd = nullptr;
348
349
0
        if ( !bPrintAreaOk ) pEd = m_xEdPrintArea.get();
350
0
        else if ( !bRepeatRowOk ) pEd = m_xEdRepeatRow.get();
351
0
        else if ( !bRepeatColOk ) pEd = m_xEdRepeatCol.get();
352
353
0
        ERRORBOX(m_xDialog.get(), STR_INVALID_TABREF);
354
355
0
        OSL_ASSERT(pEd);
356
357
0
        if (pEd)
358
0
            pEd->GrabFocus();
359
0
    }
360
361
0
    return bOk;
362
0
}
363
364
void ScPrintAreasDlg::Impl_FillLists()
365
0
{
366
367
    // Get selection and remember String in PrintArea-ListBox
368
369
0
    ScRange  aRange;
370
0
    OUString aStrRange;
371
0
    bool bSimple = true;
372
373
0
    bSimple = (rViewData.GetSimpleArea( aRange ) == SC_MARK_SIMPLE);
374
375
0
    formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
376
377
0
    if ( bSimple )
378
0
        aStrRange = aRange.Format(rDoc, ScRefFlags::RANGE_ABS, eConv);
379
0
    else
380
0
    {
381
0
        ScRangeListRef aList( new ScRangeList );
382
0
        rViewData.GetMarkData().FillRangeListWithMarks( aList.get(), false );
383
0
        aList->Format(aStrRange, ScRefFlags::RANGE_ABS, rDoc, eConv);
384
0
    }
385
386
0
    m_xLbPrintArea->set_id(SC_AREASDLG_PR_SELECT, aStrRange);
387
388
    // Get ranges and remember in ListBoxen
389
390
0
    ScRangeName* pRangeNames = rDoc.GetRangeName();
391
392
0
    if (!pRangeNames || pRangeNames->empty())
393
        // No range names to process.
394
0
        return;
395
396
0
    for (const auto& rEntry : *pRangeNames)
397
0
    {
398
0
        if (!rEntry.second->HasType(ScRangeData::Type::AbsArea   )
399
0
            && !rEntry.second->HasType(ScRangeData::Type::RefArea)
400
0
            && !rEntry.second->HasType(ScRangeData::Type::AbsPos ))
401
0
            continue;
402
403
0
        OUString aName = rEntry.second->GetName();
404
0
        OUString aSymbol = rEntry.second->GetSymbol();
405
0
        if (aRange.ParseAny(aSymbol, rDoc, eConv) & ScRefFlags::VALID)
406
0
        {
407
0
            if (rEntry.second->HasType(ScRangeData::Type::PrintArea))
408
0
            {
409
0
                aSymbol = aRange.Format(rDoc, ScRefFlags::RANGE_ABS, eConv);
410
0
                m_xLbPrintArea->append(aSymbol, aName);
411
0
            }
412
413
0
            if (rEntry.second->HasType(ScRangeData::Type::RowHeader))
414
0
            {
415
0
                lcl_GetRepeatRangeString(aRange, rDoc, true, aSymbol);
416
0
                m_xLbRepeatRow->append(aSymbol, aName);
417
0
            }
418
419
0
            if (rEntry.second->HasType(ScRangeData::Type::ColHeader))
420
0
            {
421
0
                lcl_GetRepeatRangeString(aRange, rDoc, false, aSymbol);
422
0
                m_xLbRepeatCol->append(aSymbol, aName);
423
0
            }
424
0
        }
425
0
    }
426
0
}
427
428
// Handler:
429
430
IMPL_LINK(ScPrintAreasDlg, Impl_BtnHdl, weld::Button&, rBtn, void)
431
0
{
432
0
    if (m_xBtnOk.get() == &rBtn)
433
0
    {
434
0
        if ( Impl_CheckRefStrings() )
435
0
        {
436
0
            SfxStringItem   aPrintArea( SID_CHANGE_PRINTAREA, u""_ustr );
437
0
            SfxStringItem   aRepeatRow( FN_PARAM_2, u""_ustr );
438
0
            SfxStringItem   aRepeatCol( FN_PARAM_3, u""_ustr );
439
440
            // Printing area changed?
441
442
            // first try the list box, if "Entire sheet" is selected
443
0
            bool bEntireSheet = (m_xLbPrintArea->get_active() == SC_AREASDLG_PR_ENTIRE);
444
0
            SfxBoolItem aEntireSheet( FN_PARAM_4, bEntireSheet );
445
446
0
            bool bDataChanged = bEntireSheet != rDoc.IsPrintEntireSheet( nCurTab );
447
0
            if( !bEntireSheet )
448
0
            {
449
                // if new list box selection is not "Entire sheet", get the edit field contents
450
0
                bDataChanged |= Impl_GetItem( m_xEdPrintArea.get(), aPrintArea );
451
0
            }
452
453
            // Repeat row changed?
454
455
0
            bDataChanged |= Impl_GetItem( m_xEdRepeatRow.get(), aRepeatRow );
456
457
            // Repeat column changed?
458
459
0
            bDataChanged |= Impl_GetItem( m_xEdRepeatCol.get(), aRepeatCol );
460
461
0
            if ( bDataChanged )
462
0
            {
463
0
                SetDispatcherLock( false );
464
0
                SwitchToDocument();
465
0
                GetBindings().GetDispatcher()->ExecuteList(SID_CHANGE_PRINTAREA,
466
0
                      SfxCallMode::SLOT | SfxCallMode::RECORD,
467
0
                      { &aPrintArea, &aRepeatRow, &aRepeatCol, &aEntireSheet });
468
0
            }
469
470
0
            response(RET_OK);
471
0
        }
472
0
    }
473
0
    else if (m_xBtnCancel.get() == &rBtn)
474
0
        response(RET_CANCEL);
475
0
}
476
477
IMPL_LINK(ScPrintAreasDlg, Impl_GetEditFocusHdl, formula::RefEdit&, rCtrl, void)
478
0
{
479
0
    m_pRefInputEdit = &rCtrl;
480
0
}
481
482
IMPL_LINK(ScPrintAreasDlg, Impl_GetFocusHdl, weld::Widget&, rCtrl, void)
483
0
{
484
0
    if (&rCtrl == m_xLbPrintArea.get())
485
0
        m_pRefInputEdit = m_xEdPrintArea.get();
486
0
    else if (&rCtrl == m_xLbRepeatRow.get())
487
0
        m_pRefInputEdit = m_xEdRepeatRow.get();
488
0
    else if (&rCtrl == m_xLbRepeatCol.get())
489
0
        m_pRefInputEdit = m_xEdRepeatCol.get();
490
0
}
491
492
IMPL_LINK( ScPrintAreasDlg, Impl_SelectHdl, weld::ComboBox&, rLb, void )
493
0
{
494
0
    const sal_Int32 nSelPos = rLb.get_active();
495
0
    formula::RefEdit* pEd = nullptr;
496
497
    // list box positions of specific entries, default to "repeat row/column" list boxes
498
0
    sal_Int32 nAllSheetPos = SC_AREASDLG_RR_NONE;
499
0
    sal_Int32 nFirstCustomPos = SC_AREASDLG_RR_OFFSET;
500
501
    // find edit field for list box, and list box positions
502
0
    if (&rLb == m_xLbPrintArea.get())
503
0
    {
504
0
        pEd = m_xEdPrintArea.get();
505
0
        nAllSheetPos = SC_AREASDLG_PR_ENTIRE;
506
0
        nFirstCustomPos = SC_AREASDLG_PR_SELECT;    // "Selection" and following
507
0
    }
508
0
    else if (&rLb == m_xLbRepeatCol.get())
509
0
        pEd = m_xEdRepeatCol.get();
510
0
    else if (&rLb == m_xLbRepeatRow.get())
511
0
        pEd = m_xEdRepeatRow.get();
512
0
    else
513
0
        return;
514
515
    // fill edit field according to list box selection
516
0
    if( (nSelPos == 0) || (nSelPos == nAllSheetPos) )
517
0
        pEd->SetText( OUString() );
518
0
    else if( nSelPos >= nFirstCustomPos )
519
0
        pEd->SetText(rLb.get_id(nSelPos));
520
0
}
521
522
IMPL_LINK( ScPrintAreasDlg, Impl_ModifyHdl, formula::RefEdit&, rEd, void )
523
0
{
524
0
    weld::ComboBox* pLb = nullptr;
525
526
    // list box positions of specific entries, default to "repeat row/column" list boxes
527
0
    sal_Int32 nUserDefPos = SC_AREASDLG_RR_USER;
528
0
    sal_Int32 nFirstCustomPos = SC_AREASDLG_RR_OFFSET;
529
530
0
    if( &rEd == m_xEdPrintArea.get() )
531
0
    {
532
0
        pLb = m_xLbPrintArea.get();
533
0
        nUserDefPos = SC_AREASDLG_PR_USER;
534
0
        nFirstCustomPos = SC_AREASDLG_PR_SELECT;    // "Selection" and following
535
0
    }
536
0
    else if( &rEd == m_xEdRepeatCol.get() )
537
0
        pLb = m_xLbRepeatCol.get();
538
0
    else if( &rEd == m_xEdRepeatRow.get() )
539
0
        pLb = m_xLbRepeatRow.get();
540
0
    else
541
0
        return;
542
543
    // set list box selection according to edit field
544
0
    const sal_Int32 nEntryCount = pLb->get_count();
545
0
    OUString aStrEd( rEd.GetText() );
546
0
    OUString aEdUpper = aStrEd.toAsciiUpperCase();
547
548
0
    if ( (nEntryCount > nFirstCustomPos) && !aStrEd.isEmpty() )
549
0
    {
550
0
        bool    bFound  = false;
551
0
        sal_Int32 i;
552
553
0
        for ( i=nFirstCustomPos; i<nEntryCount && !bFound; i++ )
554
0
        {
555
0
            const OUString aSymbol = pLb->get_id(i);
556
0
            bFound = (aSymbol == aStrEd || aSymbol == aEdUpper);
557
0
        }
558
559
0
        pLb->set_active( bFound ? i-1 : nUserDefPos );
560
0
    }
561
0
    else
562
0
        pLb->set_active( !aStrEd.isEmpty() ? nUserDefPos : 0 );
563
0
}
564
565
// global functions:
566
567
// TODO: It might make sense to move these functions to address.?xx. -kohei
568
569
static bool lcl_CheckOne_OOO( const ScDocument& rDoc, const OUString& rStr, bool bIsRow, SCCOLROW& rVal )
570
0
{
571
    // Allowed syntax for rStr:
572
    // Row: [$]1-MAXTAB
573
    // Col: [$]A-IV
574
575
0
    OUString    aStr    = rStr;
576
0
    sal_Int32   nLen    = aStr.getLength();
577
0
    SCCOLROW    nNum    = 0;
578
0
    bool    bStrOk  = ( nLen > 0 ) && ( bIsRow ? ( nLen < 6 ) : ( nLen < 4 ) );
579
580
0
    if ( bStrOk )
581
0
    {
582
0
        if ( '$' == aStr[0] )
583
0
            aStr = aStr.copy( 1 );
584
585
0
        if ( bIsRow )
586
0
        {
587
0
            bStrOk = CharClass::isAsciiNumeric(aStr);
588
589
0
            if ( bStrOk )
590
0
            {
591
0
                sal_Int32 n = aStr.toInt32();
592
593
0
                bStrOk = (n > 0) && ( n <= rDoc.GetSheetLimits().GetMaxRowCount() );
594
0
                if ( bStrOk )
595
0
                    nNum = static_cast<SCCOLROW>(n - 1);
596
0
            }
597
0
        }
598
0
        else
599
0
        {
600
0
            SCCOL nCol = 0;
601
0
            bStrOk = ::AlphaToCol(rDoc, nCol, aStr);
602
0
            nNum = nCol;
603
0
        }
604
0
    }
605
606
0
    if ( bStrOk )
607
0
        rVal = nNum;
608
609
0
    return bStrOk;
610
0
}
611
612
static bool lcl_CheckOne_XL_A1( const ScDocument& rDoc, const OUString& rStr, bool bIsRow, SCCOLROW& rVal )
613
0
{
614
    // XL A1 style is identical to OOO one for print range formats.
615
0
    return lcl_CheckOne_OOO(rDoc, rStr, bIsRow, rVal);
616
0
}
617
618
static bool lcl_CheckOne_XL_R1C1( const ScDocument& rDoc, std::u16string_view aStr, bool bIsRow, SCCOLROW& rVal )
619
0
{
620
0
    sal_Int32 nLen = aStr.size();
621
0
    if (nLen <= 1)
622
        // There must be at least two characters.
623
0
        return false;
624
625
0
    const sal_Unicode preUpper = bIsRow ? 'R' : 'C';
626
0
    const sal_Unicode preLower = bIsRow ? 'r' : 'c';
627
0
    if (aStr[0] != preUpper && aStr[0] != preLower)
628
0
        return false;
629
630
0
    std::u16string_view aNumStr = aStr.substr(1);
631
0
    if (!CharClass::isAsciiNumeric(aNumStr))
632
0
        return false;
633
634
0
    sal_Int32 nNum = o3tl::toInt32(aNumStr);
635
636
0
    if (nNum <= 0)
637
0
        return false;
638
639
0
    if ((bIsRow && nNum > rDoc.GetSheetLimits().GetMaxRowCount()) ||
640
0
        (!bIsRow && nNum > rDoc.GetSheetLimits().GetMaxColCount()))
641
0
        return false;
642
643
0
    rVal = static_cast<SCCOLROW>(nNum-1);
644
0
    return true;
645
0
}
646
647
static bool lcl_CheckRepeatOne( const ScDocument& rDoc, const OUString& rStr, formula::FormulaGrammar::AddressConvention eConv, bool bIsRow, SCCOLROW& rVal )
648
0
{
649
0
    switch (eConv)
650
0
    {
651
0
        case formula::FormulaGrammar::CONV_OOO:
652
0
            return lcl_CheckOne_OOO(rDoc, rStr, bIsRow, rVal);
653
0
        case formula::FormulaGrammar::CONV_XL_A1:
654
0
            return lcl_CheckOne_XL_A1(rDoc, rStr, bIsRow, rVal);
655
0
        case formula::FormulaGrammar::CONV_XL_R1C1:
656
0
            return lcl_CheckOne_XL_R1C1(rDoc, rStr, bIsRow, rVal);
657
0
        default:
658
0
        {
659
            // added to avoid warnings
660
0
        }
661
0
    }
662
0
    return false;
663
0
}
664
665
static bool lcl_CheckRepeatString( std::u16string_view aStr, const ScDocument& rDoc, bool bIsRow, ScRange* pRange )
666
0
{
667
    // Row: [valid row] rsep [valid row]
668
    // Col: [valid col] rsep [valid col]
669
670
0
    const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
671
0
    const sal_Unicode rsep = ScCompiler::GetNativeSymbolChar(ocRange);
672
673
0
    if (pRange)
674
0
    {
675
        // initialize the range value.
676
0
        pRange->aStart.SetCol(0);
677
0
        pRange->aStart.SetRow(0);
678
0
        pRange->aEnd.SetCol(0);
679
0
        pRange->aEnd.SetRow(0);
680
0
    }
681
682
0
    OUString aBuf;
683
0
    SCCOLROW nVal = 0;
684
0
    sal_Int32 nLen = aStr.size();
685
0
    bool bEndPos = false;
686
0
    for( sal_Int32 i = 0; i < nLen; ++i )
687
0
    {
688
0
        const sal_Unicode c = aStr[i];
689
0
        if (c == rsep)
690
0
        {
691
0
            if (bEndPos)
692
                // We aren't supposed to have more than one range separator.
693
0
                return false;
694
695
            // range separator
696
0
            if (aBuf.isEmpty())
697
0
                return false;
698
699
0
            bool bRes = lcl_CheckRepeatOne(rDoc, aBuf, eConv, bIsRow, nVal);
700
0
            if (!bRes)
701
0
                return false;
702
703
0
            if (pRange)
704
0
            {
705
0
                if (bIsRow)
706
0
                {
707
0
                    pRange->aStart.SetRow(static_cast<SCROW>(nVal));
708
0
                    pRange->aEnd.SetRow(static_cast<SCROW>(nVal));
709
0
                }
710
0
                else
711
0
                {
712
0
                    pRange->aStart.SetCol(static_cast<SCCOL>(nVal));
713
0
                    pRange->aEnd.SetCol(static_cast<SCCOL>(nVal));
714
0
                }
715
0
            }
716
717
0
            aBuf.clear();
718
0
            bEndPos = true;
719
0
        }
720
0
        else
721
0
            aBuf += OUStringChar(c);
722
0
    }
723
724
0
    if (!aBuf.isEmpty())
725
0
    {
726
0
        bool bRes = lcl_CheckRepeatOne(rDoc, aBuf, eConv, bIsRow, nVal);
727
0
        if (!bRes)
728
0
            return false;
729
730
0
        if (pRange)
731
0
        {
732
0
            if (bIsRow)
733
0
            {
734
0
                if (!bEndPos)
735
0
                    pRange->aStart.SetRow(static_cast<SCROW>(nVal));
736
0
                pRange->aEnd.SetRow(static_cast<SCROW>(nVal));
737
0
            }
738
0
            else
739
0
            {
740
0
                if (!bEndPos)
741
0
                    pRange->aStart.SetCol(static_cast<SCCOL>(nVal));
742
0
                pRange->aEnd.SetCol(static_cast<SCCOL>(nVal));
743
0
            }
744
0
        }
745
0
    }
746
747
0
    return true;
748
0
}
749
750
static void lcl_GetRepeatRangeString( const std::optional<ScRange>& oRange, const ScDocument& rDoc, bool bIsRow, OUString& rStr )
751
0
{
752
0
    rStr.clear();
753
0
    if (!oRange)
754
0
        return;
755
756
0
    const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
757
0
    const ScAddress& rStart = oRange->aStart;
758
0
    const ScAddress& rEnd   = oRange->aEnd;
759
760
0
    const ScRefFlags nFmt = bIsRow
761
0
                            ? (ScRefFlags::ROW_VALID | ScRefFlags::ROW_ABS)
762
0
                            : (ScRefFlags::COL_VALID | ScRefFlags::COL_ABS);
763
0
    rStr += rStart.Format(nFmt, &rDoc, eConv);
764
0
    if ((bIsRow && rStart.Row() != rEnd.Row()) || (!bIsRow && rStart.Col() != rEnd.Col()))
765
0
    {
766
0
        rStr += ScCompiler::GetNativeSymbol(ocRange);
767
0
        rStr += rEnd.Format(nFmt, &rDoc, eConv);
768
0
    }
769
0
}
770
771
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */