tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / dbaccess / source / ui / control / tabletree.cxx
blobd1090a9aae0f7012a0ae8a0b6745d11601f93995
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 <core_resource.hxx>
21 #include <tabletree.hxx>
22 #include <imageprovider.hxx>
23 #include <strings.hrc>
24 #include <connectivity/dbtools.hxx>
25 #include <com/sun/star/sdb/application/DatabaseObject.hpp>
26 #include <com/sun/star/sdb/application/DatabaseObjectContainer.hpp>
27 #include <com/sun/star/sdbcx/XViewsSupplier.hpp>
28 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
29 #include <com/sun/star/sdbc/SQLException.hpp>
30 #include <com/sun/star/sdbc/XRow.hpp>
31 #include <comphelper/diagnose_ex.hxx>
32 #include <osl/diagnose.h>
33 #include <connectivity/dbmetadata.hxx>
35 #include <algorithm>
37 namespace dbaui
40 using namespace ::com::sun::star::uno;
41 using namespace ::com::sun::star::sdb;
42 using namespace ::com::sun::star::sdbc;
43 using namespace ::com::sun::star::sdbcx;
44 using namespace ::com::sun::star::container;
45 using namespace ::com::sun::star::sdb::application;
47 using namespace ::dbtools;
48 using namespace ::comphelper;
50 namespace DatabaseObject = ::com::sun::star::sdb::application::DatabaseObject;
51 namespace DatabaseObjectContainer = ::com::sun::star::sdb::application::DatabaseObjectContainer;
53 // OTableTreeListBox
54 OTableTreeListBox::OTableTreeListBox(std::unique_ptr<weld::TreeView> xTreeView, bool bShowToggles)
55 : TreeListBox(std::move(xTreeView), true)
56 , m_xImageProvider(new ImageProvider)
57 , m_bVirtualRoot(false)
58 , m_bNoEmptyFolders(false)
59 , m_bShowToggles(bShowToggles)
61 if (m_bShowToggles)
62 m_xTreeView->enable_toggle_buttons(weld::ColumnToggleType::Check);
65 bool OTableTreeListBox::isFolderEntry(const weld::TreeIter& rEntry) const
67 sal_Int32 nEntryType = m_xTreeView->get_id(rEntry).toInt32();
68 return ( nEntryType == DatabaseObjectContainer::TABLES )
69 || ( nEntryType == DatabaseObjectContainer::CATALOG )
70 || ( nEntryType == DatabaseObjectContainer::SCHEMA );
73 void OTableTreeListBox::implOnNewConnection( const Reference< XConnection >& _rxConnection )
75 m_xConnection = _rxConnection;
76 m_xImageProvider.reset( new ImageProvider( m_xConnection ) );
79 void OTableTreeListBox::UpdateTableList( const Reference< XConnection >& _rxConnection )
81 Sequence< OUString > sTables, sViews;
83 OUString sCurrentActionError;
84 try
86 Reference< XTablesSupplier > xTableSupp( _rxConnection, UNO_QUERY_THROW );
87 sCurrentActionError = DBA_RES(STR_NOTABLEINFO);
89 Reference< XNameAccess > xTables,xViews;
91 Reference< XViewsSupplier > xViewSupp( _rxConnection, UNO_QUERY );
92 if ( xViewSupp.is() )
94 xViews = xViewSupp->getViews();
95 if (xViews.is())
96 sViews = xViews->getElementNames();
99 xTables = xTableSupp->getTables();
100 if (xTables.is())
101 sTables = xTables->getElementNames();
103 catch(RuntimeException&)
105 TOOLS_WARN_EXCEPTION( "dbaccess", "OTableTreeListBox::UpdateTableList");
107 catch ( const SQLException& )
109 throw;
111 catch(Exception&)
113 css::uno::Any anyEx = cppu::getCaughtException();
114 // a non-SQLException exception occurred ... simply throw an SQLException
115 throw SQLException(sCurrentActionError, nullptr, u""_ustr, 0, anyEx);
118 UpdateTableList( _rxConnection, sTables, sViews );
121 namespace
123 struct OViewSetter
125 const Sequence< OUString> m_aViews;
126 ::comphelper::UStringMixEqual m_aEqualFunctor;
128 OViewSetter(const Sequence< OUString>& _rViews,bool _bCase) : m_aViews(_rViews),m_aEqualFunctor(_bCase){}
129 OTableTreeListBox::TNames::value_type operator() (const OUString& name)
131 OTableTreeListBox::TNames::value_type aRet;
132 aRet.first = name;
133 aRet.second = std::any_of(m_aViews.begin(), m_aViews.end(),
134 [this, &name](const OUString& lhs)
135 { return m_aEqualFunctor(lhs, name); } );
137 return aRet;
143 void OTableTreeListBox::UpdateTableList(
144 const Reference< XConnection >& _rxConnection,
145 const Sequence< OUString>& _rTables,
146 const Sequence< OUString>& _rViews
149 TNames aTables;
150 aTables.resize(_rTables.getLength());
153 Reference< XDatabaseMetaData > xMeta( _rxConnection->getMetaData(), UNO_SET_THROW );
154 std::transform( _rTables.begin(), _rTables.end(),
155 aTables.begin(), OViewSetter( _rViews, xMeta->supportsMixedCaseQuotedIdentifiers() ) );
157 catch(Exception&)
159 DBG_UNHANDLED_EXCEPTION("dbaccess");
161 UpdateTableList( _rxConnection, aTables );
164 namespace
166 std::vector< OUString > lcl_getMetaDataStrings_throw( const Reference< XResultSet >& _rxMetaDataResult, sal_Int32 _nColumnIndex )
168 std::vector< OUString > aStrings;
169 Reference< XRow > xRow( _rxMetaDataResult, UNO_QUERY_THROW );
170 while ( _rxMetaDataResult->next() )
171 aStrings.push_back( xRow->getString( _nColumnIndex ) );
172 return aStrings;
175 bool lcl_shouldDisplayEmptySchemasAndCatalogs( const Reference< XConnection >& _rxConnection )
177 ::dbtools::DatabaseMetaData aMetaData( _rxConnection );
178 return aMetaData.displayEmptyTableFolders();
182 void OTableTreeListBox::UpdateTableList( const Reference< XConnection >& _rxConnection, const TNames& _rTables )
184 implOnNewConnection( _rxConnection );
186 // throw away all the old stuff
187 m_xTreeView->clear();
188 m_xTreeView->make_unsorted();
192 if (haveVirtualRoot())
194 OUString sRootEntryText;
195 if ( std::none_of(_rTables.begin(),_rTables.end(),
196 [] (const TNames::value_type& name) { return !name.second; }) )
197 sRootEntryText = DBA_RES(STR_ALL_TABLES);
198 else if ( std::none_of(_rTables.begin(),_rTables.end(),
199 [] (const TNames::value_type& name) { return name.second; }) )
200 sRootEntryText = DBA_RES(STR_ALL_VIEWS);
201 else
202 sRootEntryText = DBA_RES(STR_ALL_TABLES_AND_VIEWS);
203 OUString sId(OUString::number(DatabaseObjectContainer::TABLES));
204 OUString sImageId = ImageProvider::getFolderImageId(DatabaseObject::TABLE);
205 std::unique_ptr<weld::TreeIter> xRet(m_xTreeView->make_iterator());
206 m_xTreeView->insert(nullptr, -1, nullptr, &sId, nullptr, nullptr, false, xRet.get());
207 m_xTreeView->set_image(*xRet, sImageId, -1);
208 if (m_bShowToggles)
209 m_xTreeView->set_toggle(*xRet, TRISTATE_FALSE);
210 m_xTreeView->set_text(*xRet, sRootEntryText, 0);
211 m_xTreeView->set_text_emphasis(*xRet, false, 0);
214 if ( _rTables.empty() )
215 // nothing to do (besides inserting the root entry)
216 return;
218 // get the table/view names
219 Reference< XDatabaseMetaData > xMeta( _rxConnection->getMetaData(), UNO_SET_THROW );
220 for (auto const& table : _rTables)
222 // add the entry
223 implAddEntry(xMeta, table.first, false);
226 if ( !m_bNoEmptyFolders && lcl_shouldDisplayEmptySchemasAndCatalogs( _rxConnection ) )
228 bool bSupportsCatalogs = xMeta->supportsCatalogsInDataManipulation();
229 bool bSupportsSchemas = xMeta->supportsSchemasInDataManipulation();
231 if ( bSupportsCatalogs || bSupportsSchemas )
233 // we display empty catalogs if the DB supports catalogs, and they're noted at the beginning of a
234 // composed name. Otherwise, we display empty schematas. (also see the tree structure explained in
235 // implAddEntry)
236 bool bCatalogs = bSupportsCatalogs && xMeta->isCatalogAtStart();
238 std::vector< OUString > aFolderNames( lcl_getMetaDataStrings_throw(
239 bCatalogs ? xMeta->getCatalogs() : xMeta->getSchemas(), 1 ) );
240 sal_Int32 nFolderType = bCatalogs ? DatabaseObjectContainer::CATALOG : DatabaseObjectContainer::SCHEMA;
242 OUString sImageId = ImageProvider::getFolderImageId(DatabaseObject::TABLE);
244 std::unique_ptr<weld::TreeIter> xRootEntry(getAllObjectsEntry());
245 std::unique_ptr<weld::TreeIter> xRet(m_xTreeView->make_iterator());
246 for (auto const& folderName : aFolderNames)
248 std::unique_ptr<weld::TreeIter> xFolder(GetEntryPosByName(folderName, xRootEntry.get()));
249 if (!xFolder)
251 OUString sId(OUString::number(nFolderType));
252 m_xTreeView->insert(xRootEntry.get(), -1, nullptr, &sId, nullptr, nullptr, false, xRet.get());
253 m_xTreeView->set_image(*xRet, sImageId, -1);
254 if (m_bShowToggles)
255 m_xTreeView->set_toggle(*xRet, TRISTATE_FALSE);
256 m_xTreeView->set_text(*xRet, folderName, 0);
257 m_xTreeView->set_text_emphasis(*xRet, false, 0);
263 catch ( const Exception& )
265 DBG_UNHANDLED_EXCEPTION("dbaccess");
268 m_xTreeView->make_sorted();
271 bool OTableTreeListBox::isWildcardChecked(const weld::TreeIter& rEntry)
273 return m_xTreeView->get_text_emphasis(rEntry, 0);
276 void OTableTreeListBox::checkWildcard(const weld::TreeIter& rEntry)
278 if (!m_bShowToggles)
279 return;
280 m_xTreeView->set_toggle(rEntry, TRISTATE_TRUE);
281 checkedButton_noBroadcast(rEntry);
284 std::unique_ptr<weld::TreeIter> OTableTreeListBox::getAllObjectsEntry() const
286 if (!haveVirtualRoot())
287 return nullptr;
288 auto xRet = m_xTreeView->make_iterator();
289 if (!m_xTreeView->get_iter_first(*xRet))
290 return nullptr;
291 return xRet;
294 void OTableTreeListBox::checkedButton_noBroadcast(const weld::TreeIter& rEntry)
296 if (!m_bShowToggles)
297 return;
298 TriState eState = m_xTreeView->get_toggle(rEntry);
299 OSL_ENSURE(TRISTATE_INDET != eState, "OTableTreeListBox::CheckButtonHdl: user action which lead to TRISTATE?");
301 if (m_xTreeView->iter_has_child(rEntry)) // if it has children, check those too
303 std::unique_ptr<weld::TreeIter> xChildEntry(m_xTreeView->make_iterator(&rEntry));
304 std::unique_ptr<weld::TreeIter> xSiblingEntry(m_xTreeView->make_iterator(&rEntry));
305 bool bChildEntry = m_xTreeView->iter_next(*xChildEntry);
306 bool bSiblingEntry = m_xTreeView->iter_next_sibling(*xSiblingEntry);
307 while (bChildEntry && (!bSiblingEntry || !xChildEntry->equal(*xSiblingEntry)))
309 m_xTreeView->set_toggle(*xChildEntry, eState);
310 bChildEntry = m_xTreeView->iter_next(*xChildEntry);
314 if (m_xTreeView->is_selected(rEntry))
316 m_xTreeView->selected_foreach([this, eState](weld::TreeIter& rSelected){
317 m_xTreeView->set_toggle(rSelected, eState);
318 if (m_xTreeView->iter_has_child(rSelected)) // if it has children, check those too
320 std::unique_ptr<weld::TreeIter> xChildEntry(m_xTreeView->make_iterator(&rSelected));
321 std::unique_ptr<weld::TreeIter> xSiblingEntry(m_xTreeView->make_iterator(&rSelected));
322 bool bChildEntry = m_xTreeView->iter_next(*xChildEntry);
323 bool bSiblingEntry = m_xTreeView->iter_next_sibling(*xSiblingEntry);
324 while (bChildEntry && (!bSiblingEntry || !xChildEntry->equal(*xSiblingEntry)))
326 m_xTreeView->set_toggle(*xChildEntry, eState);
327 bChildEntry = m_xTreeView->iter_next(*xChildEntry);
330 return false;
334 CheckButtons();
336 // if an entry has children, it makes a difference if the entry is checked
337 // because all children are checked or if the user checked it explicitly.
338 // So we track explicit (un)checking
339 implEmphasize(rEntry, eState == TRISTATE_TRUE);
342 void OTableTreeListBox::implEmphasize(const weld::TreeIter& rEntry, bool _bChecked, bool _bUpdateDescendants, bool _bUpdateAncestors)
344 // special emphasizing handling for the "all objects" entry
345 bool bAllObjectsEntryAffected = haveVirtualRoot() && (getAllObjectsEntry()->equal(rEntry));
346 if ( m_xTreeView->iter_has_child(rEntry) // the entry has children
347 || bAllObjectsEntryAffected // or it is the "all objects" entry
350 m_xTreeView->set_text_emphasis(rEntry, _bChecked, 0);
353 if (_bUpdateDescendants)
355 std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(&rEntry));
356 // remove the mark for all children of the checked entry
357 bool bChildLoop = m_xTreeView->iter_children(*xChild);
358 while (bChildLoop)
360 if (m_xTreeView->iter_has_child(*xChild))
361 implEmphasize(*xChild, false, true, false);
362 bChildLoop = m_xTreeView->iter_next_sibling(*xChild);
366 if (_bUpdateAncestors)
368 std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(&rEntry));
369 // remove the mark for all ancestors of the entry
370 if (m_xTreeView->iter_parent(*xParent))
371 implEmphasize(*xParent, false, false);
375 std::unique_ptr<weld::TreeIter> OTableTreeListBox::implAddEntry(
376 const Reference< XDatabaseMetaData >& _rxMeta,
377 const OUString& _rTableName,
378 bool _bCheckName
381 OSL_PRECOND( _rxMeta.is(), "OTableTreeListBox::implAddEntry: invalid meta data!" );
382 if ( !_rxMeta.is() )
383 return nullptr;
385 // split the complete name into its components
386 OUString sCatalog, sSchema, sName;
387 qualifiedNameComponents( _rxMeta, _rTableName, sCatalog, sSchema, sName, ::dbtools::EComposeRule::InDataManipulation );
389 std::unique_ptr<weld::TreeIter> xParentEntry(getAllObjectsEntry());
391 // if the DB uses catalog at the start of identifiers, then our hierarchy is
392 // catalog
393 // +- schema
394 // +- table
395 // else it is
396 // schema
397 // +- catalog
398 // +- table
399 bool bCatalogAtStart = _rxMeta->isCatalogAtStart();
400 const OUString& rFirstName = bCatalogAtStart ? sCatalog : sSchema;
401 const sal_Int32 nFirstFolderType = bCatalogAtStart ? DatabaseObjectContainer::CATALOG : DatabaseObjectContainer::SCHEMA;
402 const OUString& rSecondName = bCatalogAtStart ? sSchema : sCatalog;
403 const sal_Int32 nSecondFolderType = bCatalogAtStart ? DatabaseObjectContainer::SCHEMA : DatabaseObjectContainer::CATALOG;
405 if ( !rFirstName.isEmpty() )
407 std::unique_ptr<weld::TreeIter> xFolder(GetEntryPosByName(rFirstName, xParentEntry.get()));
408 if (!xFolder)
410 xFolder = m_xTreeView->make_iterator();
411 OUString sId(OUString::number(nFirstFolderType));
412 OUString sImageId = ImageProvider::getFolderImageId(DatabaseObject::TABLE);
413 m_xTreeView->insert(xParentEntry.get(), -1, nullptr, &sId, nullptr, nullptr, false, xFolder.get());
414 m_xTreeView->set_image(*xFolder, sImageId, -1);
415 if (m_bShowToggles)
416 m_xTreeView->set_toggle(*xFolder, TRISTATE_FALSE);
417 m_xTreeView->set_text(*xFolder, rFirstName, 0);
418 m_xTreeView->set_text_emphasis(*xFolder, false, 0);
420 xParentEntry = std::move(xFolder);
423 if ( !rSecondName.isEmpty() )
425 std::unique_ptr<weld::TreeIter> xFolder(GetEntryPosByName(rSecondName, xParentEntry.get()));
426 if (!xFolder)
428 xFolder = m_xTreeView->make_iterator();
429 OUString sId(OUString::number(nSecondFolderType));
430 OUString sImageId = ImageProvider::getFolderImageId(DatabaseObject::TABLE);
431 m_xTreeView->insert(xParentEntry.get(), -1, nullptr, &sId, nullptr, nullptr, false, xFolder.get());
432 m_xTreeView->set_image(*xFolder, sImageId, -1);
433 if (m_bShowToggles)
434 m_xTreeView->set_toggle(*xFolder, TRISTATE_FALSE);
435 m_xTreeView->set_text(*xFolder, rSecondName, 0);
436 m_xTreeView->set_text_emphasis(*xFolder, false, 0);
438 xParentEntry = std::move(xFolder);
441 if (!_bCheckName || !GetEntryPosByName(sName, xParentEntry.get()))
443 std::unique_ptr<weld::TreeIter> xEntry = m_xTreeView->make_iterator();
444 m_xTreeView->insert(xParentEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, false, xEntry.get());
446 auto xGraphic = m_xImageProvider->getXGraphic(_rTableName, DatabaseObject::TABLE);
447 if (xGraphic.is())
448 m_xTreeView->set_image(*xEntry, xGraphic, -1);
449 else
451 OUString sImageId(m_xImageProvider->getImageId(_rTableName, DatabaseObject::TABLE));
452 m_xTreeView->set_image(*xEntry, sImageId, -1);
454 if (m_bShowToggles)
455 m_xTreeView->set_toggle(*xEntry, TRISTATE_FALSE);
456 m_xTreeView->set_text(*xEntry, sName, 0);
457 m_xTreeView->set_text_emphasis(*xEntry, false, 0);
459 return xEntry;
462 return nullptr;
465 NamedDatabaseObject OTableTreeListBox::describeObject(const weld::TreeIter& rEntry)
467 NamedDatabaseObject aObject;
469 sal_Int32 nEntryType = m_xTreeView->get_id(rEntry).toInt32();
471 if ( nEntryType == DatabaseObjectContainer::TABLES )
473 aObject.Type = DatabaseObjectContainer::TABLES;
475 else if ( ( nEntryType == DatabaseObjectContainer::CATALOG )
476 || ( nEntryType == DatabaseObjectContainer::SCHEMA )
479 // nothing useful to be done
481 else
483 aObject.Type = DatabaseObject::TABLE;
484 aObject.Name = getQualifiedTableName(rEntry);
487 return aObject;
490 std::unique_ptr<weld::TreeIter> OTableTreeListBox::addedTable(const OUString& rName)
494 Reference< XDatabaseMetaData > xMeta;
495 if ( impl_getAndAssertMetaData( xMeta ) )
496 return implAddEntry( xMeta, rName );
498 catch( const Exception& )
500 DBG_UNHANDLED_EXCEPTION("dbaccess");
502 return nullptr;
505 bool OTableTreeListBox::impl_getAndAssertMetaData( Reference< XDatabaseMetaData >& _out_rMetaData ) const
507 if ( m_xConnection.is() )
508 _out_rMetaData = m_xConnection->getMetaData();
509 OSL_PRECOND( _out_rMetaData.is(), "OTableTreeListBox::impl_getAndAssertMetaData: invalid current connection!" );
510 return _out_rMetaData.is();
513 OUString OTableTreeListBox::getQualifiedTableName(const weld::TreeIter& rEntry) const
515 OSL_PRECOND( !isFolderEntry(rEntry), "OTableTreeListBox::getQualifiedTableName: folder entries not allowed here!" );
519 Reference< XDatabaseMetaData > xMeta;
520 if ( !impl_getAndAssertMetaData( xMeta ) )
521 return OUString();
523 OUString sCatalog;
524 OUString sSchema;
525 OUString sTable;
527 std::unique_ptr<weld::TreeIter> xSchema(m_xTreeView->make_iterator(&rEntry));
528 bool bSchema = m_xTreeView->iter_parent(*xSchema);
529 if (bSchema)
531 std::unique_ptr<weld::TreeIter> xCatalog(m_xTreeView->make_iterator(xSchema.get()));
532 bool bCatalog = m_xTreeView->iter_parent(*xCatalog);
533 if ( bCatalog
534 || ( xMeta->supportsCatalogsInDataManipulation()
535 && !xMeta->supportsSchemasInDataManipulation()
536 ) // here we support catalog but no schema
539 if (!bCatalog)
541 xCatalog = std::move(xSchema);
542 bSchema = false;
544 sCatalog = m_xTreeView->get_text(*xCatalog);
546 if (bSchema)
547 sSchema = m_xTreeView->get_text(*xSchema);
549 sTable = m_xTreeView->get_text(rEntry);
551 return ::dbtools::composeTableName( xMeta, sCatalog, sSchema, sTable, false, ::dbtools::EComposeRule::InDataManipulation );
553 catch( const Exception& )
555 DBG_UNHANDLED_EXCEPTION("dbaccess");
557 return OUString();
560 std::unique_ptr<weld::TreeIter> OTableTreeListBox::getEntryByQualifiedName(const OUString& rName)
564 Reference< XDatabaseMetaData > xMeta;
565 if ( !impl_getAndAssertMetaData( xMeta ) )
566 return nullptr;
568 // split the complete name into its components
569 OUString sCatalog, sSchema, sName;
570 qualifiedNameComponents(xMeta, rName, sCatalog, sSchema, sName,::dbtools::EComposeRule::InDataManipulation);
572 std::unique_ptr<weld::TreeIter> xParent(getAllObjectsEntry());
573 std::unique_ptr<weld::TreeIter> xCat;
574 std::unique_ptr<weld::TreeIter> xSchema;
575 if (!sCatalog.isEmpty())
577 xCat = GetEntryPosByName(sCatalog);
578 if (xCat)
579 xParent = std::move(xCat);
582 if (!sSchema.isEmpty())
584 xSchema = GetEntryPosByName(sSchema, xParent.get());
585 if (xSchema)
586 xParent = std::move(xSchema);
589 return GetEntryPosByName(sName, xParent.get());
591 catch( const Exception& )
593 DBG_UNHANDLED_EXCEPTION("dbaccess");
595 return nullptr;
598 void OTableTreeListBox::removedTable(const OUString& rName)
602 std::unique_ptr<weld::TreeIter> xEntry = getEntryByQualifiedName(rName);
603 if (xEntry)
604 m_xTreeView->remove(*xEntry);
606 catch( const Exception& )
608 DBG_UNHANDLED_EXCEPTION("dbaccess");
612 void OTableTreeListBox::CheckButtons()
614 if (!m_bShowToggles)
615 return;
617 auto xEntry(m_xTreeView->make_iterator());
618 if (!m_xTreeView->get_iter_first(*xEntry))
619 return;
623 implDetermineState(*xEntry);
624 } while (m_xTreeView->iter_next_sibling(*xEntry));
627 TriState OTableTreeListBox::implDetermineState(const weld::TreeIter& rEntry)
629 if (!m_bShowToggles)
630 return TRISTATE_FALSE;
632 TriState eState = m_xTreeView->get_toggle(rEntry);
633 if (!m_xTreeView->iter_has_child(rEntry))
634 // nothing to do in this bottom-up routine if there are no children ...
635 return eState;
637 // loop through the children and check their states
638 sal_uInt16 nCheckedChildren = 0;
639 sal_uInt16 nChildrenOverall = 0;
641 std::unique_ptr<weld::TreeIter> xChild(m_xTreeView->make_iterator(&rEntry));
642 bool bChildLoop = m_xTreeView->iter_children(*xChild);
643 while (bChildLoop)
645 TriState eChildState = implDetermineState(*xChild);
646 if (eChildState == TRISTATE_INDET)
647 break;
648 if (eChildState == TRISTATE_TRUE)
649 ++nCheckedChildren;
650 ++nChildrenOverall;
651 bChildLoop = m_xTreeView->iter_next_sibling(*xChild);
654 if (bChildLoop)
656 // we did not finish the loop because at least one of the children is in tristate
657 eState = TRISTATE_INDET;
659 // but this means that we did not finish all the siblings of pChildLoop,
660 // so their checking may be incorrect at the moment
661 // -> correct this
662 while (bChildLoop)
664 implDetermineState(*xChild);
665 bChildLoop = m_xTreeView->iter_next_sibling(*xChild);
668 else
670 // none if the children are in tristate
671 if (nCheckedChildren)
673 // we have at least one child checked
674 if (nCheckedChildren != nChildrenOverall)
676 // not all children are checked
677 eState = TRISTATE_INDET;
679 else
681 // all children are checked
682 eState = TRISTATE_TRUE;
685 else
687 // no children are checked
688 eState = TRISTATE_FALSE;
692 // finally set the entry to the state we just determined
693 m_xTreeView->set_toggle(rEntry, eState);
695 return eState;
698 DBTableTreeView::DBTableTreeView(weld::Container* pContainer)
699 : DBTreeViewBase(pContainer)
701 m_xTreeListBox.reset(new OTableTreeListBox(m_xBuilder->weld_tree_view(u"treeview"_ustr), /*bShowToggles*/false));
704 } // namespace dbaui
706 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */