tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / namedlg / namedefdlg.cxx
blobb7101f49446b6b9bd071ed9be6ab94d458adf248
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <namedefdlg.hxx>
12 #include <formula/errorcodes.hxx>
13 #include <sfx2/app.hxx>
14 #include <unotools/charclass.hxx>
16 #include <compiler.hxx>
17 #include <document.hxx>
18 #include <globstr.hrc>
19 #include <scresid.hxx>
20 #include <globalnames.hxx>
21 #include <rangenam.hxx>
22 #include <reffact.hxx>
23 #include <undorangename.hxx>
24 #include <tabvwsh.hxx>
25 #include <tokenarray.hxx>
27 ScNameDefDlg::ScNameDefDlg( SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
28 const ScViewData& rViewData, std::map<OUString, ScRangeName*>&& aRangeMap,
29 const ScAddress& aCursorPos, const bool bUndo )
30 : ScAnyRefDlgController( pB, pCW, pParent, u"modules/scalc/ui/definename.ui"_ustr, u"DefineNameDialog"_ustr)
31 , mbUndo( bUndo )
32 , mrDoc(rViewData.GetDocument())
33 , mpDocShell ( rViewData.GetDocShell() )
34 , maCursorPos( aCursorPos )
35 , maGlobalNameStr ( ScResId(STR_GLOBAL_SCOPE) )
36 , maErrInvalidNameStr( ScResId(STR_ERR_NAME_INVALID))
37 , maErrInvalidNameCellRefStr( ScResId(STR_ERR_NAME_INVALID_CELL_REF))
38 , maErrInvalidSheetReference(ScResId(STR_INVALID_TABREF_PRINT_AREA))
39 , maErrNameInUse ( ScResId(STR_ERR_NAME_EXISTS))
40 , maRangeMap( std::move(aRangeMap) )
41 , m_xEdName(m_xBuilder->weld_entry(u"edit"_ustr))
42 , m_xEdRange(new formula::RefEdit(m_xBuilder->weld_entry(u"range"_ustr)))
43 , m_xRbRange(new formula::RefButton(m_xBuilder->weld_button(u"refbutton"_ustr)))
44 , m_xLbScope(m_xBuilder->weld_combo_box(u"scope"_ustr))
45 , m_xBtnRowHeader(m_xBuilder->weld_check_button(u"rowheader"_ustr))
46 , m_xBtnColHeader(m_xBuilder->weld_check_button(u"colheader"_ustr))
47 , m_xBtnPrintArea(m_xBuilder->weld_check_button(u"printarea"_ustr))
48 , m_xBtnCriteria(m_xBuilder->weld_check_button(u"filter"_ustr))
49 , m_xBtnAdd(m_xBuilder->weld_button(u"add"_ustr))
50 , m_xBtnCancel(m_xBuilder->weld_button(u"cancel"_ustr))
51 , m_xFtInfo(m_xBuilder->weld_label(u"label"_ustr))
52 , m_xExpander(m_xBuilder->weld_expander(u"more"_ustr))
53 , m_xFtRange(m_xBuilder->weld_label(u"label3"_ustr))
55 m_xEdRange->SetReferences(this, m_xFtRange.get());
56 m_xRbRange->SetReferences(this, m_xEdRange.get());
57 maStrInfoDefault = m_xFtInfo->get_label();
59 // Initialize scope list.
60 m_xLbScope->append_text(maGlobalNameStr);
61 m_xLbScope->set_active(0);
62 SCTAB n = mrDoc.GetTableCount();
63 for (SCTAB i = 0; i < n; ++i)
65 OUString aTabName;
66 mrDoc.GetName(i, aTabName);
67 m_xLbScope->append_text(aTabName);
70 m_xBtnCancel->connect_clicked( LINK( this, ScNameDefDlg, CancelBtnHdl));
71 m_xBtnAdd->connect_clicked( LINK( this, ScNameDefDlg, AddBtnHdl ));
72 m_xEdName->connect_changed( LINK( this, ScNameDefDlg, NameModifyHdl ));
73 m_xEdRange->SetGetFocusHdl( LINK( this, ScNameDefDlg, AssignGetFocusHdl ) );
74 m_xEdRange->SetModifyHdl( LINK( this, ScNameDefDlg, RefEdModifyHdl ) );
75 m_xBtnPrintArea->connect_toggled(LINK(this, ScNameDefDlg, EdModifyCheckBoxHdl));
77 m_xBtnAdd->set_sensitive(false); // empty name is invalid
79 ScRange aRange;
81 rViewData.GetSimpleArea( aRange );
82 OUString aAreaStr(aRange.Format(mrDoc, ScRefFlags::RANGE_ABS_3D,
83 ScAddress::Details(mrDoc.GetAddressConvention(), 0, 0)));
85 m_xEdRange->SetText( aAreaStr );
87 m_xEdName->grab_focus();
88 m_xEdName->select_region(0, -1);
91 ScNameDefDlg::~ScNameDefDlg()
95 void ScNameDefDlg::CancelPushed()
97 if (mbUndo)
98 response(RET_CANCEL);
99 else
101 if (ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell())
102 pViewSh->SwitchBetweenRefDialogs(this);
106 bool ScNameDefDlg::IsFormulaValid()
108 const OUString aRangeOrFormulaExp = m_xEdRange->GetText();
109 // tdf#140394 - check if formula is a valid print range
110 if (m_xBtnPrintArea->get_active())
112 const ScRefFlags nValidAddr = ScRefFlags::VALID | ScRefFlags::ROW_VALID | ScRefFlags::COL_VALID;
113 const ScRefFlags nValidRange = nValidAddr | ScRefFlags::ROW2_VALID | ScRefFlags::COL2_VALID;
114 const formula::FormulaGrammar::AddressConvention eConv = mrDoc.GetAddressConvention();
115 const sal_Unicode sep = ScCompiler::GetNativeSymbolChar(ocSep);
117 ScAddress aAddr;
118 ScRange aRange;
119 for (sal_Int32 nIdx = 0; nIdx >= 0;)
121 const OUString aOne = aRangeOrFormulaExp.getToken(0, sep, nIdx);
122 ScRefFlags nResult = aRange.Parse(aOne, mrDoc, eConv);
123 if ((nResult & nValidRange) != nValidRange)
125 ScRefFlags nAddrResult = aAddr.Parse(aOne, mrDoc, eConv);
126 if ((nAddrResult & nValidAddr) != nValidAddr)
127 return false;
131 else
133 ScCompiler aComp(mrDoc, maCursorPos, mrDoc.GetGrammar());
134 std::unique_ptr<ScTokenArray> pCode = aComp.CompileString(m_xEdRange->GetText());
135 if (pCode->GetCodeError() != FormulaError::NONE)
136 return false;
139 return true;
142 bool ScNameDefDlg::IsNameValid()
144 OUString aScope = m_xLbScope->get_active_text();
145 OUString aName = m_xEdName->get_text();
147 bool bIsNameValid = true;
148 OUString aHelpText = maStrInfoDefault;
150 ScRangeName* pRangeName = nullptr;
151 if(aScope == maGlobalNameStr)
153 const auto iter = maRangeMap.find(STR_GLOBAL_RANGE_NAME);
154 assert(iter != maRangeMap.end());
155 pRangeName = iter->second;
157 else
159 const auto iter = maRangeMap.find(aScope);
160 assert(iter != maRangeMap.end());
161 pRangeName = iter->second;
164 ScRangeData::IsNameValidType eType;
165 if ( aName.isEmpty() )
167 bIsNameValid = false;
169 else if ((eType = ScRangeData::IsNameValid(aName, mrDoc))
170 != ScRangeData::IsNameValidType::NAME_VALID)
172 if (eType == ScRangeData::IsNameValidType::NAME_INVALID_BAD_STRING)
174 aHelpText = maErrInvalidNameStr;
176 else if (eType == ScRangeData::IsNameValidType::NAME_INVALID_CELL_REF)
178 aHelpText = maErrInvalidNameCellRefStr;
180 bIsNameValid = false;
182 else if (pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(aName)))
184 aHelpText = maErrNameInUse;
185 bIsNameValid = false;
188 if (!IsFormulaValid())
190 bIsNameValid = false;
191 if (m_xBtnPrintArea->get_active())
192 aHelpText = maErrInvalidSheetReference;
193 //TODO: info message for a non valid formula (print range not checked)
196 m_xEdName->set_tooltip_text(aHelpText);
197 m_xEdName->set_message_type(bIsNameValid || aName.isEmpty() ? weld::EntryMessageType::Normal
198 : weld::EntryMessageType::Error);
199 m_xBtnAdd->set_sensitive(bIsNameValid);
200 return bIsNameValid;
203 void ScNameDefDlg::AddPushed()
205 OUString aScope = m_xLbScope->get_active_text();
206 OUString aName = m_xEdName->get_text();
207 OUString aExpression = m_xEdRange->GetText();
209 if (aName.isEmpty())
211 return;
213 if (aScope.isEmpty())
215 return;
218 ScRangeName* pRangeName = nullptr;
219 if(aScope == maGlobalNameStr)
221 const auto iter = maRangeMap.find(STR_GLOBAL_RANGE_NAME);
222 assert(iter != maRangeMap.end());
223 pRangeName = iter->second;
225 else
227 const auto iter = maRangeMap.find(aScope);
228 assert(iter != maRangeMap.end());
229 pRangeName = iter->second;
231 if (!pRangeName)
232 return;
234 if (!IsNameValid()) //should not happen, but make sure we don't break anything
235 return;
236 else
238 ScRangeData::Type nType = ScRangeData::Type::Name;
240 ScRangeData* pNewEntry = new ScRangeData( mrDoc,
241 aName,
242 aExpression,
243 maCursorPos,
244 nType );
246 if ( m_xBtnRowHeader->get_active() ) nType |= ScRangeData::Type::RowHeader;
247 if ( m_xBtnColHeader->get_active() ) nType |= ScRangeData::Type::ColHeader;
248 if ( m_xBtnPrintArea->get_active() ) nType |= ScRangeData::Type::PrintArea;
249 if ( m_xBtnCriteria->get_active() ) nType |= ScRangeData::Type::Criteria;
251 pNewEntry->AddType(nType);
253 // aExpression valid?
254 if ( FormulaError::NONE == pNewEntry->GetErrCode() )
256 if ( !pRangeName->insert( pNewEntry, false /*bReuseFreeIndex*/ ) )
257 pNewEntry = nullptr;
259 if (mbUndo)
261 // this means we called directly through the menu
263 SCTAB nTab;
264 // if no table with that name is found, assume global range name
265 if (!mrDoc.GetTable(aScope, nTab))
266 nTab = -1;
268 assert( pNewEntry); // undo of no insertion smells fishy
269 if (pNewEntry)
270 mpDocShell->GetUndoManager()->AddUndoAction(
271 std::make_unique<ScUndoAddRangeData>( mpDocShell, pNewEntry, nTab) );
273 // set table stream invalid, otherwise RangeName won't be saved if no other
274 // call invalidates the stream
275 if (nTab != -1)
276 mrDoc.SetStreamValid(nTab, false);
277 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) );
278 mpDocShell->SetDocumentModified();
279 Close();
281 else
283 maName = aName;
284 maScope = aScope;
285 if (ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell())
286 pViewSh->SwitchBetweenRefDialogs(this);
289 else
291 delete pNewEntry;
292 m_xEdRange->GrabFocus();
293 m_xEdRange->SelectAll();
298 void ScNameDefDlg::GetNewData(OUString& rName, OUString& rScope)
300 rName = maName;
301 rScope = maScope;
304 bool ScNameDefDlg::IsRefInputMode() const
306 return m_xEdRange->GetWidget()->get_sensitive();
309 void ScNameDefDlg::RefInputDone( bool bForced)
311 ScAnyRefDlgController::RefInputDone(bForced);
312 IsNameValid();
315 void ScNameDefDlg::SetReference( const ScRange& rRef, ScDocument& rDocP )
317 if (m_xEdRange->GetWidget()->get_sensitive())
319 if ( rRef.aStart != rRef.aEnd )
320 RefInputStart(m_xEdRange.get());
321 OUString aRefStr(rRef.Format(rDocP, ScRefFlags::RANGE_ABS_3D,
322 ScAddress::Details(rDocP.GetAddressConvention(), 0, 0)));
323 m_xEdRange->SetRefString( aRefStr );
327 void ScNameDefDlg::Close()
329 DoClose( ScNameDefDlgWrapper::GetChildWindowId() );
332 void ScNameDefDlg::SetActive()
334 m_xEdRange->GrabFocus();
335 RefInputDone();
338 IMPL_LINK_NOARG(ScNameDefDlg, CancelBtnHdl, weld::Button&, void)
340 CancelPushed();
343 IMPL_LINK_NOARG(ScNameDefDlg, AddBtnHdl, weld::Button&, void)
345 AddPushed();
348 IMPL_LINK_NOARG(ScNameDefDlg, NameModifyHdl, weld::Entry&, void)
350 IsNameValid();
353 IMPL_LINK_NOARG(ScNameDefDlg, AssignGetFocusHdl, formula::RefEdit&, void)
355 IsNameValid();
358 IMPL_LINK_NOARG(ScNameDefDlg, EdModifyCheckBoxHdl, weld::Toggleable&, void)
360 IsNameValid();
363 IMPL_LINK_NOARG(ScNameDefDlg, RefEdModifyHdl, formula::RefEdit&, void)
365 IsNameValid();
368 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */