1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <rangelst.hxx>
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>
29 #include <areasdlg.hxx>
30 #include <rangenam.hxx>
31 #include <reffact.hxx>
32 #include <tabvwsh.hxx>
34 #include <globstr.hrc>
35 #include <scresid.hxx>
36 #include <compiler.hxx>
37 #include <markdata.hxx>
39 // List box positions for print range (PR)
41 SC_AREASDLG_PR_ENTIRE
= 1,
42 SC_AREASDLG_PR_USER
= 2,
43 SC_AREASDLG_PR_SELECT
= 3
46 // List box positions for repeat ranges (RR)
48 SC_AREASDLG_RR_NONE
= 0,
49 SC_AREASDLG_RR_USER
= 1,
50 SC_AREASDLG_RR_OFFSET
= 2
55 void ERRORBOX(weld::Window
* pParent
, TranslateId rId
)
57 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(pParent
,
58 VclMessageType::Warning
, VclButtonsType::Ok
,
64 // global functions (->at the end of the file):
66 static bool lcl_CheckRepeatString( std::u16string_view aStr
, const ScDocument
& rDoc
, bool bIsRow
, ScRange
* pRange
);
67 static void lcl_GetRepeatRangeString( std::optional
<ScRange
> oRange
, const ScDocument
& rDoc
, bool bIsRow
, OUString
& rStr
);
70 // this method is useful when debugging address flags.
71 static void printAddressFlags(ScRefFlags nFlag
)
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");
97 ScPrintAreasDlg::ScPrintAreasDlg(SfxBindings
* pB
, SfxChildWindow
* pCW
, weld::Window
* pParent
)
98 : ScAnyRefDlgController(pB
, pCW
, pParent
, "modules/scalc/ui/printareasdialog.ui", "PrintAreasDialog")
99 , bDlgLostFocus(false)
103 , m_xLbPrintArea(m_xBuilder
->weld_combo_box("lbprintarea"))
104 , m_xEdPrintArea(new formula::RefEdit(m_xBuilder
->weld_entry("edprintarea")))
105 , m_xRbPrintArea(new formula::RefButton(m_xBuilder
->weld_button("rbprintarea")))
106 , m_xLbRepeatRow(m_xBuilder
->weld_combo_box("lbrepeatrow"))
107 , m_xEdRepeatRow(new formula::RefEdit(m_xBuilder
->weld_entry("edrepeatrow")))
108 , m_xRbRepeatRow(new formula::RefButton(m_xBuilder
->weld_button("rbrepeatrow")))
109 , m_xLbRepeatCol(m_xBuilder
->weld_combo_box("lbrepeatcol"))
110 , m_xEdRepeatCol(new formula::RefEdit(m_xBuilder
->weld_entry("edrepeatcol")))
111 , m_xRbRepeatCol(new formula::RefButton(m_xBuilder
->weld_button("rbrepeatcol")))
112 , m_xBtnOk(m_xBuilder
->weld_button("ok"))
113 , m_xBtnCancel(m_xBuilder
->weld_button("cancel"))
114 , m_xPrintFrame(m_xBuilder
->weld_frame("printframe"))
115 , m_xRowFrame(m_xBuilder
->weld_frame("rowframe"))
116 , m_xColFrame(m_xBuilder
->weld_frame("colframe"))
117 , m_xPrintFrameFT(m_xPrintFrame
->weld_label_widget())
118 , m_xRowFrameFT(m_xRowFrame
->weld_label_widget())
119 , m_xColFrameFT(m_xColFrame
->weld_label_widget())
121 m_xEdPrintArea
->SetReferences(this, m_xPrintFrameFT
.get());
122 m_pRefInputEdit
= m_xEdPrintArea
.get();
123 m_xRbPrintArea
->SetReferences(this, m_xEdPrintArea
.get());
125 m_xEdRepeatRow
->SetReferences(this, m_xRowFrameFT
.get());
126 m_xRbRepeatRow
->SetReferences(this, m_xEdRepeatRow
.get());
128 m_xEdRepeatCol
->SetReferences(this, m_xColFrameFT
.get());
129 m_xRbRepeatCol
->SetReferences(this, m_xEdRepeatCol
.get());
131 ScTabViewShell
* pScViewSh
= dynamic_cast<ScTabViewShell
*>( SfxViewShell::Current() );
132 ScDocShell
* pScDocSh
= dynamic_cast<ScDocShell
*>(SfxObjectShell::Current());
133 assert(pScDocSh
&& "Current DocumentShell not found :-(");
135 pDoc
= &pScDocSh
->GetDocument();
139 pViewData
= &pScViewSh
->GetViewData();
140 nCurTab
= pViewData
->GetTabNo();
145 //@BugID 54702 Enable/Disable only in base class
146 //SFX_APPWINDOW->Enable();
149 ScPrintAreasDlg::~ScPrintAreasDlg()
153 void ScPrintAreasDlg::Close()
155 DoClose( ScPrintAreasDlgWrapper::GetChildWindowId() );
158 bool ScPrintAreasDlg::IsTableLocked() const
160 // Printing areas are per table, therefore it makes no sense,
161 // to switch the table during input
166 void ScPrintAreasDlg::SetReference( const ScRange
& rRef
, ScDocument
& /* rDoc */ )
168 if ( !m_pRefInputEdit
)
171 if ( rRef
.aStart
!= rRef
.aEnd
)
172 RefInputStart( m_pRefInputEdit
);
175 const formula::FormulaGrammar::AddressConvention eConv
= pDoc
->GetAddressConvention();
177 if (m_xEdPrintArea
.get() == m_pRefInputEdit
)
179 aStr
= rRef
.Format(*pDoc
, ScRefFlags::RANGE_ABS
, eConv
);
180 OUString aVal
= m_xEdPrintArea
->GetText();
181 Selection aSel
= m_xEdPrintArea
->GetSelection();
183 aVal
= aVal
.replaceAt( aSel
.Min(), aSel
.Len(), aStr
);
184 Selection
aNewSel( aSel
.Min(), aSel
.Min()+aStr
.getLength() );
185 m_xEdPrintArea
->SetRefString( aVal
);
186 m_xEdPrintArea
->SetSelection( aNewSel
);
190 bool bRow
= ( m_xEdRepeatRow
.get() == m_pRefInputEdit
);
191 lcl_GetRepeatRangeString(rRef
, *pDoc
, bRow
, aStr
);
192 m_pRefInputEdit
->SetRefString( aStr
);
194 Impl_ModifyHdl( *m_pRefInputEdit
);
197 void ScPrintAreasDlg::AddRefEntry()
199 if (m_pRefInputEdit
== m_xEdPrintArea
.get())
201 const sal_Unicode sep
= ScCompiler::GetNativeSymbolChar(ocSep
);
202 OUString aVal
= m_xEdPrintArea
->GetText() + OUStringChar(sep
);
203 m_xEdPrintArea
->SetText(aVal
);
205 sal_Int32 nLen
= aVal
.getLength();
206 m_xEdPrintArea
->SetSelection( Selection( nLen
, nLen
) );
208 Impl_ModifyHdl( *m_xEdPrintArea
);
212 void ScPrintAreasDlg::Deactivate()
214 bDlgLostFocus
= true;
217 void ScPrintAreasDlg::SetActive()
221 bDlgLostFocus
= false;
223 if ( m_pRefInputEdit
)
225 m_pRefInputEdit
->GrabFocus();
226 Impl_ModifyHdl( *m_pRefInputEdit
);
230 m_xDialog
->grab_focus();
235 void ScPrintAreasDlg::Impl_Reset()
238 std::optional
<ScRange
> oRepeatColRange
= pDoc
->GetRepeatColRange( nCurTab
);
239 std::optional
<ScRange
> oRepeatRowRange
= pDoc
->GetRepeatRowRange( nCurTab
);
241 m_xEdPrintArea
->SetModifyHdl (LINK( this, ScPrintAreasDlg
, Impl_ModifyHdl
));
242 m_xEdRepeatRow
->SetModifyHdl (LINK( this, ScPrintAreasDlg
, Impl_ModifyHdl
));
243 m_xEdRepeatCol
->SetModifyHdl (LINK( this, ScPrintAreasDlg
, Impl_ModifyHdl
));
244 m_xEdPrintArea
->SetGetFocusHdl(LINK( this, ScPrintAreasDlg
, Impl_GetEditFocusHdl
));
245 m_xEdRepeatRow
->SetGetFocusHdl(LINK( this, ScPrintAreasDlg
, Impl_GetEditFocusHdl
));
246 m_xEdRepeatCol
->SetGetFocusHdl(LINK( this, ScPrintAreasDlg
, Impl_GetEditFocusHdl
));
247 m_xLbPrintArea
->connect_focus_in(LINK( this, ScPrintAreasDlg
, Impl_GetFocusHdl
));
248 m_xLbRepeatRow
->connect_focus_in(LINK( this, ScPrintAreasDlg
, Impl_GetFocusHdl
));
249 m_xLbRepeatCol
->connect_focus_in(LINK( this, ScPrintAreasDlg
, Impl_GetFocusHdl
));
250 m_xLbPrintArea
->connect_changed(LINK( this, ScPrintAreasDlg
, Impl_SelectHdl
));
251 m_xLbRepeatRow
->connect_changed(LINK( this, ScPrintAreasDlg
, Impl_SelectHdl
));
252 m_xLbRepeatCol
->connect_changed(LINK( this, ScPrintAreasDlg
, Impl_SelectHdl
));
253 m_xBtnOk
->connect_clicked(LINK( this, ScPrintAreasDlg
, Impl_BtnHdl
));
254 m_xBtnCancel
->connect_clicked(LINK( this, ScPrintAreasDlg
, Impl_BtnHdl
));
261 const formula::FormulaGrammar::AddressConvention eConv
= pDoc
->GetAddressConvention();
262 const sal_Unicode sep
= ScCompiler::GetNativeSymbolChar(ocSep
);
263 sal_uInt16 nRangeCount
= pDoc
->GetPrintRangeCount( nCurTab
);
264 for (sal_uInt16 i
=0; i
<nRangeCount
; i
++)
266 const ScRange
* pPrintRange
= pDoc
->GetPrintRange( nCurTab
, i
);
269 if ( !aStrRange
.isEmpty() )
270 aStrRange
+= OUStringChar(sep
);
271 aStrRange
+= pPrintRange
->Format(*pDoc
, ScRefFlags::RANGE_ABS
, eConv
);
274 m_xEdPrintArea
->SetText( aStrRange
);
278 lcl_GetRepeatRangeString(oRepeatRowRange
, *pDoc
, true, aStrRange
);
279 m_xEdRepeatRow
->SetText( aStrRange
);
283 lcl_GetRepeatRangeString(oRepeatColRange
, *pDoc
, false, aStrRange
);
284 m_xEdRepeatCol
->SetText( aStrRange
);
286 Impl_ModifyHdl( *m_xEdPrintArea
);
287 Impl_ModifyHdl( *m_xEdRepeatRow
);
288 Impl_ModifyHdl( *m_xEdRepeatCol
);
289 if( pDoc
->IsPrintEntireSheet( nCurTab
) )
290 m_xLbPrintArea
->set_active(SC_AREASDLG_PR_ENTIRE
);
292 m_xEdPrintArea
->SaveValue(); // save for FillItemSet():
293 m_xEdRepeatRow
->SaveValue();
294 m_xEdRepeatCol
->SaveValue();
297 bool ScPrintAreasDlg::Impl_GetItem( const formula::RefEdit
* pEd
, SfxStringItem
& rItem
)
299 OUString aRangeStr
= pEd
->GetText();
300 bool bDataChanged
= pEd
->IsValueChangedFromSaved();
302 if ( !aRangeStr
.isEmpty() && m_xEdPrintArea
.get() != pEd
)
305 const formula::FormulaGrammar::AddressConvention eConv
= pDoc
->GetAddressConvention();
306 lcl_CheckRepeatString(aRangeStr
, *pDoc
, m_xEdRepeatRow
.get() == pEd
, &aRange
);
307 aRangeStr
= aRange
.Format(*pDoc
, ScRefFlags::RANGE_ABS
, eConv
);
310 rItem
.SetValue( aRangeStr
);
315 bool ScPrintAreasDlg::Impl_CheckRefStrings()
318 OUString aStrPrintArea
= m_xEdPrintArea
->GetText();
319 OUString aStrRepeatRow
= m_xEdRepeatRow
->GetText();
320 OUString aStrRepeatCol
= m_xEdRepeatCol
->GetText();
322 bool bPrintAreaOk
= true;
323 if ( !aStrPrintArea
.isEmpty() )
325 const ScRefFlags nValidAddr
= ScRefFlags::VALID
| ScRefFlags::ROW_VALID
| ScRefFlags::COL_VALID
;
326 const ScRefFlags nValidRange
= nValidAddr
| ScRefFlags::ROW2_VALID
| ScRefFlags::COL2_VALID
;
327 const formula::FormulaGrammar::AddressConvention eConv
= pDoc
->GetAddressConvention();
328 const sal_Unicode sep
= ScCompiler::GetNativeSymbolChar(ocSep
);
332 for ( sal_Int32 nIdx
= 0; nIdx
>= 0; )
334 const OUString aOne
= aStrPrintArea
.getToken(0, sep
, nIdx
);
335 ScRefFlags nResult
= aRange
.Parse( aOne
, *pDoc
, eConv
);
336 if ((nResult
& nValidRange
) != nValidRange
)
338 ScRefFlags nAddrResult
= aAddr
.Parse( aOne
, *pDoc
, eConv
);
339 if ((nAddrResult
& nValidAddr
) != nValidAddr
)
341 bPrintAreaOk
= false;
348 bool bRepeatRowOk
= aStrRepeatRow
.isEmpty();
350 bRepeatRowOk
= lcl_CheckRepeatString(aStrRepeatRow
, *pDoc
, true, nullptr);
352 bool bRepeatColOk
= aStrRepeatCol
.isEmpty();
354 bRepeatColOk
= lcl_CheckRepeatString(aStrRepeatCol
, *pDoc
, false, nullptr);
358 bOk
= (bPrintAreaOk
&& bRepeatRowOk
&& bRepeatColOk
);
362 formula::RefEdit
* pEd
= nullptr;
364 if ( !bPrintAreaOk
) pEd
= m_xEdPrintArea
.get();
365 else if ( !bRepeatRowOk
) pEd
= m_xEdRepeatRow
.get();
366 else if ( !bRepeatColOk
) pEd
= m_xEdRepeatCol
.get();
368 ERRORBOX(m_xDialog
.get(), STR_INVALID_TABREF
);
379 void ScPrintAreasDlg::Impl_FillLists()
382 // Get selection and remember String in PrintArea-ListBox
389 bSimple
= (pViewData
->GetSimpleArea( aRange
) == SC_MARK_SIMPLE
);
391 formula::FormulaGrammar::AddressConvention eConv
= pDoc
->GetAddressConvention();
394 aStrRange
= aRange
.Format(*pDoc
, ScRefFlags::RANGE_ABS
, eConv
);
397 ScRangeListRef
aList( new ScRangeList
);
398 pViewData
->GetMarkData().FillRangeListWithMarks( aList
.get(), false );
399 aList
->Format(aStrRange
, ScRefFlags::RANGE_ABS
, *pDoc
, eConv
);
402 m_xLbPrintArea
->set_id(SC_AREASDLG_PR_SELECT
, aStrRange
);
404 // Get ranges and remember in ListBoxen
406 ScRangeName
* pRangeNames
= pDoc
->GetRangeName();
408 if (!pRangeNames
|| pRangeNames
->empty())
409 // No range names to process.
412 for (const auto& rEntry
: *pRangeNames
)
414 if (!rEntry
.second
->HasType(ScRangeData::Type::AbsArea
)
415 && !rEntry
.second
->HasType(ScRangeData::Type::RefArea
)
416 && !rEntry
.second
->HasType(ScRangeData::Type::AbsPos
))
419 OUString aName
= rEntry
.second
->GetName();
420 OUString aSymbol
= rEntry
.second
->GetSymbol();
421 if (aRange
.ParseAny(aSymbol
, *pDoc
, eConv
) & ScRefFlags::VALID
)
423 if (rEntry
.second
->HasType(ScRangeData::Type::PrintArea
))
425 aSymbol
= aRange
.Format(*pDoc
, ScRefFlags::RANGE_ABS
, eConv
);
426 m_xLbPrintArea
->append(aSymbol
, aName
);
429 if (rEntry
.second
->HasType(ScRangeData::Type::RowHeader
))
431 lcl_GetRepeatRangeString(aRange
, *pDoc
, true, aSymbol
);
432 m_xLbRepeatRow
->append(aSymbol
, aName
);
435 if (rEntry
.second
->HasType(ScRangeData::Type::ColHeader
))
437 lcl_GetRepeatRangeString(aRange
, *pDoc
, false, aSymbol
);
438 m_xLbRepeatCol
->append(aSymbol
, aName
);
446 IMPL_LINK(ScPrintAreasDlg
, Impl_BtnHdl
, weld::Button
&, rBtn
, void)
448 if (m_xBtnOk
.get() == &rBtn
)
450 if ( Impl_CheckRefStrings() )
452 SfxStringItem
aPrintArea( SID_CHANGE_PRINTAREA
, "" );
453 SfxStringItem
aRepeatRow( FN_PARAM_2
, "" );
454 SfxStringItem
aRepeatCol( FN_PARAM_3
, "" );
456 // Printing area changed?
458 // first try the list box, if "Entire sheet" is selected
459 bool bEntireSheet
= (m_xLbPrintArea
->get_active() == SC_AREASDLG_PR_ENTIRE
);
460 SfxBoolItem
aEntireSheet( FN_PARAM_4
, bEntireSheet
);
462 bool bDataChanged
= bEntireSheet
!= pDoc
->IsPrintEntireSheet( nCurTab
);
465 // if new list box selection is not "Entire sheet", get the edit field contents
466 bDataChanged
|= Impl_GetItem( m_xEdPrintArea
.get(), aPrintArea
);
469 // Repeat row changed?
471 bDataChanged
|= Impl_GetItem( m_xEdRepeatRow
.get(), aRepeatRow
);
473 // Repeat column changed?
475 bDataChanged
|= Impl_GetItem( m_xEdRepeatCol
.get(), aRepeatCol
);
479 SetDispatcherLock( false );
481 GetBindings().GetDispatcher()->ExecuteList(SID_CHANGE_PRINTAREA
,
482 SfxCallMode::SLOT
| SfxCallMode::RECORD
,
483 { &aPrintArea
, &aRepeatRow
, &aRepeatCol
, &aEntireSheet
});
489 else if (m_xBtnCancel
.get() == &rBtn
)
490 response(RET_CANCEL
);
493 IMPL_LINK(ScPrintAreasDlg
, Impl_GetEditFocusHdl
, formula::RefEdit
&, rCtrl
, void)
495 m_pRefInputEdit
= &rCtrl
;
498 IMPL_LINK(ScPrintAreasDlg
, Impl_GetFocusHdl
, weld::Widget
&, rCtrl
, void)
500 if (&rCtrl
== m_xLbPrintArea
.get())
501 m_pRefInputEdit
= m_xEdPrintArea
.get();
502 else if (&rCtrl
== m_xLbRepeatRow
.get())
503 m_pRefInputEdit
= m_xEdRepeatRow
.get();
504 else if (&rCtrl
== m_xLbRepeatCol
.get())
505 m_pRefInputEdit
= m_xEdRepeatCol
.get();
508 IMPL_LINK( ScPrintAreasDlg
, Impl_SelectHdl
, weld::ComboBox
&, rLb
, void )
510 const sal_Int32 nSelPos
= rLb
.get_active();
511 formula::RefEdit
* pEd
= nullptr;
513 // list box positions of specific entries, default to "repeat row/column" list boxes
514 sal_Int32 nAllSheetPos
= SC_AREASDLG_RR_NONE
;
515 sal_Int32 nFirstCustomPos
= SC_AREASDLG_RR_OFFSET
;
517 // find edit field for list box, and list box positions
518 if (&rLb
== m_xLbPrintArea
.get())
520 pEd
= m_xEdPrintArea
.get();
521 nAllSheetPos
= SC_AREASDLG_PR_ENTIRE
;
522 nFirstCustomPos
= SC_AREASDLG_PR_SELECT
; // "Selection" and following
524 else if (&rLb
== m_xLbRepeatCol
.get())
525 pEd
= m_xEdRepeatCol
.get();
526 else if (&rLb
== m_xLbRepeatRow
.get())
527 pEd
= m_xEdRepeatRow
.get();
531 // fill edit field according to list box selection
532 if( (nSelPos
== 0) || (nSelPos
== nAllSheetPos
) )
533 pEd
->SetText( OUString() );
534 else if( nSelPos
>= nFirstCustomPos
)
535 pEd
->SetText(rLb
.get_id(nSelPos
));
538 IMPL_LINK( ScPrintAreasDlg
, Impl_ModifyHdl
, formula::RefEdit
&, rEd
, void )
540 weld::ComboBox
* pLb
= nullptr;
542 // list box positions of specific entries, default to "repeat row/column" list boxes
543 sal_Int32 nUserDefPos
= SC_AREASDLG_RR_USER
;
544 sal_Int32 nFirstCustomPos
= SC_AREASDLG_RR_OFFSET
;
546 if( &rEd
== m_xEdPrintArea
.get() )
548 pLb
= m_xLbPrintArea
.get();
549 nUserDefPos
= SC_AREASDLG_PR_USER
;
550 nFirstCustomPos
= SC_AREASDLG_PR_SELECT
; // "Selection" and following
552 else if( &rEd
== m_xEdRepeatCol
.get() )
553 pLb
= m_xLbRepeatCol
.get();
554 else if( &rEd
== m_xEdRepeatRow
.get() )
555 pLb
= m_xLbRepeatRow
.get();
559 // set list box selection according to edit field
560 const sal_Int32 nEntryCount
= pLb
->get_count();
561 OUString
aStrEd( rEd
.GetText() );
562 OUString aEdUpper
= aStrEd
.toAsciiUpperCase();
564 if ( (nEntryCount
> nFirstCustomPos
) && !aStrEd
.isEmpty() )
569 for ( i
=nFirstCustomPos
; i
<nEntryCount
&& !bFound
; i
++ )
571 const OUString
& rSymbol
= pLb
->get_id(i
);
572 bFound
= (rSymbol
== aStrEd
|| rSymbol
== aEdUpper
);
575 pLb
->set_active( bFound
? i
-1 : nUserDefPos
);
578 pLb
->set_active( !aStrEd
.isEmpty() ? nUserDefPos
: 0 );
583 // TODO: It might make sense to move these functions to address.?xx. -kohei
585 static bool lcl_CheckOne_OOO( const ScDocument
& rDoc
, const OUString
& rStr
, bool bIsRow
, SCCOLROW
& rVal
)
587 // Allowed syntax for rStr:
591 OUString aStr
= rStr
;
592 sal_Int32 nLen
= aStr
.getLength();
594 bool bStrOk
= ( nLen
> 0 ) && ( bIsRow
? ( nLen
< 6 ) : ( nLen
< 4 ) );
598 if ( '$' == aStr
[0] )
599 aStr
= aStr
.copy( 1 );
603 bStrOk
= CharClass::isAsciiNumeric(aStr
);
607 sal_Int32 n
= aStr
.toInt32();
609 bStrOk
= (n
> 0) && ( n
<= rDoc
.GetSheetLimits().GetMaxRowCount() );
611 nNum
= static_cast<SCCOLROW
>(n
- 1);
617 bStrOk
= ::AlphaToCol(rDoc
, nCol
, aStr
);
628 static bool lcl_CheckOne_XL_A1( const ScDocument
& rDoc
, const OUString
& rStr
, bool bIsRow
, SCCOLROW
& rVal
)
630 // XL A1 style is identical to OOO one for print range formats.
631 return lcl_CheckOne_OOO(rDoc
, rStr
, bIsRow
, rVal
);
634 static bool lcl_CheckOne_XL_R1C1( const ScDocument
& rDoc
, std::u16string_view aStr
, bool bIsRow
, SCCOLROW
& rVal
)
636 sal_Int32 nLen
= aStr
.size();
638 // There must be at least two characters.
641 const sal_Unicode preUpper
= bIsRow
? 'R' : 'C';
642 const sal_Unicode preLower
= bIsRow
? 'r' : 'c';
643 if (aStr
[0] != preUpper
&& aStr
[0] != preLower
)
646 std::u16string_view aNumStr
= aStr
.substr(1);
647 if (!CharClass::isAsciiNumeric(aNumStr
))
650 sal_Int32 nNum
= o3tl::toInt32(aNumStr
);
655 if ((bIsRow
&& nNum
> rDoc
.GetSheetLimits().GetMaxRowCount()) ||
656 (!bIsRow
&& nNum
> rDoc
.GetSheetLimits().GetMaxColCount()))
659 rVal
= static_cast<SCCOLROW
>(nNum
-1);
663 static bool lcl_CheckRepeatOne( const ScDocument
& rDoc
, const OUString
& rStr
, formula::FormulaGrammar::AddressConvention eConv
, bool bIsRow
, SCCOLROW
& rVal
)
667 case formula::FormulaGrammar::CONV_OOO
:
668 return lcl_CheckOne_OOO(rDoc
, rStr
, bIsRow
, rVal
);
669 case formula::FormulaGrammar::CONV_XL_A1
:
670 return lcl_CheckOne_XL_A1(rDoc
, rStr
, bIsRow
, rVal
);
671 case formula::FormulaGrammar::CONV_XL_R1C1
:
672 return lcl_CheckOne_XL_R1C1(rDoc
, rStr
, bIsRow
, rVal
);
675 // added to avoid warnings
681 static bool lcl_CheckRepeatString( std::u16string_view aStr
, const ScDocument
& rDoc
, bool bIsRow
, ScRange
* pRange
)
683 // Row: [valid row] rsep [valid row]
684 // Col: [valid col] rsep [valid col]
686 const formula::FormulaGrammar::AddressConvention eConv
= rDoc
.GetAddressConvention();
687 const sal_Unicode rsep
= ScCompiler::GetNativeSymbolChar(ocRange
);
691 // initialize the range value.
692 pRange
->aStart
.SetCol(0);
693 pRange
->aStart
.SetRow(0);
694 pRange
->aEnd
.SetCol(0);
695 pRange
->aEnd
.SetRow(0);
700 sal_Int32 nLen
= aStr
.size();
701 bool bEndPos
= false;
702 for( sal_Int32 i
= 0; i
< nLen
; ++i
)
704 const sal_Unicode c
= aStr
[i
];
708 // We aren't supposed to have more than one range separator.
715 bool bRes
= lcl_CheckRepeatOne(rDoc
, aBuf
, eConv
, bIsRow
, nVal
);
723 pRange
->aStart
.SetRow(static_cast<SCROW
>(nVal
));
724 pRange
->aEnd
.SetRow(static_cast<SCROW
>(nVal
));
728 pRange
->aStart
.SetCol(static_cast<SCCOL
>(nVal
));
729 pRange
->aEnd
.SetCol(static_cast<SCCOL
>(nVal
));
737 aBuf
+= OUStringChar(c
);
742 bool bRes
= lcl_CheckRepeatOne(rDoc
, aBuf
, eConv
, bIsRow
, nVal
);
751 pRange
->aStart
.SetRow(static_cast<SCROW
>(nVal
));
752 pRange
->aEnd
.SetRow(static_cast<SCROW
>(nVal
));
757 pRange
->aStart
.SetCol(static_cast<SCCOL
>(nVal
));
758 pRange
->aEnd
.SetCol(static_cast<SCCOL
>(nVal
));
766 static void lcl_GetRepeatRangeString( std::optional
<ScRange
> oRange
, const ScDocument
& rDoc
, bool bIsRow
, OUString
& rStr
)
772 const formula::FormulaGrammar::AddressConvention eConv
= rDoc
.GetAddressConvention();
773 const ScAddress
& rStart
= oRange
->aStart
;
774 const ScAddress
& rEnd
= oRange
->aEnd
;
776 const ScRefFlags nFmt
= bIsRow
777 ? (ScRefFlags::ROW_VALID
| ScRefFlags::ROW_ABS
)
778 : (ScRefFlags::COL_VALID
| ScRefFlags::COL_ABS
);
779 rStr
+= rStart
.Format(nFmt
, &rDoc
, eConv
);
780 if ((bIsRow
&& rStart
.Row() != rEnd
.Row()) || (!bIsRow
&& rStart
.Col() != rEnd
.Col()))
782 rStr
+= ScCompiler::GetNativeSymbol(ocRange
);
783 rStr
+= rEnd
.Format(nFmt
, &rDoc
, eConv
);
787 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */