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