summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sw/inc/charformats.hxx114
-rw-r--r--sw/inc/doc.hxx1
-rw-r--r--sw/inc/docary.hxx6
-rw-r--r--sw/source/core/doc/docfmt.cxx8
-rw-r--r--sw/source/core/doc/docnew.cxx9
-rw-r--r--sw/source/core/doc/number.cxx2
-rw-r--r--sw/source/core/txtnode/chrfmt.cxx77
-rw-r--r--sw/source/core/undo/rolbck.cxx2
-rw-r--r--sw/source/core/unocore/unosett.cxx13
-rw-r--r--sw/source/core/unocore/unostyle.cxx2
10 files changed, 206 insertions, 28 deletions
diff --git a/sw/inc/charformats.hxx b/sw/inc/charformats.hxx
new file mode 100644
index 000000000000..f72958298ea8
--- /dev/null
+++ b/sw/inc/charformats.hxx
@@ -0,0 +1,114 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "docary.hxx"
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/composite_key.hpp>
+#include <boost/multi_index/identity.hpp>
+#include <boost/multi_index/mem_fun.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/random_access_index.hpp>
+
+// Like o3tl::find_partialorder_ptrequals
+// We don't allow duplicated object entries!
+struct char_formats_name_key
+ : boost::multi_index::composite_key<
+ SwCharFormat*,
+ boost::multi_index::const_mem_fun<SwFormat, const OUString&, &SwFormat::GetName>,
+ boost::multi_index::identity<SwCharFormat*> // the actual object pointer
+ >
+{
+};
+
+typedef boost::multi_index_container<
+ SwCharFormat*,
+ boost::multi_index::indexed_by<boost::multi_index::random_access<>,
+ boost::multi_index::ordered_unique<char_formats_name_key>>>
+ SwCharFormatsBase;
+
+class SW_DLLPUBLIC SwCharFormats final : public SwFormatsBase
+{
+ // function updating ByName index via modify
+ friend void SwFormat::SetName(const OUString&, bool);
+
+public:
+ typedef SwCharFormatsBase::nth_index<0>::type ByPos;
+ typedef SwCharFormatsBase::nth_index<1>::type ByName;
+ typedef ByPos::iterator iterator;
+
+private:
+ SwCharFormatsBase m_Array;
+ ByPos& m_PosIndex;
+ ByName& m_NameIndex;
+
+public:
+ typedef ByPos::const_iterator const_iterator;
+ typedef SwCharFormatsBase::size_type size_type;
+ typedef SwCharFormatsBase::value_type value_type;
+
+ SwCharFormats();
+ // frees all SwCharFormat!
+ virtual ~SwCharFormats() override;
+
+ bool empty() const { return m_Array.empty(); }
+ size_t size() const { return m_Array.size(); }
+
+ // Only fails, if you try to insert the same object twice
+ void insert(SwCharFormat* x);
+
+ // This will try to remove the exact object!
+ void erase(const_iterator const& position);
+
+ // Get the iterator of the exact object (includes pointer!),
+ // e.g for position with std::distance.
+ // There is also ContainsFormat, if you don't need the position.
+ const_iterator find(const SwCharFormat* x) const;
+ size_t GetPos(const SwCharFormat* p) const;
+
+ // search for formats by name
+ ByName::const_iterator findByName(const OUString& name) const;
+ // So we can actually check for end()
+ ByName::const_iterator byNameEnd() const { return m_NameIndex.end(); }
+
+ SwCharFormat* operator[](size_t index_) const { return m_PosIndex.operator[](index_); }
+ const_iterator begin() const { return m_PosIndex.begin(); }
+ const_iterator end() const { return m_PosIndex.end(); }
+
+ void dumpAsXml(xmlTextWriterPtr pWriter) const;
+
+ virtual size_t GetFormatCount() const override { return m_Array.size(); }
+ virtual SwCharFormat* GetFormat(size_t idx) const override { return operator[](idx); }
+
+ /// fast check if given format is contained here
+ /// @precond pFormat must not have been deleted
+ bool ContainsFormat(SwCharFormat* pFormat) const;
+ /// not so fast check that given format is still alive (i.e. contained here)
+ bool IsAlive(SwCharFormat const*) const;
+
+ void DeleteAndDestroyAll(bool keepDefault = false);
+
+ // Override return type to reduce casting
+ virtual SwCharFormat* FindFormatByName(const OUString& rName) const override;
+
+ /** Need to call this when the format name changes */
+ void SetFormatNameAndReindex(SwCharFormat* v, const OUString& sNewName);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx
index f72c2b89cb0d..d5c3a210af42 100644
--- a/sw/inc/doc.hxx
+++ b/sw/inc/doc.hxx
@@ -37,6 +37,7 @@
#include "frmfmt.hxx"
#include "charfmt.hxx"
#include "docary.hxx"
+#include "charformats.hxx"
#include "pagedesc.hxx"
#include "tblenum.hxx"
#include "ndarr.hxx"
diff --git a/sw/inc/docary.hxx b/sw/inc/docary.hxx
index 49d1a7c368a7..43939b1d84d1 100644
--- a/sw/inc/docary.hxx
+++ b/sw/inc/docary.hxx
@@ -187,12 +187,6 @@ public:
SwFrameFormatsV() : SwFormatsModifyBase( DestructorPolicy::KeepElements ) {}
};
-class SwCharFormats final : public SwFormatsModifyBase<SwCharFormat*>
-{
-public:
- void dumpAsXml(xmlTextWriterPtr pWriter) const;
-};
-
class SwTextFormatColls final : public SwFormatsModifyBase<SwTextFormatColl*>
{
public:
diff --git a/sw/source/core/doc/docfmt.cxx b/sw/source/core/doc/docfmt.cxx
index f6ccbb799b92..7f07cf62e99c 100644
--- a/sw/source/core/doc/docfmt.cxx
+++ b/sw/source/core/doc/docfmt.cxx
@@ -845,7 +845,7 @@ SwCharFormat *SwDoc::MakeCharFormat( const OUString &rFormatName,
bool bBroadcast )
{
SwCharFormat *pFormat = new SwCharFormat( GetAttrPool(), rFormatName, pDerivedFrom );
- mpCharFormatTable->push_back( pFormat );
+ mpCharFormatTable->insert( pFormat );
pFormat->SetAuto(false);
getIDocumentState().SetModified();
@@ -1926,7 +1926,11 @@ void SwDoc::RenameFormat(SwFormat & rFormat, const OUString & sNewName,
}
}
- rFormat.SetName(sNewName);
+ // name change means the o3tl::sorted_array is not property sorted
+ if (rFormat.Which() == RES_CHRFMT)
+ mpCharFormatTable->SetFormatNameAndReindex(static_cast<SwCharFormat*>(&rFormat), sNewName);
+ else
+ rFormat.SetName(sNewName);
if (bBroadcast)
BroadcastStyleOperation(sNewName, eFamily, SfxHintId::StyleSheetModified);
diff --git a/sw/source/core/doc/docnew.cxx b/sw/source/core/doc/docnew.cxx
index ae2f24a92a8a..b1ed62e0bccc 100644
--- a/sw/source/core/doc/docnew.cxx
+++ b/sw/source/core/doc/docnew.cxx
@@ -113,6 +113,8 @@
using namespace ::com::sun::star;
using namespace ::com::sun::star::document;
+constexpr OUStringLiteral DEFAULT_CHAR_FORMAT_NAME = u"Character style";
+
/*
* global functions...
*/
@@ -223,7 +225,7 @@ SwDoc::SwDoc()
mpDfltFrameFormat( new SwFrameFormat( GetAttrPool(), "Frameformat", nullptr ) ),
mpEmptyPageFormat( new SwFrameFormat( GetAttrPool(), "Empty Page", mpDfltFrameFormat.get() ) ),
mpColumnContFormat( new SwFrameFormat( GetAttrPool(), "Columncontainer", mpDfltFrameFormat.get() ) ),
- mpDfltCharFormat( new SwCharFormat( GetAttrPool(), "Character style", nullptr ) ),
+ mpDfltCharFormat( new SwCharFormat( GetAttrPool(), DEFAULT_CHAR_FORMAT_NAME, nullptr ) ),
mpDfltTextFormatColl( new SwTextFormatColl( GetAttrPool(), "Paragraph style" ) ),
mpDfltGrfFormatColl( new SwGrfFormatColl( GetAttrPool(), "Graphikformatvorlage" ) ),
mpFrameFormatTable( new SwFrameFormats() ),
@@ -296,7 +298,7 @@ SwDoc::SwDoc()
*/
/* Formats */
mpFrameFormatTable->push_back(mpDfltFrameFormat.get());
- mpCharFormatTable->push_back(mpDfltCharFormat.get());
+ mpCharFormatTable->insert(mpDfltCharFormat.get());
/* FormatColls */
// TXT
@@ -531,7 +533,6 @@ SwDoc::~SwDoc()
* now.
*/
mpFrameFormatTable->erase( mpFrameFormatTable->begin() );
- mpCharFormatTable->erase( mpCharFormatTable->begin() );
#if HAVE_FEATURE_DBCONNECTIVITY
// On load, SwDBManager::setEmbeddedName() may register a data source.
@@ -728,7 +729,7 @@ void SwDoc::ClearDoc()
mpTextFormatCollTable->DeleteAndDestroy(2, mpTextFormatCollTable->size());
mpTextFormatCollTable->DeleteAndDestroy(1, mpTextFormatCollTable->size());
mpGrfFormatCollTable->DeleteAndDestroy(1, mpGrfFormatCollTable->size());
- mpCharFormatTable->DeleteAndDestroy(1, mpCharFormatTable->size());
+ mpCharFormatTable->DeleteAndDestroyAll(/*keepDefault*/true);
if( getIDocumentLayoutAccess().GetCurrentViewShell() )
{
diff --git a/sw/source/core/doc/number.cxx b/sw/source/core/doc/number.cxx
index 9bd2f27283b9..045d58f63fde 100644
--- a/sw/source/core/doc/number.cxx
+++ b/sw/source/core/doc/number.cxx
@@ -872,7 +872,7 @@ SwNumRule& SwNumRule::CopyNumRule( SwDoc& rDoc, const SwNumRule& rNumRule )
{
Set( n, rNumRule.maFormats[ n ].get() );
if( maFormats[ n ] && maFormats[ n ]->GetCharFormat() &&
- !rDoc.GetCharFormats()->IsAlive(maFormats[n]->GetCharFormat()))
+ !rDoc.GetCharFormats()->ContainsFormat(maFormats[n]->GetCharFormat()))
{
// If we copy across different Documents, then copy the
// corresponding CharFormat into the new Document.
diff --git a/sw/source/core/txtnode/chrfmt.cxx b/sw/source/core/txtnode/chrfmt.cxx
index 04301067ec23..3ee46ee3e8e8 100644
--- a/sw/source/core/txtnode/chrfmt.cxx
+++ b/sw/source/core/txtnode/chrfmt.cxx
@@ -20,7 +20,7 @@
#include <libxml/xmlwriter.h>
#include <charfmt.hxx>
-#include <docary.hxx>
+#include <charformats.hxx>
void SwCharFormat::dumpAsXml(xmlTextWriterPtr pWriter) const
{
@@ -39,4 +39,79 @@ void SwCharFormats::dumpAsXml(xmlTextWriterPtr pWriter) const
(void)xmlTextWriterEndElement(pWriter);
}
+SwCharFormats::SwCharFormats()
+ : m_PosIndex(m_Array.get<0>())
+ , m_NameIndex(m_Array.get<1>())
+{
+}
+
+SwCharFormats::~SwCharFormats()
+{
+ // default char format is owned by SwDoc
+ DeleteAndDestroyAll(true);
+}
+
+SwCharFormats::const_iterator SwCharFormats::find(const SwCharFormat* x) const
+{
+ ByName::iterator it
+ = m_NameIndex.find(boost::make_tuple(x->GetName(), const_cast<SwCharFormat*>(x)));
+ return m_Array.project<0>(it);
+}
+
+SwCharFormats::ByName::const_iterator SwCharFormats::findByName(const OUString& name) const
+{
+ return m_NameIndex.find(boost::make_tuple(name));
+}
+
+SwCharFormat* SwCharFormats::FindFormatByName(const OUString& rName) const
+{
+ auto it = findByName(rName);
+ if (it != m_NameIndex.end())
+ return *it;
+ return nullptr;
+}
+
+void SwCharFormats::DeleteAndDestroyAll(bool keepDefault)
+{
+ if (empty())
+ return;
+ const int _offset = keepDefault ? 1 : 0;
+ for (const_iterator it = begin() + _offset; it != end(); ++it)
+ {
+ assert(!(*it)->HasName(u"Character style"));
+ delete *it;
+ }
+ if (_offset)
+ m_PosIndex.erase(begin() + _offset, end());
+ else
+ m_Array.clear();
+}
+
+void SwCharFormats::insert(SwCharFormat* x)
+{
+ assert(!ContainsFormat(x));
+ m_PosIndex.push_back(x);
+}
+
+void SwCharFormats::erase(const_iterator const& position) { m_PosIndex.erase(position); }
+
+bool SwCharFormats::ContainsFormat(SwCharFormat* x) const { return find(x) != end(); }
+
+bool SwCharFormats::IsAlive(SwCharFormat const* const p) const { return find(p) != end(); }
+
+/** Need to call this when the format name changes */
+void SwCharFormats::SetFormatNameAndReindex(SwCharFormat* v, const OUString& sNewName)
+{
+ auto it = find(v);
+ erase(it);
+ v->SetName(sNewName);
+ insert(v);
+}
+
+size_t SwCharFormats::GetPos(const SwCharFormat* p) const
+{
+ auto it = find(p);
+ return it == end() ? SIZE_MAX : it - begin();
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/undo/rolbck.cxx b/sw/source/core/undo/rolbck.cxx
index 402f1486654b..cf308182c60b 100644
--- a/sw/source/core/undo/rolbck.cxx
+++ b/sw/source/core/undo/rolbck.cxx
@@ -254,7 +254,7 @@ void SwHistorySetText::SetInDoc( SwDoc* pDoc, bool )
if ( RES_TXTATR_CHARFMT == m_pAttr->Which() )
{
// ask the Doc if the CharFormat still exists
- if (!pDoc->GetCharFormats()->IsAlive(static_cast<SwFormatCharFormat&>(*m_pAttr).GetCharFormat()))
+ if (!pDoc->GetCharFormats()->ContainsFormat(static_cast<SwFormatCharFormat&>(*m_pAttr).GetCharFormat()))
return; // do not set, format does not exist
}
diff --git a/sw/source/core/unocore/unosett.cxx b/sw/source/core/unocore/unosett.cxx
index 186b0e98116e..101a70f10ada 100644
--- a/sw/source/core/unocore/unosett.cxx
+++ b/sw/source/core/unocore/unosett.cxx
@@ -1589,21 +1589,10 @@ void SwXNumberingRules::SetPropertiesToNumFormat(
}
else if (pLocalDoc)
{
- const SwCharFormats* pFormats = pLocalDoc->GetCharFormats();
- const size_t nChCount = pFormats->size();
-
SwCharFormat* pCharFormat = nullptr;
if (!sCharFormatName.isEmpty())
{
- for(size_t j = 0; j< nChCount; ++j)
- {
- SwCharFormat* pTmp = (*pFormats)[j];
- if(pTmp->GetName() == sCharFormatName)
- {
- pCharFormat = pTmp;
- break;
- }
- }
+ pCharFormat = pLocalDoc->FindCharFormatByName(sCharFormatName);
if(!pCharFormat)
{
diff --git a/sw/source/core/unocore/unostyle.cxx b/sw/source/core/unocore/unostyle.cxx
index a6a14abef2dc..86d9381b8573 100644
--- a/sw/source/core/unocore/unostyle.cxx
+++ b/sw/source/core/unocore/unostyle.cxx
@@ -891,7 +891,7 @@ uno::Any XStyleFamily::getByName(const OUString& rName)
throw uno::RuntimeException();
SfxStyleSheetBase* pBase = m_pBasePool->Find(sStyleName, m_rEntry.m_eFamily);
if(!pBase)
- throw container::NoSuchElementException();
+ throw container::NoSuchElementException(rName);
uno::Reference<style::XStyle> xStyle = FindStyle(sStyleName);
if(!xStyle.is())
xStyle = m_rEntry.m_fCreateStyle(m_pBasePool, m_pDocShell, m_rEntry.m_eFamily == SfxStyleFamily::Frame ? pBase->GetName() : sStyleName);