[Libreoffice-commits] core.git: 2 commits - editeng/Library_editeng.mk editeng/qa editeng/source include/editeng sc/inc sc/Library_sc.mk sc/qa sc/source

Kohei Yoshida kohei.yoshida at gmail.com
Tue Aug 20 19:59:12 PDT 2013


 editeng/Library_editeng.mk                  |    1 
 editeng/qa/unit/core-test.cxx               |   93 +++++++++++++++++
 editeng/source/editeng/editobj.cxx          |  149 ++++++++++++++++++++++++++++
 editeng/source/editeng/editobj2.hxx         |    8 +
 editeng/source/editeng/sectionattribute.cxx |   21 +++
 include/editeng/editobj.hxx                 |   13 ++
 include/editeng/sectionattribute.hxx        |   37 ++++++
 sc/Library_sc.mk                            |    1 
 sc/inc/column.hxx                           |    2 
 sc/inc/document.hxx                         |    2 
 sc/inc/edittextiterator.hxx                 |   61 +++++++++++
 sc/inc/table.hxx                            |    1 
 sc/qa/unit/ucalc.cxx                        |   94 +++++++++++++++++
 sc/qa/unit/ucalc.hxx                        |    2 
 sc/source/core/data/edittextiterator.cxx    |   86 ++++++++++++++++
 15 files changed, 571 insertions(+)

New commits:
commit 6c4bedffb98a33b202692b225fc250b858ff9f65
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Aug 20 17:23:12 2013 -0400

    Add edit text iterator that iterates through only edit text cells.
    
    Change-Id: I898d7a2d3f0ea472daddb9dd32f772a5d7268773

diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index 83e3358..1ef9a82 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -147,6 +147,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
 	sc/source/core/data/dputil \
 	sc/source/core/data/drawpage \
 	sc/source/core/data/drwlayer \
+	sc/source/core/data/edittextiterator \
 	sc/source/core/data/fillinfo \
 	sc/source/core/data/formulacell \
 	sc/source/core/data/formulaiter \
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 49cc24a..4322c24 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -51,6 +51,7 @@ namespace sc {
     struct RefUpdateInsertTabContext;
     struct RefUpdateDeleteTabContext;
     struct RefUpdateMoveTabContext;
+    class EditTextIterator;
 }
 
 class Fraction;
@@ -132,6 +133,7 @@ friend class ScColumnTextWidthIterator;
 friend class ScDocumentImport;
 friend class sc::SingleColumnSpanSet;
 friend class sc::ColumnSpanSet;
+friend class sc::EditTextIterator;
 
     ScColumn(const ScColumn&); // disabled
     ScColumn& operator= (const ScColumn&); // disabled
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index c74c6c8..ab84d4c 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -56,6 +56,7 @@ namespace sc {
     class ColumnSpanSet;
     struct ColumnBlockPosition;
     struct RefUpdateContext;
+    class EditTextIterator;
 }
 class SvxFontItem;
 
@@ -231,6 +232,7 @@ friend class ScTable;
 friend struct ScRefCellValue;
 friend class ScDocumentImport;
 friend class sc::ColumnSpanSet;
+friend class sc::EditTextIterator;
 
     typedef ::std::vector<ScTable*> TableContainer;
 private:
