/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <rangelst.hxx>
#include <o3tl/string_view.hxx>
#include <sfx2/dispatch.hxx>
#include <svl/stritem.hxx>
#include <vcl/svapp.hxx>
#include <vcl/weld.hxx>
#include <unotools/charclass.hxx>
#include <areasdlg.hxx>
#include <rangenam.hxx>
#include <reffact.hxx>
#include <tabvwsh.hxx>
#include <docsh.hxx>
#include <globstr.hrc>
#include <scresid.hxx>
#include <compiler.hxx>
#include <markdata.hxx>
// List box positions for print range (PR)
enum {
SC_AREASDLG_PR_ENTIRE = 1,
SC_AREASDLG_PR_USER = 2,
SC_AREASDLG_PR_SELECT = 3
};
// List box positions for repeat ranges (RR)
enum {
SC_AREASDLG_RR_NONE = 0,
SC_AREASDLG_RR_USER = 1,
SC_AREASDLG_RR_OFFSET = 2
};
namespace
{
void ERRORBOX(weld::Window* pParent, TranslateId rId)
{
std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pParent,
VclMessageType::Warning, VclButtonsType::Ok,
ScResId(rId)));
xBox->run();
}
}
// global functions (->at the end of the file):
static bool lcl_CheckRepeatString( std::u16string_view aStr,
const ScDocument& rDoc
, bool bIsRow, ScRange* pRange );
static void lcl_GetRepeatRangeString( const std::optional<ScRange>& oRange, const ScDocument& rDoc, bool bIsRow, OUString& rStr );
#if 0
// this method is useful when debugging address flags.
static void printAddressFlags(ScRefFlags nFlag)
{
if ((nFlag & ScRefFlags::COL_ABS ) == ScRefFlags::COL_ABS ) printf("ScRefFlags::COL_ABS \n" );
if ((nFlag & ScRefFlags::ROW_ABS ) == ScRefFlags::ROW_ABS ) printf("ScRefFlags::ROW_ABS \n" );
if ((nFlag & ScRefFlags::TAB_ABS ) == ScRefFlags::TAB_ABS ) printf("ScRefFlags::TAB_ABS \n" );
if ((nFlag & ScRefFlags::TAB_3D ) == ScRefFlags::TAB_3D ) printf("ScRefFlags::TAB_3D \n" );
if ((nFlag & ScRefFlags::COL2_ABS ) == ScRefFlags::COL2_ABS ) printf("ScRefFlags::COL2_ABS \n" );
if ((nFlag & ScRefFlags::ROW2_ABS ) == ScRefFlags::ROW2_ABS ) printf("ScRefFlags::ROW2_ABS \n" );
if ((nFlag & ScRefFlags::TAB2_ABS ) == ScRefFlags::TAB2_ABS ) printf("ScRefFlags::TAB2_ABS \n" );
if ((nFlag & ScRefFlags::TAB2_3D ) == ScRefFlags::TAB2_3D ) printf("ScRefFlags::TAB2_3D \n" );
if ((nFlag & ScRefFlags::ROW_VALID ) == ScRefFlags::ROW_VALID ) printf("ScRefFlags::ROW_VALID \n" );
if ((nFlag & ScRefFlags::COL_VALID ) == ScRefFlags::COL_VALID ) printf("ScRefFlags::COL_VALID \n" );
if ((nFlag & ScRefFlags::TAB_VALID ) == ScRefFlags::TAB_VALID ) printf("ScRefFlags::TAB_VALID \n" );
if ((nFlag & ScRefFlags::FORCE_DOC ) == ScRefFlags::FORCE_DOC ) printf("ScRefFlags::FORCE_DOC \n" );
if ((nFlag & ScRefFlags::ROW2_VALID ) == ScRefFlags::ROW2_VALID ) printf("ScRefFlags::ROW2_VALID \n" );
if ((nFlag & ScRefFlags::COL2_VALID ) == ScRefFlags::COL2_VALID ) printf("ScRefFlags::COL2_VALID \n" );
if ((nFlag & ScRefFlags::TAB2_VALID ) == ScRefFlags::TAB2_VALID ) printf("ScRefFlags::TAB2_VALID \n" );
if ((nFlag & ScRefFlags::VALID ) == ScRefFlags::VALID ) printf("ScRefFlags::VALID \n" );
if ((nFlag & ScRefFlags::ADDR_ABS ) == ScRefFlags::ADDR_ABS ) printf("ScRefFlags::ADDR_ABS \n" );
if ((nFlag & ScRefFlags::RANGE_ABS ) == ScRefFlags::RANGE_ABS ) printf("ScRefFlags::RANGE_ABS \n" );
if ((nFlag & ScRefFlags::ADDR_ABS_3D ) == ScRefFlags::ADDR_ABS_3D ) printf("ScRefFlags::ADDR_ABS_3D \n" );
if ((nFlag & ScRefFlags::RANGE_ABS_3D ) == ScRefFlags::RANGE_ABS_3D ) printf("ScRefFlags::RANGE_ABS_3D \n" );
}
#endif
ScPrintAreasDlg::ScPrintAreasDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent, ScViewData& rData)
: ScAnyRefDlgController(pB, pCW, pParent, u"modules/scalc/ui/printareasdialog.ui" _ustr, u"PrintAreasDialog" _ustr)
, bDlgLostFocus(false )
, rViewData(rData)
, rDoc(rViewData.GetDocument())
, nCurTab(rViewData.GetTabNo())
, m_xLbPrintArea(m_xBuilder->weld_combo_box(u"lbprintarea" _ustr))
, m_xEdPrintArea(new formula::RefEdit(m_xBuilder->weld_entry(u"edprintarea" _ustr)))
, m_xRbPrintArea(new formula::RefButton(m_xBuilder->weld_button(u"rbprintarea" _ustr)))
, m_xLbRepeatRow(m_xBuilder->weld_combo_box(u"lbrepeatrow" _ustr))
, m_xEdRepeatRow(new formula::RefEdit(m_xBuilder->weld_entry(u"edrepeatrow" _ustr)))
, m_xRbRepeatRow(new formula::RefButton(m_xBuilder->weld_button(u"rbrepeatrow" _ustr)))
, m_xLbRepeatCol(m_xBuilder->weld_combo_box(u"lbrepeatcol" _ustr))
, m_xEdRepeatCol(new formula::RefEdit(m_xBuilder->weld_entry(u"edrepeatcol" _ustr)))
, m_xRbRepeatCol(new formula::RefButton(m_xBuilder->weld_button(u"rbrepeatcol" _ustr)))
, m_xBtnOk(m_xBuilder->weld_button(u"ok" _ustr))
, m_xBtnCancel(m_xBuilder->weld_button(u"cancel" _ustr))
, m_xPrintFrame(m_xBuilder->weld_frame(u"printframe" _ustr))
, m_xRowFrame(m_xBuilder->weld_frame(u"rowframe" _ustr))
, m_xColFrame(m_xBuilder->weld_frame(u"colframe" _ustr))
, m_xPrintFrameFT(m_xPrintFrame->weld_label_widget())
, m_xRowFrameFT(m_xRowFrame->weld_label_widget())
, m_xColFrameFT(m_xColFrame->weld_label_widget())
{
m_xEdPrintArea->SetReferences(this , m_xPrintFrameFT.get());
m_pRefInputEdit = m_xEdPrintArea.get();
m_xRbPrintArea->SetReferences(this , m_xEdPrintArea.get());
m_xEdRepeatRow->SetReferences(this , m_xRowFrameFT.get());
m_xRbRepeatRow->SetReferences(this , m_xEdRepeatRow.get());
m_xEdRepeatCol->SetReferences(this , m_xColFrameFT.get());
m_xRbRepeatCol->SetReferences(this , m_xEdRepeatCol.get());
Impl_Reset();
//@BugID 54702 Enable/Disable only in base class
//SFX_APPWINDOW->Enable();
}
ScPrintAreasDlg::~ScPrintAreasDlg()
{
}
void ScPrintAreasDlg::Close()
{
DoClose( ScPrintAreasDlgWrapper::GetChildWindowId() );
}
bool ScPrintAreasDlg::IsTableLocked() const
{
// Printing areas are per table, therefore it makes no sense,
// to switch the table during input
return true ;
}
void ScPrintAreasDlg::SetReference( const ScRange& rRef, ScDocument& /* rDoc */ )
{
if ( !m_pRefInputEdit )
return ;
if ( rRef.aStart != rRef.aEnd )
RefInputStart( m_pRefInputEdit );
OUString aStr;
const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
if (m_xEdPrintArea.get() == m_pRefInputEdit)
{
aStr = rRef.Format(rDoc, ScRefFlags::RANGE_ABS, eConv);
OUString aVal = m_xEdPrintArea->GetText();
Selection aSel = m_xEdPrintArea->GetSelection();
aSel.Normalize();
aVal = aVal.replaceAt( aSel.Min(), aSel.Len(), aStr );
Selection aNewSel( aSel.Min(), aSel.Min()+aStr.getLength() );
m_xEdPrintArea->SetRefString( aVal );
m_xEdPrintArea->SetSelection( aNewSel );
}
else
{
bool bRow = ( m_xEdRepeatRow.get() == m_pRefInputEdit );
lcl_GetRepeatRangeString(rRef, rDoc, bRow, aStr);
m_pRefInputEdit->SetRefString( aStr );
}
Impl_ModifyHdl( *m_pRefInputEdit );
}
void ScPrintAreasDlg::AddRefEntry()
{
if (m_pRefInputEdit == m_xEdPrintArea.get())
{
const sal_Unicode sep = ScCompiler::GetNativeSymbolChar(ocSep);
OUString aVal = m_xEdPrintArea->GetText() + OUStringChar(sep);
m_xEdPrintArea->SetText(aVal);
sal_Int32 nLen = aVal.getLength();
m_xEdPrintArea->SetSelection( Selection( nLen, nLen ) );
Impl_ModifyHdl( *m_xEdPrintArea );
}
}
void ScPrintAreasDlg::Deactivate()
{
bDlgLostFocus = true ;
}
void ScPrintAreasDlg::SetActive()
{
if ( bDlgLostFocus )
{
bDlgLostFocus = false ;
if ( m_pRefInputEdit )
{
m_pRefInputEdit->GrabFocus();
Impl_ModifyHdl( *m_pRefInputEdit );
}
}
else
m_xDialog->grab_focus();
RefInputDone();
}
void ScPrintAreasDlg::Impl_Reset()
{
OUString aStrRange;
std::optional<ScRange> oRepeatColRange = rDoc.GetRepeatColRange( nCurTab );
std::optional<ScRange> oRepeatRowRange = rDoc.GetRepeatRowRange( nCurTab );
m_xEdPrintArea->SetModifyHdl (LINK( this , ScPrintAreasDlg, Impl_ModifyHdl));
m_xEdRepeatRow->SetModifyHdl (LINK( this , ScPrintAreasDlg, Impl_ModifyHdl));
m_xEdRepeatCol->SetModifyHdl (LINK( this , ScPrintAreasDlg, Impl_ModifyHdl));
m_xEdPrintArea->SetGetFocusHdl(LINK( this , ScPrintAreasDlg, Impl_GetEditFocusHdl));
m_xEdRepeatRow->SetGetFocusHdl(LINK( this , ScPrintAreasDlg, Impl_GetEditFocusHdl));
m_xEdRepeatCol->SetGetFocusHdl(LINK( this , ScPrintAreasDlg, Impl_GetEditFocusHdl));
m_xLbPrintArea->connect_focus_in(LINK( this , ScPrintAreasDlg, Impl_GetFocusHdl));
m_xLbRepeatRow->connect_focus_in(LINK( this , ScPrintAreasDlg, Impl_GetFocusHdl));
m_xLbRepeatCol->connect_focus_in(LINK( this , ScPrintAreasDlg, Impl_GetFocusHdl));
m_xLbPrintArea->connect_changed(LINK( this , ScPrintAreasDlg, Impl_SelectHdl));
m_xLbRepeatRow->connect_changed(LINK( this , ScPrintAreasDlg, Impl_SelectHdl));
m_xLbRepeatCol->connect_changed(LINK( this , ScPrintAreasDlg, Impl_SelectHdl));
m_xBtnOk->connect_clicked(LINK( this , ScPrintAreasDlg, Impl_BtnHdl));
m_xBtnCancel->connect_clicked(LINK( this , ScPrintAreasDlg, Impl_BtnHdl));
Impl_FillLists();
// printing area
aStrRange.clear();
const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
const sal_Unicode sep = ScCompiler::GetNativeSymbolChar(ocSep);
sal_uInt16 nRangeCount = rDoc.GetPrintRangeCount( nCurTab );
for (sal_uInt16 i=0; i<nRangeCount; i++)
{
const ScRange* pPrintRange = rDoc.GetPrintRange( nCurTab, i );
if (pPrintRange)
{
if ( !aStrRange.isEmpty() )
aStrRange += OUStringChar(sep);
aStrRange += pPrintRange->Format(rDoc, ScRefFlags::RANGE_ABS, eConv);
}
}
m_xEdPrintArea->SetText( aStrRange );
// repeat row
lcl_GetRepeatRangeString(oRepeatRowRange, rDoc, true , aStrRange);
m_xEdRepeatRow->SetText( aStrRange );
// repeat column
lcl_GetRepeatRangeString(oRepeatColRange, rDoc, false , aStrRange);
m_xEdRepeatCol->SetText( aStrRange );
Impl_ModifyHdl( *m_xEdPrintArea );
Impl_ModifyHdl( *m_xEdRepeatRow );
Impl_ModifyHdl( *m_xEdRepeatCol );
if ( rDoc.IsPrintEntireSheet( nCurTab ) )
m_xLbPrintArea->set_active(SC_AREASDLG_PR_ENTIRE);
m_xEdPrintArea->SaveValue(); // save for FillItemSet():
m_xEdRepeatRow->SaveValue();
m_xEdRepeatCol->SaveValue();
}
bool ScPrintAreasDlg::Impl_GetItem( const formula::RefEdit* pEd, SfxStringItem& rItem )
{
OUString aRangeStr = pEd->GetText();
bool bDataChanged = pEd->IsValueChangedFromSaved();
if ( !aRangeStr.isEmpty() && m_xEdPrintArea.get() != pEd )
{
ScRange aRange;
const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
lcl_CheckRepeatString(aRangeStr, rDoc, m_xEdRepeatRow.get() == pEd, &aRange);
aRangeStr = aRange.Format(rDoc, ScRefFlags::RANGE_ABS, eConv);
}
rItem.SetValue( aRangeStr );
return bDataChanged;
}
bool ScPrintAreasDlg::Impl_CheckRefStrings()
{
bool bOk = false ;
OUString aStrPrintArea = m_xEdPrintArea->GetText();
OUString aStrRepeatRow = m_xEdRepeatRow->GetText();
OUString aStrRepeatCol = m_xEdRepeatCol->GetText();
bool bPrintAreaOk = true ;
if ( !aStrPrintArea.isEmpty() )
{
const ScRefFlags nValidAddr = ScRefFlags::VALID | ScRefFlags::ROW_VALID | ScRefFlags::COL_VALID;
const ScRefFlags nValidRange = nValidAddr | ScRefFlags::ROW2_VALID | ScRefFlags::COL2_VALID;
const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
const sal_Unicode sep = ScCompiler::GetNativeSymbolChar(ocSep);
ScAddress aAddr;
ScRange aRange;
for ( sal_Int32 nIdx = 0; nIdx >= 0; )
{
const OUString aOne = aStrPrintArea.getToken(0, sep, nIdx);
ScRefFlags nResult = aRange.Parse( aOne, rDoc, eConv );
if ((nResult & nValidRange) != nValidRange)
{
ScRefFlags nAddrResult = aAddr.Parse( aOne, rDoc, eConv );
if ((nAddrResult & nValidAddr) != nValidAddr)
{
bPrintAreaOk = false ;
break ;
}
}
}
}
bool bRepeatRowOk = aStrRepeatRow.isEmpty();
if ( !bRepeatRowOk )
bRepeatRowOk = lcl_CheckRepeatString(aStrRepeatRow, rDoc, true , nullptr);
bool bRepeatColOk = aStrRepeatCol.isEmpty();
if ( !bRepeatColOk )
bRepeatColOk = lcl_CheckRepeatString(aStrRepeatCol, rDoc, false , nullptr);
// error messages
bOk = (bPrintAreaOk && bRepeatRowOk && bRepeatColOk);
if ( !bOk )
{
formula::RefEdit* pEd = nullptr;
if ( !bPrintAreaOk ) pEd = m_xEdPrintArea.get();
else if ( !bRepeatRowOk ) pEd = m_xEdRepeatRow.get();
else if ( !bRepeatColOk ) pEd = m_xEdRepeatCol.get();
ERRORBOX(m_xDialog.get(), STR_INVALID_TABREF);
OSL_ASSERT(pEd);
if (pEd)
pEd->GrabFocus();
}
return bOk;
}
void ScPrintAreasDlg::Impl_FillLists()
{
// Get selection and remember String in PrintArea-ListBox
ScRange aRange;
OUString aStrRange;
bool bSimple = true ;
bSimple = (rViewData.GetSimpleArea( aRange ) == SC_MARK_SIMPLE);
formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
if ( bSimple )
aStrRange = aRange.Format(rDoc, ScRefFlags::RANGE_ABS, eConv);
else
{
ScRangeListRef aList( new ScRangeList );
rViewData.GetMarkData().FillRangeListWithMarks( aList.get(), false );
aList->Format(aStrRange, ScRefFlags::RANGE_ABS, rDoc, eConv);
}
m_xLbPrintArea->set_id(SC_AREASDLG_PR_SELECT, aStrRange);
// Get ranges and remember in ListBoxen
ScRangeName* pRangeNames = rDoc.GetRangeName();
if (!pRangeNames || pRangeNames->empty())
// No range names to process.
return ;
for (const auto & rEntry : *pRangeNames)
{
if (!rEntry.second->HasType(ScRangeData::Type::AbsArea )
&& !rEntry.second->HasType(ScRangeData::Type::RefArea)
&& !rEntry.second->HasType(ScRangeData::Type::AbsPos ))
continue ;
OUString aName = rEntry.second->GetName();
OUString aSymbol = rEntry.second->GetSymbol();
if (aRange.ParseAny(aSymbol, rDoc, eConv) & ScRefFlags::VALID)
{
if (rEntry.second->HasType(ScRangeData::Type::PrintArea))
{
aSymbol = aRange.Format(rDoc, ScRefFlags::RANGE_ABS, eConv);
m_xLbPrintArea->append(aSymbol, aName);
}
if (rEntry.second->HasType(ScRangeData::Type::RowHeader))
{
lcl_GetRepeatRangeString(aRange, rDoc, true , aSymbol);
m_xLbRepeatRow->append(aSymbol, aName);
}
if (rEntry.second->HasType(ScRangeData::Type::ColHeader))
{
lcl_GetRepeatRangeString(aRange, rDoc, false , aSymbol);
m_xLbRepeatCol->append(aSymbol, aName);
}
}
}
}
// Handler:
IMPL_LINK(ScPrintAreasDlg, Impl_BtnHdl, weld::Button&, rBtn, void )
{
if (m_xBtnOk.get() == &rBtn)
{
if ( Impl_CheckRefStrings() )
{
SfxStringItem aPrintArea( SID_CHANGE_PRINTAREA, u"" _ustr );
SfxStringItem aRepeatRow( FN_PARAM_2, u"" _ustr );
SfxStringItem aRepeatCol( FN_PARAM_3, u"" _ustr );
// Printing area changed?
// first try the list box, if "Entire sheet" is selected
bool bEntireSheet = (m_xLbPrintArea->get_active() == SC_AREASDLG_PR_ENTIRE);
SfxBoolItem aEntireSheet( FN_PARAM_4, bEntireSheet );
bool bDataChanged = bEntireSheet != rDoc.IsPrintEntireSheet( nCurTab );
if ( !bEntireSheet )
{
// if new list box selection is not "Entire sheet", get the edit field contents
bDataChanged |= Impl_GetItem( m_xEdPrintArea.get(), aPrintArea );
}
// Repeat row changed?
bDataChanged |= Impl_GetItem( m_xEdRepeatRow.get(), aRepeatRow );
// Repeat column changed?
bDataChanged |= Impl_GetItem( m_xEdRepeatCol.get(), aRepeatCol );
if ( bDataChanged )
{
SetDispatcherLock( false );
SwitchToDocument();
GetBindings().GetDispatcher()->ExecuteList(SID_CHANGE_PRINTAREA,
SfxCallMode::SLOT | SfxCallMode::RECORD,
{ &aPrintArea, &aRepeatRow, &aRepeatCol, &aEntireSheet });
}
response(RET_OK);
}
}
else if (m_xBtnCancel.get() == &rBtn)
response(RET_CANCEL);
}
IMPL_LINK(ScPrintAreasDlg, Impl_GetEditFocusHdl, formula::RefEdit&, rCtrl, void )
{
m_pRefInputEdit = &rCtrl;
}
IMPL_LINK(ScPrintAreasDlg, Impl_GetFocusHdl, weld::Widget&, rCtrl, void )
{
if (&rCtrl == m_xLbPrintArea.get())
m_pRefInputEdit = m_xEdPrintArea.get();
else if (&rCtrl == m_xLbRepeatRow.get())
m_pRefInputEdit = m_xEdRepeatRow.get();
else if (&rCtrl == m_xLbRepeatCol.get())
m_pRefInputEdit = m_xEdRepeatCol.get();
}
IMPL_LINK( ScPrintAreasDlg, Impl_SelectHdl, weld::ComboBox&, rLb, void )
{
const sal_Int32 nSelPos = rLb.get_active();
formula::RefEdit* pEd = nullptr;
// list box positions of specific entries, default to "repeat row/column" list boxes
sal_Int32 nAllSheetPos = SC_AREASDLG_RR_NONE;
sal_Int32 nFirstCustomPos = SC_AREASDLG_RR_OFFSET;
// find edit field for list box, and list box positions
if (&rLb == m_xLbPrintArea.get())
{
pEd = m_xEdPrintArea.get();
nAllSheetPos = SC_AREASDLG_PR_ENTIRE;
nFirstCustomPos = SC_AREASDLG_PR_SELECT; // "Selection" and following
}
else if (&rLb == m_xLbRepeatCol.get())
pEd = m_xEdRepeatCol.get();
else if (&rLb == m_xLbRepeatRow.get())
pEd = m_xEdRepeatRow.get();
else
return ;
// fill edit field according to list box selection
if ( (nSelPos == 0) || (nSelPos == nAllSheetPos) )
pEd->SetText( OUString() );
else if ( nSelPos >= nFirstCustomPos )
pEd->SetText(rLb.get_id(nSelPos));
}
IMPL_LINK( ScPrintAreasDlg, Impl_ModifyHdl, formula::RefEdit&, rEd, void )
{
weld::ComboBox* pLb = nullptr;
// list box positions of specific entries, default to "repeat row/column" list boxes
sal_Int32 nUserDefPos = SC_AREASDLG_RR_USER;
sal_Int32 nFirstCustomPos = SC_AREASDLG_RR_OFFSET;
if ( &rEd == m_xEdPrintArea.get() )
{
pLb = m_xLbPrintArea.get();
nUserDefPos = SC_AREASDLG_PR_USER;
nFirstCustomPos = SC_AREASDLG_PR_SELECT; // "Selection" and following
}
else if ( &rEd == m_xEdRepeatCol.get() )
pLb = m_xLbRepeatCol.get();
else if ( &rEd == m_xEdRepeatRow.get() )
pLb = m_xLbRepeatRow.get();
else
return ;
// set list box selection according to edit field
const sal_Int32 nEntryCount = pLb->get_count();
OUString aStrEd( rEd.GetText() );
OUString aEdUpper = aStrEd.toAsciiUpperCase();
if ( (nEntryCount > nFirstCustomPos) && !aStrEd.isEmpty() )
{
bool bFound = false ;
sal_Int32 i;
for ( i=nFirstCustomPos; i<nEntryCount && !bFound; i++ )
{
const OUString aSymbol = pLb->get_id(i);
bFound = (aSymbol == aStrEd || aSymbol == aEdUpper);
}
pLb->set_active( bFound ? i-1 : nUserDefPos );
}
else
pLb->set_active( !aStrEd.isEmpty() ? nUserDefPos : 0 );
}
// global functions:
// TODO: It might make sense to move these functions to address.?xx. -kohei
static bool lcl_CheckOne_OOO( const ScDocument& rDoc, const OUString& rStr, bool bIsRow, SCCOLROW& rVal )
{
// Allowed syntax for rStr:
// Row: [$]1-MAXTAB
// Col: [$]A-IV
OUString aStr = rStr;
sal_Int32 nLen = aStr.getLength();
SCCOLROW nNum = 0;
bool bStrOk = ( nLen > 0 ) && ( bIsRow ? ( nLen < 6 ) : ( nLen < 4 ) );
if ( bStrOk )
{
if ( '$' == aStr[0] )
aStr = aStr.copy( 1 );
if ( bIsRow )
{
bStrOk = CharClass::isAsciiNumeric(aStr);
if ( bStrOk )
{
sal_Int32 n = aStr.toInt32();
bStrOk = (n > 0) && ( n <= rDoc.GetSheetLimits().GetMaxRowCount() );
if ( bStrOk )
nNum = static_cast <SCCOLROW>(n - 1);
}
}
else
{
SCCOL nCol = 0;
bStrOk = ::AlphaToCol(rDoc, nCol, aStr);
nNum = nCol;
}
}
if ( bStrOk )
rVal = nNum;
return bStrOk;
}
static bool lcl_CheckOne_XL_A1( const ScDocument& rDoc, const OUString& rStr, bool bIsRow, SCCOLROW& rVal )
{
// XL A1 style is identical to OOO one for print range formats.
return lcl_CheckOne_OOO(rDoc, rStr, bIsRow, rVal);
}
static bool lcl_CheckOne_XL_R1C1( const ScDocument& rDoc, std::u16string_view aStr, bool bIsRow, SCCOLROW& rVal )
{
sal_Int32 nLen = aStr.size();
if (nLen <= 1)
// There must be at least two characters.
return false ;
const sal_Unicode preUpper = bIsRow ? 'R' : 'C' ;
const sal_Unicode preLower = bIsRow ? 'r' : 'c' ;
if (aStr[0] != preUpper && aStr[0] != preLower)
return false ;
std::u16string_view aNumStr = aStr.substr(1);
if (!CharClass::isAsciiNumeric(aNumStr))
return false ;
sal_Int32 nNum = o3tl::toInt32(aNumStr);
if (nNum <= 0)
return false ;
if ((bIsRow && nNum > rDoc.GetSheetLimits().GetMaxRowCount()) ||
(!bIsRow && nNum > rDoc.GetSheetLimits().GetMaxColCount()))
return false ;
rVal = static_cast <SCCOLROW>(nNum-1);
return true ;
}
static bool lcl_CheckRepeatOne( const ScDocument& rDoc, const OUString& rStr, formula::FormulaGrammar::AddressConvention eConv, bool bIsRow, SCCOLROW& rVal )
{
switch (eConv)
{
case formula::FormulaGrammar::CONV_OOO:
return lcl_CheckOne_OOO(rDoc, rStr, bIsRow, rVal);
case formula::FormulaGrammar::CONV_XL_A1:
return lcl_CheckOne_XL_A1(rDoc, rStr, bIsRow, rVal);
case formula::FormulaGrammar::CONV_XL_R1C1:
return lcl_CheckOne_XL_R1C1(rDoc, rStr, bIsRow, rVal);
default :
{
// added to avoid warnings
}
}
return false ;
}
static bool lcl_CheckRepeatString( std::u16string_view aStr, const ScDocument& rDoc, bool bIsRow, ScRange* pRange )
{
// Row: [valid row] rsep [valid row]
// Col: [valid col] rsep [valid col]
const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
const sal_Unicode rsep = ScCompiler::GetNativeSymbolChar(ocRange);
if (pRange)
{
// initialize the range value.
pRange->aStart.SetCol(0);
pRange->aStart.SetRow(0);
pRange->aEnd.SetCol(0);
pRange->aEnd.SetRow(0);
}
OUString aBuf;
SCCOLROW nVal = 0;
sal_Int32 nLen = aStr.size();
bool bEndPos = false ;
for ( sal_Int32 i = 0; i < nLen; ++i )
{
const sal_Unicode c = aStr[i];
if (c == rsep)
{
if (bEndPos)
// We aren't supposed to have more than one range separator.
return false ;
// range separator
if (aBuf.isEmpty())
return false ;
bool bRes = lcl_CheckRepeatOne(rDoc, aBuf, eConv, bIsRow, nVal);
if (!bRes)
return false ;
if (pRange)
{
if (bIsRow)
{
pRange->aStart.SetRow(static_cast <SCROW>(nVal));
pRange->aEnd.SetRow(static_cast <SCROW>(nVal));
}
else
{
pRange->aStart.SetCol(static_cast <SCCOL>(nVal));
pRange->aEnd.SetCol(static_cast <SCCOL>(nVal));
}
}
aBuf.clear();
bEndPos = true ;
}
else
aBuf += OUStringChar(c);
}
if (!aBuf.isEmpty())
{
bool bRes = lcl_CheckRepeatOne(rDoc, aBuf, eConv, bIsRow, nVal);
if (!bRes)
return false ;
if (pRange)
{
if (bIsRow)
{
if (!bEndPos)
pRange->aStart.SetRow(static_cast <SCROW>(nVal));
pRange->aEnd.SetRow(static_cast <SCROW>(nVal));
}
else
{
if (!bEndPos)
pRange->aStart.SetCol(static_cast <SCCOL>(nVal));
pRange->aEnd.SetCol(static_cast <SCCOL>(nVal));
}
}
}
return true ;
}
static void lcl_GetRepeatRangeString( const std::optional<ScRange>& oRange, const ScDocument& rDoc, bool bIsRow, OUString& rStr )
{
rStr.clear();
if (!oRange)
return ;
const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
const ScAddress& rStart = oRange->aStart;
const ScAddress& rEnd = oRange->aEnd;
const ScRefFlags nFmt = bIsRow
? (ScRefFlags::ROW_VALID | ScRefFlags::ROW_ABS)
: (ScRefFlags::COL_VALID | ScRefFlags::COL_ABS);
rStr += rStart.Format(nFmt, &rDoc, eConv);
if ((bIsRow && rStart.Row() != rEnd.Row()) || (!bIsRow && rStart.Col() != rEnd.Col()))
{
rStr += ScCompiler::GetNativeSymbol(ocRange);
rStr += rEnd.Format(nFmt, &rDoc, eConv);
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Messung V0.5 C=65 H=96 G=81
¤ Dauer der Verarbeitung: 0.2 Sekunden
(vorverarbeitet)
¤
*© Formatika GbR, Deutschland