/src/libreoffice/sc/source/ui/xmlsource/xmlsourcedlg.cxx
Line | Count | Source |
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 <xmlsourcedlg.hxx> |
11 | | #include <bitmaps.hlst> |
12 | | #include <document.hxx> |
13 | | #include <orcusfilters.hxx> |
14 | | #include <filter.hxx> |
15 | | #include <reffact.hxx> |
16 | | #include <tabvwsh.hxx> |
17 | | |
18 | | #include <tools/urlobj.hxx> |
19 | | #include <sfx2/filedlghelper.hxx> |
20 | | #include <vcl/weld/Dialog.hxx> |
21 | | |
22 | | #include <com/sun/star/ui/dialogs/XFilePicker3.hpp> |
23 | | #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp> |
24 | | #include <com/sun/star/ui/dialogs/TemplateDescription.hpp> |
25 | | |
26 | | using namespace com::sun::star; |
27 | | |
28 | | namespace { |
29 | | |
30 | | bool isAttribute(const weld::TreeView& rControl, const weld::TreeIter& rEntry) |
31 | 0 | { |
32 | 0 | const ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(rControl, rEntry); |
33 | 0 | if (!pUserData) |
34 | 0 | return false; |
35 | | |
36 | 0 | return pUserData->meType == ScOrcusXMLTreeParam::Attribute; |
37 | 0 | } |
38 | | |
39 | | OUString getXPath( |
40 | | const weld::TreeView& rTree, const weld::TreeIter& rEntry, std::vector<size_t>& rNamespaces) |
41 | 0 | { |
42 | 0 | OUStringBuffer aBuf; |
43 | 0 | std::unique_ptr<weld::TreeIter> xEntry(rTree.make_iterator(&rEntry)); |
44 | 0 | do |
45 | 0 | { |
46 | | // Collect used namespace. |
47 | 0 | const ScOrcusXMLTreeParam::EntryData* pData = ScOrcusXMLTreeParam::getUserData(rTree, *xEntry); |
48 | 0 | if (pData) |
49 | 0 | rNamespaces.push_back(pData->mnNamespaceID); |
50 | | |
51 | | // element separator is '/' whereas attribute separator is '/@' in xpath. |
52 | 0 | std::u16string_view sSeparator; |
53 | 0 | if (isAttribute(rTree, *xEntry)) |
54 | 0 | sSeparator = u"/@"; |
55 | 0 | else |
56 | 0 | sSeparator = u"/"; |
57 | 0 | aBuf.insert(0, sSeparator + rTree.get_text(*xEntry, 0)); |
58 | 0 | } |
59 | 0 | while (rTree.iter_parent(*xEntry)); |
60 | |
|
61 | 0 | return aBuf.makeStringAndClear(); |
62 | 0 | } |
63 | | |
64 | | } |
65 | | |
66 | | ScXMLSourceDlg::ScXMLSourceDlg( |
67 | | SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent, ScDocument& rDoc) |
68 | 0 | : ScAnyRefDlgController(pB, pCW, pParent, u"modules/scalc/ui/xmlsourcedialog.ui"_ustr, u"XMLSourceDialog"_ustr) |
69 | 0 | , mrDoc(rDoc) |
70 | 0 | , mbDlgLostFocus(false) |
71 | 0 | , mxBtnSelectSource(m_xBuilder->weld_button(u"selectsource"_ustr)) |
72 | 0 | , mxFtSourceFile(m_xBuilder->weld_label(u"sourcefile"_ustr)) |
73 | 0 | , mxMapGrid(m_xBuilder->weld_container(u"mapgrid"_ustr)) |
74 | 0 | , mxLbTree(m_xBuilder->weld_tree_view(u"tree"_ustr)) |
75 | 0 | , mxRefEdit(new formula::RefEdit(m_xBuilder->weld_entry(u"edit"_ustr))) |
76 | 0 | , mxRefBtn(new formula::RefButton(m_xBuilder->weld_button(u"ref"_ustr))) |
77 | 0 | , mxBtnOk(m_xBuilder->weld_button(u"ok"_ustr)) |
78 | 0 | , mxBtnCancel(m_xBuilder->weld_button(u"cancel"_ustr)) |
79 | 0 | , maCustomCompare(*mxLbTree) |
80 | 0 | , maCellLinks(maCustomCompare) |
81 | 0 | , maRangeLinks(maCustomCompare) |
82 | 0 | { |
83 | 0 | mxLbTree->set_size_request(mxLbTree->get_approximate_digit_width() * 40, |
84 | 0 | mxLbTree->get_height_rows(15)); |
85 | 0 | mxLbTree->set_selection_mode(SelectionMode::Multiple); |
86 | 0 | mxRefEdit->SetReferences(this); |
87 | 0 | mxRefBtn->SetReferences(this, mxRefEdit.get()); |
88 | |
|
89 | 0 | mpActiveEdit = mxRefEdit.get(); |
90 | |
|
91 | 0 | maXMLParam.maImgElementDefault = RID_BMP_ELEMENT_DEFAULT; |
92 | 0 | maXMLParam.maImgElementRepeat = RID_BMP_ELEMENT_REPEAT; |
93 | 0 | maXMLParam.maImgAttribute = RID_BMP_ELEMENT_ATTRIBUTE; |
94 | |
|
95 | 0 | Link<weld::Button&,void> aBtnHdl = LINK(this, ScXMLSourceDlg, BtnPressedHdl); |
96 | 0 | mxBtnSelectSource->connect_clicked(aBtnHdl); |
97 | 0 | mxBtnOk->connect_clicked(aBtnHdl); |
98 | 0 | mxBtnCancel->connect_clicked(aBtnHdl); |
99 | |
|
100 | 0 | mxLbTree->connect_selection_changed(LINK(this, ScXMLSourceDlg, TreeItemSelectHdl)); |
101 | |
|
102 | 0 | Link<formula::RefEdit&,void> aLink = LINK(this, ScXMLSourceDlg, RefModifiedHdl); |
103 | 0 | mxRefEdit->SetModifyHdl(aLink); |
104 | |
|
105 | 0 | mxBtnOk->set_sensitive(false); |
106 | |
|
107 | 0 | SetNonLinkable(); |
108 | 0 | mxBtnSelectSource->grab_focus(); // Initial focus is on the select source button. |
109 | 0 | } |
110 | | |
111 | | ScXMLSourceDlg::~ScXMLSourceDlg() |
112 | 0 | { |
113 | 0 | } |
114 | | |
115 | | bool ScXMLSourceDlg::IsRefInputMode() const |
116 | 0 | { |
117 | 0 | return mpActiveEdit != nullptr && mpActiveEdit->GetWidget()->get_sensitive(); |
118 | 0 | } |
119 | | |
120 | | void ScXMLSourceDlg::SetReference(const ScRange& rRange, ScDocument& rDoc) |
121 | 0 | { |
122 | 0 | if (!mpActiveEdit) |
123 | 0 | return; |
124 | | |
125 | 0 | if (rRange.aStart != rRange.aEnd) |
126 | 0 | RefInputStart(mpActiveEdit); |
127 | |
|
128 | 0 | OUString aStr(rRange.aStart.Format(ScRefFlags::ADDR_ABS_3D, &rDoc, rDoc.GetAddressConvention())); |
129 | 0 | mpActiveEdit->SetRefString(aStr); |
130 | |
|
131 | 0 | RefEditModified(); |
132 | 0 | } |
133 | | |
134 | | void ScXMLSourceDlg::Deactivate() |
135 | 0 | { |
136 | 0 | mbDlgLostFocus = true; |
137 | 0 | } |
138 | | |
139 | | void ScXMLSourceDlg::SetActive() |
140 | 0 | { |
141 | 0 | if (mbDlgLostFocus) |
142 | 0 | { |
143 | 0 | mbDlgLostFocus = false; |
144 | 0 | if (mpActiveEdit) |
145 | 0 | { |
146 | 0 | mpActiveEdit->GrabFocus(); |
147 | 0 | } |
148 | 0 | } |
149 | 0 | else |
150 | 0 | { |
151 | 0 | m_xDialog->grab_focus(); |
152 | 0 | } |
153 | |
|
154 | 0 | RefInputDone(); |
155 | 0 | } |
156 | | |
157 | | void ScXMLSourceDlg::Close() |
158 | 0 | { |
159 | 0 | DoClose(ScXMLSourceDlgWrapper::GetChildWindowId()); |
160 | 0 | } |
161 | | |
162 | | void ScXMLSourceDlg::SelectSourceFile() |
163 | 0 | { |
164 | 0 | sfx2::FileDialogHelper aDlgHelper(ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, |
165 | 0 | FileDialogFlags::NONE, m_xDialog.get()); |
166 | 0 | aDlgHelper.SetContext(sfx2::FileDialogHelper::CalcXMLSource); |
167 | | |
168 | | // Use the directory of current source file. |
169 | 0 | INetURLObject aURL(maSrcPath); |
170 | 0 | aURL.removeSegment(); |
171 | 0 | aURL.removeFinalSlash(); |
172 | 0 | OUString aPath = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE); |
173 | |
|
174 | 0 | if (!aPath.isEmpty()) |
175 | 0 | aDlgHelper.SetDisplayFolder(aPath); |
176 | 0 | if (aDlgHelper.Execute() != ERRCODE_NONE) |
177 | | // File picker dialog cancelled. |
178 | 0 | return; |
179 | | |
180 | 0 | uno::Sequence<OUString> aFiles = aDlgHelper.GetSelectedFiles(); |
181 | 0 | if (!aFiles.hasElements()) |
182 | 0 | return; |
183 | | |
184 | | // There should only be one file returned from the file picker. |
185 | 0 | maSrcPath = aFiles[0]; |
186 | 0 | mxFtSourceFile->set_label(maSrcPath); |
187 | 0 | LoadSourceFileStructure(maSrcPath); |
188 | 0 | } |
189 | | |
190 | | void ScXMLSourceDlg::LoadSourceFileStructure(const OUString& rPath) |
191 | 0 | { |
192 | 0 | ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters(); |
193 | 0 | if (!pOrcus) |
194 | 0 | return; |
195 | | |
196 | 0 | mpXMLContext = pOrcus->createXMLContext(mrDoc, rPath); |
197 | 0 | if (!mpXMLContext) |
198 | 0 | return; |
199 | | |
200 | 0 | mpXMLContext->loadXMLStructure(*mxLbTree, maXMLParam); |
201 | 0 | } |
202 | | |
203 | | namespace { |
204 | | |
205 | | /** |
206 | | * The current entry is the reference entry for a cell link. For a range |
207 | | * link, the reference entry is the shallowest repeat element entry up from |
208 | | * the current entry position. The mapped cell position for a range link is |
209 | | * stored with the reference entry. |
210 | | */ |
211 | | std::unique_ptr<weld::TreeIter> getReferenceEntry(const weld::TreeView& rTree, const weld::TreeIter& rCurEntry) |
212 | 0 | { |
213 | 0 | std::unique_ptr<weld::TreeIter> xParent(rTree.make_iterator(&rCurEntry)); |
214 | 0 | bool bParent = rTree.iter_parent(*xParent); |
215 | 0 | std::unique_ptr<weld::TreeIter> xRefEntry; |
216 | 0 | while (bParent) |
217 | 0 | { |
218 | 0 | ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(rTree, *xParent); |
219 | 0 | assert(pUserData); |
220 | 0 | if (pUserData->meType == ScOrcusXMLTreeParam::ElementRepeat) |
221 | 0 | { |
222 | | // This is a repeat element - a potential reference entry. |
223 | 0 | xRefEntry = rTree.make_iterator(xParent.get()); |
224 | 0 | } |
225 | 0 | bParent = rTree.iter_parent(*xParent); |
226 | 0 | } |
227 | |
|
228 | 0 | if (xRefEntry) |
229 | 0 | return xRefEntry; |
230 | | |
231 | 0 | std::unique_ptr<weld::TreeIter> xCurEntry(rTree.make_iterator(&rCurEntry)); |
232 | 0 | return xCurEntry; |
233 | 0 | } |
234 | | |
235 | | } |
236 | | |
237 | | void ScXMLSourceDlg::TreeItemSelected() |
238 | 0 | { |
239 | 0 | std::unique_ptr<weld::TreeIter> xEntry = mxLbTree->get_cursor(); |
240 | 0 | if (!xEntry) |
241 | 0 | return; |
242 | | |
243 | 0 | mxLbTree->unselect_all(); |
244 | 0 | mxLbTree->select(*xEntry); |
245 | |
|
246 | 0 | mxCurRefEntry = getReferenceEntry(*mxLbTree, *xEntry); |
247 | |
|
248 | 0 | ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(*mxLbTree, *mxCurRefEntry); |
249 | 0 | assert(pUserData); |
250 | |
|
251 | 0 | const ScAddress& rPos = pUserData->maLinkedPos; |
252 | 0 | if (rPos.IsValid()) |
253 | 0 | { |
254 | 0 | OUString aStr(rPos.Format(ScRefFlags::ADDR_ABS_3D, &mrDoc, mrDoc.GetAddressConvention())); |
255 | 0 | mxRefEdit->SetRefString(aStr); |
256 | 0 | } |
257 | 0 | else |
258 | 0 | mxRefEdit->SetRefString(OUString()); |
259 | |
|
260 | 0 | switch (pUserData->meType) |
261 | 0 | { |
262 | 0 | case ScOrcusXMLTreeParam::Attribute: |
263 | 0 | AttributeSelected(*mxCurRefEntry); |
264 | 0 | break; |
265 | 0 | case ScOrcusXMLTreeParam::ElementDefault: |
266 | 0 | DefaultElementSelected(*mxCurRefEntry); |
267 | 0 | break; |
268 | 0 | case ScOrcusXMLTreeParam::ElementRepeat: |
269 | 0 | RepeatElementSelected(*mxCurRefEntry); |
270 | 0 | break; |
271 | 0 | default: |
272 | 0 | ; |
273 | 0 | } |
274 | 0 | } |
275 | | |
276 | | void ScXMLSourceDlg::DefaultElementSelected(const weld::TreeIter& rEntry) |
277 | 0 | { |
278 | 0 | if (mxLbTree->iter_has_child(rEntry)) |
279 | 0 | { |
280 | | // Only an element with no child elements (leaf element) can be linked. |
281 | 0 | bool bHasChild = false; |
282 | 0 | std::unique_ptr<weld::TreeIter> xChild(mxLbTree->make_iterator(&rEntry)); |
283 | 0 | (void)mxLbTree->iter_children(*xChild); |
284 | 0 | do |
285 | 0 | { |
286 | 0 | ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(*mxLbTree, *xChild); |
287 | 0 | assert(pUserData); |
288 | 0 | if (pUserData->meType != ScOrcusXMLTreeParam::Attribute) |
289 | 0 | { |
290 | | // This child is not an attribute. Bail out. |
291 | 0 | bHasChild = true; |
292 | 0 | break; |
293 | 0 | } |
294 | 0 | } |
295 | 0 | while (mxLbTree->iter_next_sibling(*xChild)); |
296 | |
|
297 | 0 | if (bHasChild) |
298 | 0 | { |
299 | 0 | SetNonLinkable(); |
300 | 0 | return; |
301 | 0 | } |
302 | 0 | } |
303 | | |
304 | | // Check all its parents and make sure non of them are range-linked nor |
305 | | // repeat elements. |
306 | 0 | if (IsParentDirty(&rEntry)) |
307 | 0 | { |
308 | 0 | SetNonLinkable(); |
309 | 0 | return; |
310 | 0 | } |
311 | | |
312 | 0 | SetSingleLinkable(); |
313 | 0 | } |
314 | | |
315 | | void ScXMLSourceDlg::RepeatElementSelected(const weld::TreeIter& rEntry) |
316 | 0 | { |
317 | | // Check all its parents first. |
318 | |
|
319 | 0 | if (IsParentDirty(&rEntry)) |
320 | 0 | { |
321 | 0 | SetNonLinkable(); |
322 | 0 | return; |
323 | 0 | } |
324 | | |
325 | | // Check all its child elements / attributes and make sure non of them are |
326 | | // linked. |
327 | | |
328 | 0 | if (IsChildrenDirty(&rEntry)) |
329 | 0 | { |
330 | 0 | SetNonLinkable(); |
331 | 0 | return; |
332 | 0 | } |
333 | | |
334 | 0 | if (!mxLbTree->is_selected(rEntry)) |
335 | 0 | { |
336 | | // Highlight the entry if not highlighted already. This can happen |
337 | | // when the current entry is a child entry of a repeat element entry. |
338 | 0 | mxLbTree->select(rEntry); |
339 | 0 | } |
340 | |
|
341 | 0 | SelectAllChildEntries(rEntry); |
342 | 0 | SetRangeLinkable(); |
343 | 0 | } |
344 | | |
345 | | void ScXMLSourceDlg::AttributeSelected(const weld::TreeIter& rEntry) |
346 | 0 | { |
347 | | // Check all its parent elements and make sure non of them are linked nor |
348 | | // repeat elements. In attribute's case, it's okay to have the immediate |
349 | | // parent element linked (but not range-linked). |
350 | 0 | std::unique_ptr<weld::TreeIter> xParent(mxLbTree->make_iterator(&rEntry)); |
351 | 0 | mxLbTree->iter_parent(*xParent); |
352 | |
|
353 | 0 | ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(*mxLbTree, *xParent); |
354 | 0 | assert(pUserData); |
355 | 0 | if (pUserData->maLinkedPos.IsValid() && pUserData->mbRangeParent) |
356 | 0 | { |
357 | | // Parent element is range-linked. Bail out. |
358 | 0 | SetNonLinkable(); |
359 | 0 | return; |
360 | 0 | } |
361 | | |
362 | 0 | if (IsParentDirty(&rEntry)) |
363 | 0 | { |
364 | 0 | SetNonLinkable(); |
365 | 0 | return; |
366 | 0 | } |
367 | | |
368 | 0 | SetSingleLinkable(); |
369 | 0 | } |
370 | | |
371 | | void ScXMLSourceDlg::SetNonLinkable() |
372 | 0 | { |
373 | 0 | mxMapGrid->set_sensitive(false); |
374 | 0 | } |
375 | | |
376 | | void ScXMLSourceDlg::SetSingleLinkable() |
377 | 0 | { |
378 | 0 | mxMapGrid->set_sensitive(true); |
379 | 0 | } |
380 | | |
381 | | void ScXMLSourceDlg::SetRangeLinkable() |
382 | 0 | { |
383 | 0 | mxMapGrid->set_sensitive(true); |
384 | 0 | } |
385 | | |
386 | | void ScXMLSourceDlg::SelectAllChildEntries(const weld::TreeIter& rEntry) |
387 | 0 | { |
388 | 0 | std::unique_ptr<weld::TreeIter> xChild(mxLbTree->make_iterator(&rEntry)); |
389 | 0 | if (!mxLbTree->iter_children(*xChild)) |
390 | 0 | return; |
391 | 0 | do |
392 | 0 | { |
393 | 0 | SelectAllChildEntries(*xChild); // select recursively. |
394 | 0 | mxLbTree->select(*xChild); |
395 | 0 | } while (mxLbTree->iter_next_sibling(*xChild)); |
396 | 0 | } |
397 | | |
398 | | bool ScXMLSourceDlg::IsParentDirty(const weld::TreeIter* pEntry) const |
399 | 0 | { |
400 | 0 | std::unique_ptr<weld::TreeIter> xParent(mxLbTree->make_iterator(pEntry)); |
401 | 0 | if (!mxLbTree->iter_parent(*xParent)) |
402 | 0 | return false; |
403 | 0 | do |
404 | 0 | { |
405 | 0 | ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(*mxLbTree, *xParent); |
406 | 0 | assert(pUserData); |
407 | 0 | if (pUserData->maLinkedPos.IsValid()) |
408 | 0 | { |
409 | | // This parent is already linked. |
410 | 0 | return true; |
411 | 0 | } |
412 | 0 | } |
413 | 0 | while (mxLbTree->iter_parent(*xParent)); |
414 | 0 | return false; |
415 | 0 | } |
416 | | |
417 | | bool ScXMLSourceDlg::IsChildrenDirty(const weld::TreeIter* pEntry) const |
418 | 0 | { |
419 | 0 | std::unique_ptr<weld::TreeIter> xChild(mxLbTree->make_iterator(pEntry)); |
420 | 0 | if (!mxLbTree->iter_children(*xChild)) |
421 | 0 | return false; |
422 | | |
423 | 0 | do |
424 | 0 | { |
425 | 0 | ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(*mxLbTree, *xChild); |
426 | 0 | assert(pUserData); |
427 | 0 | if (pUserData->maLinkedPos.IsValid()) |
428 | | // Already linked. |
429 | 0 | return true; |
430 | | |
431 | 0 | if (pUserData->meType == ScOrcusXMLTreeParam::ElementDefault) |
432 | 0 | { |
433 | | // Check recursively. |
434 | 0 | if (IsChildrenDirty(xChild.get())) |
435 | 0 | return true; |
436 | 0 | } |
437 | 0 | } while (mxLbTree->iter_next_sibling(*xChild)); |
438 | | |
439 | 0 | return false; |
440 | 0 | } |
441 | | |
442 | | namespace { |
443 | | |
444 | | /** |
445 | | * Pick only the leaf elements. |
446 | | */ |
447 | | void getFieldLinks( |
448 | | ScOrcusImportXMLParam::RangeLink& rRangeLink, std::vector<size_t>& rNamespaces, |
449 | | const weld::TreeView& rTree, const weld::TreeIter& rEntry) |
450 | 0 | { |
451 | 0 | OUString aPath = getXPath(rTree, rEntry, rNamespaces); |
452 | 0 | const ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(rTree, rEntry); |
453 | |
|
454 | 0 | if (pUserData) |
455 | 0 | { |
456 | 0 | if (pUserData->meType == ScOrcusXMLTreeParam::ElementRepeat) |
457 | | // nested repeat element automatically becomes a row-group node. |
458 | 0 | rRangeLink.maRowGroups.push_back( |
459 | 0 | OUStringToOString(aPath, RTL_TEXTENCODING_UTF8)); |
460 | |
|
461 | 0 | if (pUserData->mbLeafNode && !aPath.isEmpty()) |
462 | | // XPath should never be empty anyway, but it won't hurt to check... |
463 | 0 | rRangeLink.maFieldPaths.push_back(OUStringToOString(aPath, RTL_TEXTENCODING_UTF8)); |
464 | 0 | } |
465 | |
|
466 | 0 | std::unique_ptr<weld::TreeIter> xChild(rTree.make_iterator(&rEntry)); |
467 | |
|
468 | 0 | if (!rTree.iter_children(*xChild)) |
469 | | // No more children. We're done. |
470 | 0 | return; |
471 | | |
472 | 0 | do |
473 | 0 | { |
474 | | // Walk recursively. |
475 | 0 | getFieldLinks(rRangeLink, rNamespaces, rTree, *xChild); |
476 | 0 | } |
477 | 0 | while (rTree.iter_next_sibling(*xChild)); |
478 | 0 | } |
479 | | |
480 | | void removeDuplicates(std::vector<size_t>& rArray) |
481 | 0 | { |
482 | 0 | std::sort(rArray.begin(), rArray.end()); |
483 | 0 | std::vector<size_t>::iterator it = std::unique(rArray.begin(), rArray.end()); |
484 | 0 | rArray.erase(it, rArray.end()); |
485 | 0 | } |
486 | | |
487 | | } |
488 | | |
489 | | void ScXMLSourceDlg::OkPressed() |
490 | 0 | { |
491 | 0 | if (!mpXMLContext) |
492 | 0 | return; |
493 | | |
494 | | // Begin import. |
495 | | |
496 | 0 | ScOrcusImportXMLParam aParam; |
497 | | |
498 | | // Convert single cell links. |
499 | 0 | for (const auto& rEntry : maCellLinks) |
500 | 0 | { |
501 | 0 | OUString aPath = getXPath(*mxLbTree, *rEntry, aParam.maNamespaces); |
502 | 0 | const ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(*mxLbTree, *rEntry); |
503 | |
|
504 | 0 | aParam.maCellLinks.emplace_back( |
505 | 0 | pUserData->maLinkedPos, OUStringToOString(aPath, RTL_TEXTENCODING_UTF8)); |
506 | 0 | } |
507 | | |
508 | | // Convert range links. For now, an element with range link takes all its |
509 | | // child elements as its fields. |
510 | 0 | for (const auto& rEntry: maRangeLinks) |
511 | 0 | { |
512 | 0 | const ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(*mxLbTree, *rEntry); |
513 | |
|
514 | 0 | ScOrcusImportXMLParam::RangeLink aRangeLink; |
515 | 0 | aRangeLink.maPos = pUserData->maLinkedPos; |
516 | | |
517 | | // Go through all its child elements. |
518 | 0 | getFieldLinks(aRangeLink, aParam.maNamespaces, *mxLbTree, *rEntry); |
519 | | |
520 | | // Add the reference entry as a row-group node, which will be used |
521 | | // as a row position increment point. |
522 | 0 | OUString aThisEntry = getXPath(*mxLbTree, *rEntry, aParam.maNamespaces); |
523 | 0 | aRangeLink.maRowGroups.push_back( |
524 | 0 | OUStringToOString(aThisEntry, RTL_TEXTENCODING_UTF8)); |
525 | |
|
526 | 0 | aParam.maRangeLinks.push_back(std::move(aRangeLink)); |
527 | 0 | } |
528 | | |
529 | | // Remove duplicate namespace IDs. |
530 | 0 | removeDuplicates(aParam.maNamespaces); |
531 | | |
532 | | // Now do the import. |
533 | 0 | mpXMLContext->importXML(aParam); |
534 | | |
535 | | // Don't forget to broadcast the change. |
536 | 0 | ScDocShell* pShell = mrDoc.GetDocumentShell(); |
537 | 0 | pShell->Broadcast(SfxHint(SfxHintId::ScDataChanged)); |
538 | | |
539 | | // Repaint the grid to force repaint the cell values. |
540 | 0 | ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); |
541 | 0 | if (pViewShell) |
542 | 0 | pViewShell->PaintGrid(); |
543 | |
|
544 | 0 | m_xDialog->response(RET_OK); |
545 | 0 | } |
546 | | |
547 | | void ScXMLSourceDlg::CancelPressed() |
548 | 0 | { |
549 | 0 | m_xDialog->response(RET_CANCEL); |
550 | 0 | } |
551 | | |
552 | | void ScXMLSourceDlg::RefEditModified() |
553 | 0 | { |
554 | 0 | OUString aRefStr = mxRefEdit->GetText(); |
555 | | |
556 | | // Check if the address is valid. |
557 | | // Preset current sheet in case only address was entered. |
558 | 0 | ScAddress aLinkedPos; |
559 | 0 | aLinkedPos.SetTab( ScDocShell::GetCurTab()); |
560 | 0 | ScRefFlags nRes = aLinkedPos.Parse(aRefStr, mrDoc, mrDoc.GetAddressConvention()); |
561 | 0 | bool bValid = ( (nRes & ScRefFlags::VALID) == ScRefFlags::VALID ); |
562 | | |
563 | | // TODO: For some unknown reason, setting the ref invalid will hide the text altogether. |
564 | | // Find out how to make this work. |
565 | | // mxRefEdit->SetRefValid(bValid); |
566 | |
|
567 | 0 | if (!bValid) |
568 | 0 | aLinkedPos.SetInvalid(); |
569 | | |
570 | | // Set this address to the current reference entry. |
571 | 0 | if (!mxCurRefEntry) |
572 | | // This should never happen. |
573 | 0 | return; |
574 | | |
575 | 0 | ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(*mxLbTree, *mxCurRefEntry); |
576 | 0 | if (!pUserData) |
577 | | // This should never happen either. |
578 | 0 | return; |
579 | | |
580 | 0 | bool bRepeatElem = pUserData->meType == ScOrcusXMLTreeParam::ElementRepeat; |
581 | 0 | pUserData->maLinkedPos = aLinkedPos; |
582 | 0 | pUserData->mbRangeParent = aLinkedPos.IsValid() && bRepeatElem; |
583 | |
|
584 | 0 | if (bRepeatElem) |
585 | 0 | { |
586 | 0 | if (bValid) |
587 | 0 | maRangeLinks.insert(mxLbTree->make_iterator(mxCurRefEntry.get())); |
588 | 0 | else |
589 | 0 | maRangeLinks.erase(mxCurRefEntry); |
590 | 0 | } |
591 | 0 | else |
592 | 0 | { |
593 | 0 | if (bValid) |
594 | 0 | maCellLinks.insert(mxLbTree->make_iterator(mxCurRefEntry.get())); |
595 | 0 | else |
596 | 0 | maCellLinks.erase(mxCurRefEntry); |
597 | 0 | } |
598 | | |
599 | | // Enable the import button only when at least one link exists. |
600 | 0 | bool bHasLink = !maCellLinks.empty() || !maRangeLinks.empty(); |
601 | 0 | mxBtnOk->set_sensitive(bHasLink); |
602 | 0 | } |
603 | | |
604 | | IMPL_LINK(ScXMLSourceDlg, BtnPressedHdl, weld::Button&, rBtn, void) |
605 | 0 | { |
606 | 0 | if (&rBtn == mxBtnSelectSource.get()) |
607 | 0 | SelectSourceFile(); |
608 | 0 | else if (&rBtn == mxBtnOk.get()) |
609 | 0 | OkPressed(); |
610 | 0 | else if (&rBtn == mxBtnCancel.get()) |
611 | 0 | CancelPressed(); |
612 | 0 | } |
613 | | |
614 | | IMPL_LINK_NOARG(ScXMLSourceDlg, TreeItemSelectHdl, weld::TreeView&, void) |
615 | 0 | { |
616 | 0 | TreeItemSelected(); |
617 | 0 | } |
618 | | |
619 | | IMPL_LINK_NOARG(ScXMLSourceDlg, RefModifiedHdl, formula::RefEdit&, void) |
620 | 0 | { |
621 | 0 | RefEditModified(); |
622 | 0 | } |
623 | | |
624 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |