nss: upgrade to release 3.73
[LibreOffice.git] / sc / source / ui / namedlg / namedlg.cxx
blob799e94a2e0e756a0fe0e08393e0a07fccb4e2b9d
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/settings.hxx>
36 #include <vcl/svapp.hxx>
37 #include <formula/errorcodes.hxx>
38 #include <unotools/charclass.hxx>
40 #include <map>
42 //logic
44 ScNameDlg::ScNameDlg( SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
45 ScViewData& rViewData,
46 const ScAddress& aCursorPos,
47 std::map<OUString, std::unique_ptr<ScRangeName>> *const pRangeMap)
48 : ScAnyRefDlgController(pB, pCW, pParent, "modules/scalc/ui/managenamesdialog.ui",
49 "ManageNamesDialog")
51 , maGlobalNameStr(ScResId(STR_GLOBAL_SCOPE))
52 , maErrInvalidNameStr(ScResId(STR_ERR_NAME_INVALID))
53 , maErrNameInUse(ScResId(STR_ERR_NAME_EXISTS))
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("name"))
63 , m_xFtAssign(m_xBuilder->weld_label("label3"))
64 , m_xEdAssign(new formula::RefEdit(m_xBuilder->weld_entry("range")))
65 , m_xRbAssign(new formula::RefButton(m_xBuilder->weld_button("assign")))
66 , m_xLbScope(m_xBuilder->weld_combo_box("scope"))
67 , m_xBtnPrintArea(m_xBuilder->weld_check_button("printrange"))
68 , m_xBtnColHeader(m_xBuilder->weld_check_button("colheader"))
69 , m_xBtnCriteria(m_xBuilder->weld_check_button("filter"))
70 , m_xBtnRowHeader(m_xBuilder->weld_check_button("rowheader"))
71 , m_xBtnAdd(m_xBuilder->weld_button("add"))
72 , m_xBtnDelete(m_xBuilder->weld_button("delete"))
73 , m_xBtnOk(m_xBuilder->weld_button("ok"))
74 , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
75 , m_xFtInfo(m_xBuilder->weld_label("info"))
76 , m_xExpander(m_xBuilder->weld_expander("more"))
78 m_xEdAssign->SetReferences(this, m_xFtAssign.get());
79 m_xRbAssign->SetReferences(this, m_xEdAssign.get());
80 maStrInfoDefault = m_xFtInfo->get_label();
81 m_xFtInfo->set_label(OUString());
83 if (!pRangeMap)
85 std::map<OUString, ScRangeName*> aRangeMap;
86 mrDoc.GetRangeNameMap(aRangeMap);
87 for (const auto& [aTemp, pRangeName] : aRangeMap)
89 m_RangeMap.insert(std::make_pair(aTemp, std::make_unique<ScRangeName>(*pRangeName)));
92 else
94 m_RangeMap.swap(*pRangeMap);
96 Init();
99 ScNameDlg::~ScNameDlg()
103 void ScNameDlg::Init()
105 //init UI
107 std::unique_ptr<weld::TreeView> xTreeView(m_xBuilder->weld_tree_view("names"));
108 xTreeView->set_size_request(xTreeView->get_approximate_digit_width() * 75,
109 xTreeView->get_height_rows(10));
110 m_xRangeManagerTable.reset(new ScRangeManagerTable(std::move(xTreeView), m_RangeMap, maCursorPos));
112 m_xRangeManagerTable->connect_changed( LINK( this, ScNameDlg, SelectionChangedHdl_Impl ) );
114 m_xBtnOk->connect_clicked( LINK( this, ScNameDlg, OkBtnHdl ) );
115 m_xBtnCancel->connect_clicked( LINK( this, ScNameDlg, CancelBtnHdl ) );
116 m_xBtnAdd->connect_clicked( LINK( this, ScNameDlg, AddBtnHdl ) );
117 m_xEdAssign->SetGetFocusHdl( LINK( this, ScNameDlg, AssignGetFocusHdl ) );
118 m_xEdAssign->SetModifyHdl ( LINK( this, ScNameDlg, RefEdModifyHdl ) );
119 m_xEdName->connect_changed( LINK( this, ScNameDlg, EdModifyHdl ) );
120 m_xLbScope->connect_changed( LINK(this, ScNameDlg, ScopeChangedHdl) );
121 m_xBtnDelete->connect_clicked( LINK( this, ScNameDlg, RemoveBtnHdl ) );
122 m_xBtnPrintArea->connect_toggled( LINK(this, ScNameDlg, EdModifyCheckBoxHdl ) );
123 m_xBtnCriteria->connect_toggled( LINK(this, ScNameDlg, EdModifyCheckBoxHdl ) );
124 m_xBtnRowHeader->connect_toggled( LINK(this, ScNameDlg, EdModifyCheckBoxHdl ) );
125 m_xBtnColHeader->connect_toggled( LINK(this, ScNameDlg, EdModifyCheckBoxHdl ) );
127 // Initialize scope list.
128 m_xLbScope->append_text(maGlobalNameStr);
129 m_xLbScope->set_active(0);
130 SCTAB n = mrDoc.GetTableCount();
131 for (SCTAB i = 0; i < n; ++i)
133 OUString aTabName;
134 mrDoc.GetName(i, aTabName);
135 m_xLbScope->append_text(aTabName);
138 CheckForEmptyTable();
140 if (m_xRangeManagerTable->n_children())
142 m_xRangeManagerTable->set_cursor(0);
143 m_xRangeManagerTable->CheckForFormulaString();
144 SelectionChanged();
149 bool ScNameDlg::IsRefInputMode() const
151 return m_xEdAssign->GetWidget()->get_sensitive();
154 void ScNameDlg::RefInputDone( bool bForced)
156 ScAnyRefDlgController::RefInputDone(bForced);
157 RefEdModifyHdl(*m_xEdAssign);
160 void ScNameDlg::SetReference( const ScRange& rRef, ScDocument& rDocP )
162 if (m_xEdAssign->GetWidget()->get_sensitive())
164 if ( rRef.aStart != rRef.aEnd )
165 RefInputStart(m_xEdAssign.get());
166 OUString aRefStr(rRef.Format(rDocP, ScRefFlags::RANGE_ABS_3D,
167 ScAddress::Details(rDocP.GetAddressConvention(), 0, 0)));
168 m_xEdAssign->SetRefString( aRefStr );
172 void ScNameDlg::Close()
174 if (mbDataChanged && !mbCloseWithoutUndo)
175 mrViewData.GetDocFunc().ModifyAllRangeNames(m_RangeMap);
176 DoClose(ScNameDlgWrapper::GetChildWindowId());
179 void ScNameDlg::CheckForEmptyTable()
181 if (!m_xRangeManagerTable->n_children())
183 m_xBtnDelete->set_sensitive(false);
184 m_xEdAssign->GetWidget()->set_sensitive(false);
185 m_xRbAssign->GetWidget()->set_sensitive(false);
186 m_xEdName->set_sensitive(false);
187 m_xLbScope->set_sensitive(false);
189 m_xBtnCriteria->set_sensitive(false);
190 m_xBtnPrintArea->set_sensitive(false);
191 m_xBtnColHeader->set_sensitive(false);
192 m_xBtnRowHeader->set_sensitive(false);
194 else
196 m_xBtnDelete->set_sensitive(true);
197 m_xEdAssign->GetWidget()->set_sensitive(true);
198 m_xRbAssign->GetWidget()->set_sensitive(true);
199 m_xEdName->set_sensitive(true);
200 m_xLbScope->set_sensitive(true);
202 m_xBtnCriteria->set_sensitive(true);
203 m_xBtnPrintArea->set_sensitive(true);
204 m_xBtnColHeader->set_sensitive(true);
205 m_xBtnRowHeader->set_sensitive(true);
209 void ScNameDlg::SetActive()
211 m_xEdAssign->GrabFocus();
212 RefInputDone();
215 void ScNameDlg::UpdateChecks(const ScRangeData* pData)
217 // remove handlers, we only want the handlers to process
218 // user input and not when we are syncing the controls with our internal
219 // model ( also UpdateChecks is called already from some other event
220 // handlers, triggering handlers while already processing a handler can
221 // ( and does in this case ) corrupt the internal data
223 m_xBtnCriteria->connect_toggled( Link<weld::ToggleButton&,void>() );
224 m_xBtnPrintArea->connect_toggled( Link<weld::ToggleButton&,void>() );
225 m_xBtnColHeader->connect_toggled( Link<weld::ToggleButton&,void>() );
226 m_xBtnRowHeader->connect_toggled( Link<weld::ToggleButton&,void>() );
228 m_xBtnCriteria->set_active( pData->HasType( ScRangeData::Type::Criteria ) );
229 m_xBtnPrintArea->set_active( pData->HasType( ScRangeData::Type::PrintArea ) );
230 m_xBtnColHeader->set_active( pData->HasType( ScRangeData::Type::ColHeader ) );
231 m_xBtnRowHeader->set_active( pData->HasType( ScRangeData::Type::RowHeader ) );
233 // Restore handlers so user input is processed again
234 Link<weld::ToggleButton&,void> aToggleHandler = LINK( this, ScNameDlg, EdModifyCheckBoxHdl );
235 m_xBtnCriteria->connect_toggled( aToggleHandler );
236 m_xBtnPrintArea->connect_toggled( aToggleHandler );
237 m_xBtnColHeader->connect_toggled( aToggleHandler );
238 m_xBtnRowHeader->connect_toggled( aToggleHandler );
241 bool ScNameDlg::IsNameValid()
243 OUString aScope = m_xLbScope->get_active_text();
244 OUString aName = m_xEdName->get_text();
245 aName = aName.trim();
247 if (aName.isEmpty())
248 return false;
250 ScRangeName* pRangeName = GetRangeName( aScope );
252 if (ScRangeData::IsNameValid( aName, mrDoc ) != ScRangeData::NAME_VALID)
254 m_xFtInfo->set_label_type(weld::LabelType::Error);
255 m_xFtInfo->set_label(maErrInvalidNameStr);
256 return false;
258 else if (pRangeName && pRangeName->findByUpperName(ScGlobal::getCharClassPtr()->uppercase(aName)))
260 m_xFtInfo->set_label_type(weld::LabelType::Error);
261 m_xFtInfo->set_label(maErrNameInUse);
262 return false;
264 m_xFtInfo->set_label( maStrInfoDefault );
265 return true;
268 bool ScNameDlg::IsFormulaValid()
270 ScCompiler aComp(mrDoc, maCursorPos, mrDoc.GetGrammar());
271 std::unique_ptr<ScTokenArray> pCode = aComp.CompileString(m_xEdAssign->GetText());
272 if (pCode->GetCodeError() != FormulaError::NONE)
274 m_xFtInfo->set_label_type(weld::LabelType::Error);
275 return false;
277 else
279 return true;
283 ScRangeName* ScNameDlg::GetRangeName(const OUString& rScope)
285 if (rScope == maGlobalNameStr)
286 return m_RangeMap.find(OUString(STR_GLOBAL_RANGE_NAME))->second.get();
287 else
288 return m_RangeMap.find(rScope)->second.get();
291 void ScNameDlg::ShowOptions(const ScRangeNameLine& rLine)
293 ScRangeName* pRangeName = GetRangeName(rLine.aScope);
294 ScRangeData* pData = pRangeName->findByUpperName(ScGlobal::getCharClassPtr()->uppercase(rLine.aName));
295 if (pData)
297 UpdateChecks(pData);
301 void ScNameDlg::AddPushed()
303 mbCloseWithoutUndo = true;
304 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
305 pViewSh->SwitchBetweenRefDialogs(this);
308 void ScNameDlg::SetEntry(const OUString& rName, const OUString& rScope)
310 if (!rName.isEmpty())
312 mbDataChanged = true;
313 ScRangeNameLine aLine;
314 aLine.aName = rName;
315 aLine.aScope = rScope;
316 m_xRangeManagerTable->SetEntry(aLine);
320 void ScNameDlg::RemovePushed()
322 std::vector<ScRangeNameLine> aEntries = m_xRangeManagerTable->GetSelectedEntries();
323 m_xRangeManagerTable->DeleteSelectedEntries();
324 for (const auto& rEntry : aEntries)
326 ScRangeName* pRangeName = GetRangeName(rEntry.aScope);
327 ScRangeData* pData = pRangeName->findByUpperName(ScGlobal::getCharClassPtr()->uppercase(rEntry.aName));
328 OSL_ENSURE(pData, "table and model should be in sync");
329 // be safe and check for possible problems
330 if (pData)
331 pRangeName->erase(*pData);
333 mbDataChanged = true;
335 CheckForEmptyTable();
338 void ScNameDlg::NameModified()
340 ScRangeNameLine aLine;
341 m_xRangeManagerTable->GetCurrentLine(aLine);
342 OUString aOldName = aLine.aName;
343 OUString aNewName = m_xEdName->get_text();
344 aNewName = aNewName.trim();
345 m_xFtInfo->set_label_type(weld::LabelType::Normal);
346 if (aNewName != aOldName)
348 if (!IsNameValid())
349 return;
351 else
353 m_xFtInfo->set_label( maStrInfoDefault );
356 if (!IsFormulaValid())
358 //TODO: implement an info text
359 return;
362 OUString aOldScope = aLine.aScope;
363 //empty table
364 if (aOldScope.isEmpty())
365 return;
366 OUString aExpr = m_xEdAssign->GetText();
367 OUString aNewScope = m_xLbScope->get_active_text();
369 ScRangeName* pOldRangeName = GetRangeName( aOldScope );
370 ScRangeData* pData = pOldRangeName->findByUpperName( ScGlobal::getCharClassPtr()->uppercase(aOldName) );
371 ScRangeName* pNewRangeName = GetRangeName( aNewScope );
372 OSL_ENSURE(pData, "model and table should be in sync");
373 // be safe and check for range data
374 if (!pData)
375 return;
377 // Assign new index (0) only if the scope is changed, else keep the
378 // existing index.
379 sal_uInt16 nIndex = (aNewScope != aOldScope ? 0 : pData->GetIndex());
381 pOldRangeName->erase(*pData);
382 m_xRangeManagerTable->BlockUpdate();
383 m_xRangeManagerTable->DeleteSelectedEntries();
384 ScRangeData::Type nType = ScRangeData::Type::Name;
385 if ( m_xBtnRowHeader->get_active() ) nType |= ScRangeData::Type::RowHeader;
386 if ( m_xBtnColHeader->get_active() ) nType |= ScRangeData::Type::ColHeader;
387 if ( m_xBtnPrintArea->get_active() ) nType |= ScRangeData::Type::PrintArea;
388 if ( m_xBtnCriteria->get_active() ) nType |= ScRangeData::Type::Criteria;
390 ScRangeData* pNewEntry = new ScRangeData( mrDoc, aNewName, aExpr,
391 maCursorPos, nType);
392 pNewEntry->SetIndex( nIndex);
393 pNewRangeName->insert(pNewEntry, false /*bReuseFreeIndex*/);
394 aLine.aName = aNewName;
395 aLine.aExpression = aExpr;
396 aLine.aScope = aNewScope;
397 m_xRangeManagerTable->addEntry(aLine, true);
398 // tdf#128137 process pending async row change events while UpdatesBlocked in place
399 Application::Reschedule(true);
400 m_xRangeManagerTable->UnblockUpdate();
401 mbDataChanged = true;
404 void ScNameDlg::SelectionChanged()
406 //don't update if we have just modified due to user input
407 if (m_xRangeManagerTable->UpdatesBlocked())
409 return;
412 if (m_xRangeManagerTable->IsMultiSelection())
414 m_xEdName->set_text(maStrMultiSelect);
415 m_xEdAssign->SetText(maStrMultiSelect);
417 m_xEdName->set_sensitive(false);
418 m_xEdAssign->GetWidget()->set_sensitive(false);
419 m_xRbAssign->GetWidget()->set_sensitive(false);
420 m_xLbScope->set_sensitive(false);
421 m_xBtnRowHeader->set_sensitive(false);
422 m_xBtnColHeader->set_sensitive(false);
423 m_xBtnPrintArea->set_sensitive(false);
424 m_xBtnCriteria->set_sensitive(false);
426 else
428 ScRangeNameLine aLine;
429 m_xRangeManagerTable->GetCurrentLine(aLine);
430 m_xEdAssign->SetText(aLine.aExpression);
431 m_xEdName->set_text(aLine.aName);
432 m_xLbScope->set_active_text(aLine.aScope);
433 ShowOptions(aLine);
434 m_xBtnDelete->set_sensitive(true);
435 m_xEdName->set_sensitive(true);
436 m_xEdAssign->GetWidget()->set_sensitive(true);
437 m_xRbAssign->GetWidget()->set_sensitive(true);
438 m_xLbScope->set_sensitive(true);
439 m_xBtnRowHeader->set_sensitive(true);
440 m_xBtnColHeader->set_sensitive(true);
441 m_xBtnPrintArea->set_sensitive(true);
442 m_xBtnCriteria->set_sensitive(true);
446 void ScNameDlg::ScopeChanged()
448 NameModified();
451 void ScNameDlg::GetRangeNames(std::map<OUString, std::unique_ptr<ScRangeName>>& rRangeMap)
453 m_RangeMap.swap(rRangeMap);
456 IMPL_LINK_NOARG(ScNameDlg, OkBtnHdl, weld::Button&, void)
458 response(RET_OK);
461 IMPL_LINK_NOARG(ScNameDlg, CancelBtnHdl, weld::Button&, void)
463 mbCloseWithoutUndo = true;
464 response(RET_CANCEL);
467 IMPL_LINK_NOARG(ScNameDlg, AddBtnHdl, weld::Button&, void)
469 AddPushed();
472 IMPL_LINK_NOARG(ScNameDlg, RemoveBtnHdl, weld::Button&, void)
474 RemovePushed();
477 IMPL_LINK_NOARG(ScNameDlg, EdModifyCheckBoxHdl, weld::ToggleButton&, void)
479 NameModified();
482 IMPL_LINK_NOARG(ScNameDlg, EdModifyHdl, weld::Entry&, void)
484 NameModified();
487 IMPL_LINK_NOARG(ScNameDlg, RefEdModifyHdl, formula::RefEdit&, void)
489 NameModified();
492 IMPL_LINK_NOARG(ScNameDlg, AssignGetFocusHdl, formula::RefEdit&, void)
494 RefEdModifyHdl(*m_xEdAssign);
497 IMPL_LINK_NOARG(ScNameDlg, SelectionChangedHdl_Impl, weld::TreeView&, void)
499 SelectionChanged();
502 IMPL_LINK_NOARG(ScNameDlg, ScopeChangedHdl, weld::ComboBox&, void)
504 ScopeChanged();
507 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */