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  std::sort(
154  aDBNames.begin(), aDBNames.end(),
155  [&sort](OUString const & x, OUString const & y)
156  { return sort.compare(x, y) < 0; });
157 
158  OUString aImg(RID_BMP_DB);
159  for (const OUString& rDBName : std::as_const(aDBNames))
160  {
161  // If this database has a password or a (missing) remote connection,
162  // then it might take a long time or spam for unnecessary credentials.
163  // Just check that it basically exists to weed out any broken/obsolete registrations.
164  if (SwDBManager::getDataSourceAsParent(Reference<sdbc::XConnection>(), rDBName).is())
165  {
166  m_xTreeView->insert(nullptr, -1, &rDBName, nullptr, nullptr, nullptr, true, m_xScratchIter.get());
167  m_xTreeView->set_image(*m_xScratchIter, aImg);
168  }
169  }
170  Select(u"", u"", u"");
171 
172  bInitialized = true;
173 }
174 
175 void SwDBTreeList::AddDataSource(const OUString& rSource)
176 {
177  m_xTreeView->insert(nullptr, -1, &rSource, nullptr, nullptr, nullptr, true, m_xScratchIter.get());
178  m_xTreeView->set_image(*m_xScratchIter, RID_BMP_DB);
179  m_xTreeView->select(*m_xScratchIter);
180 }
181 
182 IMPL_LINK(SwDBTreeList, RequestingChildrenHdl, const weld::TreeIter&, rParent, bool)
183 {
184  if (!m_xTreeView->iter_has_child(rParent))
185  {
186  if (m_xTreeView->get_iter_depth(rParent)) // column names
187  {
188  try
189  {
190  std::unique_ptr<weld::TreeIter> xGrandParent(m_xTreeView->make_iterator(&rParent));
191  m_xTreeView->iter_parent(*xGrandParent);
192  OUString sSourceName = m_xTreeView->get_text(*xGrandParent);
193  OUString sTableName = m_xTreeView->get_text(rParent);
194 
195  if(!pImpl->GetContext()->hasByName(sSourceName))
196  return true;
197  Reference<XConnection> xConnection = pImpl->GetConnection(sSourceName);
198  bool bTable = m_xTreeView->get_id(rParent).isEmpty();
199  Reference<XColumnsSupplier> xColsSupplier;
200  if(bTable)
201  {
202  Reference<XTablesSupplier> xTSupplier(xConnection, UNO_QUERY);
203  if(xTSupplier.is())
204  {
205  Reference<XNameAccess> xTables = xTSupplier->getTables();
206  OSL_ENSURE(xTables->hasByName(sTableName), "table not available anymore?");
207  try
208  {
209  Any aTable = xTables->getByName(sTableName);
210  Reference<XPropertySet> xPropSet;
211  aTable >>= xPropSet;
212  xColsSupplier.set(xPropSet, UNO_QUERY);
213  }
214  catch (const Exception&)
215  {
216  }
217  }
218  }
219  else
220  {
221  Reference<XQueriesSupplier> xQSupplier(xConnection, UNO_QUERY);
222  if(xQSupplier.is())
223  {
224  Reference<XNameAccess> xQueries = xQSupplier->getQueries();
225  OSL_ENSURE(xQueries->hasByName(sTableName), "table not available anymore?");
226  try
227  {
228  Any aQuery = xQueries->getByName(sTableName);
229  Reference<XPropertySet> xPropSet;
230  aQuery >>= xPropSet;
231  xColsSupplier.set(xPropSet, UNO_QUERY);
232  }
233  catch (const Exception&)
234  {
235  }
236  }
237  }
238 
239  if(xColsSupplier.is())
240  {
241  Reference <XNameAccess> xCols = xColsSupplier->getColumns();
242  const Sequence< OUString> aColNames = xCols->getElementNames();
243  for (const OUString& rColName : aColNames)
244  {
245  m_xTreeView->append(&rParent, rColName);
246  }
247  }
248  }
249  catch (const Exception&)
250  {
251  }
252  }
253  else // table names
254  {
255  try
256  {
257  OUString sSourceName = m_xTreeView->get_text(rParent);
258  if (!pImpl->GetContext()->hasByName(sSourceName))
259  return true;
260  Reference<XConnection> xConnection = pImpl->GetConnection(sSourceName);
261  if (xConnection.is())
262  {
263  Reference<XTablesSupplier> xTSupplier(xConnection, UNO_QUERY);
264  if(xTSupplier.is())
265  {
266  Reference<XNameAccess> xTables = xTSupplier->getTables();
267  const Sequence< OUString> aTableNames = xTables->getElementNames();
268  OUString aImg(RID_BMP_DBTABLE);
269  for (const OUString& rTableName : aTableNames)
270  {
271  m_xTreeView->insert(&rParent, -1, &rTableName, nullptr,
272  nullptr, nullptr, bShowColumns, m_xScratchIter.get());
273  m_xTreeView->set_image(*m_xScratchIter, aImg);
274  }
275  }
276 
277  Reference<XQueriesSupplier> xQSupplier(xConnection, UNO_QUERY);
278  if(xQSupplier.is())
279  {
280  Reference<XNameAccess> xQueries = xQSupplier->getQueries();
281  const Sequence< OUString> aQueryNames = xQueries->getElementNames();
282  OUString aImg(RID_BMP_DBQUERY);
283  for (const OUString& rQueryName : aQueryNames)
284  {
285  //to discriminate between queries and tables the user data of query entries is set
286  OUString sId(OUString::number(1));
287  m_xTreeView->insert(&rParent, -1, &rQueryName, &sId,
288  nullptr, nullptr, bShowColumns, m_xScratchIter.get());
289  m_xTreeView->set_image(*m_xScratchIter, aImg);
290  }
291  }
292  }
293  }
294  catch (const Exception&)
295  {
296  }
297  }
298  }
299  return true;
300 }
301 
302 OUString SwDBTreeList::GetDBName(OUString& rTableName, OUString& rColumnName, sal_Bool* pbIsTable)
303 {
304  OUString sDBName;
305  std::unique_ptr<weld::TreeIter> xIter(m_xTreeView->make_iterator());
306  if (m_xTreeView->get_selected(xIter.get()))
307  {
308  if (m_xTreeView->get_iter_depth(*xIter) == 2)
309  {
310  rColumnName = m_xTreeView->get_text(*xIter);
311  m_xTreeView->iter_parent(*xIter); // column name was selected
312  }
313  if (m_xTreeView->get_iter_depth(*xIter) == 1)
314  {
315  if (pbIsTable)
316  *pbIsTable = m_xTreeView->get_id(*xIter).isEmpty();
317  rTableName = m_xTreeView->get_text(*xIter);
318  m_xTreeView->iter_parent(*xIter);
319  }
320  sDBName = m_xTreeView->get_text(*xIter);
321  }
322  return sDBName;
323 }
324 
325 // Format: database.table
326 void SwDBTreeList::Select(std::u16string_view rDBName, std::u16string_view rTableName, std::u16string_view rColumnName)
327 {
328  std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator());
329  if (!m_xTreeView->get_iter_first(*xParent))
330  return;
331 
332  do
333  {
334  if (rDBName == m_xTreeView->get_text(*xParent))
335  {
336  if (rTableName.empty() && rColumnName.empty())
337  {
338  // Just select the database node, do not expand
339  m_xTreeView->scroll_to_row(*xParent);
340  m_xTreeView->select(*xParent);
341  return;
342  }
343  if (!m_xTreeView->iter_has_child(*xParent))
344  {
345  RequestingChildrenHdl(*xParent);
346  // If successful, it will be expanded in a call to scroll_to_row for its children
347  }
348  std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(xParent.get()));
349  if (!m_xTreeView->iter_children(*xChild))
350  {
351  m_xTreeView->scroll_to_row(*xParent);
352  m_xTreeView->select(*xParent);
353  continue;
354  }
355  do
356  {
357  if (rTableName == m_xTreeView->get_text(*xChild))
358  {
359  m_xTreeView->copy_iterator(*xChild, *xParent);
360 
361  bool bNoChild = false;
362  if (bShowColumns && !rColumnName.empty())
363  {
364  if (!m_xTreeView->iter_has_child(*xParent))
365  {
366  RequestingChildrenHdl(*xParent);
367  m_xTreeView->expand_row(*xParent);
368  }
369 
370  bNoChild = true;
371  if (m_xTreeView->iter_children(*xChild))
372  {
373  do
374  {
375  if (rColumnName == m_xTreeView->get_text(*xChild))
376  {
377  bNoChild = false;
378  break;
379  }
380  }
381  while (m_xTreeView->iter_next_sibling(*xChild));
382  }
383  }
384 
385  if (bNoChild)
386  m_xTreeView->copy_iterator(*xParent, *xChild);
387 
388  m_xTreeView->scroll_to_row(*xChild);
389  m_xTreeView->select(*xChild);
390  return;
391  }
392  }
393  while (m_xTreeView->iter_next_sibling(*xChild));
394  }
395  } while (m_xTreeView->iter_next_sibling(*xParent));
396 }
397 
399 {
400  pImpl->SetWrtShell(rSh);
401  if (m_xTreeView->get_visible() && !bInitialized)
402  InitTreeList();
403 }
404 
405 namespace
406 {
407  void GotoRootLevelParent(const weld::TreeView& rTreeView, weld::TreeIter& rEntry)
408  {
409  while (rTreeView.get_iter_depth(rEntry))
410  rTreeView.iter_parent(rEntry);
411  }
412 }
413 
414 void SwDBTreeList::ShowColumns(bool bShowCol)
415 {
416  if (bShowCol == bShowColumns)
417  return;
418 
419  bShowColumns = bShowCol;
420  OUString sTableName;
421  OUString sColumnName;
422  const OUString sDBName(GetDBName(sTableName, sColumnName));
423 
424  m_xTreeView->freeze();
425 
426  std::unique_ptr<weld::TreeIter> xIter(m_xTreeView->make_iterator());
427  std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator());
428  if (m_xTreeView->get_iter_first(*xIter))
429  {
430  do
431  {
432  GotoRootLevelParent(*m_xTreeView, *xIter);
433  m_xTreeView->collapse_row(*xIter);
434  while (m_xTreeView->iter_has_child(*xIter))
435  {
436  m_xTreeView->copy_iterator(*xIter, *xChild);
437  (void)m_xTreeView->iter_children(*xChild);
438  m_xTreeView->remove(*xChild);
439  }
440  } while (m_xTreeView->iter_next(*xIter));
441  }
442 
443  m_xTreeView->thaw();
444 
445  if (!sDBName.isEmpty())
446  {
447  Select(sDBName, sTableName, sColumnName); // force RequestingChildren
448  }
449 }
450 
451 /* 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:2332
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:326
float x
Used by the UI to modify the document model.
Definition: wrtsh.hxx:91
SwDBTreeList(std::unique_ptr< weld::TreeView > xTreeView)
Definition: dbtree.cxx:130
SwWrtShell * m_pWrtShell
Definition: dbtree.cxx:55
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:3081
float y
SwDBManager * GetDBManager() const
For evaluation of DB fields (new DB-manager).
Definition: edfld.cxx:326
SwWrtShell * GetWrtShell()
Definition: dbtree.cxx:70
const Reference< XDatabaseContext > & GetContext() const
Definition: dbtree.cxx:72
void SetWrtShell(SwWrtShell &rSh)
Definition: dbtree.cxx:398
float u
unsigned char sal_Bool
bool bShowColumns
Definition: dbtree.hxx:33
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:175
virtual void SAL_CALL elementInserted(const ContainerEvent &Event) override
Definition: dbtree.cxx:90
void ShowColumns(bool bShowCol)
Definition: dbtree.cxx:414
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
OUString sId
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:302
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:182
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo