diff options
Diffstat (limited to 'sc/source/ui/namedlg')
-rw-r--r-- | sc/source/ui/namedlg/namedefdlg.cxx | 330 | ||||
-rw-r--r-- | sc/source/ui/namedlg/namedlg.cxx | 512 | ||||
-rw-r--r-- | sc/source/ui/namedlg/namemgrtable.cxx | 187 | ||||
-rw-r--r-- | sc/source/ui/namedlg/namepast.cxx | 99 |
4 files changed, 1128 insertions, 0 deletions
diff --git a/sc/source/ui/namedlg/namedefdlg.cxx b/sc/source/ui/namedlg/namedefdlg.cxx new file mode 100644 index 0000000000..3304f4d39b --- /dev/null +++ b/sc/source/ui/namedlg/namedefdlg.cxx @@ -0,0 +1,330 @@ +/* -*- 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 <namedefdlg.hxx> + +#include <formula/errorcodes.hxx> +#include <sfx2/app.hxx> +#include <unotools/charclass.hxx> + +#include <compiler.hxx> +#include <document.hxx> +#include <globstr.hrc> +#include <scresid.hxx> +#include <globalnames.hxx> +#include <rangenam.hxx> +#include <reffact.hxx> +#include <undorangename.hxx> +#include <tabvwsh.hxx> +#include <tokenarray.hxx> + +ScNameDefDlg::ScNameDefDlg( SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent, + const ScViewData& rViewData, std::map<OUString, ScRangeName*>&& aRangeMap, + const ScAddress& aCursorPos, const bool bUndo ) + : ScAnyRefDlgController( pB, pCW, pParent, "modules/scalc/ui/definename.ui", "DefineNameDialog") + , 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)) + , maErrNameInUse ( ScResId(STR_ERR_NAME_EXISTS)) + , maRangeMap( std::move(aRangeMap) ) + , m_xEdName(m_xBuilder->weld_entry("edit")) + , m_xEdRange(new formula::RefEdit(m_xBuilder->weld_entry("range"))) + , m_xRbRange(new formula::RefButton(m_xBuilder->weld_button("refbutton"))) + , m_xLbScope(m_xBuilder->weld_combo_box("scope")) + , m_xBtnRowHeader(m_xBuilder->weld_check_button("rowheader")) + , m_xBtnColHeader(m_xBuilder->weld_check_button("colheader")) + , m_xBtnPrintArea(m_xBuilder->weld_check_button("printarea")) + , m_xBtnCriteria(m_xBuilder->weld_check_button("filter")) + , m_xBtnAdd(m_xBuilder->weld_button("add")) + , m_xBtnCancel(m_xBuilder->weld_button("cancel")) + , m_xFtInfo(m_xBuilder->weld_label("label")) + , m_xFtRange(m_xBuilder->weld_label("label3")) +{ + 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_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 + { + ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell(); + pViewSh->SwitchBetweenRefDialogs(this); + } +} + +bool ScNameDefDlg::IsFormulaValid() +{ + ScCompiler aComp(mrDoc, maCursorPos, mrDoc.GetGrammar()); + std::unique_ptr<ScTokenArray> pCode = aComp.CompileString(m_xEdRange->GetText()); + if (pCode->GetCodeError() != FormulaError::NONE) + { + //TODO: info message + return false; + } + else + { + 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; + } + + 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<ScUndoAddRangeData>( 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; + 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(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/namedlg/namedlg.cxx b/sc/source/ui/namedlg/namedlg.cxx new file mode 100644 index 0000000000..a6a182cd82 --- /dev/null +++ b/sc/source/ui/namedlg/namedlg.cxx @@ -0,0 +1,512 @@ +/* -*- 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 <global.hxx> +#include <reffact.hxx> +#include <compiler.hxx> +#include <document.hxx> +#include <docfunc.hxx> +#include <globstr.hrc> +#include <scresid.hxx> +#include <namedlg.hxx> +#include <viewdata.hxx> +#include <tabvwsh.hxx> + +#include <globalnames.hxx> +#include <tokenarray.hxx> + +#include <vcl/svapp.hxx> +#include <formula/errorcodes.hxx> +#include <unotools/charclass.hxx> + +#include <map> + +//logic + +ScNameDlg::ScNameDlg( SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent, + ScViewData& rViewData, + const ScAddress& aCursorPos, + std::map<OUString, ScRangeName> *const pRangeMap) + : ScAnyRefDlgController(pB, pCW, pParent, "modules/scalc/ui/managenamesdialog.ui", + "ManageNamesDialog") + + , maGlobalNameStr(ScResId(STR_GLOBAL_SCOPE)) + , maErrInvalidNameStr(ScResId(STR_ERR_NAME_INVALID)) + , maErrNameInUse(ScResId(STR_ERR_NAME_EXISTS)) + , maStrMultiSelect(ScResId(STR_MULTI_SELECT)) + + , mrViewData(rViewData) + , mrDoc(rViewData.GetDocument()) + , maCursorPos(aCursorPos) + , mbDataChanged(false) + , mbCloseWithoutUndo(false) + + , m_xEdName(m_xBuilder->weld_entry("name")) + , m_xFtAssign(m_xBuilder->weld_label("label3")) + , m_xEdAssign(new formula::RefEdit(m_xBuilder->weld_entry("range"))) + , m_xRbAssign(new formula::RefButton(m_xBuilder->weld_button("assign"))) + , m_xLbScope(m_xBuilder->weld_combo_box("scope")) + , m_xBtnPrintArea(m_xBuilder->weld_check_button("printrange")) + , m_xBtnColHeader(m_xBuilder->weld_check_button("colheader")) + , m_xBtnCriteria(m_xBuilder->weld_check_button("filter")) + , m_xBtnRowHeader(m_xBuilder->weld_check_button("rowheader")) + , m_xBtnAdd(m_xBuilder->weld_button("add")) + , m_xBtnDelete(m_xBuilder->weld_button("delete")) + , m_xBtnOk(m_xBuilder->weld_button("ok")) + , m_xBtnCancel(m_xBuilder->weld_button("cancel")) + , m_xFtInfo(m_xBuilder->weld_label("info")) +{ + m_xEdAssign->SetReferences(this, m_xFtAssign.get()); + m_xRbAssign->SetReferences(this, m_xEdAssign.get()); + maStrInfoDefault = m_xFtInfo->get_label(); + + if (!pRangeMap) + { + std::map<OUString, ScRangeName*> aRangeMap; + mrDoc.GetRangeNameMap(aRangeMap); + for (const auto& [aTemp, pRangeName] : aRangeMap) + { + m_RangeMap.insert(std::make_pair(aTemp, *pRangeName)); + } + } + else + { + m_RangeMap.swap(*pRangeMap); + } + Init(); +} + +ScNameDlg::~ScNameDlg() +{ +} + +void ScNameDlg::Init() +{ + //init UI + + std::unique_ptr<weld::TreeView> xTreeView(m_xBuilder->weld_tree_view("names")); + xTreeView->set_size_request(xTreeView->get_approximate_digit_width() * 75, + xTreeView->get_height_rows(10)); + m_xRangeManagerTable.reset(new ScRangeManagerTable(std::move(xTreeView), m_RangeMap, maCursorPos)); + + m_xRangeManagerTable->connect_changed( LINK( this, ScNameDlg, SelectionChangedHdl_Impl ) ); + + m_xBtnOk->connect_clicked( LINK( this, ScNameDlg, OkBtnHdl ) ); + m_xBtnCancel->connect_clicked( LINK( this, ScNameDlg, CancelBtnHdl ) ); + m_xBtnAdd->connect_clicked( LINK( this, ScNameDlg, AddBtnHdl ) ); + m_xEdAssign->SetGetFocusHdl( LINK( this, ScNameDlg, AssignGetFocusHdl ) ); + m_xEdAssign->SetModifyHdl ( LINK( this, ScNameDlg, RefEdModifyHdl ) ); + m_xEdName->connect_changed( LINK( this, ScNameDlg, EdModifyHdl ) ); + m_xLbScope->connect_changed( LINK(this, ScNameDlg, ScopeChangedHdl) ); + m_xBtnDelete->connect_clicked( LINK( this, ScNameDlg, RemoveBtnHdl ) ); + m_xBtnPrintArea->connect_toggled( LINK(this, ScNameDlg, EdModifyCheckBoxHdl ) ); + m_xBtnCriteria->connect_toggled( LINK(this, ScNameDlg, EdModifyCheckBoxHdl ) ); + m_xBtnRowHeader->connect_toggled( LINK(this, ScNameDlg, EdModifyCheckBoxHdl ) ); + m_xBtnColHeader->connect_toggled( LINK(this, ScNameDlg, EdModifyCheckBoxHdl ) ); + + // 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); + } + + CheckForEmptyTable(); + + if (m_xRangeManagerTable->n_children()) + { + m_xRangeManagerTable->set_cursor(0); + m_xRangeManagerTable->CheckForFormulaString(); + SelectionChanged(); + } + +} + +bool ScNameDlg::IsRefInputMode() const +{ + return m_xEdAssign->GetWidget()->get_sensitive(); +} + +void ScNameDlg::RefInputDone( bool bForced) +{ + ScAnyRefDlgController::RefInputDone(bForced); + RefEdModifyHdl(*m_xEdAssign); +} + +void ScNameDlg::SetReference( const ScRange& rRef, ScDocument& rDocP ) +{ + if (m_xEdAssign->GetWidget()->get_sensitive()) + { + if ( rRef.aStart != rRef.aEnd ) + RefInputStart(m_xEdAssign.get()); + OUString aRefStr(rRef.Format(rDocP, ScRefFlags::RANGE_ABS_3D, + ScAddress::Details(rDocP.GetAddressConvention(), 0, 0))); + m_xEdAssign->SetRefString( aRefStr ); + } +} + +void ScNameDlg::Close() +{ + if (mbDataChanged && !mbCloseWithoutUndo) + mrViewData.GetDocFunc().ModifyAllRangeNames(m_RangeMap); + DoClose(ScNameDlgWrapper::GetChildWindowId()); +} + +void ScNameDlg::CheckForEmptyTable() +{ + if (!m_xRangeManagerTable->n_children()) + { + m_xBtnDelete->set_sensitive(false); + m_xEdAssign->GetWidget()->set_sensitive(false); + m_xRbAssign->GetWidget()->set_sensitive(false); + m_xEdName->set_sensitive(false); + m_xLbScope->set_sensitive(false); + + m_xBtnCriteria->set_sensitive(false); + m_xBtnPrintArea->set_sensitive(false); + m_xBtnColHeader->set_sensitive(false); + m_xBtnRowHeader->set_sensitive(false); + } + else + { + m_xBtnDelete->set_sensitive(true); + m_xEdAssign->GetWidget()->set_sensitive(true); + m_xRbAssign->GetWidget()->set_sensitive(true); + m_xEdName->set_sensitive(true); + m_xLbScope->set_sensitive(true); + + m_xBtnCriteria->set_sensitive(true); + m_xBtnPrintArea->set_sensitive(true); + m_xBtnColHeader->set_sensitive(true); + m_xBtnRowHeader->set_sensitive(true); + } +} + +void ScNameDlg::SetActive() +{ + m_xEdAssign->GrabFocus(); + RefInputDone(); +} + +void ScNameDlg::UpdateChecks(const ScRangeData* pData) +{ + // remove handlers, we only want the handlers to process + // user input and not when we are syncing the controls with our internal + // model ( also UpdateChecks is called already from some other event + // handlers, triggering handlers while already processing a handler can + // ( and does in this case ) corrupt the internal data + + m_xBtnCriteria->connect_toggled( Link<weld::Toggleable&,void>() ); + m_xBtnPrintArea->connect_toggled( Link<weld::Toggleable&,void>() ); + m_xBtnColHeader->connect_toggled( Link<weld::Toggleable&,void>() ); + m_xBtnRowHeader->connect_toggled( Link<weld::Toggleable&,void>() ); + + m_xBtnCriteria->set_active( pData->HasType( ScRangeData::Type::Criteria ) ); + m_xBtnPrintArea->set_active( pData->HasType( ScRangeData::Type::PrintArea ) ); + m_xBtnColHeader->set_active( pData->HasType( ScRangeData::Type::ColHeader ) ); + m_xBtnRowHeader->set_active( pData->HasType( ScRangeData::Type::RowHeader ) ); + + // Restore handlers so user input is processed again + Link<weld::Toggleable&,void> aToggleHandler = LINK( this, ScNameDlg, EdModifyCheckBoxHdl ); + m_xBtnCriteria->connect_toggled( aToggleHandler ); + m_xBtnPrintArea->connect_toggled( aToggleHandler ); + m_xBtnColHeader->connect_toggled( aToggleHandler ); + m_xBtnRowHeader->connect_toggled( aToggleHandler ); +} + +bool ScNameDlg::IsNameValid() +{ + OUString aScope = m_xLbScope->get_active_text(); + OUString aName = m_xEdName->get_text(); + aName = aName.trim(); + + if (aName.isEmpty()) + return false; + + ScRangeName* pRangeName = GetRangeName( aScope ); + + if (ScRangeData::IsNameValid(aName, mrDoc) != ScRangeData::IsNameValidType::NAME_VALID) + { + m_xFtInfo->set_label_type(weld::LabelType::Error); + m_xFtInfo->set_label(maErrInvalidNameStr); + return false; + } + else if (pRangeName && pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(aName))) + { + m_xFtInfo->set_label_type(weld::LabelType::Error); + m_xFtInfo->set_label(maErrNameInUse); + return false; + } + m_xFtInfo->set_label( maStrInfoDefault ); + return true; +} + +bool ScNameDlg::IsFormulaValid() +{ + ScCompiler aComp(mrDoc, maCursorPos, mrDoc.GetGrammar()); + std::unique_ptr<ScTokenArray> pCode = aComp.CompileString(m_xEdAssign->GetText()); + if (pCode->GetCodeError() != FormulaError::NONE) + { + m_xFtInfo->set_label_type(weld::LabelType::Error); + return false; + } + else + { + return true; + } +} + +ScRangeName* ScNameDlg::GetRangeName(const OUString& rScope) +{ + if (rScope == maGlobalNameStr) + { + const auto iter = m_RangeMap.find(STR_GLOBAL_RANGE_NAME); + assert(iter != m_RangeMap.end()); + return &iter->second; + } + else + { + const auto iter = m_RangeMap.find(rScope); + assert(iter != m_RangeMap.end()); + return &iter->second; + } +} + +void ScNameDlg::ShowOptions(const ScRangeNameLine& rLine) +{ + ScRangeName* pRangeName = GetRangeName(rLine.aScope); + ScRangeData* pData = pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(rLine.aName)); + if (pData) + { + UpdateChecks(pData); + } +} + +void ScNameDlg::AddPushed() +{ + mbCloseWithoutUndo = true; + ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell(); + pViewSh->SwitchBetweenRefDialogs(this); +} + +void ScNameDlg::SetEntry(const OUString& rName, const OUString& rScope) +{ + if (!rName.isEmpty()) + { + mbDataChanged = true; + ScRangeNameLine aLine; + aLine.aName = rName; + aLine.aScope = rScope; + m_xRangeManagerTable->SetEntry(aLine); + } +} + +void ScNameDlg::RemovePushed() +{ + std::vector<ScRangeNameLine> aEntries = m_xRangeManagerTable->GetSelectedEntries(); + m_xRangeManagerTable->DeleteSelectedEntries(); + for (const auto& rEntry : aEntries) + { + ScRangeName* pRangeName = GetRangeName(rEntry.aScope); + ScRangeData* pData = pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(rEntry.aName)); + OSL_ENSURE(pData, "table and model should be in sync"); + // be safe and check for possible problems + if (pData) + pRangeName->erase(*pData); + + mbDataChanged = true; + } + CheckForEmptyTable(); +} + +void ScNameDlg::NameModified() +{ + ScRangeNameLine aLine; + m_xRangeManagerTable->GetCurrentLine(aLine); + OUString aOldName = aLine.aName; + OUString aNewName = m_xEdName->get_text(); + aNewName = aNewName.trim(); + m_xFtInfo->set_label_type(weld::LabelType::Normal); + if (aNewName != aOldName) + { + if (!IsNameValid()) + return; + } + else + { + m_xFtInfo->set_label( maStrInfoDefault ); + } + + if (!IsFormulaValid()) + { + //TODO: implement an info text + return; + } + + OUString aOldScope = aLine.aScope; + //empty table + if (aOldScope.isEmpty()) + return; + OUString aExpr = m_xEdAssign->GetText(); + OUString aNewScope = m_xLbScope->get_active_text(); + + ScRangeName* pOldRangeName = GetRangeName( aOldScope ); + ScRangeData* pData = pOldRangeName->findByUpperName( ScGlobal::getCharClass().uppercase(aOldName) ); + ScRangeName* pNewRangeName = GetRangeName( aNewScope ); + OSL_ENSURE(pData, "model and table should be in sync"); + // be safe and check for range data + if (!pData) + return; + + // Assign new index (0) only if the scope is changed, else keep the + // existing index. + sal_uInt16 nIndex = (aNewScope != aOldScope ? 0 : pData->GetIndex()); + + pOldRangeName->erase(*pData); + m_xRangeManagerTable->BlockUpdate(); + m_xRangeManagerTable->DeleteSelectedEntries(); + ScRangeData::Type nType = ScRangeData::Type::Name; + 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; + + ScRangeData* pNewEntry = new ScRangeData( mrDoc, aNewName, aExpr, + maCursorPos, nType); + pNewEntry->SetIndex( nIndex); + pNewRangeName->insert(pNewEntry, false /*bReuseFreeIndex*/); + aLine.aName = aNewName; + aLine.aExpression = aExpr; + aLine.aScope = aNewScope; + m_xRangeManagerTable->addEntry(aLine, true); + // tdf#128137 process pending async row change events while UpdatesBlocked in place + Application::Reschedule(true); + m_xRangeManagerTable->UnblockUpdate(); + mbDataChanged = true; +} + +void ScNameDlg::SelectionChanged() +{ + //don't update if we have just modified due to user input + if (m_xRangeManagerTable->UpdatesBlocked()) + { + return; + } + + if (m_xRangeManagerTable->IsMultiSelection()) + { + m_xEdName->set_text(maStrMultiSelect); + m_xEdAssign->SetText(maStrMultiSelect); + + m_xEdName->set_sensitive(false); + m_xEdAssign->GetWidget()->set_sensitive(false); + m_xRbAssign->GetWidget()->set_sensitive(false); + m_xLbScope->set_sensitive(false); + m_xBtnRowHeader->set_sensitive(false); + m_xBtnColHeader->set_sensitive(false); + m_xBtnPrintArea->set_sensitive(false); + m_xBtnCriteria->set_sensitive(false); + } + else + { + ScRangeNameLine aLine; + m_xRangeManagerTable->GetCurrentLine(aLine); + m_xEdAssign->SetText(aLine.aExpression); + m_xEdName->set_text(aLine.aName); + m_xLbScope->set_active_text(aLine.aScope); + ShowOptions(aLine); + m_xBtnDelete->set_sensitive(true); + m_xEdName->set_sensitive(true); + m_xEdAssign->GetWidget()->set_sensitive(true); + m_xRbAssign->GetWidget()->set_sensitive(true); + m_xLbScope->set_sensitive(true); + m_xBtnRowHeader->set_sensitive(true); + m_xBtnColHeader->set_sensitive(true); + m_xBtnPrintArea->set_sensitive(true); + m_xBtnCriteria->set_sensitive(true); + } +} + +void ScNameDlg::ScopeChanged() +{ + NameModified(); +} + +void ScNameDlg::GetRangeNames(std::map<OUString, ScRangeName>& rRangeMap) +{ + m_RangeMap.swap(rRangeMap); +} + +IMPL_LINK_NOARG(ScNameDlg, OkBtnHdl, weld::Button&, void) +{ + response(RET_OK); +} + +IMPL_LINK_NOARG(ScNameDlg, CancelBtnHdl, weld::Button&, void) +{ + mbCloseWithoutUndo = true; + response(RET_CANCEL); +} + +IMPL_LINK_NOARG(ScNameDlg, AddBtnHdl, weld::Button&, void) +{ + AddPushed(); +} + +IMPL_LINK_NOARG(ScNameDlg, RemoveBtnHdl, weld::Button&, void) +{ + RemovePushed(); +} + +IMPL_LINK_NOARG(ScNameDlg, EdModifyCheckBoxHdl, weld::Toggleable&, void) +{ + NameModified(); +} + +IMPL_LINK_NOARG(ScNameDlg, EdModifyHdl, weld::Entry&, void) +{ + NameModified(); +} + +IMPL_LINK_NOARG(ScNameDlg, RefEdModifyHdl, formula::RefEdit&, void) +{ + NameModified(); +} + +IMPL_LINK_NOARG(ScNameDlg, AssignGetFocusHdl, formula::RefEdit&, void) +{ + RefEdModifyHdl(*m_xEdAssign); +} + +IMPL_LINK_NOARG(ScNameDlg, SelectionChangedHdl_Impl, weld::TreeView&, void) +{ + SelectionChanged(); +} + +IMPL_LINK_NOARG(ScNameDlg, ScopeChangedHdl, weld::ComboBox&, void) +{ + ScopeChanged(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/namedlg/namemgrtable.cxx b/sc/source/ui/namedlg/namemgrtable.cxx new file mode 100644 index 0000000000..5b23306653 --- /dev/null +++ b/sc/source/ui/namedlg/namemgrtable.cxx @@ -0,0 +1,187 @@ +/* -*- 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/. + */ + +//ScRangeManagerTable +#include <memory> +#include <global.hxx> +#include <globstr.hrc> +#include <o3tl/safeint.hxx> +#include <scresid.hxx> +#include <globalnames.hxx> +#include <namemgrtable.hxx> +#include <rangenam.hxx> + +#include <unotools/charclass.hxx> +#include <vcl/weld.hxx> +#include <tools/link.hxx> + +void ScRangeManagerTable::GetCurrentLine(ScRangeNameLine& rLine) +{ + std::unique_ptr<weld::TreeIter> xCurrentEntry(m_xTreeView->make_iterator()); + if (m_xTreeView->get_cursor(xCurrentEntry.get())) + GetLine(rLine, *xCurrentEntry); +} + +void ScRangeManagerTable::DeleteSelectedEntries() +{ + std::vector<int> aRows = m_xTreeView->get_selected_rows(); + std::sort(aRows.begin(), aRows.end()); + for (auto it = aRows.rbegin(); it != aRows.rend(); ++it) + m_xTreeView->remove(*it); +} + +bool ScRangeManagerTable::IsMultiSelection() const +{ + return m_xTreeView->count_selected_rows() > 1; +} + +void ScRangeManagerTable::SetEntry(const ScRangeNameLine& rLine) +{ + for (int i = 0, nEntryCount = m_xTreeView->n_children(); i < nEntryCount; ++i) + { + if (rLine.aName == m_xTreeView->get_text(i, 0) + && rLine.aScope == m_xTreeView->get_text(i, 2)) + { + m_xTreeView->set_cursor(i); + } + } +} + +ScRangeManagerTable::ScRangeManagerTable(std::unique_ptr<weld::TreeView> xTreeView, + const std::map<OUString, ScRangeName>& rRangeMap, + const ScAddress& rPos) + : m_xTreeView(std::move(xTreeView)) + , maGlobalString(ScResId(STR_GLOBAL_SCOPE)) + , m_RangeMap(rRangeMap) + , maPos(rPos) + , m_nId(0) + , mbNeedUpdate(true) +{ + auto nColWidth = m_xTreeView->get_size_request().Width() / 7; + std::vector<int> aWidths{ o3tl::narrowing<int>(nColWidth * 2), + o3tl::narrowing<int>(nColWidth * 3) }; + m_xTreeView->set_column_fixed_widths(aWidths); + + Init(); + m_xTreeView->set_selection_mode(SelectionMode::Multiple); + m_xTreeView->connect_size_allocate(LINK(this, ScRangeManagerTable, SizeAllocHdl)); + m_xTreeView->connect_visible_range_changed(LINK(this, ScRangeManagerTable, VisRowsScrolledHdl)); +} + +IMPL_LINK_NOARG(ScRangeManagerTable, VisRowsScrolledHdl, weld::TreeView&, void) +{ + CheckForFormulaString(); +} + +const ScRangeData* ScRangeManagerTable::findRangeData(const ScRangeNameLine& rLine) +{ + const ScRangeName* pRangeName; + if (rLine.aScope == maGlobalString) + { + const auto iter = m_RangeMap.find(STR_GLOBAL_RANGE_NAME); + assert(iter != m_RangeMap.end()); + pRangeName = &iter->second; + } + else + { + const auto iter = m_RangeMap.find(rLine.aScope); + assert(iter != m_RangeMap.end()); + pRangeName = &iter->second; + } + + return pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(rLine.aName)); +} + +void ScRangeManagerTable::CheckForFormulaString() +{ + if (UpdatesBlocked()) + return; + + auto lambda = [this](weld::TreeIter& rEntry) { + OUString sId(m_xTreeView->get_id(rEntry)); + std::map<OUString, bool>::const_iterator itr = maCalculatedFormulaEntries.find(sId); + if (itr == maCalculatedFormulaEntries.end() || !itr->second) + { + ScRangeNameLine aLine; + GetLine(aLine, rEntry); + const ScRangeData* pData = findRangeData(aLine); + OUString aFormulaString = pData->GetSymbol(maPos); + m_xTreeView->set_text(rEntry, aFormulaString, 1); + maCalculatedFormulaEntries.insert(std::pair<OUString, bool>(sId, true)); + } + return false; + }; + + // ensure all visible entries are up to date + m_xTreeView->visible_foreach(lambda); + // and ensure all selected entries are up to date + m_xTreeView->selected_foreach(lambda); +} + +IMPL_LINK_NOARG(ScRangeManagerTable, SizeAllocHdl, const Size&, void) { CheckForFormulaString(); } + +void ScRangeManagerTable::addEntry(const ScRangeNameLine& rLine, bool bSetCurEntry) +{ + int nRow = m_xTreeView->n_children(); + m_xTreeView->append(); + m_xTreeView->set_text(nRow, rLine.aName, 0); + m_xTreeView->set_text(nRow, rLine.aExpression, 1); + m_xTreeView->set_text(nRow, rLine.aScope, 2); + // just unique to track which one has been cached by maCalculatedFormulaEntries + m_xTreeView->set_id(nRow, OUString::number(m_nId++)); + if (bSetCurEntry) + m_xTreeView->set_cursor(nRow); +} + +void ScRangeManagerTable::GetLine(ScRangeNameLine& rLine, const weld::TreeIter& rEntry) +{ + rLine.aName = m_xTreeView->get_text(rEntry, 0); + rLine.aExpression = m_xTreeView->get_text(rEntry, 1); + rLine.aScope = m_xTreeView->get_text(rEntry, 2); +} + +void ScRangeManagerTable::Init() +{ + m_xTreeView->freeze(); + m_xTreeView->clear(); + for (auto const& itr : m_RangeMap) + { + const ScRangeName& rLocalRangeName = itr.second; + ScRangeNameLine aLine; + if (itr.first == STR_GLOBAL_RANGE_NAME) + aLine.aScope = maGlobalString; + else + aLine.aScope = itr.first; + for (const auto& rEntry : rLocalRangeName) + { + // Database and hidden named ranges are not shown in the Manage Names dialog + if (!rEntry.second->HasType(ScRangeData::Type::Database) + && !rEntry.second->HasType(ScRangeData::Type::Hidden)) + { + aLine.aName = rEntry.second->GetName(); + addEntry(aLine, false); + } + } + } + m_xTreeView->thaw(); +} + +std::vector<ScRangeNameLine> ScRangeManagerTable::GetSelectedEntries() +{ + std::vector<ScRangeNameLine> aSelectedEntries; + m_xTreeView->selected_foreach([this, &aSelectedEntries](weld::TreeIter& rEntry) { + ScRangeNameLine aLine; + GetLine(aLine, rEntry); + aSelectedEntries.push_back(aLine); + return false; + }); + return aSelectedEntries; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/namedlg/namepast.cxx b/sc/source/ui/namedlg/namepast.cxx new file mode 100644 index 0000000000..1d144f3fdf --- /dev/null +++ b/sc/source/ui/namedlg/namepast.cxx @@ -0,0 +1,99 @@ +/* -*- 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 . + */ + +#undef SC_DLLIMPLEMENTATION + +#include <namepast.hxx> +#include <docsh.hxx> +#include <rangenam.hxx> +#include <viewdata.hxx> +#include <scui_def.hxx> +#include <globstr.hrc> +#include <scresid.hxx> +#include <compiler.hxx> + +ScNamePasteDlg::ScNamePasteDlg(weld::Window* pParent, ScDocShell* pShell) + : GenericDialogController(pParent, "modules/scalc/ui/insertname.ui", "InsertNameDialog") + , m_xBtnPasteAll(m_xBuilder->weld_button("pasteall")) + , m_xBtnPaste(m_xBuilder->weld_button("paste")) + , m_xBtnClose(m_xBuilder->weld_button("close")) +{ + ScDocument& rDoc = pShell->GetDocument(); + m_aSheetSep = OUString(rDoc.GetSheetSeparator()); + std::map<OUString, ScRangeName*> aCopyMap; + rDoc.GetRangeNameMap(aCopyMap); + for (const auto & [ aTemp, pName ] : aCopyMap) + { + m_RangeMap.insert(std::make_pair(aTemp, *pName)); + } + + ScAddress aPos; + if (ScViewData* pViewData = ScDocShell::GetViewData()) + aPos = ScAddress(pViewData->GetCurX(), pViewData->GetCurY(), pViewData->GetTabNo()); + + std::unique_ptr<weld::TreeView> xTreeView(m_xBuilder->weld_tree_view("ctrl")); + xTreeView->set_size_request(xTreeView->get_approximate_digit_width() * 75, + xTreeView->get_height_rows(10)); + m_xTable.reset(new ScRangeManagerTable(std::move(xTreeView), m_RangeMap, aPos)); + + m_xBtnPaste->connect_clicked(LINK(this, ScNamePasteDlg, ButtonHdl)); + m_xBtnPasteAll->connect_clicked(LINK(this, ScNamePasteDlg, ButtonHdl)); + m_xBtnClose->connect_clicked(LINK(this, ScNamePasteDlg, ButtonHdl)); + + if (!m_xTable->n_children()) + { + m_xBtnPaste->set_sensitive(false); + m_xBtnPasteAll->set_sensitive(false); + } +} + +ScNamePasteDlg::~ScNamePasteDlg() {} + +IMPL_LINK(ScNamePasteDlg, ButtonHdl, weld::Button&, rButton, void) +{ + if (&rButton == m_xBtnPasteAll.get()) + { + m_xDialog->response(BTN_PASTE_LIST); + } + else if (&rButton == m_xBtnPaste.get()) + { + const OUString aGlobalScope(ScResId(STR_GLOBAL_SCOPE)); + std::vector<ScRangeNameLine> aSelectedLines = m_xTable->GetSelectedEntries(); + for (const auto& rLine : aSelectedLines) + { + if (rLine.aScope == aGlobalScope) + maSelectedNames.push_back(rLine.aName); + else + { + OUString aSheet(rLine.aScope); + ScCompiler::CheckTabQuotes(aSheet); + maSelectedNames.push_back(aSheet + m_aSheetSep + rLine.aName); + } + } + m_xDialog->response(BTN_PASTE_NAME); + } + else if (&rButton == m_xBtnClose.get()) + { + m_xDialog->response(BTN_PASTE_CLOSE); + } +} + +const std::vector<OUString>& ScNamePasteDlg::GetSelectedNames() const { return maSelectedNames; } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |