/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include #include namespace { size_t family_to_index(SfxStyleFamily family) { switch (family) { case SfxStyleFamily::Char: return 0; case SfxStyleFamily::Para: return 1; case SfxStyleFamily::Frame: return 2; case SfxStyleFamily::Page: return 3; case SfxStyleFamily::Pseudo: return 4; case SfxStyleFamily::Table: return 5; default: break; } assert(false); // only for compiler warning. all cases are handled in the switch return 0; } } namespace svl { IndexedStyleSheets::IndexedStyleSheets() { } void IndexedStyleSheets::Register(SfxStyleSheetBase& style, sal_Int32 pos) { mPositionsByName.insert(std::make_pair(style.GetName(), pos)); size_t position = family_to_index(style.GetFamily()); mStyleSheetsByFamily.at(position).push_back(&style); } void IndexedStyleSheets::Reindex() { mPositionsByName.clear(); for (size_t i = 0; i < NUMBER_OF_FAMILIES; i++) { mStyleSheetsByFamily[i].clear(); } sal_Int32 i = 0; for (const auto& rxStyleSheet : mStyleSheets) { SfxStyleSheetBase* p = rxStyleSheet.get(); Register(*p, i); ++i; } } void IndexedStyleSheets::ReindexOnNameChange(const SfxStyleSheetBase& style, const OUString& rOldName, const OUString& rNewName) { std::pair range = mPositionsByName.equal_range(rOldName); for (MapType::const_iterator it = range.first; it != range.second; ++it) { if (mStyleSheets[it->second].get() == &style) { unsigned nPos = it->second; mPositionsByName.erase(it); mPositionsByName.insert(std::make_pair(rNewName, nPos)); break; } } } void IndexedStyleSheets::AddStyleSheet(const rtl::Reference< SfxStyleSheetBase >& style) { if (!HasStyleSheet(style)) { mStyleSheets.push_back(style); // since we just added an element to the vector, we can safely do -1 as it will always be >= 1 Register(*style, mStyleSheets.size()-1); } } bool IndexedStyleSheets::RemoveStyleSheet(const rtl::Reference< SfxStyleSheetBase >& style) { std::pair range = mPositionsByName.equal_range(style->GetName()); for (MapType::const_iterator it = range.first; it != range.second; ++it) { sal_Int32 pos = it->second; if (mStyleSheets.at(pos) == style) { mStyleSheets.erase(mStyleSheets.begin() + pos); Reindex(); return true; } } return false; } std::vector IndexedStyleSheets::FindPositionsByName(const OUString& name) const { std::vector r; std::pair range = mPositionsByName.equal_range(name); for (MapType::const_iterator it = range.first; it != range.second; ++it) { r.push_back(it->second); } return r; } std::vector IndexedStyleSheets::FindPositionsByNameAndPredicate(const OUString& name, StyleSheetPredicate& predicate, SearchBehavior behavior) const { std::vector r; auto range = mPositionsByName.equal_range(name); for (auto it = range.first; it != range.second; ++it) { sal_Int32 pos = it->second; SfxStyleSheetBase *ssheet = mStyleSheets.at(pos).get(); if (predicate.Check(*ssheet)) { r.push_back(pos); if (behavior == SearchBehavior::ReturnFirst) { break; } } } return r; } sal_Int32 IndexedStyleSheets::GetNumberOfStyleSheetsWithPredicate(StyleSheetPredicate& predicate) const { return std::count_if(mStyleSheets.begin(), mStyleSheets.end(), [&predicate](const rtl::Reference& rxStyleSheet) { const SfxStyleSheetBase *ssheet = rxStyleSheet.get(); return predicate.Check(*ssheet); }); } std::pair IndexedStyleSheets::GetNthStyleSheetThatMatchesPredicate( sal_Int32 n, StyleSheetPredicate& predicate, sal_Int32 startAt) { SfxStyleSheetBase* retval = nullptr; sal_Int32 matching = 0; VectorType::const_iterator it = mStyleSheets.begin()+startAt; for (; it != mStyleSheets.end(); ++it) { SfxStyleSheetBase *ssheet = it->get(); if (predicate.Check(*ssheet)) { if (matching == n) { retval = it->get(); break; } ++matching; } } return { retval, std::distance(mStyleSheets.cbegin(), it) }; } sal_Int32 IndexedStyleSheets::FindStyleSheetPosition(const SfxStyleSheetBase& style) const { VectorType::const_iterator it = std::find(mStyleSheets.begin(), mStyleSheets.end(), &style); if (it == mStyleSheets.end()) { throw std::runtime_error("IndexedStyleSheets::FindStylePosition Looked for style not in index"); } return std::distance(mStyleSheets.begin(), it); } void IndexedStyleSheets::Clear(StyleSheetDisposer& disposer) { for (auto& rxStyleSheet : mStyleSheets) { disposer.Dispose(rxStyleSheet); // tdf#161729 clear style sheets in same order as they were added // std::vector::clear() appears to delete elements in the // reverse order added. In the case of tdf#161729, a style // sheet's SfxItemSet can have a parent SfxItemSet and that // parent is the SfxItemSet for a style sheet added later. // Deleting from the end of the vector deletes a style sheet // and its SfxItemSet. If the now deleted SfxItemSet is a // parent SfxItemSet of a style sheet that was added earlier, // the style sheet added earlier will now have an SfxItemSet // with its parent set to an already deleted pointer. And so // a crash will occur when that earlier style sheet is deleted. rxStyleSheet.clear(); } mStyleSheets.clear(); mPositionsByName.clear(); } IndexedStyleSheets::~IndexedStyleSheets() { } bool IndexedStyleSheets::HasStyleSheet(const rtl::Reference< SfxStyleSheetBase >& style) const { std::pair range = mPositionsByName.equal_range(style->GetName()); for (MapType::const_iterator it = range.first; it != range.second; ++it) { if (mStyleSheets.at(it->second) == style) return true; } return false; } SfxStyleSheetBase* IndexedStyleSheets::GetStyleSheetByPosition(sal_Int32 pos) { if( pos < static_cast(mStyleSheets.size()) ) return mStyleSheets.at(pos).get(); return nullptr; } void IndexedStyleSheets::ApplyToAllStyleSheets(StyleSheetCallback& callback) const { for (const auto& rxStyleSheet : mStyleSheets) { callback.DoIt(*rxStyleSheet); } } std::vector IndexedStyleSheets::FindPositionsByPredicate(StyleSheetPredicate& predicate) const { std::vector r; for (VectorType::const_iterator it = mStyleSheets.begin(); it != mStyleSheets.end(); ++it) { if (predicate.Check(**it)) { r.push_back(std::distance(mStyleSheets.begin(), it)); } } return r; } const std::vector& IndexedStyleSheets::GetStyleSheetsByFamily(SfxStyleFamily e) const { size_t position = family_to_index(e); return mStyleSheetsByFamily.at(position); } } /* namespace svl */ /* vim:set shiftwidth=4 softtabstop=4 expandtab: */