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>
30 #include <cppuhelper/implbase.hxx>
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 
43 using namespace ::com::sun::star;
44 using namespace ::com::sun::star::uno;
45 using namespace ::com::sun::star::container;
46 using namespace ::com::sun::star::lang;
47 using namespace ::com::sun::star::sdb;
48 using namespace ::com::sun::star::sdbc;
49 using namespace ::com::sun::star::sdbcx;
50 using namespace ::com::sun::star::beans;
51 
52 class SwDBTreeList_Impl : public cppu::WeakImplHelper < XContainerListener >
53 {
54  Reference< XDatabaseContext > m_xDatabaseContext;
56 
57  public:
58  explicit SwDBTreeList_Impl()
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 
90 void SwDBTreeList_Impl::elementInserted( const ContainerEvent& )
91 {
92  // information not needed
93 }
94 
95 void SwDBTreeList_Impl::elementRemoved( const ContainerEvent& )
96 {
97 }
98 
99 void SwDBTreeList_Impl::disposing( const EventObject& )
100 {
101  m_xDatabaseContext = nullptr;
102 }
103 
104 void SwDBTreeList_Impl::elementReplaced( const ContainerEvent& rEvent )
105 {
106  elementRemoved(rEvent);
107 }
108 
110 {
111  if(!m_xDatabaseContext.is())
112  {
114  m_xDatabaseContext = DatabaseContext::create(xContext);
115  m_xDatabaseContext->addContainerListener( this );
116  }
117  return m_xDatabaseContext.is();
118 }
119 
121 {
123  if (m_xDatabaseContext.is() && m_pWrtShell)
124  {
125  xRet = m_pWrtShell->GetDBManager()->RegisterConnection(rSourceName);
126  }
127  return xRet;
128 }
129 
130 SwDBTreeList::SwDBTreeList(std::unique_ptr<weld::TreeView> xTreeView)
131  : bInitialized(false)
132  , bShowColumns(false)
133  , pImpl(new SwDBTreeList_Impl)
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 (!pImpl->HasContext() && pImpl->GetWrtShell())
147  return;
148 
149  Sequence< OUString > aDBNames = pImpl->GetContext()->getElementNames();
150  auto const sort = comphelper::string::NaturalStringSorter(
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  bInitialized = true;
174 }
175 
176 void 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 
183 IMPL_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(!pImpl->GetContext()->hasByName(sSourceName))
197  return true;
198  Reference<XConnection> xConnection = 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 (!pImpl->GetContext()->hasByName(sSourceName))
260  return true;
261  Reference<XConnection> xConnection = 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, 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, 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 
303 OUString 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
327 void 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 (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  pImpl->SetWrtShell(rSh);
404  if (m_xTreeView->get_visible() && !bInitialized)
405  InitTreeList();
406 }
407 
408 namespace
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 
417 void SwDBTreeList::ShowColumns(bool bShowCol)
418 {
419  if (bShowCol == bShowColumns)
420  return;
421 
422  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: */
virtual bool iter_parent(TreeIter &rIter) const =0
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:2330
const Color aColNames[SC_RANGECOLORS]
ULONG m_refCount
static const AllSettings & GetSettings()
void SetWrtShell(SwWrtShell &rSh)
Definition: dbtree.cxx:71
Reference< XDatabaseContext > m_xDatabaseContext
Definition: dbtree.cxx:54
virtual void SAL_CALL elementReplaced(const ContainerEvent &Event) override
Definition: dbtree.cxx:104
void Select(std::u16string_view rDBName, std::u16string_view rTableName, std::u16string_view rColumnName)
Definition: dbtree.cxx:327
float x
Used by the UI to modify the document model.
Definition: wrtsh.hxx:93
SwDBTreeList(std::unique_ptr< weld::TreeView > xTreeView)
Definition: dbtree.cxx:130
SwWrtShell * m_pWrtShell
Definition: dbtree.cxx:55
enumrange< T >::Iterator begin(enumrange< T >)
Reference< XConnection > GetConnection(const OUString &rSourceName)
Definition: dbtree.cxx:120
std::unique_ptr< weld::TreeView > m_xTreeView
Definition: dbtree.hxx:36
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:3078
float y
SwDBManager * GetDBManager() const
For evaluation of DB fields (new DB-manager).
Definition: edfld.cxx:327
SwWrtShell * GetWrtShell()
Definition: dbtree.cxx:70
const Reference< XDatabaseContext > & GetContext() const
Definition: dbtree.cxx:72
void SetWrtShell(SwWrtShell &rSh)
Definition: dbtree.cxx:401
float u
unsigned char sal_Bool
bool bShowColumns
Definition: dbtree.hxx:33
enumrange< T >::Iterator end(enumrange< T >)
const LanguageTag & getLocale()
rtl::Reference< SwDBTreeList_Impl > pImpl
Definition: dbtree.hxx:35
SAL_DLLPRIVATE void InitTreeList()
Definition: dbtree.cxx:144
void AddDataSource(const OUString &rSource)
Definition: dbtree.cxx:176
virtual void SAL_CALL elementInserted(const ContainerEvent &Event) override
Definition: dbtree.cxx:90
void ShowColumns(bool bShowCol)
Definition: dbtree.cxx:417
bool HasContext()
Definition: dbtree.cxx:109
virtual void SAL_CALL elementRemoved(const ContainerEvent &Event) override
Definition: dbtree.cxx:95
Reference< XComponentContext > getProcessComponentContext()
bool bInitialized
Definition: dbtree.hxx:32
std::unique_ptr< weld::TreeIter > m_xScratchIter
Definition: dbtree.hxx:37
virtual void SAL_CALL disposing(const EventObject &Source) override
Definition: dbtree.cxx:99
OUString GetDBName(OUString &rTableName, OUString &rColumnName, sal_Bool *pbIsTable=nullptr)
Definition: dbtree.cxx:303
virtual ~SwDBTreeList_Impl() override
Definition: dbtree.cxx:76
virtual int get_iter_depth(const TreeIter &rIter) const =0
IMPL_LINK(SwDBTreeList, RequestingChildrenHdl, const weld::TreeIter &, rParent, bool)
Definition: dbtree.cxx:183
OUString sId
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo