calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / sc / source / ui / pagedlg / areasdlg.cxx
blobb90a3a664ba23214e06aa801e675075c7cfe55c4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * 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>
33 #include <docsh.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)
40 enum {
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)
47 enum {
48 SC_AREASDLG_RR_NONE = 0,
49 SC_AREASDLG_RR_USER = 1,
50 SC_AREASDLG_RR_OFFSET = 2
53 namespace
55 void ERRORBOX(weld::Window* pParent, TranslateId rId)
57 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pParent,
58 VclMessageType::Warning, VclButtonsType::Ok,
59 ScResId(rId)));
60 xBox->run();
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 );
69 #if 0
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");
94 #endif
97 ScPrintAreasDlg::ScPrintAreasDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent)
98 : ScAnyRefDlgController(pB, pCW, pParent, "modules/scalc/ui/printareasdialog.ui", "PrintAreasDialog")
99 , bDlgLostFocus(false)
100 , pDoc(nullptr)
101 , pViewData(nullptr)
102 , nCurTab(0)
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();
137 if ( pScViewSh )
139 pViewData = &pScViewSh->GetViewData();
140 nCurTab = pViewData->GetTabNo();
143 Impl_Reset();
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
163 return true;
166 void ScPrintAreasDlg::SetReference( const ScRange& rRef, ScDocument& /* rDoc */ )
168 if ( !m_pRefInputEdit )
169 return;
171 if ( rRef.aStart != rRef.aEnd )
172 RefInputStart( m_pRefInputEdit );
174 OUString aStr;
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();
182 aSel.Normalize();
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 );
188 else
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()
219 if ( bDlgLostFocus )
221 bDlgLostFocus = false;
223 if ( m_pRefInputEdit )
225 m_pRefInputEdit->GrabFocus();
226 Impl_ModifyHdl( *m_pRefInputEdit );
229 else
230 m_xDialog->grab_focus();
232 RefInputDone();
235 void ScPrintAreasDlg::Impl_Reset()
237 OUString aStrRange;
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));
256 Impl_FillLists();
258 // printing area
260 aStrRange.clear();
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 );
267 if (pPrintRange)
269 if ( !aStrRange.isEmpty() )
270 aStrRange += OUStringChar(sep);
271 aStrRange += pPrintRange->Format(*pDoc, ScRefFlags::RANGE_ABS, eConv);
274 m_xEdPrintArea->SetText( aStrRange );
276 // repeat row
278 lcl_GetRepeatRangeString(oRepeatRowRange, *pDoc, true, aStrRange);
279 m_xEdRepeatRow->SetText( aStrRange );
281 // repeat column
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 )
304 ScRange aRange;
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 );
312 return bDataChanged;
315 bool ScPrintAreasDlg::Impl_CheckRefStrings()
317 bool bOk = false;
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);
330 ScAddress aAddr;
331 ScRange aRange;
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;
342 break;
348 bool bRepeatRowOk = aStrRepeatRow.isEmpty();
349 if ( !bRepeatRowOk )
350 bRepeatRowOk = lcl_CheckRepeatString(aStrRepeatRow, *pDoc, true, nullptr);
352 bool bRepeatColOk = aStrRepeatCol.isEmpty();
353 if ( !bRepeatColOk )
354 bRepeatColOk = lcl_CheckRepeatString(aStrRepeatCol, *pDoc, false, nullptr);
356 // error messages
358 bOk = (bPrintAreaOk && bRepeatRowOk && bRepeatColOk);
360 if ( !bOk )
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);
370 OSL_ASSERT(pEd);
372 if (pEd)
373 pEd->GrabFocus();
376 return bOk;
379 void ScPrintAreasDlg::Impl_FillLists()
382 // Get selection and remember String in PrintArea-ListBox
384 ScRange aRange;
385 OUString aStrRange;
386 bool bSimple = true;
388 if ( pViewData )
389 bSimple = (pViewData->GetSimpleArea( aRange ) == SC_MARK_SIMPLE);
391 formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention();
393 if ( bSimple )
394 aStrRange = aRange.Format(*pDoc, ScRefFlags::RANGE_ABS, eConv);
395 else
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.
410 return;
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 ))
417 continue;
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);
444 // Handler:
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 );
463 if( !bEntireSheet )
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 );
477 if ( bDataChanged )
479 SetDispatcherLock( false );
480 SwitchToDocument();
481 GetBindings().GetDispatcher()->ExecuteList(SID_CHANGE_PRINTAREA,
482 SfxCallMode::SLOT | SfxCallMode::RECORD,
483 { &aPrintArea, &aRepeatRow, &aRepeatCol, &aEntireSheet });
486 response(RET_OK);
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();
528 else
529 return;
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();
556 else
557 return;
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() )
566 bool bFound = false;
567 sal_Int32 i;
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 );
577 else
578 pLb->set_active( !aStrEd.isEmpty() ? nUserDefPos : 0 );
581 // global functions:
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:
588 // Row: [$]1-MAXTAB
589 // Col: [$]A-IV
591 OUString aStr = rStr;
592 sal_Int32 nLen = aStr.getLength();
593 SCCOLROW nNum = 0;
594 bool bStrOk = ( nLen > 0 ) && ( bIsRow ? ( nLen < 6 ) : ( nLen < 4 ) );
596 if ( bStrOk )
598 if ( '$' == aStr[0] )
599 aStr = aStr.copy( 1 );
601 if ( bIsRow )
603 bStrOk = CharClass::isAsciiNumeric(aStr);
605 if ( bStrOk )
607 sal_Int32 n = aStr.toInt32();
609 bStrOk = (n > 0) && ( n <= rDoc.GetSheetLimits().GetMaxRowCount() );
610 if ( bStrOk )
611 nNum = static_cast<SCCOLROW>(n - 1);
614 else
616 SCCOL nCol = 0;
617 bStrOk = ::AlphaToCol(rDoc, nCol, aStr);
618 nNum = nCol;
622 if ( bStrOk )
623 rVal = nNum;
625 return bStrOk;
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();
637 if (nLen <= 1)
638 // There must be at least two characters.
639 return false;
641 const sal_Unicode preUpper = bIsRow ? 'R' : 'C';
642 const sal_Unicode preLower = bIsRow ? 'r' : 'c';
643 if (aStr[0] != preUpper && aStr[0] != preLower)
644 return false;
646 std::u16string_view aNumStr = aStr.substr(1);
647 if (!CharClass::isAsciiNumeric(aNumStr))
648 return false;
650 sal_Int32 nNum = o3tl::toInt32(aNumStr);
652 if (nNum <= 0)
653 return false;
655 if ((bIsRow && nNum > rDoc.GetSheetLimits().GetMaxRowCount()) ||
656 (!bIsRow && nNum > rDoc.GetSheetLimits().GetMaxColCount()))
657 return false;
659 rVal = static_cast<SCCOLROW>(nNum-1);
660 return true;
663 static bool lcl_CheckRepeatOne( const ScDocument& rDoc, const OUString& rStr, formula::FormulaGrammar::AddressConvention eConv, bool bIsRow, SCCOLROW& rVal )
665 switch (eConv)
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);
673 default:
675 // added to avoid warnings
678 return false;
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);
689 if (pRange)
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);
698 OUString aBuf;
699 SCCOLROW nVal = 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];
705 if (c == rsep)
707 if (bEndPos)
708 // We aren't supposed to have more than one range separator.
709 return false;
711 // range separator
712 if (aBuf.isEmpty())
713 return false;
715 bool bRes = lcl_CheckRepeatOne(rDoc, aBuf, eConv, bIsRow, nVal);
716 if (!bRes)
717 return false;
719 if (pRange)
721 if (bIsRow)
723 pRange->aStart.SetRow(static_cast<SCROW>(nVal));
724 pRange->aEnd.SetRow(static_cast<SCROW>(nVal));
726 else
728 pRange->aStart.SetCol(static_cast<SCCOL>(nVal));
729 pRange->aEnd.SetCol(static_cast<SCCOL>(nVal));
733 aBuf.clear();
734 bEndPos = true;
736 else
737 aBuf += OUStringChar(c);
740 if (!aBuf.isEmpty())
742 bool bRes = lcl_CheckRepeatOne(rDoc, aBuf, eConv, bIsRow, nVal);
743 if (!bRes)
744 return false;
746 if (pRange)
748 if (bIsRow)
750 if (!bEndPos)
751 pRange->aStart.SetRow(static_cast<SCROW>(nVal));
752 pRange->aEnd.SetRow(static_cast<SCROW>(nVal));
754 else
756 if (!bEndPos)
757 pRange->aStart.SetCol(static_cast<SCCOL>(nVal));
758 pRange->aEnd.SetCol(static_cast<SCCOL>(nVal));
763 return true;
766 static void lcl_GetRepeatRangeString( std::optional<ScRange> oRange, const ScDocument& rDoc, bool bIsRow, OUString& rStr )
768 rStr.clear();
769 if (!oRange)
770 return;
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: */