1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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
;
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
)
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
;
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
);
94 xViews
= xViewSupp
->getViews();
96 sViews
= xViews
->getElementNames();
99 xTables
= xTableSupp
->getTables();
101 sTables
= xTables
->getElementNames();
103 catch(RuntimeException
&)
105 TOOLS_WARN_EXCEPTION( "dbaccess", "OTableTreeListBox::UpdateTableList");
107 catch ( const SQLException
& )
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
);
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
;
133 aRet
.second
= std::any_of(m_aViews
.begin(), m_aViews
.end(),
134 [this, &name
](const OUString
& lhs
)
135 { return m_aEqualFunctor(lhs
, name
); } );
143 void OTableTreeListBox::UpdateTableList(
144 const Reference
< XConnection
>& _rxConnection
,
145 const Sequence
< OUString
>& _rTables
,
146 const Sequence
< OUString
>& _rViews
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() ) );
159 DBG_UNHANDLED_EXCEPTION("dbaccess");
161 UpdateTableList( _rxConnection
, aTables
);
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
) );
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
);
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);
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)
218 // get the table/view names
219 Reference
< XDatabaseMetaData
> xMeta( _rxConnection
->getMetaData(), UNO_SET_THROW
);
220 for (auto const& table
: _rTables
)
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
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()));
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);
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
)
280 m_xTreeView
->set_toggle(rEntry
, TRISTATE_TRUE
);
281 checkedButton_noBroadcast(rEntry
);
284 std::unique_ptr
<weld::TreeIter
> OTableTreeListBox::getAllObjectsEntry() const
286 if (!haveVirtualRoot())
288 auto xRet
= m_xTreeView
->make_iterator();
289 if (!m_xTreeView
->get_iter_first(*xRet
))
294 void OTableTreeListBox::checkedButton_noBroadcast(const weld::TreeIter
& rEntry
)
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
);
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
);
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
,
381 OSL_PRECOND( _rxMeta
.is(), "OTableTreeListBox::implAddEntry: invalid meta data!" );
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
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()));
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);
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()));
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);
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
);
448 m_xTreeView
->set_image(*xEntry
, xGraphic
, -1);
451 OUString
sImageId(m_xImageProvider
->getImageId(_rTableName
, DatabaseObject::TABLE
));
452 m_xTreeView
->set_image(*xEntry
, sImageId
, -1);
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);
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
483 aObject
.Type
= DatabaseObject::TABLE
;
484 aObject
.Name
= getQualifiedTableName(rEntry
);
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");
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
) )
527 std::unique_ptr
<weld::TreeIter
> xSchema(m_xTreeView
->make_iterator(&rEntry
));
528 bool bSchema
= m_xTreeView
->iter_parent(*xSchema
);
531 std::unique_ptr
<weld::TreeIter
> xCatalog(m_xTreeView
->make_iterator(xSchema
.get()));
532 bool bCatalog
= m_xTreeView
->iter_parent(*xCatalog
);
534 || ( xMeta
->supportsCatalogsInDataManipulation()
535 && !xMeta
->supportsSchemasInDataManipulation()
536 ) // here we support catalog but no schema
541 xCatalog
= std::move(xSchema
);
544 sCatalog
= m_xTreeView
->get_text(*xCatalog
);
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");
560 std::unique_ptr
<weld::TreeIter
> OTableTreeListBox::getEntryByQualifiedName(const OUString
& rName
)
564 Reference
< XDatabaseMetaData
> xMeta
;
565 if ( !impl_getAndAssertMetaData( xMeta
) )
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
);
579 xParent
= std::move(xCat
);
582 if (!sSchema
.isEmpty())
584 xSchema
= GetEntryPosByName(sSchema
, xParent
.get());
586 xParent
= std::move(xSchema
);
589 return GetEntryPosByName(sName
, xParent
.get());
591 catch( const Exception
& )
593 DBG_UNHANDLED_EXCEPTION("dbaccess");
598 void OTableTreeListBox::removedTable(const OUString
& rName
)
602 std::unique_ptr
<weld::TreeIter
> xEntry
= getEntryByQualifiedName(rName
);
604 m_xTreeView
->remove(*xEntry
);
606 catch( const Exception
& )
608 DBG_UNHANDLED_EXCEPTION("dbaccess");
612 void OTableTreeListBox::CheckButtons()
617 auto xEntry(m_xTreeView
->make_iterator());
618 if (!m_xTreeView
->get_iter_first(*xEntry
))
623 implDetermineState(*xEntry
);
624 } while (m_xTreeView
->iter_next_sibling(*xEntry
));
627 TriState
OTableTreeListBox::implDetermineState(const weld::TreeIter
& rEntry
)
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 ...
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
);
645 TriState eChildState
= implDetermineState(*xChild
);
646 if (eChildState
== TRISTATE_INDET
)
648 if (eChildState
== TRISTATE_TRUE
)
651 bChildLoop
= m_xTreeView
->iter_next_sibling(*xChild
);
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
664 implDetermineState(*xChild
);
665 bChildLoop
= m_xTreeView
->iter_next_sibling(*xChild
);
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
;
681 // all children are checked
682 eState
= TRISTATE_TRUE
;
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
);
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));
706 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */