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