LibreOffice Module sw (master) 1
dbtree.cxx
Go to the documentation of this file.
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 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <com/sun/star/container/XNameAccess.hpp>
21#include <com/sun/star/sdbc/XConnection.hpp>
22#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
23#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
24#include <com/sun/star/sdb/DatabaseContext.hpp>
25#include <com/sun/star/sdb/XQueriesSupplier.hpp>
26#include <com/sun/star/beans/XPropertySet.hpp>
28#include <comphelper/string.hxx>
29#include <com/sun/star/container/XContainerListener.hpp>
32#include <osl/diagnose.h>
33
34#include <dbmgr.hxx>
35#include <wrtsh.hxx>
36#include <dbtree.hxx>
37#include <vcl/settings.hxx>
38#include <vcl/svapp.hxx>
39
40#include <bitmaps.hlst>
41
42
43using namespace ::com::sun::star;
44using namespace ::com::sun::star::uno;
45using namespace ::com::sun::star::container;
46using namespace ::com::sun::star::lang;
47using namespace ::com::sun::star::sdb;
48using namespace ::com::sun::star::sdbc;
49using namespace ::com::sun::star::sdbcx;
50using namespace ::com::sun::star::beans;
51
52class SwDBTreeList_Impl : public cppu::WeakImplHelper < XContainerListener >
53{
54 Reference< XDatabaseContext > m_xDatabaseContext;
56
57 public:
59 : m_pWrtShell(nullptr)
60 {
61 }
62 virtual ~SwDBTreeList_Impl() override;
63
64 virtual void SAL_CALL elementInserted( const ContainerEvent& Event ) override;
65 virtual void SAL_CALL elementRemoved( const ContainerEvent& Event ) override;
66 virtual void SAL_CALL elementReplaced( const ContainerEvent& Event ) override;
67 virtual void SAL_CALL disposing( const EventObject& Source ) override;
68
69 bool HasContext();
71 void SetWrtShell(SwWrtShell& rSh) { m_pWrtShell = &rSh;}
72 const Reference<XDatabaseContext>& GetContext() const {return m_xDatabaseContext;}
73 Reference<XConnection> GetConnection(const OUString& rSourceName);
74};
75
77{
78 if(m_xDatabaseContext.is())
79 {
80 osl_atomic_increment(&m_refCount);
81 //block necessary due to solaris' compiler behaviour to
82 //remove temporaries at the block's end
83 {
84 m_xDatabaseContext->removeContainerListener( this );
85 }
86 osl_atomic_decrement(&m_refCount);
87 }
88}
89
90void SwDBTreeList_Impl::elementInserted( const ContainerEvent& )
91{
92 // information not needed
93}
94
95void SwDBTreeList_Impl::elementRemoved( const ContainerEvent& )
96{
97}
98
99void SwDBTreeList_Impl::disposing( const EventObject& )
100{
101 m_xDatabaseContext = nullptr;
102}
103
104void SwDBTreeList_Impl::elementReplaced( const ContainerEvent& rEvent )
105{
106 elementRemoved(rEvent);
107}
108
110{
111 if(!m_xDatabaseContext.is())
112 {
113 Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
114 m_xDatabaseContext = DatabaseContext::create(xContext);
115 m_xDatabaseContext->addContainerListener( this );
116 }
117 return m_xDatabaseContext.is();
118}
119
120Reference<XConnection> SwDBTreeList_Impl::GetConnection(const OUString& rSourceName)
121{
122 Reference<XConnection> xRet;
124 {
125 xRet = m_pWrtShell->GetDBManager()->RegisterConnection(rSourceName);
126 }
127 return xRet;
128}
129
130SwDBTreeList::SwDBTreeList(std::unique_ptr<weld::TreeView> xTreeView)
131 : m_bInitialized(false)
132 , m_bShowColumns(false)
134 , m_xTreeView(std::move(xTreeView))
135 , m_xScratchIter(m_xTreeView->make_iterator())
136{
137 m_xTreeView->connect_expanding(LINK(this, SwDBTreeList, RequestingChildrenHdl));
138}
139
141{
142}
143
145{
146 if (!m_pImpl->HasContext() && m_pImpl->GetWrtShell())
147 return;
148
149 Sequence< OUString > aDBNames = m_pImpl->GetContext()->getElementNames();
152 Application::GetSettings().GetUILanguageTag().getLocale());
153 auto [begin, end] = asNonConstRange(aDBNames);
154 std::sort(
155 begin, end,
156 [&sort](OUString const & x, OUString const & y)
157 { return sort.compare(x, y) < 0; });
158
159 OUString aImg(RID_BMP_DB);
160 for (const OUString& rDBName : std::as_const(aDBNames))
161 {
162 // If this database has a password or a (missing) remote connection,
163 // then it might take a long time or spam for unnecessary credentials.
164 // Just check that it basically exists to weed out any broken/obsolete registrations.
165 if (SwDBManager::getDataSourceAsParent(Reference<sdbc::XConnection>(), rDBName).is())
166 {
167 m_xTreeView->insert(nullptr, -1, &rDBName, nullptr, nullptr, nullptr, true, m_xScratchIter.get());
168 m_xTreeView->set_image(*m_xScratchIter, aImg);
169 }
170 }
171 Select(u"", u"", u"");
172
173 m_bInitialized = true;
174}
175
176void SwDBTreeList::AddDataSource(const OUString& rSource)
177{
178 m_xTreeView->insert(nullptr, -1, &rSource, nullptr, nullptr, nullptr, true, m_xScratchIter.get());
179 m_xTreeView->set_image(*m_xScratchIter, RID_BMP_DB);
180 m_xTreeView->select(*m_xScratchIter);
181}
182
183IMPL_LINK(SwDBTreeList, RequestingChildrenHdl, const weld::TreeIter&, rParent, bool)
184{
185 if (!m_xTreeView->iter_has_child(rParent))
186 {
187 if (m_xTreeView->get_iter_depth(rParent)) // column names
188 {
189 try
190 {
191 std::unique_ptr<weld::TreeIter> xGrandParent(m_xTreeView->make_iterator(&rParent));
192 m_xTreeView->iter_parent(*xGrandParent);
193 OUString sSourceName = m_xTreeView->get_text(*xGrandParent);
194 OUString sTableName = m_xTreeView->get_text(rParent);
195
196 if(!m_pImpl->GetContext()->hasByName(sSourceName))
197 return true;
198 Reference<XConnection> xConnection = m_pImpl->GetConnection(sSourceName);
199 bool bTable = m_xTreeView->get_id(rParent).isEmpty();
200 Reference<XColumnsSupplier> xColsSupplier;
201 if(bTable)
202 {
203 Reference<XTablesSupplier> xTSupplier(xConnection, UNO_QUERY);
204 if(xTSupplier.is())
205 {
206 Reference<XNameAccess> xTables = xTSupplier->getTables();
207 OSL_ENSURE(xTables->hasByName(sTableName), "table not available anymore?");
208 try
209 {
210 Any aTable = xTables->getByName(sTableName);
211 Reference<XPropertySet> xPropSet;
212 aTable >>= xPropSet;
213 xColsSupplier.set(xPropSet, UNO_QUERY);
214 }
215 catch (const Exception&)
216 {
217 }
218 }
219 }
220 else
221 {
222 Reference<XQueriesSupplier> xQSupplier(xConnection, UNO_QUERY);
223 if(xQSupplier.is())
224 {
225 Reference<XNameAccess> xQueries = xQSupplier->getQueries();
226 OSL_ENSURE(xQueries->hasByName(sTableName), "table not available anymore?");
227 try
228 {
229 Any aQuery = xQueries->getByName(sTableName);
230 Reference<XPropertySet> xPropSet;
231 aQuery >>= xPropSet;
232 xColsSupplier.set(xPropSet, UNO_QUERY);
233 }
234 catch (const Exception&)
235 {
236 }
237 }
238 }
239
240 if(xColsSupplier.is())
241 {
242 Reference <XNameAccess> xCols = xColsSupplier->getColumns();
243 const Sequence< OUString> aColNames = xCols->getElementNames();
244 for (const OUString& rColName : aColNames)
245 {
246 m_xTreeView->append(&rParent, rColName);
247 }
248 }
249 }
250 catch (const Exception&)
251 {
252 }
253 }
254 else // table names
255 {
256 try
257 {
258 OUString sSourceName = m_xTreeView->get_text(rParent);
259 if (!m_pImpl->GetContext()->hasByName(sSourceName))
260 return true;
261 Reference<XConnection> xConnection = m_pImpl->GetConnection(sSourceName);
262 if (xConnection.is())
263 {
264 Reference<XTablesSupplier> xTSupplier(xConnection, UNO_QUERY);
265 if(xTSupplier.is())
266 {
267 Reference<XNameAccess> xTables = xTSupplier->getTables();
268 const Sequence< OUString> aTableNames = xTables->getElementNames();
269 OUString aImg(RID_BMP_DBTABLE);
270 for (const OUString& rTableName : aTableNames)
271 {
272 m_xTreeView->insert(&rParent, -1, &rTableName, nullptr,
273 nullptr, nullptr, m_bShowColumns, m_xScratchIter.get());
274 m_xTreeView->set_image(*m_xScratchIter, aImg);
275 }
276 }
277
278 Reference<XQueriesSupplier> xQSupplier(xConnection, UNO_QUERY);
279 if(xQSupplier.is())
280 {
281 Reference<XNameAccess> xQueries = xQSupplier->getQueries();
282 const Sequence< OUString> aQueryNames = xQueries->getElementNames();
283 OUString aImg(RID_BMP_DBQUERY);
284 for (const OUString& rQueryName : aQueryNames)
285 {
286 //to discriminate between queries and tables the user data of query entries is set
287 OUString sId(OUString::number(1));
288 m_xTreeView->insert(&rParent, -1, &rQueryName, &sId,
289 nullptr, nullptr, m_bShowColumns, m_xScratchIter.get());
290 m_xTreeView->set_image(*m_xScratchIter, aImg);
291 }
292 }
293 }
294 }
295 catch (const Exception&)
296 {
297 }
298 }
299 }
300 return true;
301}
302
303OUString SwDBTreeList::GetDBName(OUString& rTableName, OUString& rColumnName, sal_Bool* pbIsTable)
304{
305 OUString sDBName;
306 std::unique_ptr<weld::TreeIter> xIter(m_xTreeView->make_iterator());
307 if (m_xTreeView->get_selected(xIter.get()))
308 {
309 if (m_xTreeView->get_iter_depth(*xIter) == 2)
310 {
311 rColumnName = m_xTreeView->get_text(*xIter);
312 m_xTreeView->iter_parent(*xIter); // column name was selected
313 }
314 if (m_xTreeView->get_iter_depth(*xIter) == 1)
315 {
316 if (pbIsTable)
317 *pbIsTable = m_xTreeView->get_id(*xIter).isEmpty();
318 rTableName = m_xTreeView->get_text(*xIter);
319 m_xTreeView->iter_parent(*xIter);
320 }
321 sDBName = m_xTreeView->get_text(*xIter);
322 }
323 return sDBName;
324}
325
326// Format: database.table
327void SwDBTreeList::Select(std::u16string_view rDBName, std::u16string_view rTableName, std::u16string_view rColumnName)
328{
329 std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator());
330 if (!m_xTreeView->get_iter_first(*xParent))
331 return;
332
333 do
334 {
335 if (rDBName == m_xTreeView->get_text(*xParent))
336 {
337 if (rTableName.empty() && rColumnName.empty())
338 {
339 // Just select the database node, do not expand
340 m_xTreeView->scroll_to_row(*xParent);
341 m_xTreeView->select(*xParent);
342 return;
343 }
344 if (!m_xTreeView->iter_has_child(*xParent))
345 {
346 m_xTreeView->set_children_on_demand(*xParent, false); // tdf#142294 drop placeholder on-demand node
347 RequestingChildrenHdl(*xParent);
348 // If successful, it will be expanded in a call to scroll_to_row for its children
349 }
350 std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(xParent.get()));
351 if (!m_xTreeView->iter_children(*xChild))
352 {
353 m_xTreeView->scroll_to_row(*xParent);
354 m_xTreeView->select(*xParent);
355 continue;
356 }
357 do
358 {
359 if (rTableName == m_xTreeView->get_text(*xChild))
360 {
361 m_xTreeView->copy_iterator(*xChild, *xParent);
362
363 bool bNoChild = false;
364 if (m_bShowColumns && !rColumnName.empty())
365 {
366 if (!m_xTreeView->iter_has_child(*xParent))
367 {
368 m_xTreeView->set_children_on_demand(*xParent, false); // tdf#142294 drop placeholder on-demand node
369 RequestingChildrenHdl(*xParent);
370 m_xTreeView->expand_row(*xParent);
371 }
372
373 bNoChild = true;
374 if (m_xTreeView->iter_children(*xChild))
375 {
376 do
377 {
378 if (rColumnName == m_xTreeView->get_text(*xChild))
379 {
380 bNoChild = false;
381 break;
382 }
383 }
384 while (m_xTreeView->iter_next_sibling(*xChild));
385 }
386 }
387
388 if (bNoChild)
389 m_xTreeView->copy_iterator(*xParent, *xChild);
390
391 m_xTreeView->scroll_to_row(*xChild);
392 m_xTreeView->select(*xChild);
393 return;
394 }
395 }
396 while (m_xTreeView->iter_next_sibling(*xChild));
397 }
398 } while (m_xTreeView->iter_next_sibling(*xParent));
399}
400
402{
403 m_pImpl->SetWrtShell(rSh);
404 if (m_xTreeView->get_visible() && !m_bInitialized)
405 InitTreeList();
406}
407
408namespace
409{
410 void GotoRootLevelParent(const weld::TreeView& rTreeView, weld::TreeIter& rEntry)
411 {
412 while (rTreeView.get_iter_depth(rEntry))
413 rTreeView.iter_parent(rEntry);
414 }
415}
416
417void SwDBTreeList::ShowColumns(bool bShowCol)
418{
419 if (bShowCol == m_bShowColumns)
420 return;
421
422 m_bShowColumns = bShowCol;
423 OUString sTableName;
424 OUString sColumnName;
425 const OUString sDBName(GetDBName(sTableName, sColumnName));
426
427 m_xTreeView->freeze();
428
429 std::unique_ptr<weld::TreeIter> xIter(m_xTreeView->make_iterator());
430 std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator());
431 if (m_xTreeView->get_iter_first(*xIter))
432 {
433 do
434 {
435 GotoRootLevelParent(*m_xTreeView, *xIter);
436 m_xTreeView->collapse_row(*xIter);
437 while (m_xTreeView->iter_has_child(*xIter))
438 {
439 m_xTreeView->copy_iterator(*xIter, *xChild);
440 (void)m_xTreeView->iter_children(*xChild);
441 m_xTreeView->remove(*xChild);
442 }
443 } while (m_xTreeView->iter_next(*xIter));
444 }
445
446 m_xTreeView->thaw();
447
448 if (!sDBName.isEmpty())
449 {
450 Select(sDBName, sTableName, sColumnName); // force RequestingChildren
451 }
452}
453
454/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
::std::unique_ptr< XmlIdRegistry_Impl > m_pImpl
static const AllSettings & GetSettings()
css::uno::Reference< css::sdbc::XConnection > const & RegisterConnection(OUString const &rSource)
create and store or find an already stored connection to a data source for use in SwFieldMgr and SwDB...
Definition: dbmgr.cxx:2357
static css::uno::Reference< css::sdbc::XDataSource > getDataSourceAsParent(const css::uno::Reference< css::sdbc::XConnection > &_xConnection, const OUString &_sDataSourceName)
try to get the data source from the given connection through the XChild interface.
Definition: dbmgr.cxx:3092
SwWrtShell * m_pWrtShell
Definition: dbtree.cxx:55
SwWrtShell * GetWrtShell()
Definition: dbtree.cxx:70
void SetWrtShell(SwWrtShell &rSh)
Definition: dbtree.cxx:71
virtual void SAL_CALL elementRemoved(const ContainerEvent &Event) override
Definition: dbtree.cxx:95
virtual ~SwDBTreeList_Impl() override
Definition: dbtree.cxx:76
Reference< XConnection > GetConnection(const OUString &rSourceName)
Definition: dbtree.cxx:120
virtual void SAL_CALL elementReplaced(const ContainerEvent &Event) override
Definition: dbtree.cxx:104
Reference< XDatabaseContext > m_xDatabaseContext
Definition: dbtree.cxx:54
bool HasContext()
Definition: dbtree.cxx:109
virtual void SAL_CALL elementInserted(const ContainerEvent &Event) override
Definition: dbtree.cxx:90
const Reference< XDatabaseContext > & GetContext() const
Definition: dbtree.cxx:72
virtual void SAL_CALL disposing(const EventObject &Source) override
Definition: dbtree.cxx:99
void AddDataSource(const OUString &rSource)
Definition: dbtree.cxx:176
SwDBTreeList(std::unique_ptr< weld::TreeView > xTreeView)
Definition: dbtree.cxx:130
bool m_bInitialized
Definition: dbtree.hxx:32
SAL_DLLPRIVATE void InitTreeList()
Definition: dbtree.cxx:144
void Select(std::u16string_view rDBName, std::u16string_view rTableName, std::u16string_view rColumnName)
Definition: dbtree.cxx:327
void ShowColumns(bool bShowCol)
Definition: dbtree.cxx:417
void SetWrtShell(SwWrtShell &rSh)
Definition: dbtree.cxx:401
rtl::Reference< SwDBTreeList_Impl > m_pImpl
Definition: dbtree.hxx:35
std::unique_ptr< weld::TreeIter > m_xScratchIter
Definition: dbtree.hxx:37
OUString GetDBName(OUString &rTableName, OUString &rColumnName, sal_Bool *pbIsTable=nullptr)
Definition: dbtree.cxx:303
std::unique_ptr< weld::TreeView > m_xTreeView
Definition: dbtree.hxx:36
bool m_bShowColumns
Definition: dbtree.hxx:33
SwDBManager * GetDBManager() const
For evaluation of DB fields (new DB-manager).
Definition: edfld.cxx:329
Used by the UI to modify the document model.
Definition: wrtsh.hxx:97
virtual bool iter_parent(TreeIter &rIter) const=0
virtual int get_iter_depth(const TreeIter &rIter) const=0
IMPL_LINK(SwDBTreeList, RequestingChildrenHdl, const weld::TreeIter &, rParent, bool)
Definition: dbtree.cxx:183
ULONG m_refCount
float u
float y
float x
@ Exception
const LanguageTag & getLocale()
Reference< XComponentContext > getProcessComponentContext()
enumrange< T >::Iterator begin(enumrange< T >)
end
const Color aColNames[SC_RANGECOLORS]
unsigned char sal_Bool
OUString sId