diff --git a/sc/inc/edittextiterator.hxx b/sc/inc/edittextiterator.hxx
new file mode 100644
index 0000000..f160b63
--- /dev/null
+++ b/sc/inc/edittextiterator.hxx
@@ -0,0 +1,61 @@
+/* -*- 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/.
+ */
+
+#ifndef SC_EDITTEXTITERATOR_HXX
+#define SC_EDITTEXTITERATOR_HXX
+
+#include "address.hxx"
+#include "mtvelements.hxx"
+
+class ScColumn;
+class ScTable;
+class ScDocument;
+class EditTextObject;
+
+namespace sc {
+
+/**
+ * Iterate through all edit text cells in a given sheet.  The caller must
+ * check the validity of the sheet index passed to its constructor.
+ *
+ * It iterates from top to bottom, and then left to right order.
+ */
+class EditTextIterator
+{
+    const ScTable& mrTable;
+    const ScColumn* mpCol;
+    const ScColumn* mpColEnd;
+    const CellStoreType* mpCells;
+    CellStoreType::const_position_type maPos;
+    CellStoreType::const_iterator miEnd;
+
+    /**
+     * Move to the next edit text cell position if the current position is not
+     * an edit text.
+     */
+    const EditTextObject* seek();
+
+    /**
+     * Increment current position by one.
+     */
+    void incPos();
+    void incBlock();
+
+public:
+    EditTextIterator( const ScDocument& rDoc, SCTAB nTab );
+
+    const EditTextObject* first();
+    const EditTextObject* next();
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 06e8151..99c506b 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -210,6 +210,7 @@ friend class ScAttrRectIterator;
 friend class ScColumnTextWidthIterator;
 friend class ScDocumentImport;
 friend class sc::ColumnSpanSet;
+friend class sc::EditTextIterator;
 
 public:
                 ScTable( ScDocument* pDoc, SCTAB nNewTab, const OUString& rNewName,
diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index 468d7c6..4ed2092 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -49,6 +49,8 @@
 #include "dociter.hxx"
 #include "docsh.hxx"
 #include "queryparam.hxx"
+#include "edittextiterator.hxx"
+#include "editutil.hxx"
 
 #include "formula/IFunctionDescription.hxx"
 
@@ -4022,6 +4024,98 @@ void Test::testCellTextWidth()
     m_pDoc->DeleteTab(0);
 }
 
+bool checkEditTextIterator(sc::EditTextIterator& rIter, const char** pChecks)
+{
+    const EditTextObject* pText = rIter.first();
+    const char* p = *pChecks;
+
+    for (int i = 0; i < 100; ++i) // cap it to 100 loops.
+    {
+        if (!pText)
+            // No more edit cells. The check string array should end too.
+            return p == NULL;
+
+        if (!p)
+            // More edit cell, but no more check string. Bad.
+            return false;
+
+        if (pText->GetParagraphCount() != 1)
+            // For this test, we don't handle multi-paragraph text.
+            return false;
+
+        if (pText->GetText(0) != OUString::createFromAscii(p))
+            // Text differs from what's expected.
+            return false;
+
+        pText = rIter.next();
+        ++pChecks;
+        p = *pChecks;
+    }
+
+    return false;
+}
+
+void Test::testEditTextIterator()
+{
+    m_pDoc->InsertTab(0, "Test");
+
+    {
+        // First, try with an empty sheet.
+        sc::EditTextIterator aIter(*m_pDoc,0);
+        const char* pChecks[] = { NULL };
+        CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter, pChecks));
+    }
+
+    ScFieldEditEngine& rEditEngine = m_pDoc->GetEditEngine();
+
+    {
+        // Only set one edit cell.
+        rEditEngine.SetText("A2");
+        m_pDoc->SetEditText(ScAddress(0,1,0), rEditEngine.CreateTextObject());
+        sc::EditTextIterator aIter(*m_pDoc,0);
+        const char* pChecks[] = { "A2", NULL };
+        CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter, pChecks));
+    }
+
+    {
+        // Add a series of edit cells.
+        rEditEngine.SetText("A5");
+        m_pDoc->SetEditText(ScAddress(0,4,0), rEditEngine.CreateTextObject());
+        rEditEngine.SetText("A6");
+        m_pDoc->SetEditText(ScAddress(0,5,0), rEditEngine.CreateTextObject());
+        rEditEngine.SetText("A7");
+        m_pDoc->SetEditText(ScAddress(0,6,0), rEditEngine.CreateTextObject());
+        sc::EditTextIterator aIter(*m_pDoc,0);
+        const char* pChecks[] = { "A2", "A5", "A6", "A7", NULL };
+        CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter, pChecks));
+    }
+
+    {
+        // Add more edit cells to column C. Skip column B.
+        rEditEngine.SetText("C1");
+        m_pDoc->SetEditText(ScAddress(2,0,0), rEditEngine.CreateTextObject());
+        rEditEngine.SetText("C3");
+        m_pDoc->SetEditText(ScAddress(2,2,0), rEditEngine.CreateTextObject());
+        rEditEngine.SetText("C4");
+        m_pDoc->SetEditText(ScAddress(2,3,0), rEditEngine.CreateTextObject());
+        sc::EditTextIterator aIter(*m_pDoc,0);
+        const char* pChecks[] = { "A2", "A5", "A6", "A7", "C1", "C3", "C4", NULL };
+        CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter, pChecks));
+    }
+
+    {
+        // Add some numeric, string and formula cells.  This shouldn't affect the outcome.
+        m_pDoc->SetString(ScAddress(0,99,0), "=ROW()");
+        m_pDoc->SetValue(ScAddress(1,3,0), 1.2);
+        m_pDoc->SetString(ScAddress(2,4,0), "Simple string");
+        sc::EditTextIterator aIter(*m_pDoc,0);
+        const char* pChecks[] = { "A2", "A5", "A6", "A7", "C1", "C3", "C4", NULL };
+        CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter, pChecks));
+    }
+
+    m_pDoc->DeleteTab(0);
+}
+
 void Test::testCondFormatINSDEL()
 {
     // fdo#62206
diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index 5e8933c..fba750f 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -268,6 +268,7 @@ public:
     void testDeleteCol();
     void testAnchoredRotatedShape();
     void testCellTextWidth();
+    void testEditTextIterator();
 
     void testCondFormatINSDEL();
 
@@ -364,6 +365,7 @@ public:
     CPPUNIT_TEST(testDeleteCol);
     CPPUNIT_TEST(testAnchoredRotatedShape);
     CPPUNIT_TEST(testCellTextWidth);
+    CPPUNIT_TEST(testEditTextIterator);
     CPPUNIT_TEST(testCondFormatINSDEL);
     CPPUNIT_TEST_SUITE_END();
 
diff --git a/sc/source/core/data/edittextiterator.cxx b/sc/source/core/data/edittextiterator.cxx
new file mode 100644
index 0000000..e563f04
--- /dev/null
+++ b/sc/source/core/data/edittextiterator.cxx
@@ -0,0 +1,86 @@
+/* -*- 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 "edittextiterator.hxx"
+#include "document.hxx"
+#include "table.hxx"
+#include "column.hxx"
+
+namespace sc {
+
+EditTextIterator::EditTextIterator( const ScDocument& rDoc, SCTAB nTab ) :
+    mrTable(*rDoc.maTabs.at(nTab)),
+    mpCol(&mrTable.aCol[0]),
+    mpColEnd(mpCol + static_cast<size_t>(MAXCOLCOUNT)),
+    mpCells(&mpCol->maCells),
+    maPos(mpCells->position(0)),
+    miEnd(mpCells->end())
+{
+}
+
+const EditTextObject* EditTextIterator::seek()
+{
+    while (maPos.first->type != sc::element_type_edittext)
+    {
+        incBlock();
+        if (maPos.first == miEnd)
+        {
+            // Move to the next column.
+            ++mpCol;
+            if (mpCol == mpColEnd)
+                // No more columns.
+                return NULL;
+
+            mpCells = &mpCol->maCells;
+            maPos = mpCells->position(0);
+            miEnd = mpCells->end();
+        }
+    }
+
+    // We are on the right block type.
+    return sc::edittext_block::at(*maPos.first->data, maPos.second);
+}
+
+void EditTextIterator::incPos()
+{
+    if (maPos.second + 1 < maPos.first->size)
+        // Increment within the block.
+        ++maPos.second;
+    else
+        incBlock();
+}
+
+void EditTextIterator::incBlock()
+{
+    ++maPos.first;
+    maPos.second = 0;
+}
+
+const EditTextObject* EditTextIterator::first()
+{
+    mpCol = &mrTable.aCol[0];
+    mpColEnd = mpCol + static_cast<size_t>(MAXCOLCOUNT);
+    mpCells = &mpCol->maCells;
+    maPos = mpCells->position(0);
+    miEnd = mpCells->end();
+    return seek();
+}
+
+const EditTextObject* EditTextIterator::next()
+{
+    if (maPos.first == miEnd)
+        return NULL;
+
+    incPos();
+    return seek();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 9ca5e3da5ca5f68ced1917cf38773fd1060bede4
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Aug 20 14:56:27 2013 -0400

    Add a means to retrieve all formatting attributes in non-overlapping sections.
    
    Change-Id: Id04dffc135fad6bb66ea157cd280dd481cb80117

diff --git a/editeng/Library_editeng.mk b/editeng/Library_editeng.mk
index e9c5b4b..c4a9fbe 100644
--- a/editeng/Library_editeng.mk
+++ b/editeng/Library_editeng.mk
@@ -60,6 +60,7 @@ $(eval $(call gb_Library_add_exception_objects,editeng,\
     editeng/source/editeng/impedit3 \
     editeng/source/editeng/impedit4 \
     editeng/source/editeng/impedit5 \
+    editeng/source/editeng/sectionattribute \
     editeng/source/editeng/textconv \
     editeng/source/items/borderline \
     editeng/source/items/bulitem \
diff --git a/editeng/qa/unit/core-test.cxx b/editeng/qa/unit/core-test.cxx
index ae3749c..86f5eb8 100644
--- a/editeng/qa/unit/core-test.cxx
+++ b/editeng/qa/unit/core-test.cxx
@@ -21,9 +21,15 @@
 #include "editeng/editdoc.hxx"
 #include "editeng/svxacorr.hxx"
 #include "editeng/unofield.hxx"
+#include "editeng/wghtitem.hxx"
+#include "editeng/postitem.hxx"
+#include "editeng/sectionattribute.hxx"
+#include "editeng/editobj.hxx"
 
 #include <com/sun/star/text/textfield/Type.hpp>
 
+#include <boost/scoped_ptr.hpp>
+
 using namespace com::sun::star;
 
 namespace {
@@ -48,10 +54,13 @@ public:
      */
     void testAutocorrect();
 
+    void testSectionAttributes();
+
     CPPUNIT_TEST_SUITE(Test);
     CPPUNIT_TEST(testConstruction);
     CPPUNIT_TEST(testUnoTextFields);
     CPPUNIT_TEST(testAutocorrect);
+    CPPUNIT_TEST(testSectionAttributes);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -331,7 +340,91 @@ void Test::testAutocorrect()
 
         CPPUNIT_ASSERT_EQUAL(sExpected, aFoo.getResult());
     }
