260 lines
7.8 KiB
C++
260 lines
7.8 KiB
C++
/* -*- 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 <svl/IndexedStyleSheets.hxx>
|
|
#include <svl/style.hxx>
|
|
|
|
#include <stdexcept>
|
|
#include <algorithm>
|
|
#include <utility>
|
|
|
|
|
|
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<MapType::const_iterator, MapType::const_iterator> 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<MapType::const_iterator, MapType::const_iterator> 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<sal_Int32> IndexedStyleSheets::FindPositionsByName(const OUString& name) const
|
|
{
|
|
std::vector<sal_Int32> r;
|
|
std::pair<MapType::const_iterator, MapType::const_iterator> 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<sal_Int32> IndexedStyleSheets::FindPositionsByNameAndPredicate(const OUString& name,
|
|
StyleSheetPredicate& predicate, SearchBehavior behavior) const
|
|
{
|
|
std::vector<sal_Int32> 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<SfxStyleSheetBase>& rxStyleSheet) {
|
|
const SfxStyleSheetBase *ssheet = rxStyleSheet.get();
|
|
return predicate.Check(*ssheet);
|
|
});
|
|
}
|
|
|
|
std::pair<SfxStyleSheetBase*, sal_Int32>
|
|
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<MapType::const_iterator, MapType::const_iterator> 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<sal_Int32>(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<sal_Int32>
|
|
IndexedStyleSheets::FindPositionsByPredicate(StyleSheetPredicate& predicate) const
|
|
{
|
|
std::vector<sal_Int32> 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<SfxStyleSheetBase*>&
|
|
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: */
|