Coverage Report

Created: 2025-07-07 10:01

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