+}
+
+bool hasBold(const editeng::SectionAttribute& rSecAttr)
+{
+    std::vector<const SfxPoolItem*>::const_iterator it = rSecAttr.maAttributes.begin(), itEnd = rSecAttr.maAttributes.end();
+    for (; it != itEnd; ++it)
+    {
+        const SfxPoolItem* p = *it;
+        if (p->Which() != EE_CHAR_WEIGHT)
+            continue;
+
+        if (static_cast<const SvxWeightItem*>(p)->GetWeight() != WEIGHT_BOLD)
+            continue;
+
+        return true;
+    }
+    return false;
+}
+
+bool hasItalic(const editeng::SectionAttribute& rSecAttr)
+{
+    std::vector<const SfxPoolItem*>::const_iterator it = rSecAttr.maAttributes.begin(), itEnd = rSecAttr.maAttributes.end();
+    for (; it != itEnd; ++it)
+    {
+        const SfxPoolItem* p = *it;
+        if (p->Which() != EE_CHAR_ITALIC)
+            continue;
+
+        if (static_cast<const SvxPostureItem*>(p)->GetPosture() != ITALIC_NORMAL)
+            continue;
+
+        return true;
+    }
+    return false;
+}
+
+void Test::testSectionAttributes()
+{
+    EditEngine aEngine(mpItemPool);
+
+    boost::scoped_ptr<SfxItemSet> pSet(new SfxItemSet(aEngine.GetEmptyItemSet()));
+    SvxWeightItem aBold(WEIGHT_BOLD, EE_CHAR_WEIGHT);
+    SvxPostureItem aItalic(ITALIC_NORMAL, EE_CHAR_ITALIC);
 
+    OUString aParaText = "aaabbbccc";
+    aEngine.SetText(aParaText);
+    pSet->Put(aBold);
+    CPPUNIT_ASSERT_MESSAGE("There should be exactly one item.", pSet->Count() == 1);
+    aEngine.QuickSetAttribs(*pSet, ESelection(0,0,0,6)); // 'aaabbb' - end point is not inclusive.
+    pSet.reset(new SfxItemSet(aEngine.GetEmptyItemSet()));
+    pSet->Put(aItalic);
+    CPPUNIT_ASSERT_MESSAGE("There should be exactly one item.", pSet->Count() == 1);
+
+    aEngine.QuickSetAttribs(*pSet, ESelection(0,3,0,9)); // 'bbbccc'
+    boost::scoped_ptr<EditTextObject> pEditText(aEngine.CreateTextObject());
+    CPPUNIT_ASSERT_MESSAGE("Failed to create text object.", pEditText.get());
+    std::vector<editeng::SectionAttribute> aAttrs;
+    pEditText->GetAllSectionAttributes(aAttrs);
+
+    // Now, we should have a total of 3 sections.
+    CPPUNIT_ASSERT_MESSAGE("There should be 3 sections.", aAttrs.size() == 3);
+
+    // First section should be 0-3 of paragraph 0, and it should only have boldness applied.
+    const editeng::SectionAttribute* pSecAttr = &aAttrs[0];
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), pSecAttr->mnParagraph);
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), pSecAttr->mnStart);
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), pSecAttr->mnEnd);
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pSecAttr->maAttributes.size());
+    CPPUNIT_ASSERT_MESSAGE("This section must be bold.", hasBold(*pSecAttr));
+
+    // Second section should be 3-6, and it should be both bold and italic.
+    pSecAttr = &aAttrs[1];
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), pSecAttr->mnParagraph);
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), pSecAttr->mnStart);
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(6), pSecAttr->mnEnd);
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), pSecAttr->maAttributes.size());
+    CPPUNIT_ASSERT_MESSAGE("This section must be bold and italic.", hasBold(*pSecAttr) && hasItalic(*pSecAttr));
+
+    // Third section should be 6-9, and it should be only italic.
+    pSecAttr = &aAttrs[2];
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), pSecAttr->mnParagraph);
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(6), pSecAttr->mnStart);
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(9), pSecAttr->mnEnd);
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pSecAttr->maAttributes.size());
+    CPPUNIT_ASSERT_MESSAGE("This section must be italic.", hasItalic(*pSecAttr));
 }
 
 CPPUNIT_TEST_SUITE_REGISTRATION(Test);
diff --git a/editeng/source/editeng/editobj.cxx b/editeng/source/editeng/editobj.cxx
index bcbef1e..dbfd833 100644
--- a/editeng/source/editeng/editobj.cxx
+++ b/editeng/source/editeng/editobj.cxx
@@ -28,6 +28,7 @@
 
 #include "editeng/fieldupdater.hxx"
 #include "editeng/macros.hxx"
+#include "editeng/sectionattribute.hxx"
 #include <editobj2.hxx>
 #include <editeng/editdata.hxx>
 #include <editattr.hxx>
@@ -276,6 +277,11 @@ bool EditTextObject::RemoveCharAttribs( sal_uInt16 nWhich )
     return mpImpl->RemoveCharAttribs(nWhich);
 }
 
+void EditTextObject::GetAllSectionAttributes( std::vector<editeng::SectionAttribute>& rAttrs ) const
+{
+    mpImpl->GetAllSectionAttributes(rAttrs);
+}
+
 void EditTextObject::GetStyleSheet(sal_Int32 nPara, OUString& rName, SfxStyleFamily& eFamily) const
 {
     mpImpl->GetStyleSheet(nPara, rName, eFamily);
@@ -824,6 +830,149 @@ bool EditTextObjectImpl::RemoveCharAttribs( sal_uInt16 _nWhich )
     return bChanged;
 }
 
+namespace {
+
+class FindByParagraph : std::unary_function<editeng::SectionAttribute, bool>
+{
+    size_t mnPara;
+public:
+    FindByParagraph(size_t nPara) : mnPara(nPara) {}
+    bool operator() (const editeng::SectionAttribute& rAttr) const
+    {
+        return rAttr.mnParagraph == mnPara;
+    }
+};
+
+class FindBySectionStart : std::unary_function<editeng::SectionAttribute, bool>
+{
+    size_t mnPara;
+    size_t mnStart;
+public:
+    FindBySectionStart(size_t nPara, size_t nStart) : mnPara(nPara), mnStart(nStart) {}
+    bool operator() (const editeng::SectionAttribute& rAttr) const
+    {
+        return rAttr.mnParagraph == mnPara && rAttr.mnStart == mnStart;
+    }
+};
+
+}
+
+void EditTextObjectImpl::GetAllSectionAttributes( std::vector<editeng::SectionAttribute>& rAttrs ) const
+{
+    typedef std::vector<size_t> SectionBordersType;
+    typedef std::map<size_t, SectionBordersType> ParagraphsType;
+    ParagraphsType aParaBorders;
+
+    // First pass: determine section borders for each paragraph.
+    for (size_t nPara = 0; nPara < aContents.size(); ++nPara)
+    {
+        const ContentInfo& rC = aContents[nPara];
+        for (size_t nAttr = 0; nAttr < rC.aAttribs.size(); ++nAttr)
+        {
+            const XEditAttribute& rAttr = rC.aAttribs[nAttr];
+            const SfxPoolItem* pItem = rAttr.GetItem();
+            if (!pItem || pItem->Which() == EE_FEATURE_FIELD)
+                continue;
+
+            ParagraphsType::iterator it = aParaBorders.lower_bound(nPara);
+            SectionBordersType* pBorders = NULL;
+            if (it != aParaBorders.end() && !aParaBorders.key_comp()(nPara, it->first))
+            {
+                // Container for this paragraph already exists.
+                pBorders = &it->second;
+            }
+            else
+            {
+                it = aParaBorders.insert(it, ParagraphsType::value_type(nPara, SectionBordersType()));
+                pBorders = &it->second;
+            }
+
+            pBorders->push_back(rAttr.GetStart());
+            pBorders->push_back(rAttr.GetEnd());
+        }
+    }
+
+    // Sort and remove duplicates for each paragraph.
+    ParagraphsType::iterator it = aParaBorders.begin(), itEnd = aParaBorders.end();
+    for (; it != itEnd; ++it)
+    {
+        SectionBordersType& rBorders = it->second;
+        std::sort(rBorders.begin(), rBorders.end());
+        SectionBordersType::iterator itUniqueEnd = std::unique(rBorders.begin(), rBorders.end());
+        rBorders.erase(itUniqueEnd, rBorders.end());
+    }
+
+    std::vector<editeng::SectionAttribute> aAttrs;
+
+    // Create storage for each section.  Note that this creates storage even
+    // for unformatted sections.  The entries are sorted first by paragraph,
+    // then by section positions.  They don't overlap with each other.
+    it = aParaBorders.begin();
+    for (; it != itEnd; ++it)
+    {
+        size_t nPara = it->first;
+        const SectionBordersType& rBorders = it->second;
+        if (rBorders.empty())
+            continue;
+
+        SectionBordersType::const_iterator itBorder = rBorders.begin(), itBorderEnd = rBorders.end();
+        size_t nPrev = *itBorder;
+        size_t nCur;
+        for (++itBorder; itBorder != itBorderEnd; ++itBorder, nPrev = nCur)
+        {
+            nCur = *itBorder;
+            aAttrs.push_back(editeng::SectionAttribute(nPara, nPrev, nCur));
+        }
+    }
+
+    if (aAttrs.empty())
+        return;
+
+    // Go through all formatted paragraphs, and store format items.
+    it = aParaBorders.begin();
+    std::vector<editeng::SectionAttribute>::iterator itAttr = aAttrs.begin();
+    for (; it != itEnd; ++it)
+    {
+        size_t nPara = it->first;
+        const ContentInfo& rC = aContents[nPara];
+        if (itAttr->mnParagraph != nPara)
+            // Find the first container for the current paragraph.
+            itAttr = std::find_if(itAttr, aAttrs.end(), FindByParagraph(nPara));
+
+        if (itAttr == aAttrs.end())
+            // This should never happen. There is a logic error somewhere...
+            return;
+
+        // Remember this position.
+        std::vector<editeng::SectionAttribute>::iterator itAttrHead = itAttr;
+
+        for (size_t i = 0; i < rC.aAttribs.size(); ++i)
+        {
+            const XEditAttribute& rAttr = rC.aAttribs[i];
+            const SfxPoolItem* pItem = rAttr.GetItem();
+            if (!pItem || pItem->Which() == EE_FEATURE_FIELD)
+                continue;
+
+            size_t nStart = rAttr.GetStart(), nEnd = rAttr.GetEnd();
+            itAttr = itAttrHead;
+
+            // Find the container whose start position matches.
+            itAttr = std::find_if(itAttr, aAttrs.end(), FindBySectionStart(nPara, nStart));
+            if (itAttr == aAttrs.end())
+                // This should never happen. There is a logic error somewhere...
+                return;
+
+            for (; itAttr != aAttrs.end() && itAttr->mnEnd <= nEnd; ++itAttr)
+            {
+                editeng::SectionAttribute& rSecAttr = *itAttr;
+                rSecAttr.maAttributes.push_back(pItem);
+            }
+        }
+    }
+
+    rAttrs.swap(aAttrs);
+}
+
 void EditTextObjectImpl::GetStyleSheet(sal_Int32 nPara, OUString& rName, SfxStyleFamily& rFamily) const
 {
     if (nPara < 0 || static_cast<size_t>(nPara) >= aContents.size())
diff --git a/editeng/source/editeng/editobj2.hxx b/editeng/source/editeng/editobj2.hxx
index d602753..b243647 100644
--- a/editeng/source/editeng/editobj2.hxx
+++ b/editeng/source/editeng/editobj2.hxx
@@ -28,6 +28,12 @@
 #include <boost/ptr_container/ptr_vector.hpp>
 #include <boost/noncopyable.hpp>
 
+namespace editeng {
+
+struct SectionAttribute;
+
+}
+
 class XEditAttribute
 {
 private:
@@ -219,6 +225,8 @@ public:
 
     bool RemoveCharAttribs( sal_uInt16 nWhich = 0 );
 
+    void GetAllSectionAttributes( std::vector<editeng::SectionAttribute>& rAttrs ) const;
+
     bool IsFieldObject() const;
     const SvxFieldItem* GetField() const;
     const SvxFieldData* GetFieldData(sal_Int32 nPara, size_t nPos, sal_Int32 nType) const;
diff --git a/editeng/source/editeng/sectionattribute.cxx b/editeng/source/editeng/sectionattribute.cxx
new file mode 100644
index 0000000..d8e0e57
--- /dev/null
+++ b/editeng/source/editeng/sectionattribute.cxx
@@ -0,0 +1,21 @@
+/* -*- 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 "editeng/sectionattribute.hxx"
+
+namespace editeng {
+
+SectionAttribute::SectionAttribute() : mnParagraph(0), mnStart(0), mnEnd(0) {}
+
+SectionAttribute::SectionAttribute(size_t nPara, size_t nStart, size_t nEnd) :
+    mnParagraph(nPara), mnStart(nStart), mnEnd(nEnd){}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/editeng/editobj.hxx b/include/editeng/editobj.hxx
index 570615f..c61f682 100644
--- a/include/editeng/editobj.hxx
+++ b/include/editeng/editobj.hxx
@@ -45,6 +45,7 @@ namespace editeng {
 
 class FieldUpdater;
 class FieldUpdaterImpl;
+struct SectionAttribute;
 
 }
 
@@ -99,6 +100,18 @@ public:
 
     bool RemoveCharAttribs( sal_uInt16 nWhich = 0 );
 
+    /**
+     * Get all attributes that are applied to this content, separated by
+     * sections.  If multiple attributes are applied to the same section, the
+     * object representing that section will store multiple attributes.
+     * Sections never overlap each other; if an attribute was applied to [0-6]
+     * and another applied to [3-10], you would get 3 sections that are [0-3],
+     * [3-6] and [6-10].
+     *
+     * <p>Note that this method skips field attributes.</p>
+     */
+    void GetAllSectionAttributes( std::vector<editeng::SectionAttribute>& rAttrs ) const;
+
     bool IsFieldObject() const;
     const SvxFieldItem* GetField() const;
     const SvxFieldData* GetFieldData(sal_Int32 nPara, size_t nPos, sal_Int32 nType) const;
diff --git a/include/editeng/sectionattribute.hxx b/include/editeng/sectionattribute.hxx
new file mode 100644
index 0000000..eafd4e2
--- /dev/null
+++ b/include/editeng/sectionattribute.hxx
@@ -0,0 +1,37 @@
+/* -*- 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/.
+ */
+
+#ifndef EDITENG_SECTIONATTRIBUTE_HXX
+#define EDITENG_SECTIONATTRIBUTE_HXX
+
+#include "editeng/editengdllapi.h"
+
+#include <vector>
+
+class SfxPoolItem;
+
+namespace editeng {
+
+struct EDITENG_DLLPUBLIC SectionAttribute
+{
+    size_t mnParagraph;
+    size_t mnStart;
+    size_t mnEnd;
+
+    std::vector<const SfxPoolItem*> maAttributes;
+
+    SectionAttribute();
+    SectionAttribute(size_t nPara, size_t nStart, size_t nEnd);
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list