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