diff options
Diffstat (limited to 'sc/source/ui/formdlg')
-rw-r--r-- | sc/source/ui/formdlg/dwfunctr.cxx | 410 | ||||
-rw-r--r-- | sc/source/ui/formdlg/formdata.cxx | 33 | ||||
-rw-r--r-- | sc/source/ui/formdlg/formula.cxx | 691 |
3 files changed, 1134 insertions, 0 deletions
diff --git a/sc/source/ui/formdlg/dwfunctr.cxx b/sc/source/ui/formdlg/dwfunctr.cxx new file mode 100644 index 000000000..424c0ee99 --- /dev/null +++ b/sc/source/ui/formdlg/dwfunctr.cxx @@ -0,0 +1,410 @@ +/* -*- 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 <comphelper/string.hxx> +#include <editeng/editview.hxx> +#include <sfx2/viewsh.hxx> +#include <formula/funcvarargs.h> + +#include <global.hxx> +#include <scmod.hxx> +#include <inputhdl.hxx> +#include <tabvwsh.hxx> +#include <funcdesc.hxx> + +#include <dwfunctr.hxx> + +/************************************************************************* +#* Member: ScFunctionWin +#*------------------------------------------------------------------------ +#* +#* Class: ScFunctionWin +#* +#* Function: Constructor of ScFunctionWin Class +#* +#* Input: Sfx - links, window, resource +#* +#* Output: --- +#* +#************************************************************************/ + +ScFunctionWin::ScFunctionWin(weld::Widget* pParent) + : PanelLayout(pParent, "FunctionPanel", "modules/scalc/ui/functionpanel.ui") + , xCatBox(m_xBuilder->weld_combo_box("category")) + , xFuncList(m_xBuilder->weld_tree_view("funclist")) + , xInsertButton(m_xBuilder->weld_button("insert")) + , xFiFuncDesc(m_xBuilder->weld_label("funcdesc")) + , xConfigListener(new comphelper::ConfigurationListener("/org.openoffice.Office.Calc/Formula/Syntax")) + , xConfigChange(std::make_unique<EnglishFunctionNameChange>(xConfigListener, this)) + , pFuncDesc(nullptr) +{ + xFuncList->set_size_request(-1, xFuncList->get_height_rows(10)); + + InitLRUList(); + + nArgs=0; + xFiFuncDesc->set_size_request(-1, 5 * xFiFuncDesc->get_text_height()); + + xCatBox->connect_changed(LINK( this, ScFunctionWin, SelComboHdl)); + xFuncList->connect_changed(LINK( this, ScFunctionWin, SelTreeHdl)); + + xFuncList->connect_row_activated(LINK( this, ScFunctionWin, SetRowActivatedHdl)); + xInsertButton->connect_clicked(LINK( this, ScFunctionWin, SetSelectionClickHdl)); + + xCatBox->set_active(0); + + SelComboHdl(*xCatBox); +} + +/************************************************************************* +#* Member: ScFunctionWin +#*------------------------------------------------------------------------ +#* +#* Class: ScFunctionWin +#* +#* Function: Destructor of ScFunctionWin Class +#* +#* Input: --- +#* +#* Output: --- +#* +#************************************************************************/ + +ScFunctionWin::~ScFunctionWin() +{ + xConfigChange.reset(); + xConfigListener->dispose(); + xConfigListener.clear(); + + xCatBox.reset(); + xFuncList.reset(); + xInsertButton.reset(); + xFiFuncDesc.reset(); +} + +/************************************************************************* +#* Member: UpdateFunctionList +#*------------------------------------------------------------------------ +#* +#* Class: ScFunctionWin +#* +#* Function: Updates the list of functions depending on the set category +#* +#* Input: --- +#* +#* Output: --- +#* +#************************************************************************/ + +void ScFunctionWin::InitLRUList() +{ + ScFunctionMgr* pFuncMgr = ScGlobal::GetStarCalcFunctionMgr(); + pFuncMgr->fillLastRecentlyUsedFunctions(aLRUList); + + sal_Int32 nSelPos = xCatBox->get_active(); + + if (nSelPos == 0) + UpdateFunctionList(); +} + +/************************************************************************* +#* Member: UpdateFunctionList +#*------------------------------------------------------------------------ +#* +#* Class: ScFunctionWin +#* +#* Function: Updates the list of last used functions. +#* +#* Input: --- +#* +#* Output: --- +#* +#************************************************************************/ + +void ScFunctionWin::UpdateLRUList() +{ + if (pFuncDesc && pFuncDesc->nFIndex!=0) + { + ScModule* pScMod = SC_MOD(); + pScMod->InsertEntryToLRUList(pFuncDesc->nFIndex); + } +} + +/************************************************************************* +#* Member: SetDescription +#*------------------------------------------------------------------------ +#* +#* Class: ScFunctionWin +#* +#* Function: +#* +#* Input: --- +#* +#* Output: --- +#* +#************************************************************************/ + +void ScFunctionWin::SetDescription() +{ + xFiFuncDesc->set_label(OUString()); + const ScFuncDesc* pDesc = + weld::fromId<const ScFuncDesc*>(xFuncList->get_selected_id()); + if (pDesc) + { + pDesc->initArgumentInfo(); // full argument info is needed + + OUString aBuf = xFuncList->get_selected_text() + + ":\n\n" + + pDesc->GetParamList() + + "\n\n" + + *pDesc->mxFuncDesc; + + xFiFuncDesc->set_label(aBuf); + } +} + +/************************************************************************* +#* Member: UpdateFunctionList +#*------------------------------------------------------------------------ +#* +#* Class: ScFunctionWin +#* +#* Function: Updates the list of functions depending on the set category +#* +#* Input: --- +#* +#* Output: --- +#* +#************************************************************************/ + +void ScFunctionWin::UpdateFunctionList() +{ + sal_Int32 nSelPos = xCatBox->get_active(); + sal_Int32 nCategory = ( -1 != nSelPos ) + ? (nSelPos-1) : 0; + + xFuncList->clear(); + xFuncList->freeze(); + + if ( nSelPos > 0 ) + { + ScFunctionMgr* pFuncMgr = ScGlobal::GetStarCalcFunctionMgr(); + + const ScFuncDesc* pDesc = pFuncMgr->First( nCategory ); + while ( pDesc ) + { + xFuncList->append(weld::toId(pDesc), *(pDesc->mxFuncName)); + pDesc = pFuncMgr->Next(); + } + } + else // LRU list + { + for (const formula::IFunctionDescription* pDesc : aLRUList) + { + if (pDesc) + { + xFuncList->append(weld::toId(pDesc), pDesc->getFunctionName()); + } + } + } + + xFuncList->thaw(); + + if (xFuncList->n_children() > 0) + { + xFuncList->set_sensitive(true); + xFuncList->select(0); + } + else + { + xFuncList->set_sensitive(false); + } +} + +/************************************************************************* +#* Member: DoEnter +#*------------------------------------------------------------------------ +#* +#* Class: ScFunctionWin +#* +#* Function: Save input into document. Is called after clicking the +#* Apply button or a double-click on the function list. +#* +#* Input: --- +#* +#* Output: --- +#* +#************************************************************************/ + +void ScFunctionWin::DoEnter() +{ + OUStringBuffer aArgStr; + OUString aString=xFuncList->get_selected_text(); + SfxViewShell* pCurSh = SfxViewShell::Current(); + nArgs=0; + + if(!aString.isEmpty()) + { + OUString aFirstArgStr; + ScModule* pScMod = SC_MOD(); + ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( pCurSh ); + ScInputHandler* pHdl = pScMod->GetInputHdl( pViewSh ); + if(!pScMod->IsEditMode()) + { + rtl::Reference<comphelper::ConfigurationListener> xDetectDisposed(xConfigListener); + pScMod->SetInputMode(SC_INPUT_TABLE); + // the above call can result in us being disposed + if (xDetectDisposed->isDisposed()) + return; + aString = "=" + xFuncList->get_selected_text(); + if (pHdl) + pHdl->ClearText(); + } + const ScFuncDesc* pDesc = + weld::fromId<const ScFuncDesc*>(xFuncList->get_selected_id()); + if (pDesc) + { + pFuncDesc=pDesc; + UpdateLRUList(); + nArgs = pDesc->nArgCount; + if(nArgs>0) + { + // NOTE: Theoretically the first parameter could have the + // suppress flag as well, but practically it doesn't. + aFirstArgStr = pDesc->maDefArgNames[0]; + aFirstArgStr = comphelper::string::strip(aFirstArgStr, ' '); + aFirstArgStr = aFirstArgStr.replaceAll(" ", "_"); + aArgStr = aFirstArgStr; + if ( nArgs != VAR_ARGS && nArgs != PAIRED_VAR_ARGS ) + { // no VarArgs or Fix plus VarArgs, but not VarArgs only + sal_uInt16 nFix; + if (nArgs >= PAIRED_VAR_ARGS) + nFix = nArgs - PAIRED_VAR_ARGS + 2; + else if (nArgs >= VAR_ARGS) + nFix = nArgs - VAR_ARGS + 1; + else + nFix = nArgs; + for ( sal_uInt16 nArg = 1; + nArg < nFix && !pDesc->pDefArgFlags[nArg].bOptional; nArg++ ) + { + aArgStr.append("; "); + OUString sTmp = pDesc->maDefArgNames[nArg]; + sTmp = comphelper::string::strip(sTmp, ' '); + sTmp = sTmp.replaceAll(" ", "_"); + aArgStr.append(sTmp); + } + } + } + } + if (pHdl) + { + if (pHdl->GetEditString().isEmpty()) + { + aString = "=" + xFuncList->get_selected_text(); + } + EditView *pEdView=pHdl->GetActiveView(); + if(pEdView!=nullptr) // @ needed because of crash during setting a name + { + if(nArgs>0) + { + pHdl->InsertFunction(aString); + pEdView->InsertText(aArgStr.makeStringAndClear(),true); + ESelection aESel=pEdView->GetSelection(); + aESel.nEndPos = aESel.nStartPos + aFirstArgStr.getLength(); + pEdView->SetSelection(aESel); + pHdl->DataChanged(); + } + else + { + aString += "()"; + pEdView->InsertText(aString); + pHdl->DataChanged(); + } + } + } + InitLRUList(); + } + if ( pCurSh ) + { + vcl::Window* pShellWnd = pCurSh->GetWindow(); + + if ( pShellWnd ) + pShellWnd->GrabFocus(); + } + +} + +/************************************************************************* +#* Handle: SelHdl +#*------------------------------------------------------------------------ +#* +#* Class: ScFunctionWin +#* +#* Function: A change of the category will update the list of functions. +#* +#* Input: --- +#* +#* Output: --- +#* +#************************************************************************/ + +IMPL_LINK_NOARG(ScFunctionWin, SelComboHdl, weld::ComboBox&, void) +{ + UpdateFunctionList(); + SetDescription(); +} + +IMPL_LINK_NOARG(ScFunctionWin, SelTreeHdl, weld::TreeView&, void) +{ + SetDescription(); +} + +/************************************************************************* +#* Handle: SelHdl +#*------------------------------------------------------------------------ +#* +#* Class: ScFunctionWin +#* +#* Function: A change of the category will update the list of functions. +#* +#* Input: --- +#* +#* Output: --- +#* +#************************************************************************/ + +IMPL_LINK_NOARG( ScFunctionWin, SetSelectionClickHdl, weld::Button&, void ) +{ + DoEnter(); // saves the input +} + +IMPL_LINK_NOARG( ScFunctionWin, SetRowActivatedHdl, weld::TreeView&, bool ) +{ + DoEnter(); // saves the input + return true; +} + +void EnglishFunctionNameChange::setProperty(const css::uno::Any &rProperty) +{ + ConfigurationListenerProperty::setProperty(rProperty); + m_pFunctionWin->InitLRUList(); + m_pFunctionWin->UpdateFunctionList(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/formdlg/formdata.cxx b/sc/source/ui/formdlg/formdata.cxx new file mode 100644 index 000000000..aabce7653 --- /dev/null +++ b/sc/source/ui/formdlg/formdata.cxx @@ -0,0 +1,33 @@ +/* -*- 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 <formdata.hxx> + +ScFormEditData::ScFormEditData() + : pInputHandler(nullptr) + , pScDocShell(nullptr) +{ + Reset(); +} + +ScFormEditData::~ScFormEditData() {} + +void ScFormEditData::SaveValues() { Reset(); } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/formdlg/formula.cxx b/sc/source/ui/formdlg/formula.cxx new file mode 100644 index 000000000..6f4dfab2c --- /dev/null +++ b/sc/source/ui/formdlg/formula.cxx @@ -0,0 +1,691 @@ +/* -*- 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 <memory> +#include <scitems.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/objsh.hxx> +#include <svl/numformat.hxx> +#include <svl/stritem.hxx> +#include <sfx2/viewfrm.hxx> +#include <tools/urlobj.hxx> +#include <formula/formulahelper.hxx> +#include <formula/IFunctionDescription.hxx> +#include <formula/errorcodes.hxx> + +#include <compiler.hxx> +#include <formula.hxx> +#include <formdata.hxx> +#include <reffact.hxx> +#include <document.hxx> +#include <simpleformulacalc.hxx> +#include <scmod.hxx> +#include <inputhdl.hxx> +#include <tabvwsh.hxx> +#include <docsh.hxx> +#include <funcdesc.hxx> +#include <tokenarray.hxx> +#include <sc.hrc> +#include <servuno.hxx> +#include <unonames.hxx> +#include <externalrefmgr.hxx> + +#include <com/sun/star/table/CellAddress.hpp> +#include <com/sun/star/sheet/XFormulaOpCodeMapper.hpp> +#include <com/sun/star/sheet/XFormulaParser.hpp> + +using namespace formula; +using namespace com::sun::star; + +// init/ shared functions for dialog + +ScFormulaDlg::ScFormulaDlg(SfxBindings* pB, SfxChildWindow* pCW, + weld::Window* pParent, const ScViewData& rViewData, const formula::IFunctionManager* _pFunctionMgr) + : formula::FormulaDlg(pB, pCW, pParent, _pFunctionMgr, this) + , m_aHelper(this,pB) + , m_pViewShell( nullptr ) +{ + m_aHelper.SetDialog(m_xDialog.get()); + ScModule* pScMod = SC_MOD(); + pScMod->InputEnterHandler(); + m_pViewShell = nullptr; + + // title has to be from the view that opened the dialog, + // even if it's not the current view + + if ( pB ) + { + SfxDispatcher* pMyDisp = pB->GetDispatcher(); + if (pMyDisp) + { + SfxViewFrame* pMyViewFrm = pMyDisp->GetFrame(); + if (pMyViewFrm) + { + m_pViewShell = dynamic_cast<ScTabViewShell*>( pMyViewFrm->GetViewShell() ); + if( m_pViewShell ) + m_pViewShell->UpdateInputHandler(true); + } + } + } + + m_pDoc = &rViewData.GetDocument(); + m_xParser.set(ScServiceProvider::MakeInstance(ScServiceProvider::Type::FORMULAPARS, + static_cast<ScDocShell*>(m_pDoc->GetDocumentShell())),uno::UNO_QUERY); + uno::Reference< beans::XPropertySet> xSet(m_xParser,uno::UNO_QUERY); + xSet->setPropertyValue(SC_UNO_COMPILEFAP, uno::Any(true)); + + m_xOpCodeMapper.set(ScServiceProvider::MakeInstance(ScServiceProvider::Type::OPCODEMAPPER, + static_cast<ScDocShell*>(m_pDoc->GetDocumentShell())),uno::UNO_QUERY); + + ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl(m_pViewShell); + + assert(pInputHdl && "Missing input handler :-/"); + + pInputHdl->NotifyChange( nullptr ); + + ScFormulaReferenceHelper::enableInput( true ); + ScFormulaReferenceHelper::EnableSpreadsheets(); + m_aHelper.Init(); + m_aHelper.SetDispatcherLock( true ); + + notifyChange(); + fill(); + + ScFormEditData* pData = m_pViewShell->GetFormEditData(); + if (pData) + return; + + pScMod->SetRefInputHdl(pInputHdl); + + m_pDoc = &rViewData.GetDocument(); + SCCOL nCol = rViewData.GetCurX(); + SCROW nRow = rViewData.GetCurY(); + SCTAB nTab = rViewData.GetTabNo(); + m_CursorPos = ScAddress( nCol, nRow, nTab ); + + m_pViewShell->InitFormEditData(); // create new + pData = m_pViewShell->GetFormEditData(); + pData->SetInputHandler(pInputHdl); + pData->SetDocShell(rViewData.GetDocShell()); + + OSL_ENSURE(pData,"FormEditData not available"); + + formula::FormulaDlgMode eMode = FormulaDlgMode::Formula; // default... + + // edit if formula exists + + OUString aFormula = m_pDoc->GetFormula( nCol, nRow, nTab ); + bool bEdit = ( aFormula.getLength() > 1 ); + bool bMatrix = false; + if ( bEdit ) + { + bMatrix = CheckMatrix(aFormula); + + sal_Int32 nFStart = 0; + sal_Int32 nFEnd = 0; + if ( GetFormulaHelper().GetNextFunc( aFormula, false, nFStart, &nFEnd) ) + { + pInputHdl->InputReplaceSelection( aFormula ); + pInputHdl->InputSetSelection( nFStart, nFEnd ); + sal_Int32 PrivStart, PrivEnd; + pInputHdl->InputGetSelection( PrivStart, PrivEnd); + + eMode = SetMeText(pInputHdl->GetFormString(),PrivStart, PrivEnd, bMatrix, true, true); + pData->SetFStart( nFStart ); + } + else + bEdit = false; + } + + if ( !bEdit ) + { + OUString aNewFormula('='); + if ( aFormula.startsWith("=") ) + aNewFormula = aFormula; + + pInputHdl->InputReplaceSelection( aNewFormula ); + pInputHdl->InputSetSelection( 1, aNewFormula.getLength()+1 ); + sal_Int32 PrivStart, PrivEnd; + pInputHdl->InputGetSelection( PrivStart, PrivEnd); + SetMeText(pInputHdl->GetFormString(),PrivStart, PrivEnd,bMatrix,false,false); + + pData->SetFStart( 1 ); // after "=" + } + + pData->SetMode( eMode ); + OUString rStrExp = GetMeText(); + + Update(rStrExp); + +} + +void ScFormulaDlg::notifyChange() +{ + ScInputHandler* pInputHdl = m_pViewShell->GetInputHandler(); + if ( pInputHdl ) + pInputHdl->NotifyChange( nullptr ); +} + +void ScFormulaDlg::fill() +{ + ScModule* pScMod = SC_MOD(); + ScFormEditData* pData = static_cast<ScFormEditData*>(getFormEditData()); + notifyChange(); + OUString rStrExp; + if (!pData) + return; + + // data exists -> restore state (after switch) + // don't reinitialise m_pDoc and m_CursorPos + //pDoc = rViewData.GetDocument(); + if(IsInputHdl(pData->GetInputHandler())) + { + pScMod->SetRefInputHdl(pData->GetInputHandler()); + } + else + { + ScTabViewShell* pTabViewShell; + ScInputHandler* pInputHdl = GetNextInputHandler(pData->GetDocShell(),&pTabViewShell); + + if ( pInputHdl == nullptr ) //no more InputHandler for DocShell + { + disableOk(); + pInputHdl = pScMod->GetInputHdl(); + } + else + { + pInputHdl->SetRefViewShell(pTabViewShell); + } + pScMod->SetRefInputHdl(pInputHdl); + pData->SetInputHandler(pInputHdl); + } + + OUString aOldFormulaTmp(pData->GetInputHandler()->GetFormString()); + pData->GetInputHandler()->InputSetSelection( 0, aOldFormulaTmp.getLength()); + + rStrExp=pData->GetUndoStr(); + pData->GetInputHandler()->InputReplaceSelection(rStrExp); + + SetMeText(rStrExp); + + Update(); + // switch back, maybe new Doc has been opened + pScMod->SetRefInputHdl(nullptr); +} + +ScFormulaDlg::~ScFormulaDlg() COVERITY_NOEXCEPT_FALSE +{ + ScFormEditData* pData = m_pViewShell->GetFormEditData(); + + m_aHelper.dispose(); + + if (pData) // close doesn't destroy; + { + //set back reference input handler + SC_MOD()->SetRefInputHdl(nullptr); + StoreFormEditData(pData); + } + + m_pViewShell->ClearFormEditData(); +} + +bool ScFormulaDlg::IsInputHdl(const ScInputHandler* pHdl) +{ + bool bAlive = false; + + // belongs InputHandler to a ViewShell? + + SfxViewShell* pSh = SfxViewShell::GetFirst( true, checkSfxViewShell<ScTabViewShell> ); + while ( pSh && !bAlive ) + { + if (static_cast<ScTabViewShell*>(pSh)->GetInputHandler() == pHdl) + bAlive = true; + pSh = SfxViewShell::GetNext( *pSh, true, checkSfxViewShell<ScTabViewShell> ); + } + + return bAlive; + +} + +ScInputHandler* ScFormulaDlg::GetNextInputHandler(const ScDocShell* pDocShell, ScTabViewShell** ppViewSh) +{ + ScInputHandler* pHdl=nullptr; + + SfxViewFrame* pFrame = SfxViewFrame::GetFirst( pDocShell ); + while( pFrame && pHdl==nullptr) + { + SfxViewShell* p = pFrame->GetViewShell(); + ScTabViewShell* pViewSh = dynamic_cast< ScTabViewShell *>( p ); + if(pViewSh!=nullptr) + { + pHdl=pViewSh->GetInputHandler(); + if(ppViewSh!=nullptr) *ppViewSh=pViewSh; + } + pFrame = SfxViewFrame::GetNext( *pFrame, pDocShell ); + } + + return pHdl; +} + +void ScFormulaDlg::Close() +{ + if (IsClosing()) + return; + + DoEnter(); +} + +// functions for right side + +bool ScFormulaDlg::calculateValue( const OUString& rStrExp, OUString& rStrResult, bool bMatrixFormula ) +{ + std::optional<ScSimpleFormulaCalculator> pFCell(std::in_place, + *m_pDoc, m_CursorPos, rStrExp, bMatrixFormula); + pFCell->SetLimitString(true); + + // HACK! to avoid neither #REF! from ColRowNames + // if a name is added as actually range in the overall formula, + // but is interpreted at the individual representation as single-cell reference + bool bColRowName = pFCell->HasColRowName(); + if ( bColRowName ) + { + // ColRowName from RPN-Code? + if ( pFCell->GetCode()->GetCodeLen() <= 1 ) + { // ==1: area + // ==0: would be an area if... + OUString aBraced = "(" + rStrExp + ")"; + pFCell.emplace(*m_pDoc, m_CursorPos, aBraced, bMatrixFormula); + pFCell->SetLimitString(true); + } + else + bColRowName = false; + } + + FormulaError nErrCode = pFCell->GetErrCode(); + if ( nErrCode == FormulaError::NONE || pFCell->IsMatrix() ) + { + SvNumberFormatter& aFormatter = *(m_pDoc->GetFormatTable()); + const Color* pColor; + if (pFCell->IsMatrix()) + { + rStrResult = pFCell->GetString().getString(); + } + else if (pFCell->IsValue()) + { + double n = pFCell->GetValue(); + sal_uLong nFormat = aFormatter.GetStandardFormat( n, 0, + pFCell->GetFormatType(), ScGlobal::eLnge ); + aFormatter.GetOutputString( n, nFormat, rStrResult, &pColor ); + } + else + { + sal_uLong nFormat = aFormatter.GetStandardFormat( + pFCell->GetFormatType(), ScGlobal::eLnge); + aFormatter.GetOutputString( pFCell->GetString().getString(), nFormat, + rStrResult, &pColor ); + // Indicate it's a string, so a number string doesn't look numeric. + // Escape embedded quotation marks first by doubling them, as + // usual. Actually the result can be copy-pasted from the result + // box as literal into a formula expression. + rStrResult = "\"" + rStrResult.replaceAll( "\"", "\"\"") + "\""; + } + + ScRange aTestRange; + if ( bColRowName || (aTestRange.Parse(rStrExp, *m_pDoc) & ScRefFlags::VALID) ) + rStrResult += " ..."; + // area + } + else + rStrResult += ScGlobal::GetErrorString(nErrCode); + + return true; +} + +std::shared_ptr<formula::FormulaCompiler> ScFormulaDlg::getCompiler() const +{ + if (!m_xCompiler) + m_xCompiler = std::make_shared<ScCompiler>(*m_pDoc, m_CursorPos, m_pDoc->GetGrammar()); + return m_xCompiler; +} + +std::unique_ptr<formula::FormulaCompiler> ScFormulaDlg::createCompiler( formula::FormulaTokenArray& rArray ) const +{ + ScCompiler* pCompiler = nullptr; + ScTokenArray* pArr = dynamic_cast<ScTokenArray*>(&rArray); + assert(pArr); // violation of contract and not created using convertToTokenArray()? + if (pArr) + pCompiler = new ScCompiler(*m_pDoc, m_CursorPos, *pArr, m_pDoc->GetGrammar()); + return std::unique_ptr<formula::FormulaCompiler>(pCompiler); +} + +// virtual methods of ScAnyRefDlg: +void ScFormulaDlg::RefInputStart( formula::RefEdit* pEdit, formula::RefButton* pButton ) +{ + pEdit->SelectAll(); + ::std::pair<formula::RefButton*,formula::RefEdit*> aPair = RefInputStartBefore( pEdit, pButton ); + m_aHelper.RefInputStart( aPair.second, aPair.first); + RefInputStartAfter(); +} + +void ScFormulaDlg::RefInputDone( bool bForced ) +{ + m_aHelper.RefInputDone( bForced ); + RefInputDoneAfter( bForced ); +} + +void ScFormulaDlg::SetReference( const ScRange& rRef, ScDocument& rRefDoc ) +{ + const IFunctionDescription* pFunc = getCurrentFunctionDescription(); + if ( !(pFunc && pFunc->getSuppressedArgumentCount() > 0) ) + return; + + Selection theSel; + bool bRefNull = UpdateParaWin(theSel); + + if ( rRef.aStart != rRef.aEnd && bRefNull ) + { + RefInputStart(GetActiveEdit()); + } + + // Pointer-selected => absolute range references for the non-single + // dimensions, so in the other dimension (if any) it's still + // copy-adjustable. + constexpr ScRefFlags eColFlags = ScRefFlags::COL_ABS | ScRefFlags::COL2_ABS; + constexpr ScRefFlags eRowFlags = ScRefFlags::ROW_ABS | ScRefFlags::ROW2_ABS; + ScRefFlags eRangeFlags = ScRefFlags::ZERO; + if (rRef.aStart.Col() != rRef.aEnd.Col()) + eRangeFlags |= eColFlags; + if (rRef.aStart.Row() != rRef.aEnd.Row()) + eRangeFlags |= eRowFlags; + OUString aRefStr; + bool bOtherDoc = (&rRefDoc != m_pDoc && rRefDoc.GetDocumentShell()->HasName()); + if ( bOtherDoc ) + { + // reference to other document - like inputhdl.cxx + + OSL_ENSURE(rRef.aStart.Tab()==rRef.aEnd.Tab(), "nStartTab!=nEndTab"); + + // Sheet always 3D and absolute. + OUString aTmp( rRef.Format(rRefDoc, ScRefFlags::VALID | ScRefFlags::TAB_ABS_3D | eRangeFlags)); + + SfxObjectShell* pObjSh = rRefDoc.GetDocumentShell(); + + // #i75893# convert escaped URL of the document to something user friendly +// OUString aFileName = pObjSh->GetMedium()->GetName(); + OUString aFileName = pObjSh->GetMedium()->GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ); + + aRefStr = "'" + aFileName + "'#" + aTmp; + } + else + { + // We can't use ScRange::Format here because in R1C1 mode we need + // to display the reference position relative to the cursor + // position. + ScTokenArray aArray(rRefDoc); + ScComplexRefData aRefData; + aRefData.InitRangeRel(rRefDoc, rRef, m_CursorPos); + if ((eRangeFlags & eColFlags) == eColFlags) + { + aRefData.Ref1.SetAbsCol( rRef.aStart.Col() ); + aRefData.Ref2.SetAbsCol( rRef.aEnd.Col() ); + } + if ((eRangeFlags & eRowFlags) == eRowFlags) + { + aRefData.Ref1.SetAbsRow( rRef.aStart.Row() ); + aRefData.Ref2.SetAbsRow( rRef.aEnd.Row() ); + } + bool bSingle = aRefData.Ref1 == aRefData.Ref2; + if (m_CursorPos.Tab() != rRef.aStart.Tab()) + { + // pointer-selected => absolute sheet reference + aRefData.Ref1.SetAbsTab( rRef.aStart.Tab() ); + aRefData.Ref1.SetFlag3D(true); + } + if (bSingle) + aArray.AddSingleReference(aRefData.Ref1); + else + aArray.AddDoubleReference(aRefData); + ScCompiler aComp(*m_pDoc, m_CursorPos, aArray, m_pDoc->GetGrammar()); + OUStringBuffer aBuf; + aComp.CreateStringFromTokenArray(aBuf); + aRefStr = aBuf.makeStringAndClear(); + } + + UpdateParaWin(theSel,aRefStr); +} + +bool ScFormulaDlg::IsRefInputMode() const +{ + const IFunctionDescription* pDesc = getCurrentFunctionDescription(); + bool bRef = (pDesc && (pDesc->getSuppressedArgumentCount() > 0)) && (m_pDoc != nullptr); + return bRef; +} + +bool ScFormulaDlg::IsDocAllowed(SfxObjectShell* pDocSh) const +{ + // not allowed: different from this doc, and no name + // pDocSh is always a ScDocShell + return !pDocSh || &static_cast<ScDocShell*>(pDocSh)->GetDocument() == m_pDoc || pDocSh->HasName(); // everything else is allowed +} + +void ScFormulaDlg::SetActive() +{ + const IFunctionDescription* pFunc = getCurrentFunctionDescription(); + if ( pFunc && pFunc->getSuppressedArgumentCount() > 0 ) + { + RefInputDone(); + SetEdSelection(); + } +} + +void ScFormulaDlg::SaveLRUEntry(const ScFuncDesc* pFuncDescP) +{ + if (pFuncDescP && pFuncDescP->nFIndex!=0) + { + ScModule* pScMod = SC_MOD(); + pScMod->InsertEntryToLRUList(pFuncDescP->nFIndex); + } +} + +void ScFormulaDlg::doClose(bool /*_bOk*/) +{ + m_aHelper.DoClose( ScFormulaDlgWrapper::GetChildWindowId() ); +} +void ScFormulaDlg::insertEntryToLRUList(const formula::IFunctionDescription* _pDesc) +{ + const ScFuncDesc* pDesc = dynamic_cast<const ScFuncDesc*>(_pDesc); + SaveLRUEntry(pDesc); +} +void ScFormulaDlg::showReference(const OUString& _sFormula) +{ + ShowReference(_sFormula); +} +void ScFormulaDlg::ShowReference(const OUString& _sFormula) +{ + m_aHelper.ShowReference(_sFormula); +} +void ScFormulaDlg::HideReference( bool bDoneRefMode ) +{ + m_aHelper.HideReference(bDoneRefMode); +} +void ScFormulaDlg::ViewShellChanged() +{ + ScFormulaReferenceHelper::ViewShellChanged(); +} +void ScFormulaDlg::AddRefEntry( ) +{ + +} +bool ScFormulaDlg::IsTableLocked( ) const +{ + // default: reference input can also be used to switch the table + return false; +} + +void ScFormulaDlg::ToggleCollapsed( formula::RefEdit* pEdit, formula::RefButton* pButton) +{ + m_aHelper.ToggleCollapsed(pEdit,pButton); +} + +void ScFormulaDlg::ReleaseFocus( formula::RefEdit* pEdit) +{ + m_aHelper.ReleaseFocus(pEdit); +} + +void ScFormulaDlg::dispatch(bool _bOK, bool _bMatrixChecked) +{ + SfxBoolItem aRetItem( SID_DLG_RETOK, _bOK ); + SfxBoolItem aMatItem( SID_DLG_MATRIX, _bMatrixChecked ); + SfxStringItem aStrItem( SCITEM_STRING, getCurrentFormula() ); + + // if edit line is empty (caused by document switching) -> string is empty + // -> don't delete old formula + if ( aStrItem.GetValue().isEmpty() ) + aRetItem.SetValue( false ); // sal_False = Cancel + + m_aHelper.SetDispatcherLock( false ); // turn off modal-mode + + clear(); + + GetBindings().GetDispatcher()->ExecuteList( SID_INS_FUNCTION, + SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, + { &aRetItem, &aStrItem, &aMatItem }); +} +void ScFormulaDlg::setDispatcherLock( bool bLock ) +{ + m_aHelper.SetDispatcherLock( bLock ); +} +void ScFormulaDlg::deleteFormData() +{ + if (m_pViewShell) + m_pViewShell->ClearFormEditData(); // pData is invalid! +} +void ScFormulaDlg::clear() +{ + m_pDoc = nullptr; + + //restore reference inputhandler + ScModule* pScMod = SC_MOD(); + pScMod->SetRefInputHdl(nullptr); + + // force Enable() of edit line + ScTabViewShell* pScViewShell = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() ); + if ( pScViewShell ) + pScViewShell->UpdateInputHandler(); +} +void ScFormulaDlg::switchBack() +{ + // back to the document + // (foreign doc could be above - #34222#) + ScInputHandler* pHdl = m_pViewShell->GetInputHandler(); + if ( pHdl ) + { + pHdl->ViewShellGone(nullptr); // -> get active view + pHdl->ShowRefFrame(); + } + + // restore current chart (cause mouse-RefInput) + ScTabViewShell* pScViewShell = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() ); + if ( !pScViewShell ) + return; + + ScViewData& rVD=pScViewShell->GetViewData(); + SCTAB nExecTab = m_CursorPos.Tab(); + if ( nExecTab != rVD.GetTabNo() ) + pScViewShell->SetTabNo( nExecTab ); + + SCROW nRow = m_CursorPos.Row(); + SCCOL nCol = m_CursorPos.Col(); + + if(rVD.GetCurX()!=nCol || rVD.GetCurY()!=nRow) + pScViewShell->SetCursor(nCol,nRow); +} +formula::FormEditData* ScFormulaDlg::getFormEditData() const +{ + ScTabViewShell* pViewShell = m_pViewShell; + if (pViewShell) + return pViewShell->GetFormEditData(); + return nullptr; +} +void ScFormulaDlg::setCurrentFormula(const OUString& _sReplacement) +{ + ScModule* pScMod = SC_MOD(); + { + //fdo#69971 We need the EditEngine Modification handler of the inputbar that we + //are feeding to be disabled while this dialog is open. Otherwise we end up in + //a situation where... + //a) this ScFormulaDlg changes the editengine + //b) the modify callback gets called + //c) which also modifies the editengine + //d) on return from that modify handler the editengine attempts to use + // old node pointers which were replaced and removed by c + // + //We turn it off in the ctor and back on in the dtor, but if calc has + //to repaint, e.g. when switching to another window and back, then in + //ScMultiTextWnd::Paint a new editengine will have been created via + //GetEditView with its default Modification handler enabled. So ensure + //its off when we will access it via InputReplaceSelection + pScMod->InputTurnOffWinEngine(); + } + pScMod->InputReplaceSelection(_sReplacement); +} +void ScFormulaDlg::setSelection(sal_Int32 _nStart, sal_Int32 _nEnd) +{ + ScModule* pScMod = SC_MOD(); + pScMod->InputSetSelection( _nStart, _nEnd ); +} +void ScFormulaDlg::getSelection(sal_Int32& _nStart, sal_Int32& _nEnd) const +{ + ScModule* pScMod = SC_MOD(); + pScMod->InputGetSelection( _nStart, _nEnd ); +} +OUString ScFormulaDlg::getCurrentFormula() const +{ + ScFormEditData* pData = m_pViewShell->GetFormEditData(); + if (pData && pData->GetInputHandler()) + return pData->GetInputHandler()->GetFormString(); + return ""; +} +formula::IFunctionManager* ScFormulaDlg::getFunctionManager() +{ + return ScGlobal::GetStarCalcFunctionMgr(); +} +uno::Reference< sheet::XFormulaParser> ScFormulaDlg::getFormulaParser() const +{ + return m_xParser; +} +uno::Reference< sheet::XFormulaOpCodeMapper> ScFormulaDlg::getFormulaOpCodeMapper() const +{ + return m_xOpCodeMapper; +} + +table::CellAddress ScFormulaDlg::getReferencePosition() const +{ + return table::CellAddress(m_CursorPos.Tab(), m_CursorPos.Col(), m_CursorPos.Row()); +} + +::std::unique_ptr<formula::FormulaTokenArray> ScFormulaDlg::convertToTokenArray(const uno::Sequence< sheet::FormulaToken >& _aTokenList) +{ + ::std::unique_ptr<formula::FormulaTokenArray> pArray(new ScTokenArray(*m_pDoc)); + pArray->Fill(_aTokenList, m_pDoc->GetSharedStringPool(), m_pDoc->GetExternalRefManager()); + return pArray; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |