1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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 */
9
10 #include <namedefdlg.hxx>
11
12 #include <vcl/settings.hxx>
13 #include <formula/errorcodes.hxx>
14 #include <sfx2/app.hxx>
15 #include <unotools/charclass.hxx>
16
17 #include <compiler.hxx>
18 #include <document.hxx>
19 #include <globstr.hrc>
20 #include <scresid.hxx>
21 #include <globalnames.hxx>
22 #include <rangenam.hxx>
23 #include <reffact.hxx>
24 #include <undorangename.hxx>
25 #include <tabvwsh.hxx>
26 #include <tokenarray.hxx>
27
ScNameDefDlg(SfxBindings * pB,SfxChildWindow * pCW,weld::Window * pParent,const ScViewData * pViewData,const std::map<OUString,ScRangeName * > & aRangeMap,const ScAddress & aCursorPos,const bool bUndo)28 ScNameDefDlg::ScNameDefDlg( SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
29 const ScViewData* pViewData, const std::map<OUString, ScRangeName*>& aRangeMap,
30 const ScAddress& aCursorPos, const bool bUndo )
31 : ScAnyRefDlgController( pB, pCW, pParent, "modules/scalc/ui/definename.ui", "DefineNameDialog")
32 , mbUndo( bUndo )
33 , mpDoc( pViewData->GetDocument() )
34 , mpDocShell ( pViewData->GetDocShell() )
35 , maCursorPos( aCursorPos )
36 , maGlobalNameStr ( ScResId(STR_GLOBAL_SCOPE) )
37 , maErrInvalidNameStr( ScResId(STR_ERR_NAME_INVALID))
38 , maErrInvalidNameCellRefStr( ScResId(STR_ERR_NAME_INVALID_CELL_REF))
39 , maErrNameInUse ( ScResId(STR_ERR_NAME_EXISTS))
40 , maRangeMap( aRangeMap )
41 , m_xEdName(m_xBuilder->weld_entry("edit"))
42 , m_xEdRange(new formula::RefEdit(m_xBuilder->weld_entry("range")))
43 , m_xRbRange(new formula::RefButton(m_xBuilder->weld_button("refbutton")))
44 , m_xLbScope(m_xBuilder->weld_combo_box("scope"))
45 , m_xBtnRowHeader(m_xBuilder->weld_check_button("rowheader"))
46 , m_xBtnColHeader(m_xBuilder->weld_check_button("colheader"))
47 , m_xBtnPrintArea(m_xBuilder->weld_check_button("printarea"))
48 , m_xBtnCriteria(m_xBuilder->weld_check_button("filter"))
49 , m_xBtnAdd(m_xBuilder->weld_button("add"))
50 , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
51 , m_xFtInfo(m_xBuilder->weld_label("label"))
52 , m_xExpander(m_xBuilder->weld_expander("more"))
53 , m_xFtRange(m_xBuilder->weld_label("label3"))
54 {
55 m_xEdRange->SetReferences(this, m_xFtRange.get());
56 m_xRbRange->SetReferences(this, m_xEdRange.get());
57 maStrInfoDefault = m_xFtInfo->get_label();
58
59 // Initialize scope list.
60 m_xLbScope->append_text(maGlobalNameStr);
61 m_xLbScope->set_active(0);
62 SCTAB n = mpDoc->GetTableCount();
63 for (SCTAB i = 0; i < n; ++i)
64 {
65 OUString aTabName;
66 mpDoc->GetName(i, aTabName);
67 m_xLbScope->append_text(aTabName);
68 }
69
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
75 m_xBtnAdd->set_sensitive(false); // empty name is invalid
76
77 ScRange aRange;
78
79 pViewData->GetSimpleArea( aRange );
80 OUString aAreaStr(aRange.Format(ScRefFlags::RANGE_ABS_3D, mpDoc,
81 ScAddress::Details(mpDoc->GetAddressConvention(), 0, 0)));
82
83 m_xEdRange->SetText( aAreaStr );
84
85 m_xEdName->grab_focus();
86 m_xEdName->select_region(0, -1);
87 }
88
~ScNameDefDlg()89 ScNameDefDlg::~ScNameDefDlg()
90 {
91 }
92
CancelPushed()93 void ScNameDefDlg::CancelPushed()
94 {
95 if (mbUndo)
96 response(RET_CANCEL);
97 else
98 {
99 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
100 pViewSh->SwitchBetweenRefDialogs(this);
101 }
102 }
103
IsFormulaValid()104 bool ScNameDefDlg::IsFormulaValid()
105 {
106 ScCompiler aComp( mpDoc, maCursorPos, mpDoc->GetGrammar());
107 std::unique_ptr<ScTokenArray> pCode = aComp.CompileString(m_xEdRange->GetText());
108 if (pCode->GetCodeError() != FormulaError::NONE)
109 {
110 //TODO: info message
111 return false;
112 }
113 else
114 {
115 return true;
116 }
117 }
118
IsNameValid()119 bool ScNameDefDlg::IsNameValid()
120 {
121 OUString aScope = m_xLbScope->get_active_text();
122 OUString aName = m_xEdName->get_text();
123
124 ScRangeName* pRangeName = nullptr;
125 if(aScope == maGlobalNameStr)
126 {
127 pRangeName = maRangeMap.find(OUString(STR_GLOBAL_RANGE_NAME))->second;
128 }
129 else
130 {
131 pRangeName = maRangeMap.find(aScope)->second;
132 }
133
134 ScRangeData::IsNameValidType eType;
135 m_xFtInfo->set_message_type(weld::EntryMessageType::Normal);
136 if ( aName.isEmpty() )
137 {
138 m_xBtnAdd->set_sensitive(false);
139 m_xFtInfo->set_label(maStrInfoDefault);
140 return false;
141 }
142 else if ((eType = ScRangeData::IsNameValid( aName, mpDoc )) != ScRangeData::NAME_VALID)
143 {
144 m_xFtInfo->set_message_type(weld::EntryMessageType::Error);
145 if (eType == ScRangeData::NAME_INVALID_BAD_STRING)
146 {
147 m_xFtInfo->set_label(maErrInvalidNameStr);
148 }
149 else if (eType == ScRangeData::NAME_INVALID_CELL_REF)
150 {
151 m_xFtInfo->set_label(maErrInvalidNameCellRefStr);
152 }
153 m_xBtnAdd->set_sensitive(false);
154 return false;
155 }
156 else if (pRangeName->findByUpperName(ScGlobal::pCharClass->uppercase(aName)))
157 {
158 m_xFtInfo->set_message_type(weld::EntryMessageType::Error);
159 m_xFtInfo->set_label(maErrNameInUse);
160 m_xBtnAdd->set_sensitive(false);
161 return false;
162 }
163
164 if (!IsFormulaValid())
165 {
166 m_xFtInfo->set_message_type(weld::EntryMessageType::Error);
167 m_xBtnAdd->set_sensitive(false);
168 return false;
169 }
170
171 m_xFtInfo->set_label(maStrInfoDefault);
172 m_xBtnAdd->set_sensitive(true);
173 return true;
174 }
175
AddPushed()176 void ScNameDefDlg::AddPushed()
177 {
178 OUString aScope = m_xLbScope->get_active_text();
179 OUString aName = m_xEdName->get_text();
180 OUString aExpression = m_xEdRange->GetText();
181
182 if (aName.isEmpty())
183 {
184 return;
185 }
186 if (aScope.isEmpty())
187 {
188 return;
189 }
190
191 ScRangeName* pRangeName = nullptr;
192 if(aScope == maGlobalNameStr)
193 {
194 pRangeName = maRangeMap.find(OUString(STR_GLOBAL_RANGE_NAME))->second;
195 }
196 else
197 {
198 pRangeName = maRangeMap.find(aScope)->second;
199 }
200 if (!pRangeName)
201 return;
202
203 if (!IsNameValid()) //should not happen, but make sure we don't break anything
204 return;
205 else
206 {
207 if ( mpDoc )
208 {
209 ScRangeData::Type nType = ScRangeData::Type::Name;
210
211 ScRangeData* pNewEntry = new ScRangeData( mpDoc,
212 aName,
213 aExpression,
214 maCursorPos,
215 nType );
216
217 if ( m_xBtnRowHeader->get_active() ) nType |= ScRangeData::Type::RowHeader;
218 if ( m_xBtnColHeader->get_active() ) nType |= ScRangeData::Type::ColHeader;
219 if ( m_xBtnPrintArea->get_active() ) nType |= ScRangeData::Type::PrintArea;
220 if ( m_xBtnCriteria->get_active() ) nType |= ScRangeData::Type::Criteria;
221
222 pNewEntry->AddType(nType);
223
224 // aExpression valid?
225 if ( FormulaError::NONE == pNewEntry->GetErrCode() )
226 {
227 if ( !pRangeName->insert( pNewEntry, false /*bReuseFreeIndex*/ ) )
228 pNewEntry = nullptr;
229
230 if (mbUndo)
231 {
232 // this means we called directly through the menu
233
234 SCTAB nTab;
235 // if no table with that name is found, assume global range name
236 if (!mpDoc->GetTable(aScope, nTab))
237 nTab = -1;
238
239 assert( pNewEntry); // undo of no insertion smells fishy
240 if (pNewEntry)
241 mpDocShell->GetUndoManager()->AddUndoAction(
242 std::make_unique<ScUndoAddRangeData>( mpDocShell, pNewEntry, nTab) );
243
244 // set table stream invalid, otherwise RangeName won't be saved if no other
245 // call invalidates the stream
246 if (nTab != -1)
247 mpDoc->SetStreamValid(nTab, false);
248 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) );
249 mpDocShell->SetDocumentModified();
250 Close();
251 }
252 else
253 {
254 maName = aName;
255 maScope = aScope;
256 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
257 pViewSh->SwitchBetweenRefDialogs(this);
258 }
259 }
260 else
261 {
262 delete pNewEntry;
263 m_xEdRange->GrabFocus();
264 m_xEdRange->SelectAll();
265 }
266 }
267 }
268 }
269
GetNewData(OUString & rName,OUString & rScope)270 void ScNameDefDlg::GetNewData(OUString& rName, OUString& rScope)
271 {
272 rName = maName;
273 rScope = maScope;
274 }
275
IsRefInputMode() const276 bool ScNameDefDlg::IsRefInputMode() const
277 {
278 return m_xEdRange->GetWidget()->get_sensitive();
279 }
280
RefInputDone(bool bForced)281 void ScNameDefDlg::RefInputDone( bool bForced)
282 {
283 ScAnyRefDlgController::RefInputDone(bForced);
284 IsNameValid();
285 }
286
SetReference(const ScRange & rRef,ScDocument * pDocP)287 void ScNameDefDlg::SetReference( const ScRange& rRef, ScDocument* pDocP )
288 {
289 if (m_xEdRange->GetWidget()->get_sensitive())
290 {
291 if ( rRef.aStart != rRef.aEnd )
292 RefInputStart(m_xEdRange.get());
293 OUString aRefStr(rRef.Format(ScRefFlags::RANGE_ABS_3D, pDocP,
294 ScAddress::Details(pDocP->GetAddressConvention(), 0, 0)));
295 m_xEdRange->SetRefString( aRefStr );
296 }
297 }
298
Close()299 void ScNameDefDlg::Close()
300 {
301 DoClose( ScNameDefDlgWrapper::GetChildWindowId() );
302 }
303
SetActive()304 void ScNameDefDlg::SetActive()
305 {
306 m_xEdRange->GrabFocus();
307 RefInputDone();
308 }
309
IMPL_LINK_NOARG(ScNameDefDlg,CancelBtnHdl,weld::Button &,void)310 IMPL_LINK_NOARG(ScNameDefDlg, CancelBtnHdl, weld::Button&, void)
311 {
312 CancelPushed();
313 }
314
IMPL_LINK_NOARG(ScNameDefDlg,AddBtnHdl,weld::Button &,void)315 IMPL_LINK_NOARG(ScNameDefDlg, AddBtnHdl, weld::Button&, void)
316 {
317 AddPushed();
318 };
319
IMPL_LINK_NOARG(ScNameDefDlg,NameModifyHdl,weld::Entry &,void)320 IMPL_LINK_NOARG(ScNameDefDlg, NameModifyHdl, weld::Entry&, void)
321 {
322 IsNameValid();
323 }
324
IMPL_LINK_NOARG(ScNameDefDlg,AssignGetFocusHdl,formula::RefEdit &,void)325 IMPL_LINK_NOARG(ScNameDefDlg, AssignGetFocusHdl, formula::RefEdit&, void)
326 {
327 IsNameValid();
328 }
329
330 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
331