sw/CppunitTest_sw_tox.mk                    |    1 
 sw/Library_sw.mk                            |    1 
 sw/inc/ToxLinkProcessor.hxx                 |   86 ++++++++++++++++++
 sw/inc/ToxTextGenerator.hxx                 |   12 +-
 sw/qa/cppunit/tox/test_ToxLinkProcessor.cxx |  133 ++++++++++++++++++++++++++++
 sw/source/core/tox/ToxLinkProcessor.cxx     |   70 ++++++++++++++
 sw/source/core/tox/ToxTextGenerator.cxx     |   66 ++-----------
 7 files changed, 312 insertions(+), 57 deletions(-)

New commits:
commit 94b296d5416dd71d721ad16216b50bce79e3dc04
Author: Tobias Lippert <d...@fastmail.fm>
Date:   Sun Jun 1 14:18:39 2014 +0200

    Unittest link generation for table of contents.
    
    The logic was moved to a separate class and unittested.
    
    Conflicts:
        sw/inc/ToxTextGenerator.hxx
    
    Change-Id: I0e4475f5e2950cdfdfb07b89128c4ce1d6af3f22
    Reviewed-on: https://gerrit.libreoffice.org/9609
    Reviewed-by: Caolán McNamara <caol...@redhat.com>
    Tested-by: Caolán McNamara <caol...@redhat.com>

diff --git a/sw/CppunitTest_sw_tox.mk b/sw/CppunitTest_sw_tox.mk
index f372442..7911de3 100644
--- a/sw/CppunitTest_sw_tox.mk
+++ b/sw/CppunitTest_sw_tox.mk
@@ -14,6 +14,7 @@ $(eval $(call gb_CppunitTest_CppunitTest,sw_tox_test))
 
 $(eval $(call gb_CppunitTest_add_exception_objects,sw_tox_test, \
        sw/qa/cppunit/tox/test_ToxWhitespaceStripper \
+       sw/qa/cppunit/tox/test_ToxLinkProcessor \
 ))
 
 $(eval $(call gb_CppunitTest_use_libraries,sw_tox_test, \
diff --git a/sw/Library_sw.mk b/sw/Library_sw.mk
index a7500ad..c073564 100644
--- a/sw/Library_sw.mk
+++ b/sw/Library_sw.mk
@@ -388,6 +388,7 @@ $(eval $(call gb_Library_add_exception_objects,sw,\
     sw/source/core/tox/tox \
     sw/source/core/tox/toxhlp \
     sw/source/core/tox/txmsrt \
+    sw/source/core/tox/ToxLinkProcessor \
     sw/source/core/tox/ToxTextGenerator \
     sw/source/core/tox/ToxWhitespaceStripper \
     sw/source/core/txtnode/SwGrammarContact \
diff --git a/sw/inc/ToxLinkProcessor.hxx b/sw/inc/ToxLinkProcessor.hxx
new file mode 100644
index 0000000..5a45465
--- /dev/null
+++ b/sw/inc/ToxLinkProcessor.hxx
@@ -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/.
+ */
+
+#ifndef SW_TOXLINKPROCESSOR_HXX_
+#define SW_TOXLINKPROCESSOR_HXX_
+
+#include "fmtinfmt.hxx"
+#include "rtl/ustring.hxx"
+
+#include <vector>
+
+class SwTxtNode;
+
+class ToxLinkProcessorTest;
+
+namespace sw {
+
+/** A helper class for ToxTextGenerator.
+ * It collects information about encountered link tokens and allows access in 
a processed form.
+ */
+class SW_DLLPUBLIC ToxLinkProcessor {
+public:
+    ToxLinkProcessor() {;}
+    virtual ~ToxLinkProcessor() {;}
+
+    void
+    StartNewLink(sal_Int32 startPosition, const OUString& characterStyle);
+
+    /** Close a link which has been found during processing.
+     *
+     * @throw std::runtime_error If there are no open links.
+     */
+    void
+    CloseLink(sal_Int32 endPosition, const OUString& url);
+
+    /** Insert the found links as attributes to a text node */
+    void
+    InsertLinkAttributes(SwTxtNode& node);
+
+private:
+    /** Obtain the pool id which belongs to a character style.
+     *
+     * @internal
+     * This method is overridden in the unittests. You should not override it 
yourself.
+     */
+    virtual sal_uInt16
+    ObtainPoolId(const OUString& characterStyle) const;
+
+    /** Information about a started link */
+    struct StartedLink {
+        StartedLink(sal_Int32 startPosition, OUString characterStyle) :
+                mStartPosition(startPosition), mCharacterStyle(characterStyle) 
{
+            ;
+        }
+        sal_Int32 mStartPosition;
+        OUString mCharacterStyle;
+    };
+
+    /** A link that has been encountered while parsing a tox.
+     * A link is closed if it has both a start and an end token.
+     */
+    struct ClosedLink {
+        ClosedLink(const OUString& url, sal_Int32 startPosition, sal_Int32 
endPosition) :
+                mINetFmt(url, OUString()), mStartTextPos(endPosition), 
mEndTextPos(startPosition) {
+        }
+        SwFmtINetFmt mINetFmt;
+        sal_Int32 mStartTextPos;
+        sal_Int32 mEndTextPos;
+    };
+
+    std::vector<ClosedLink> mClosedLinks;
+
+    std::vector<StartedLink> mStartedLinks;
+
+    friend class ::ToxLinkProcessorTest;
+};
+
+}
+
+#endif /* SW_TOXLINKPROCESSOR_HXX_ */
diff --git a/sw/inc/ToxTextGenerator.hxx b/sw/inc/ToxTextGenerator.hxx
index e64c8b6..d83736b 100644
--- a/sw/inc/ToxTextGenerator.hxx
+++ b/sw/inc/ToxTextGenerator.hxx
@@ -22,6 +22,7 @@
 
 #include "sal/types.h"
 #include "swdllapi.h"
+#include <boost/shared_ptr.hpp>
 #include <vector>
 
 class SwDoc;
@@ -31,12 +32,15 @@ struct SwTOXSortTabBase;
 
 namespace sw {
 
+class ToxLinkProcessor;
+
 class SW_DLLPUBLIC ToxTextGenerator
 {
 public:
-    ToxTextGenerator(const SwForm& toxForm)
-        : mToxForm(toxForm)
-    {}
+    ToxTextGenerator(const SwForm& toxForm);
+
+    ~ToxTextGenerator();
+
     /** Generate the text for an entry of a table of X (X is, e.g., content).
      *
      * This method will process the entries in @p entries, starting at @p 
indexOfEntryToProcess and
@@ -47,9 +51,9 @@ public:
                       sal_uInt16 indexOfEntryToProcess, sal_uInt16 
numberOfEntriesToProcess,
                       sal_uInt32 _nTOXSectNdIdx, const SwPageDesc* 
_pDefaultPageDesc);
 
-
 private:
     const SwForm& mToxForm;
+    boost::shared_ptr<ToxLinkProcessor> mLinkProcessor;
 };
 
 }
diff --git a/sw/qa/cppunit/tox/test_ToxLinkProcessor.cxx 
b/sw/qa/cppunit/tox/test_ToxLinkProcessor.cxx
new file mode 100644
index 0000000..9dc621f
--- /dev/null
+++ b/sw/qa/cppunit/tox/test_ToxLinkProcessor.cxx
@@ -0,0 +1,133 @@
+/* -*- 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 <stdexcept>
+
+#include <sal/types.h>
+
+#include <rtl/ustring.hxx>
+
+#include <ToxLinkProcessor.hxx>
+
+#include <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+
+using namespace sw;
+
+class ToxLinkProcessorTest : public CppUnit::TestFixture
+{
+    void ExceptionIsThrownIfTooManyLinksAreClosed();
+    void AddingAndClosingTwoLinksResultsInTwoClosedLinks();
+    void LinkIsCreatedCorrectly();
+    void LinkSequenceIsPreserved();
+
+    CPPUNIT_TEST_SUITE(ToxLinkProcessorTest);
+    CPPUNIT_TEST(ExceptionIsThrownIfTooManyLinksAreClosed);
+    CPPUNIT_TEST(AddingAndClosingTwoLinksResultsInTwoClosedLinks);
+    CPPUNIT_TEST(LinkIsCreatedCorrectly);
+    CPPUNIT_TEST(LinkSequenceIsPreserved);
+    CPPUNIT_TEST_SUITE_END();
+public:
+    static const OUString STYLE_NAME_1;
+    static const OUString STYLE_NAME_2;
+    static const sal_uInt16 POOL_ID_1;
+    static const sal_uInt16 POOL_ID_2;
+    static const OUString URL_1;
+    static const OUString URL_2;
+};
+
+const OUString ToxLinkProcessorTest::STYLE_NAME_1 = "anyStyle1";
+const OUString ToxLinkProcessorTest::STYLE_NAME_2 = "anyStyle2";
+const OUString ToxLinkProcessorTest::URL_1 = "anyUrl1";
+const OUString ToxLinkProcessorTest::URL_2 = "anyUrl2";
+const sal_uInt16 ToxLinkProcessorTest::POOL_ID_1 = 42;
+const sal_uInt16 ToxLinkProcessorTest::POOL_ID_2 = 43;
+
+void
+ToxLinkProcessorTest::ExceptionIsThrownIfTooManyLinksAreClosed()
+{
+    ToxLinkProcessor sut;
+    sut.StartNewLink(0, STYLE_NAME_1);
+    sut.CloseLink(1, URL_1);
+    CPPUNIT_ASSERT_THROW(sut.CloseLink(1, URL_1), std::runtime_error);
+}
+
+void
+ToxLinkProcessorTest::AddingAndClosingTwoLinksResultsInTwoClosedLinks()
+{
+    ToxLinkProcessor sut;
+    sut.StartNewLink(0, STYLE_NAME_1);
+    sut.StartNewLink(0, STYLE_NAME_2);
+    sut.CloseLink(1, URL_1);
+    sut.CloseLink(1, URL_2);
+    CPPUNIT_ASSERT_EQUAL(2u, static_cast<unsigned>(sut.mClosedLinks.size()));
+    CPPUNIT_ASSERT_MESSAGE("no links are open", sut.mStartedLinks.empty());
+}
+
+class ToxLinkProcessorWithOverriddenObtainPoolId : public ToxLinkProcessor {
+public:
+    /*virtual*/ sal_uInt16
+    ObtainPoolId(const OUString& characterStyle) const {
+        if (characterStyle == ToxLinkProcessorTest::STYLE_NAME_1) {
+            return ToxLinkProcessorTest::POOL_ID_1;
+        }
+        if (characterStyle == ToxLinkProcessorTest::STYLE_NAME_2) {
+            return ToxLinkProcessorTest::POOL_ID_2;
+        }
+        return 0;
+    }
+};
+
+void
+ToxLinkProcessorTest::LinkIsCreatedCorrectly()
+{
+    // obtainpoolid needs to be overridden to check what we are
+    ToxLinkProcessorWithOverriddenObtainPoolId sut;
+
+    sut.StartNewLink(0, STYLE_NAME_1);
+    sut.CloseLink(1, URL_1);
+
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Style is stored correctly in link", 
STYLE_NAME_1, sut.mClosedLinks.at(0).mINetFmt.GetVisitedFmt());
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Url is stored correctly in link", URL_1, 
sut.mClosedLinks.at(0).mINetFmt.GetValue());
+}
+
+void
+ToxLinkProcessorTest::LinkSequenceIsPreserved()
+{
+
+    // obtainpoolid needs to be overridden to check what we are
+    ToxLinkProcessorWithOverriddenObtainPoolId sut;
+
+    sut.StartNewLink(0, STYLE_NAME_1);
+    sut.StartNewLink(0, STYLE_NAME_2);
+    sut.CloseLink(1, URL_2);
+    sut.CloseLink(1, URL_1);
+
+    // check first closed element
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Style is stored correctly in link",
+            STYLE_NAME_2, sut.mClosedLinks.at(0).mINetFmt.GetVisitedFmt());
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Pool id is stored correctly in link",
+            POOL_ID_2, sut.mClosedLinks.at(0).mINetFmt.GetINetFmtId());
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Url is stored correctly in link",
+            URL_2, sut.mClosedLinks.at(0).mINetFmt.GetValue());
+    // check second closed element
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Style is stored correctly in link",
+            STYLE_NAME_1, sut.mClosedLinks.at(1).mINetFmt.GetVisitedFmt());
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Pool id is stored correctly in link",
+            POOL_ID_1, sut.mClosedLinks.at(1).mINetFmt.GetINetFmtId());
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Url is stored correctly in link",
+            URL_1, sut.mClosedLinks.at(1).mINetFmt.GetValue());
+}
+
+// Put the test suite in the registry
+CPPUNIT_TEST_SUITE_REGISTRATION(ToxLinkProcessorTest);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/tox/ToxLinkProcessor.cxx 
b/sw/source/core/tox/ToxLinkProcessor.cxx
new file mode 100644
index 0000000..e236f00
--- /dev/null
+++ b/sw/source/core/tox/ToxLinkProcessor.cxx
@@ -0,0 +1,70 @@
+/* -*- 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 "ToxLinkProcessor.hxx"
+
+#include "SwStyleNameMapper.hxx"
+#include "ndtxt.hxx"
+
+#include <boost/foreach.hpp>
+#include <stdexcept>
+
+namespace sw {
+
+void
+ToxLinkProcessor::StartNewLink(sal_Int32 startPosition, const OUString& 
characterStyle)
+{
+    mStartedLinks.push_back(StartedLink(startPosition, characterStyle));
+}
+
+void
+ToxLinkProcessor::CloseLink(sal_Int32 endPosition, const OUString& url)
+{
+    if (mStartedLinks.empty()) {
+        throw std::runtime_error("ToxLinkProcessor: More calls for CloseLink() 
than open links exist.");
+    }
+    StartedLink startedLink = mStartedLinks.back();
+    mStartedLinks.pop_back();
+
+    if (url.isEmpty()) {
+        return;
+    }
+
+    ClosedLink closedLink(url, startedLink.mStartPosition, endPosition);
+
+    const OUString& characterStyle = startedLink.mCharacterStyle;
+    sal_uInt16 poolId = ObtainPoolId(characterStyle);
+    closedLink.mINetFmt.SetVisitedFmtAndId(characterStyle, poolId);
+    closedLink.mINetFmt.SetINetFmtAndId(characterStyle, poolId);
+
+    mClosedLinks.push_back(closedLink);
+}
+
+sal_uInt16
+ToxLinkProcessor::ObtainPoolId(const OUString& characterStyle) const
+{
+    if (characterStyle.isEmpty()) {
+        return USHRT_MAX;
+    }
+    else {
+        return SwStyleNameMapper::GetPoolIdFromUIName(characterStyle, 
nsSwGetPoolIdFromName::GET_POOLID_CHRFMT);
+    }
+}
+
+
+void
+ToxLinkProcessor::InsertLinkAttributes(SwTxtNode& node)
+{
+    BOOST_FOREACH(ClosedLink& clink, mClosedLinks) {
+        node.InsertItem(clink.mINetFmt, clink.mStartTextPos, 
clink.mEndTextPos);
+    }
+}
+
+}
+
diff --git a/sw/source/core/tox/ToxTextGenerator.cxx 
b/sw/source/core/tox/ToxTextGenerator.cxx
index 8554c88..86e8777 100644
--- a/sw/source/core/tox/ToxTextGenerator.cxx
+++ b/sw/source/core/tox/ToxTextGenerator.cxx
@@ -34,22 +34,12 @@
 #include "DocumentSettingManager.hxx"
 #include "SwStyleNameMapper.hxx"
 #include "ToxWhitespaceStripper.hxx"
+#include "ToxLinkProcessor.hxx"
 
 #include "editeng/tstpitem.hxx"
 #include "editeng/lrspitem.hxx"
 #include "rtl/ustring.hxx"
 
-struct LinkStruct
-{
-    SwFmtINetFmt    aINetFmt;
-    sal_Int32 nStartTextPos, nEndTextPos;
-
-    LinkStruct( const OUString& rURL, sal_Int32 nStart, sal_Int32 nEnd )
-        : aINetFmt( rURL, OUString()),
-        nStartTextPos( nStart),
-        nEndTextPos(nEnd) {}
-};
-
 /// Generate String according to the Form and remove the
 /// special characters 0-31 and 255.
 static OUString lcl_GetNumString( const SwTOXSortTabBase& rBase, bool 
bUsePrefix, sal_uInt8 nLevel )
@@ -70,18 +60,22 @@ static OUString lcl_GetNumString( const SwTOXSortTabBase& 
rBase, bool bUsePrefix
     return sRet;
 }
 
-typedef std::vector<LinkStruct*> LinkStructArr;
-
 namespace sw {
 
+ToxTextGenerator::ToxTextGenerator(const SwForm& toxForm)
+:mToxForm(toxForm),
+ mLinkProcessor(new ToxLinkProcessor())
+{;}
+
+ToxTextGenerator::~ToxTextGenerator()
+{;}
+
 // Add parameter <_TOXSectNdIdx> and <_pDefaultPageDesc> in order to control,
 // which page description is used, no appropriate one is found.
 void ToxTextGenerator::GenerateText(SwDoc* pDoc, const 
std::vector<SwTOXSortTabBase*> &entries,
         sal_uInt16 indexOfEntryToProcess, sal_uInt16 numberOfEntriesToProcess, 
sal_uInt32 _nTOXSectNdIdx,
         const SwPageDesc* _pDefaultPageDesc)
 {
-    LinkStructArr   aLinkArr;
-
     // pTOXNd is only set at the first mark
     SwTxtNode* pTOXNd = (SwTxtNode*)entries.at(indexOfEntryToProcess)->pTOXNd;
     // FIXME this operates directly on the node text
@@ -97,9 +91,6 @@ void ToxTextGenerator::GenerateText(SwDoc* pDoc, const 
std::vector<SwTOXSortTabB
         OSL_ENSURE( nLvl < mToxForm.GetFormMax(), "invalid FORM_LEVEL");
 
         SvxTabStopItem aTStops( 0, 0, SVX_TAB_ADJUST_DEFAULT, 
RES_PARATR_TABSTOP );
-        sal_Int32 nLinkStartPosition = -1;
-        OUString  sLinkCharacterStyle; // default to "Default" character style 
- which is none
-        OUString sURL;
         // create an enumerator
         // #i21237#
         SwFormTokens aPattern = mToxForm.GetPattern(nLvl);
@@ -276,36 +267,11 @@ void ToxTextGenerator::GenerateText(SwDoc* pDoc, const 
std::vector<SwTOXSortTabB
                 break;
 
             case TOKEN_LINK_START:
-                nLinkStartPosition = rTxt.getLength();
-                sLinkCharacterStyle = aToken.sCharStyleName;
-            break;
+                mLinkProcessor->StartNewLink(rTxt.getLength(), 
aToken.sCharStyleName);
+                break;
 
             case TOKEN_LINK_END:
-                    //TODO: only paired start/end tokens are valid
-                if (nLinkStartPosition != -1)
-                {
-                    SwIndex aIdx( pTOXNd, nLinkStartPosition );
-                    // pTOXNd->Erase( aIdx, SwForm::nFormLinkSttLen );
-                    sal_Int32 nEnd = rTxt.getLength();
-
-                    if( sURL.isEmpty() )
-                    {
-                        sURL = rBase.GetURL();
-                        if( sURL.isEmpty() )
-                            break;
-                    }
-                    LinkStruct* pNewLink = new LinkStruct(sURL, 
nLinkStartPosition,
-                                                    nEnd);
-                    const sal_uInt16 nPoolId =
-                            sLinkCharacterStyle.isEmpty()
-                            ? USHRT_MAX
-                            : SwStyleNameMapper::GetPoolIdFromUIName( 
sLinkCharacterStyle, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT );
-                    pNewLink->aINetFmt.SetVisitedFmtAndId( 
sLinkCharacterStyle, nPoolId );
-                    pNewLink->aINetFmt.SetINetFmtAndId( sLinkCharacterStyle, 
nPoolId );
-                    aLinkArr.push_back(pNewLink);
-                    nLinkStartPosition = -1;
-                    sLinkCharacterStyle = "";
-                }
+                mLinkProcessor->CloseLink(rTxt.getLength(), rBase.GetURL());
                 break;
 
             case TOKEN_AUTHORITY:
@@ -339,13 +305,7 @@ void ToxTextGenerator::GenerateText(SwDoc* pDoc, const 
std::vector<SwTOXSortTabB
 
         pTOXNd->SetAttr( aTStops );
     }
-
-    for(LinkStructArr::const_iterator i = aLinkArr.begin(); i != 
aLinkArr.end(); ++i)
-    {
-        pTOXNd->InsertItem((*i)->aINetFmt, (*i)->nStartTextPos,
-                           (*i)->nEndTextPos);
-        delete (*i);
-    }
+    mLinkProcessor->InsertLinkAttributes(*pTOXNd);
 }
 
 } // end namespace sw
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to