/* -*- 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/. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include ScNameDefDlg::ScNameDefDlg( SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent, const ScViewData& rViewData, std::map&& aRangeMap, const ScAddress& aCursorPos, const bool bUndo ) : ScAnyRefDlgController( pB, pCW, pParent, u"modules/scalc/ui/definename.ui"_ustr, u"DefineNameDialog"_ustr) , mbUndo( bUndo ) , mrDoc(rViewData.GetDocument()) , mpDocShell ( rViewData.GetDocShell() ) , maCursorPos( aCursorPos ) , maGlobalNameStr ( ScResId(STR_GLOBAL_SCOPE) ) , maErrInvalidNameStr( ScResId(STR_ERR_NAME_INVALID)) , maErrInvalidNameCellRefStr( ScResId(STR_ERR_NAME_INVALID_CELL_REF)) , maErrInvalidSheetReference(ScResId(STR_INVALID_TABREF_PRINT_AREA)) , maErrNameInUse ( ScResId(STR_ERR_NAME_EXISTS)) , maRangeMap( std::move(aRangeMap) ) , m_xEdName(m_xBuilder->weld_entry(u"edit"_ustr)) , m_xEdRange(new formula::RefEdit(m_xBuilder->weld_entry(u"range"_ustr))) , m_xRbRange(new formula::RefButton(m_xBuilder->weld_button(u"refbutton"_ustr))) , m_xLbScope(m_xBuilder->weld_combo_box(u"scope"_ustr)) , m_xBtnRowHeader(m_xBuilder->weld_check_button(u"rowheader"_ustr)) , m_xBtnColHeader(m_xBuilder->weld_check_button(u"colheader"_ustr)) , m_xBtnPrintArea(m_xBuilder->weld_check_button(u"printarea"_ustr)) , m_xBtnCriteria(m_xBuilder->weld_check_button(u"filter"_ustr)) , m_xBtnAdd(m_xBuilder->weld_button(u"add"_ustr)) , m_xBtnCancel(m_xBuilder->weld_button(u"cancel"_ustr)) , m_xFtInfo(m_xBuilder->weld_label(u"label"_ustr)) , m_xExpander(m_xBuilder->weld_expander(u"more"_ustr)) , m_xFtRange(m_xBuilder->weld_label(u"label3"_ustr)) { m_xEdRange->SetReferences(this, m_xFtRange.get()); m_xRbRange->SetReferences(this, m_xEdRange.get()); maStrInfoDefault = m_xFtInfo->get_label(); // Initialize scope list. m_xLbScope->append_text(maGlobalNameStr); m_xLbScope->set_active(0); SCTAB n = mrDoc.GetTableCount(); for (SCTAB i = 0; i < n; ++i) { OUString aTabName; mrDoc.GetName(i, aTabName); m_xLbScope->append_text(aTabName); } m_xBtnCancel->connect_clicked( LINK( this, ScNameDefDlg, CancelBtnHdl)); m_xBtnAdd->connect_clicked( LINK( this, ScNameDefDlg, AddBtnHdl )); m_xEdName->connect_changed( LINK( this, ScNameDefDlg, NameModifyHdl )); m_xEdRange->SetGetFocusHdl( LINK( this, ScNameDefDlg, AssignGetFocusHdl ) ); m_xEdRange->SetModifyHdl( LINK( this, ScNameDefDlg, RefEdModifyHdl ) ); m_xBtnPrintArea->connect_toggled(LINK(this, ScNameDefDlg, EdModifyCheckBoxHdl)); m_xBtnAdd->set_sensitive(false); // empty name is invalid ScRange aRange; rViewData.GetSimpleArea( aRange ); OUString aAreaStr(aRange.Format(mrDoc, ScRefFlags::RANGE_ABS_3D, ScAddress::Details(mrDoc.GetAddressConvention(), 0, 0))); m_xEdRange->SetText( aAreaStr ); m_xEdName->grab_focus(); m_xEdName->select_region(0, -1); } ScNameDefDlg::~ScNameDefDlg() { } void ScNameDefDlg::CancelPushed() { if (mbUndo) response(RET_CANCEL); else { if (ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell()) pViewSh->SwitchBetweenRefDialogs(this); } } bool ScNameDefDlg::IsFormulaValid() { const OUString aRangeOrFormulaExp = m_xEdRange->GetText(); // tdf#140394 - check if formula is a valid print range if (m_xBtnPrintArea->get_active()) { 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 = mrDoc.GetAddressConvention(); const sal_Unicode sep = ScCompiler::GetNativeSymbolChar(ocSep); ScAddress aAddr; ScRange aRange; for (sal_Int32 nIdx = 0; nIdx >= 0;) { const OUString aOne = aRangeOrFormulaExp.getToken(0, sep, nIdx); ScRefFlags nResult = aRange.Parse(aOne, mrDoc, eConv); if ((nResult & nValidRange) != nValidRange) { ScRefFlags nAddrResult = aAddr.Parse(aOne, mrDoc, eConv); if ((nAddrResult & nValidAddr) != nValidAddr) return false; } } } else { ScCompiler aComp(mrDoc, maCursorPos, mrDoc.GetGrammar()); std::unique_ptr pCode = aComp.CompileString(m_xEdRange->GetText()); if (pCode->GetCodeError() != FormulaError::NONE) return false; } return true; } bool ScNameDefDlg::IsNameValid() { OUString aScope = m_xLbScope->get_active_text(); OUString aName = m_xEdName->get_text(); bool bIsNameValid = true; OUString aHelpText = maStrInfoDefault; ScRangeName* pRangeName = nullptr; if(aScope == maGlobalNameStr) { const auto iter = maRangeMap.find(STR_GLOBAL_RANGE_NAME); assert(iter != maRangeMap.end()); pRangeName = iter->second; } else { const auto iter = maRangeMap.find(aScope); assert(iter != maRangeMap.end()); pRangeName = iter->second; } ScRangeData::IsNameValidType eType; if ( aName.isEmpty() ) { bIsNameValid = false; } else if ((eType = ScRangeData::IsNameValid(aName, mrDoc)) != ScRangeData::IsNameValidType::NAME_VALID) { if (eType == ScRangeData::IsNameValidType::NAME_INVALID_BAD_STRING) { aHelpText = maErrInvalidNameStr; } else if (eType == ScRangeData::IsNameValidType::NAME_INVALID_CELL_REF) { aHelpText = maErrInvalidNameCellRefStr; } bIsNameValid = false; } else if (pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(aName))) { aHelpText = maErrNameInUse; bIsNameValid = false; } if (!IsFormulaValid()) { bIsNameValid = false; if (m_xBtnPrintArea->get_active()) aHelpText = maErrInvalidSheetReference; //TODO: info message for a non valid formula (print range not checked) } m_xEdName->set_tooltip_text(aHelpText); m_xEdName->set_message_type(bIsNameValid || aName.isEmpty() ? weld::EntryMessageType::Normal : weld::EntryMessageType::Error); m_xBtnAdd->set_sensitive(bIsNameValid); return bIsNameValid; } void ScNameDefDlg::AddPushed() { OUString aScope = m_xLbScope->get_active_text(); OUString aName = m_xEdName->get_text(); OUString aExpression = m_xEdRange->GetText(); if (aName.isEmpty()) { return; } if (aScope.isEmpty()) { return; } ScRangeName* pRangeName = nullptr; if(aScope == maGlobalNameStr) { const auto iter = maRangeMap.find(STR_GLOBAL_RANGE_NAME); assert(iter != maRangeMap.end()); pRangeName = iter->second; } else { const auto iter = maRangeMap.find(aScope); assert(iter != maRangeMap.end()); pRangeName = iter->second; } if (!pRangeName) return; if (!IsNameValid()) //should not happen, but make sure we don't break anything return; else { ScRangeData::Type nType = ScRangeData::Type::Name; ScRangeData* pNewEntry = new ScRangeData( mrDoc, aName, aExpression, maCursorPos, nType ); if ( m_xBtnRowHeader->get_active() ) nType |= ScRangeData::Type::RowHeader; if ( m_xBtnColHeader->get_active() ) nType |= ScRangeData::Type::ColHeader; if ( m_xBtnPrintArea->get_active() ) nType |= ScRangeData::Type::PrintArea; if ( m_xBtnCriteria->get_active() ) nType |= ScRangeData::Type::Criteria; pNewEntry->AddType(nType); // aExpression valid? if ( FormulaError::NONE == pNewEntry->GetErrCode() ) { if ( !pRangeName->insert( pNewEntry, false /*bReuseFreeIndex*/ ) ) pNewEntry = nullptr; if (mbUndo) { // this means we called directly through the menu SCTAB nTab; // if no table with that name is found, assume global range name if (!mrDoc.GetTable(aScope, nTab)) nTab = -1; assert( pNewEntry); // undo of no insertion smells fishy if (pNewEntry) mpDocShell->GetUndoManager()->AddUndoAction( std::make_unique( mpDocShell, pNewEntry, nTab) ); // set table stream invalid, otherwise RangeName won't be saved if no other // call invalidates the stream if (nTab != -1) mrDoc.SetStreamValid(nTab, false); SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) ); mpDocShell->SetDocumentModified(); Close(); } else { maName = aName; maScope = aScope; if (ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell()) pViewSh->SwitchBetweenRefDialogs(this); } } else { delete pNewEntry; m_xEdRange->GrabFocus(); m_xEdRange->SelectAll(); } } } void ScNameDefDlg::GetNewData(OUString& rName, OUString& rScope) { rName = maName; rScope = maScope; } bool ScNameDefDlg::IsRefInputMode() const { return m_xEdRange->GetWidget()->get_sensitive(); } void ScNameDefDlg::RefInputDone( bool bForced) { ScAnyRefDlgController::RefInputDone(bForced); IsNameValid(); } void ScNameDefDlg::SetReference( const ScRange& rRef, ScDocument& rDocP ) { if (m_xEdRange->GetWidget()->get_sensitive()) { if ( rRef.aStart != rRef.aEnd ) RefInputStart(m_xEdRange.get()); OUString aRefStr(rRef.Format(rDocP, ScRefFlags::RANGE_ABS_3D, ScAddress::Details(rDocP.GetAddressConvention(), 0, 0))); m_xEdRange->SetRefString( aRefStr ); } } void ScNameDefDlg::Close() { DoClose( ScNameDefDlgWrapper::GetChildWindowId() ); } void ScNameDefDlg::SetActive() { m_xEdRange->GrabFocus(); RefInputDone(); } IMPL_LINK_NOARG(ScNameDefDlg, CancelBtnHdl, weld::Button&, void) { CancelPushed(); } IMPL_LINK_NOARG(ScNameDefDlg, AddBtnHdl, weld::Button&, void) { AddPushed(); }; IMPL_LINK_NOARG(ScNameDefDlg, NameModifyHdl, weld::Entry&, void) { IsNameValid(); } IMPL_LINK_NOARG(ScNameDefDlg, AssignGetFocusHdl, formula::RefEdit&, void) { IsNameValid(); } IMPL_LINK_NOARG(ScNameDefDlg, EdModifyCheckBoxHdl, weld::Toggleable&, void) { IsNameValid(); } IMPL_LINK_NOARG(ScNameDefDlg, RefEdModifyHdl, formula::RefEdit&, void) { IsNameValid(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */