tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / namedlg / namedlg.cxx
blobf5d6a9b881f94b4f70c9ff1c76deb21c34a3c8c0
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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <memory>
21 #include <global.hxx>
22 #include <reffact.hxx>
23 #include <compiler.hxx>
24 #include <document.hxx>
25 #include <docfunc.hxx>
26 #include <globstr.hrc>
27 #include <scresid.hxx>
28 #include <namedlg.hxx>
29 #include <viewdata.hxx>
30 #include <tabvwsh.hxx>
32 #include <globalnames.hxx>
33 #include <tokenarray.hxx>
35 #include <vcl/svapp.hxx>
36 #include <formula/errorcodes.hxx>
37 #include <unotools/charclass.hxx>
39 #include <map>
41 //logic
43 ScNameDlg::ScNameDlg( SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
44 ScViewData& rViewData,
45 const ScAddress& aCursorPos,
46 std::map<OUString, ScRangeName> *const pRangeMap)
47 : ScAnyRefDlgController(pB, pCW, pParent, u"modules/scalc/ui/managenamesdialog.ui"_ustr,
48 u"ManageNamesDialog"_ustr)
50 , maGlobalNameStr(ScResId(STR_GLOBAL_SCOPE))
51 , maErrInvalidNameStr(ScResId(STR_ERR_NAME_INVALID))
52 , maErrNameInUse(ScResId(STR_ERR_NAME_EXISTS))
53 , maErrInvalidSheetReference(ScResId(STR_INVALID_TABREF_PRINT_AREA))
54 , maStrMultiSelect(ScResId(STR_MULTI_SELECT))
56 , mrViewData(rViewData)
57 , mrDoc(rViewData.GetDocument())
58 , maCursorPos(aCursorPos)
59 , mbDataChanged(false)
60 , mbCloseWithoutUndo(false)
62 , m_xEdName(m_xBuilder->weld_entry(u"name"_ustr))
63 , m_xFtAssign(m_xBuilder->weld_label(u"label3"_ustr))
64 , m_xEdAssign(new formula::RefEdit(m_xBuilder->weld_entry(u"range"_ustr)))
65 , m_xRbAssign(new formula::RefButton(m_xBuilder->weld_button(u"assign"_ustr)))
66 , m_xLbScope(m_xBuilder->weld_combo_box(u"scope"_ustr))
67 , m_xBtnPrintArea(m_xBuilder->weld_check_button(u"printrange"_ustr))
68 , m_xBtnColHeader(m_xBuilder->weld_check_button(u"colheader"_ustr))
69 , m_xBtnCriteria(m_xBuilder->weld_check_button(u"filter"_ustr))
70 , m_xBtnRowHeader(m_xBuilder->weld_check_button(u"rowheader"_ustr))
71 , m_xBtnAdd(m_xBuilder->weld_button(u"add"_ustr))
72 , m_xBtnDelete(m_xBuilder->weld_button(u"delete"_ustr))
73 , m_xBtnOk(m_xBuilder->weld_button(u"ok"_ustr))
74 , m_xBtnCancel(m_xBuilder->weld_button(u"cancel"_ustr))
75 , m_xFtInfo(m_xBuilder->weld_label(u"info"_ustr))
76 , m_xExpander(m_xBuilder->weld_expander(u"more"_ustr))
78 m_xEdAssign->SetReferences(this, m_xFtAssign.get());
79 m_xRbAssign->SetReferences(this, m_xEdAssign.get());
80 maStrInfoDefault = m_xFtInfo->get_label();
82 if (!pRangeMap)
84 std::map<OUString, ScRangeName*> aRangeMap;
85 mrDoc.GetRangeNameMap(aRangeMap);
86 for (const auto& [aTemp, pRangeName] : aRangeMap)
88 m_RangeMap.insert(std::make_pair(aTemp, *pRangeName));
91 else
93 m_RangeMap.swap(*pRangeMap);
95 Init();
98 ScNameDlg::~ScNameDlg()
102 void ScNameDlg::Init()
104 //init UI
106 std::unique_ptr<weld::TreeView> xTreeView(m_xBuilder->weld_tree_view(u"names"_ustr));
107 xTreeView->set_size_request(xTreeView->get_approximate_digit_width() * 75,
108 xTreeView->get_height_rows(10));
109 m_xRangeManagerTable.reset(new ScRangeManagerTable(std::move(xTreeView), m_RangeMap, maCursorPos));
111 m_xRangeManagerTable->connect_changed( LINK( this, ScNameDlg, SelectionChangedHdl_Impl ) );
113 m_xBtnOk->connect_clicked( LINK( this, ScNameDlg, OkBtnHdl ) );
114 m_xBtnCancel->connect_clicked( LINK( this, ScNameDlg, CancelBtnHdl ) );
115 m_xBtnAdd->connect_clicked( LINK( this, ScNameDlg, AddBtnHdl ) );
116 m_xEdAssign->SetGetFocusHdl( LINK( this, ScNameDlg, AssignGetFocusHdl ) );
117 m_xEdAssign->SetModifyHdl ( LINK( this, ScNameDlg, RefEdModifyHdl ) );
118 m_xEdName->connect_changed( LINK( this, ScNameDlg, EdModifyHdl ) );
119 m_xLbScope->connect_changed( LINK(this, ScNameDlg, ScopeChangedHdl) );
120 m_xBtnDelete->connect_clicked( LINK( this, ScNameDlg, RemoveBtnHdl ) );
121 m_xBtnPrintArea->connect_toggled( LINK(this, ScNameDlg, EdModifyCheckBoxHdl ) );
122 m_xBtnCriteria->connect_toggled( LINK(this, ScNameDlg, EdModifyCheckBoxHdl ) );
123 m_xBtnRowHeader->connect_toggled( LINK(this, ScNameDlg, EdModifyCheckBoxHdl ) );
124 m_xBtnColHeader->connect_toggled( LINK(this, ScNameDlg, EdModifyCheckBoxHdl ) );
126 // Initialize scope list.
127 m_xLbScope->append_text(maGlobalNameStr);
128 m_xLbScope->set_active(0);
129 SCTAB n = mrDoc.GetTableCount();
130 for (SCTAB i = 0; i < n; ++i)
132 OUString aTabName;
133 mrDoc.GetName(i, aTabName);
134 m_xLbScope->append_text(aTabName);
137 CheckForEmptyTable();
139 if (m_xRangeManagerTable->n_children())
141 m_xRangeManagerTable->set_cursor(0);
142 m_xRangeManagerTable->CheckForFormulaString();
143 SelectionChanged();
148 bool ScNameDlg::IsRefInputMode() const
150 return m_xEdAssign->GetWidget()->get_sensitive();
153 void ScNameDlg::RefInputDone( bool bForced)
155 ScAnyRefDlgController::RefInputDone(bForced);
156 RefEdModifyHdl(*m_xEdAssign);
159 void ScNameDlg::SetReference( const ScRange& rRef, ScDocument& rDocP )
161 if (m_xEdAssign->GetWidget()->get_sensitive())
163 if ( rRef.aStart != rRef.aEnd )
164 RefInputStart(m_xEdAssign.get());
165 OUString aRefStr(rRef.Format(rDocP, ScRefFlags::RANGE_ABS_3D,
166 ScAddress::Details(rDocP.GetAddressConvention(), 0, 0)));
167 m_xEdAssign->SetRefString( aRefStr );
171 void ScNameDlg::Close()
173 if (mbDataChanged && !mbCloseWithoutUndo)
174 mrViewData.GetDocFunc().ModifyAllRangeNames(m_RangeMap);
175 DoClose(ScNameDlgWrapper::GetChildWindowId());
178 void ScNameDlg::CheckForEmptyTable()
180 if (!m_xRangeManagerTable->n_children())
182 m_xBtnDelete->set_sensitive(false);
183 m_xEdAssign->GetWidget()->set_sensitive(false);
184 m_xRbAssign->GetWidget()->set_sensitive(false);
185 m_xEdName->set_sensitive(false);
186 m_xLbScope->set_sensitive(false);
188 m_xBtnCriteria->set_sensitive(false);
189 m_xBtnPrintArea->set_sensitive(false);
190 m_xBtnColHeader->set_sensitive(false);
191 m_xBtnRowHeader->set_sensitive(false);
193 else
195 m_xBtnDelete->set_sensitive(true);
196 m_xEdAssign->GetWidget()->set_sensitive(true);
197 m_xRbAssign->GetWidget()->set_sensitive(true);
198 m_xEdName->set_sensitive(true);
199 m_xLbScope->set_sensitive(true);
201 m_xBtnCriteria->set_sensitive(true);
202 m_xBtnPrintArea->set_sensitive(true);
203 m_xBtnColHeader->set_sensitive(true);
204 m_xBtnRowHeader->set_sensitive(true);
208 void ScNameDlg::SetActive()
210 m_xEdAssign->GrabFocus();
211 RefInputDone();
214 void ScNameDlg::UpdateChecks(const ScRangeData* pData)
216 // remove handlers, we only want the handlers to process
217 // user input and not when we are syncing the controls with our internal
218 // model ( also UpdateChecks is called already from some other event
219 // handlers, triggering handlers while already processing a handler can
220 // ( and does in this case ) corrupt the internal data
222 m_xBtnCriteria->connect_toggled( Link<weld::Toggleable&,void>() );
223 m_xBtnPrintArea->connect_toggled( Link<weld::Toggleable&,void>() );
224 m_xBtnColHeader->connect_toggled( Link<weld::Toggleable&,void>() );
225 m_xBtnRowHeader->connect_toggled( Link<weld::Toggleable&,void>() );
227 m_xBtnCriteria->set_active( pData->HasType( ScRangeData::Type::Criteria ) );
228 m_xBtnPrintArea->set_active( pData->HasType( ScRangeData::Type::PrintArea ) );
229 m_xBtnColHeader->set_active( pData->HasType( ScRangeData::Type::ColHeader ) );
230 m_xBtnRowHeader->set_active( pData->HasType( ScRangeData::Type::RowHeader ) );
232 // Restore handlers so user input is processed again
233 Link<weld::Toggleable&,void> aToggleHandler = LINK( this, ScNameDlg, EdModifyCheckBoxHdl );
234 m_xBtnCriteria->connect_toggled( aToggleHandler );
235 m_xBtnPrintArea->connect_toggled( aToggleHandler );
236 m_xBtnColHeader->connect_toggled( aToggleHandler );
237 m_xBtnRowHeader->connect_toggled( aToggleHandler );
240 bool ScNameDlg::IsNameValid()
242 OUString aScope = m_xLbScope->get_active_text();
243 OUString aName = m_xEdName->get_text();
244 aName = aName.trim();
246 if (aName.isEmpty())
247 return false;
249 ScRangeName* pRangeName = GetRangeName( aScope );
251 if (ScRangeData::IsNameValid(aName, mrDoc) != ScRangeData::IsNameValidType::NAME_VALID)
253 m_xFtInfo->set_label_type(weld::LabelType::Error);
254 m_xFtInfo->set_label(maErrInvalidNameStr);
255 return false;
257 else if (pRangeName && pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(aName)))
259 m_xFtInfo->set_label_type(weld::LabelType::Error);
260 m_xFtInfo->set_label(maErrNameInUse);
261 return false;
263 return true;
266 bool ScNameDlg::IsFormulaValid()
268 const OUString aRangeOrFormulaExp = m_xEdAssign->GetText();
269 // tdf#140394 - check if formula is a valid print range
270 if (m_xBtnPrintArea->get_active())
272 const ScRefFlags nValidAddr = ScRefFlags::VALID | ScRefFlags::ROW_VALID | ScRefFlags::COL_VALID;
273 const ScRefFlags nValidRange = nValidAddr | ScRefFlags::ROW2_VALID | ScRefFlags::COL2_VALID;
274 const formula::FormulaGrammar::AddressConvention eConv = mrDoc.GetAddressConvention();
275 const sal_Unicode sep = ScCompiler::GetNativeSymbolChar(ocSep);
277 ScAddress aAddr;
278 ScRange aRange;
279 for (sal_Int32 nIdx = 0; nIdx >= 0;)
281 const OUString aOne = aRangeOrFormulaExp.getToken(0, sep, nIdx);
282 ScRefFlags nResult = aRange.Parse(aOne, mrDoc, eConv);
283 if ((nResult & nValidRange) != nValidRange)
285 ScRefFlags nAddrResult = aAddr.Parse(aOne, mrDoc, eConv);
286 if ((nAddrResult & nValidAddr) != nValidAddr)
288 m_xFtInfo->set_label_type(weld::LabelType::Error);
289 m_xFtInfo->set_label(maErrInvalidSheetReference);
290 return false;
295 else
297 ScCompiler aComp(mrDoc, maCursorPos, mrDoc.GetGrammar());
298 std::unique_ptr<ScTokenArray> pCode = aComp.CompileString(aRangeOrFormulaExp);
299 if (pCode->GetCodeError() != FormulaError::NONE)
301 m_xFtInfo->set_label_type(weld::LabelType::Error);
302 //TODO: implement an info text
303 return false;
307 return true;
310 ScRangeName* ScNameDlg::GetRangeName(const OUString& rScope)
312 if (rScope == maGlobalNameStr)
314 const auto iter = m_RangeMap.find(STR_GLOBAL_RANGE_NAME);
315 assert(iter != m_RangeMap.end());
316 return &iter->second;
318 else
320 const auto iter = m_RangeMap.find(rScope);
321 assert(iter != m_RangeMap.end());
322 return &iter->second;
326 void ScNameDlg::ShowOptions(const ScRangeNameLine& rLine)
328 ScRangeName* pRangeName = GetRangeName(rLine.aScope);
329 ScRangeData* pData = pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(rLine.aName));
330 if (pData)
332 UpdateChecks(pData);
336 void ScNameDlg::AddPushed()
338 mbCloseWithoutUndo = true;
339 if (ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell())
340 pViewSh->SwitchBetweenRefDialogs(this);
343 void ScNameDlg::SetEntry(const OUString& rName, const OUString& rScope)
345 if (!rName.isEmpty())
347 mbDataChanged = true;
348 ScRangeNameLine aLine;
349 aLine.aName = rName;
350 aLine.aScope = rScope;
351 m_xRangeManagerTable->SetEntry(aLine);
355 void ScNameDlg::RemovePushed()
357 std::vector<ScRangeNameLine> aEntries = m_xRangeManagerTable->GetSelectedEntries();
358 m_xRangeManagerTable->DeleteSelectedEntries();
359 for (const auto& rEntry : aEntries)
361 ScRangeName* pRangeName = GetRangeName(rEntry.aScope);
362 ScRangeData* pData = pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(rEntry.aName));
363 OSL_ENSURE(pData, "table and model should be in sync");
364 // be safe and check for possible problems
365 if (pData)
366 pRangeName->erase(*pData);
368 mbDataChanged = true;
370 CheckForEmptyTable();
373 void ScNameDlg::NameModified()
375 ScRangeNameLine aLine;
376 m_xRangeManagerTable->GetCurrentLine(aLine);
377 OUString aOldName = aLine.aName;
378 OUString aNewName = m_xEdName->get_text();
379 aNewName = aNewName.trim();
380 m_xBtnOk->set_sensitive(false);
381 if (aNewName != aOldName)
383 if (!IsNameValid())
384 return;
387 if (!IsFormulaValid())
388 return;
390 m_xFtInfo->set_label_type(weld::LabelType::Normal);
391 m_xFtInfo->set_label(maStrInfoDefault);
392 m_xBtnOk->set_sensitive(true);
394 OUString aOldScope = aLine.aScope;
395 //empty table
396 if (aOldScope.isEmpty())
397 return;
398 OUString aExpr = m_xEdAssign->GetText();
399 OUString aNewScope = m_xLbScope->get_active_text();
401 ScRangeName* pOldRangeName = GetRangeName( aOldScope );
402 ScRangeData* pData = pOldRangeName->findByUpperName( ScGlobal::getCharClass().uppercase(aOldName) );
403 ScRangeName* pNewRangeName = GetRangeName( aNewScope );
404 OSL_ENSURE(pData, "model and table should be in sync");
405 // be safe and check for range data
406 if (!pData)
407 return;
409 // Assign new index (0) only if the scope is changed, else keep the
410 // existing index.
411 sal_uInt16 nIndex = (aNewScope != aOldScope ? 0 : pData->GetIndex());
413 pOldRangeName->erase(*pData);
414 m_xRangeManagerTable->BlockUpdate();
415 m_xRangeManagerTable->DeleteSelectedEntries();
416 ScRangeData::Type nType = ScRangeData::Type::Name;
417 if ( m_xBtnRowHeader->get_active() ) nType |= ScRangeData::Type::RowHeader;
418 if ( m_xBtnColHeader->get_active() ) nType |= ScRangeData::Type::ColHeader;
419 if ( m_xBtnPrintArea->get_active() ) nType |= ScRangeData::Type::PrintArea;
420 if ( m_xBtnCriteria->get_active() ) nType |= ScRangeData::Type::Criteria;
422 ScRangeData* pNewEntry = new ScRangeData( mrDoc, aNewName, aExpr,
423 maCursorPos, nType);
424 pNewEntry->SetIndex( nIndex);
425 pNewRangeName->insert(pNewEntry, false /*bReuseFreeIndex*/);
426 aLine.aName = aNewName;
427 aLine.aExpression = aExpr;
428 aLine.aScope = aNewScope;
429 m_xRangeManagerTable->addEntry(aLine, true);
430 // tdf#128137 process pending async row change events while UpdatesBlocked in place
431 Application::Reschedule(true);
432 m_xRangeManagerTable->UnblockUpdate();
433 mbDataChanged = true;
436 void ScNameDlg::SelectionChanged()
438 //don't update if we have just modified due to user input
439 if (m_xRangeManagerTable->UpdatesBlocked())
441 return;
444 if (m_xRangeManagerTable->IsMultiSelection())
446 m_xEdName->set_text(maStrMultiSelect);
447 m_xEdAssign->SetText(maStrMultiSelect);
449 m_xEdName->set_sensitive(false);
450 m_xEdAssign->GetWidget()->set_sensitive(false);
451 m_xRbAssign->GetWidget()->set_sensitive(false);
452 m_xLbScope->set_sensitive(false);
453 m_xBtnRowHeader->set_sensitive(false);
454 m_xBtnColHeader->set_sensitive(false);
455 m_xBtnPrintArea->set_sensitive(false);
456 m_xBtnCriteria->set_sensitive(false);
458 else
460 ScRangeNameLine aLine;
461 m_xRangeManagerTable->GetCurrentLine(aLine);
462 m_xEdAssign->SetText(aLine.aExpression);
463 m_xEdName->set_text(aLine.aName);
464 m_xLbScope->set_active_text(aLine.aScope);
465 ShowOptions(aLine);
466 m_xBtnDelete->set_sensitive(true);
467 m_xEdName->set_sensitive(true);
468 m_xEdAssign->GetWidget()->set_sensitive(true);
469 m_xRbAssign->GetWidget()->set_sensitive(true);
470 m_xLbScope->set_sensitive(true);
471 m_xBtnRowHeader->set_sensitive(true);
472 m_xBtnColHeader->set_sensitive(true);
473 m_xBtnPrintArea->set_sensitive(true);
474 m_xBtnCriteria->set_sensitive(true);
478 void ScNameDlg::ScopeChanged()
480 NameModified();
483 void ScNameDlg::GetRangeNames(std::map<OUString, ScRangeName>& rRangeMap)
485 m_RangeMap.swap(rRangeMap);
488 IMPL_LINK_NOARG(ScNameDlg, OkBtnHdl, weld::Button&, void)
490 response(RET_OK);
493 IMPL_LINK_NOARG(ScNameDlg, CancelBtnHdl, weld::Button&, void)
495 mbCloseWithoutUndo = true;
496 response(RET_CANCEL);
499 IMPL_LINK_NOARG(ScNameDlg, AddBtnHdl, weld::Button&, void)
501 AddPushed();
504 IMPL_LINK_NOARG(ScNameDlg, RemoveBtnHdl, weld::Button&, void)
506 RemovePushed();
509 IMPL_LINK_NOARG(ScNameDlg, EdModifyCheckBoxHdl, weld::Toggleable&, void)
511 NameModified();
514 IMPL_LINK_NOARG(ScNameDlg, EdModifyHdl, weld::Entry&, void)
516 NameModified();
519 IMPL_LINK_NOARG(ScNameDlg, RefEdModifyHdl, formula::RefEdit&, void)
521 NameModified();
524 IMPL_LINK_NOARG(ScNameDlg, AssignGetFocusHdl, formula::RefEdit&, void)
526 RefEdModifyHdl(*m_xEdAssign);
529 IMPL_LINK_NOARG(ScNameDlg, SelectionChangedHdl_Impl, weld::TreeView&, void)
531 SelectionChanged();
534 IMPL_LINK_NOARG(ScNameDlg, ScopeChangedHdl, weld::ComboBox&, void)
536 ScopeChanged();
539 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */