Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / uibase / dbui / dbtree.cxx
blob432a0a28e68bc0cd0e6f0c6f7716bb8627df2184
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
27 #include <comphelper/processfactory.hxx>
28 #include <comphelper/string.hxx>
29 #include <com/sun/star/container/XContainerListener.hpp>
30 #include <cppuhelper/implbase.hxx>
31 #include <i18nlangtag/languagetag.hxx>
32 #include <osl/diagnose.h>
34 #include <dbmgr.hxx>
35 #include <wrtsh.hxx>
36 #include <dbtree.hxx>
37 #include <vcl/settings.hxx>
38 #include <vcl/svapp.hxx>
40 #include <bitmaps.hlst>
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;
52 class SwDBTreeList_Impl : public cppu::WeakImplHelper < XContainerListener >
54 Reference< XDatabaseContext > m_xDatabaseContext;
55 SwWrtShell* m_pWrtShell;
57 public:
58 explicit SwDBTreeList_Impl()
59 : m_pWrtShell(nullptr)
62 virtual ~SwDBTreeList_Impl() override;
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;
69 bool HasContext();
70 SwWrtShell* GetWrtShell() { return m_pWrtShell;}
71 void SetWrtShell(SwWrtShell& rSh) { m_pWrtShell = &rSh;}
72 const Reference<XDatabaseContext>& GetContext() const {return m_xDatabaseContext;}
73 Reference<XConnection> GetConnection(const OUString& rSourceName);
76 SwDBTreeList_Impl::~SwDBTreeList_Impl()
78 if(m_xDatabaseContext.is())
80 osl_atomic_increment(&m_refCount);
81 //block necessary due to solaris' compiler behaviour to
82 //remove temporaries at the block's end
84 m_xDatabaseContext->removeContainerListener( this );
86 osl_atomic_decrement(&m_refCount);
90 void SwDBTreeList_Impl::elementInserted( const ContainerEvent& )
92 // information not needed
95 void SwDBTreeList_Impl::elementRemoved( const ContainerEvent& )
99 void SwDBTreeList_Impl::disposing( const EventObject& )
101 m_xDatabaseContext = nullptr;
104 void SwDBTreeList_Impl::elementReplaced( const ContainerEvent& rEvent )
106 elementRemoved(rEvent);
109 bool SwDBTreeList_Impl::HasContext()
111 if(!m_xDatabaseContext.is())
113 Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
114 m_xDatabaseContext = DatabaseContext::create(xContext);
115 m_xDatabaseContext->addContainerListener( this );
117 return m_xDatabaseContext.is();
120 Reference<XConnection> SwDBTreeList_Impl::GetConnection(const OUString& rSourceName)
122 Reference<XConnection> xRet;
123 if (m_xDatabaseContext.is() && m_pWrtShell)
125 xRet = m_pWrtShell->GetDBManager()->RegisterConnection(rSourceName);
127 return xRet;
130 SwDBTreeList::SwDBTreeList(std::unique_ptr<weld::TreeView> xTreeView)
131 : m_bInitialized(false)
132 , m_bShowColumns(false)
133 , m_pImpl(new SwDBTreeList_Impl)
134 , m_xTreeView(std::move(xTreeView))
135 , m_xScratchIter(m_xTreeView->make_iterator())
137 m_xTreeView->connect_expanding(LINK(this, SwDBTreeList, RequestingChildrenHdl));
140 SwDBTreeList::~SwDBTreeList()
144 void SwDBTreeList::InitTreeList()
146 if (!m_pImpl->HasContext() && m_pImpl->GetWrtShell())
147 return;
149 Sequence< OUString > aDBNames = m_pImpl->GetContext()->getElementNames();
150 auto const sort = comphelper::string::NaturalStringSorter(
151 comphelper::getProcessComponentContext(),
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; });
159 OUString aImg(RID_BMP_DB);
160 for (const OUString& rDBName : std::as_const(aDBNames))
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())
167 m_xTreeView->insert(nullptr, -1, &rDBName, nullptr, nullptr, nullptr, true, m_xScratchIter.get());
168 m_xTreeView->set_image(*m_xScratchIter, aImg);
171 Select(u"", u"", u"");
173 m_bInitialized = true;
176 void SwDBTreeList::AddDataSource(const OUString& rSource)
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);
183 IMPL_LINK(SwDBTreeList, RequestingChildrenHdl, const weld::TreeIter&, rParent, bool)
185 if (!m_xTreeView->iter_has_child(rParent))
187 if (m_xTreeView->get_iter_depth(rParent)) // column names
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);
196 if(!m_pImpl->GetContext()->hasByName(sSourceName))
197 return true;
198 Reference<XConnection> xConnection = m_pImpl->GetConnection(sSourceName);
199 bool bTable = m_xTreeView->get_id(rParent).isEmpty();
200 Reference<XColumnsSupplier> xColsSupplier;
201 if(bTable)
203 Reference<XTablesSupplier> xTSupplier(xConnection, UNO_QUERY);
204 if(xTSupplier.is())
206 Reference<XNameAccess> xTables = xTSupplier->getTables();
207 OSL_ENSURE(xTables->hasByName(sTableName), "table not available anymore?");
210 Any aTable = xTables->getByName(sTableName);
211 Reference<XPropertySet> xPropSet;
212 aTable >>= xPropSet;
213 xColsSupplier.set(xPropSet, UNO_QUERY);
215 catch (const Exception&)
220 else
222 Reference<XQueriesSupplier> xQSupplier(xConnection, UNO_QUERY);
223 if(xQSupplier.is())
225 Reference<XNameAccess> xQueries = xQSupplier->getQueries();
226 OSL_ENSURE(xQueries->hasByName(sTableName), "table not available anymore?");
229 Any aQuery = xQueries->getByName(sTableName);
230 Reference<XPropertySet> xPropSet;
231 aQuery >>= xPropSet;
232 xColsSupplier.set(xPropSet, UNO_QUERY);
234 catch (const Exception&)
240 if(xColsSupplier.is())
242 Reference <XNameAccess> xCols = xColsSupplier->getColumns();
243 const Sequence< OUString> aColNames = xCols->getElementNames();
244 for (const OUString& rColName : aColNames)
246 m_xTreeView->append(&rParent, rColName);
250 catch (const Exception&)
254 else // table names
258 OUString sSourceName = m_xTreeView->get_text(rParent);
259 if (!m_pImpl->GetContext()->hasByName(sSourceName))
260 return true;
261 Reference<XConnection> xConnection = m_pImpl->GetConnection(sSourceName);
262 if (xConnection.is())
264 Reference<XTablesSupplier> xTSupplier(xConnection, UNO_QUERY);
265 if(xTSupplier.is())
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)
272 m_xTreeView->insert(&rParent, -1, &rTableName, nullptr,
273 nullptr, nullptr, m_bShowColumns, m_xScratchIter.get());
274 m_xTreeView->set_image(*m_xScratchIter, aImg);
278 Reference<XQueriesSupplier> xQSupplier(xConnection, UNO_QUERY);
279 if(xQSupplier.is())
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)
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, m_bShowColumns, m_xScratchIter.get());
290 m_xTreeView->set_image(*m_xScratchIter, aImg);
295 catch (const Exception&)
300 return true;
303 OUString SwDBTreeList::GetDBName(OUString& rTableName, OUString& rColumnName, sal_Bool* pbIsTable)
305 OUString sDBName;
306 std::unique_ptr<weld::TreeIter> xIter(m_xTreeView->make_iterator());
307 if (m_xTreeView->get_selected(xIter.get()))
309 if (m_xTreeView->get_iter_depth(*xIter) == 2)
311 rColumnName = m_xTreeView->get_text(*xIter);
312 m_xTreeView->iter_parent(*xIter); // column name was selected
314 if (m_xTreeView->get_iter_depth(*xIter) == 1)
316 if (pbIsTable)
317 *pbIsTable = m_xTreeView->get_id(*xIter).isEmpty();
318 rTableName = m_xTreeView->get_text(*xIter);
319 m_xTreeView->iter_parent(*xIter);
321 sDBName = m_xTreeView->get_text(*xIter);
323 return sDBName;
326 // Format: database.table
327 void SwDBTreeList::Select(std::u16string_view rDBName, std::u16string_view rTableName, std::u16string_view rColumnName)
329 std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator());
330 if (!m_xTreeView->get_iter_first(*xParent))
331 return;
335 if (rDBName == m_xTreeView->get_text(*xParent))
337 if (rTableName.empty() && rColumnName.empty())
339 // Just select the database node, do not expand
340 m_xTreeView->scroll_to_row(*xParent);
341 m_xTreeView->select(*xParent);
342 return;
344 if (!m_xTreeView->iter_has_child(*xParent))
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
350 std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(xParent.get()));
351 if (!m_xTreeView->iter_children(*xChild))
353 m_xTreeView->scroll_to_row(*xParent);
354 m_xTreeView->select(*xParent);
355 continue;
359 if (rTableName == m_xTreeView->get_text(*xChild))
361 m_xTreeView->copy_iterator(*xChild, *xParent);
363 bool bNoChild = false;
364 if (m_bShowColumns && !rColumnName.empty())
366 if (!m_xTreeView->iter_has_child(*xParent))
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);
373 bNoChild = true;
374 if (m_xTreeView->iter_children(*xChild))
378 if (rColumnName == m_xTreeView->get_text(*xChild))
380 bNoChild = false;
381 break;
384 while (m_xTreeView->iter_next_sibling(*xChild));
388 if (bNoChild)
389 m_xTreeView->copy_iterator(*xParent, *xChild);
391 m_xTreeView->scroll_to_row(*xChild);
392 m_xTreeView->select(*xChild);
393 return;
396 while (m_xTreeView->iter_next_sibling(*xChild));
398 } while (m_xTreeView->iter_next_sibling(*xParent));
401 void SwDBTreeList::SetWrtShell(SwWrtShell& rSh)
403 m_pImpl->SetWrtShell(rSh);
404 if (m_xTreeView->get_visible() && !m_bInitialized)
405 InitTreeList();
408 namespace
410 void GotoRootLevelParent(const weld::TreeView& rTreeView, weld::TreeIter& rEntry)
412 while (rTreeView.get_iter_depth(rEntry))
413 rTreeView.iter_parent(rEntry);
417 void SwDBTreeList::ShowColumns(bool bShowCol)
419 if (bShowCol == m_bShowColumns)
420 return;
422 m_bShowColumns = bShowCol;
423 OUString sTableName;
424 OUString sColumnName;
425 const OUString sDBName(GetDBName(sTableName, sColumnName));
427 m_xTreeView->freeze();
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))
435 GotoRootLevelParent(*m_xTreeView, *xIter);
436 m_xTreeView->collapse_row(*xIter);
437 while (m_xTreeView->iter_has_child(*xIter))
439 m_xTreeView->copy_iterator(*xIter, *xChild);
440 (void)m_xTreeView->iter_children(*xChild);
441 m_xTreeView->remove(*xChild);
443 } while (m_xTreeView->iter_next(*xIter));
446 m_xTreeView->thaw();
448 if (!sDBName.isEmpty())
450 Select(sDBName, sTableName, sColumnName); // force RequestingChildren
454 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */