[Libreoffice-commits] core.git: Branch 'feature/chained-text-boxes' - 15 commits - editeng/Library_editeng.mk editeng/source include/editeng include/svx sd/source svx/inc svx/Library_svxcore.mk svx/source xmloff/source

Thorsten Behrens Thorsten.Behrens at CIB.de
Sat Sep 19 17:02:46 PDT 2015


Rebased ref, commits from common ancestor:
commit 133498a53c9b639c29eb7c2f90dec6feb8dd476e
Author: Thorsten Behrens <Thorsten.Behrens at CIB.de>
Date:   Sun Sep 20 01:42:12 2015 +0200

    chained editeng: Convert fprintf to SAL_INFO
    
    Change-Id: I8e0cfedd34d7e0d70a30147a3bbf0f1cd8e6d3cc

diff --git a/editeng/source/editeng/impedit3.cxx b/editeng/source/editeng/impedit3.cxx
index 70072a2..74eb16d 100644
--- a/editeng/source/editeng/impedit3.cxx
+++ b/editeng/source/editeng/impedit3.cxx
@@ -564,18 +564,13 @@ void ImpEditEngine::CheckAutoPageSize()
 
 void ImpEditEngine::CheckPageOverflow()
 {
-    // FIXME(matteocam)
-    /* fprintf( stderr, IsPageOverflow(aPaperSize, aPrevPaperSize)
-                        ? "YES Overflow!\n"  : "NO Overflow!\n" ); */
-    // setting overflow status
-
-    fprintf(stderr, "[CONTROL_STATUS] AutoPageSize is %s",  ( aStatus.GetControlWord() & EEControlBits::AUTOPAGESIZE ) ? "ON\n" : "OFF\n" );
+    SAL_INFO("editeng.chaining", "[CONTROL_STATUS] AutoPageSize is " << (( aStatus.GetControlWord() & EEControlBits::AUTOPAGESIZE ) ? "ON" : "OFF") );
 
     sal_uInt32 nBoxHeight = GetMaxAutoPaperSize().Height();
-    fprintf(stderr, "[OVERFLOW-CHECK] Current MaxAutoPaperHeight is %d\n", nBoxHeight);
+    SAL_INFO("editeng.chaining", "[OVERFLOW-CHECK] Current MaxAutoPaperHeight is " << nBoxHeight);
 
     sal_uInt32 nTxtHeight = CalcTextHeight(NULL);
-    fprintf(stderr, "[OVERFLOW-CHECK] Current Text Height is %d\n", nTxtHeight);
+    SAL_INFO("editeng.chaining", "[OVERFLOW-CHECK] Current Text Height is " << nTxtHeight);
 
     sal_uInt32 nParaCount = GetParaPortions().Count();
     sal_uInt32 nFirstLineCount = GetLineCount(0);
@@ -4636,7 +4631,7 @@ void ImpEditEngine::ImplUpdateOverflowingParaNum(sal_uInt32 nPaperHeight)
         if ( nY > nPaperHeight /*nCurTextHeight*/ ) // found first paragraph overflowing
         {
             mnOverflowingPara = nPara;
-            fprintf(stderr, "[CHAINING] Setting first overflowing #Para#: %d\n", nPara);
+            SAL_INFO("editeng.chaining", "[CHAINING] Setting first overflowing #Para#: " << nPara);
             ImplUpdateOverflowingLineNum( nPaperHeight, nPara, nY-nPH);
             return;
         }
@@ -4662,13 +4657,13 @@ void ImpEditEngine::ImplUpdateOverflowingLineNum(sal_uInt32 nPaperHeight,
 
         // Debugging output
         if (nLine == 0) {
-            fprintf(stderr, "[CHAINING] First line has height %d\n", nLH);
+            SAL_INFO("editeng.chaining", "[CHAINING] First line has height " << nLH);
         }
 
         if ( nY > nPaperHeight ) // found first line overflowing
         {
             mnOverflowingLine = nLine;
-            fprintf(stderr, "[CHAINING] Setting first overflowing -Line- to: %d\n", nLine);
+            SAL_INFO("editeng.chaining", "[CHAINING] Setting first overflowing -Line- to: " << nLine);
             return;
         }
     }
diff --git a/editeng/source/outliner/outliner.cxx b/editeng/source/outliner/outliner.cxx
index 77bb66a..040bc6e 100644
--- a/editeng/source/outliner/outliner.cxx
+++ b/editeng/source/outliner/outliner.cxx
@@ -2094,17 +2094,16 @@ NonOverflowingText *Outliner::GetNonOverflowingText() const
 
     // Defensive check: oveflowing para index beyond actual # of paragraphs?
     if ( nCount > GetParagraphCount()-1) {
-        fprintf(stderr,
-                "[Overflowing] Ops, trying to retrieve para %d when max index is %d\n",
-                nCount,
-                GetParagraphCount()-1);
+        SAL_INFO("editeng.chaining",
+                 "[Overflowing] Ops, trying to retrieve para "
+                 << nCount << " when max index is " << GetParagraphCount()-1 );
         return NULL;
     }
 
      if (nCount < 0)
      {
-        fprintf(stderr,
-                "[Overflowing] No Overflowing text but GetNonOverflowinText called?!\n");
+        SAL_INFO("editeng.chaining",
+                 "[Overflowing] No Overflowing text but GetNonOverflowinText called?!");
         return NULL;
      }
 
@@ -2202,10 +2201,10 @@ OverflowingText *Outliner::GetOverflowingText() const
 
     // Defensive check: oveflowing para index beyond actual # of paragraphs?
     if ( pEditEngine->GetOverflowingParaNum() > GetParagraphCount()-1) {
-        fprintf(stderr,
-                "[Overflowing] Ops, trying to retrieve para %d when max index is %d\n",
-                pEditEngine->GetOverflowingParaNum(),
-                GetParagraphCount()-1);
+        SAL_INFO("editeng.chaining",
+                 "[Overflowing] Ops, trying to retrieve para "
+                 << pEditEngine->GetOverflowingParaNum() << " when max index is "
+                 << GetParagraphCount()-1 );
         return NULL;
     }
 
diff --git a/editeng/source/outliner/overflowingtxt.cxx b/editeng/source/outliner/overflowingtxt.cxx
index bd0f59f..fb5abd0 100644
--- a/editeng/source/outliner/overflowingtxt.cxx
+++ b/editeng/source/outliner/overflowingtxt.cxx
@@ -158,11 +158,9 @@ bool NonOverflowingText::IsLastParaInterrupted() const
 OutlinerParaObject *NonOverflowingText::RemoveOverflowingText(Outliner *pOutliner) const
 {
     pOutliner->QuickDelete(maContentSel);
-    fprintf(stderr, "Deleting selection from (Para: %d, Pos: %d) to (Para: %d, Pos: %d)\n",
-            maContentSel.nStartPara,
-            maContentSel.nStartPos,
-            maContentSel.nEndPara,
-            maContentSel.nEndPos);
+    SAL_INFO("editeng.chaining", "Deleting selection from (Para: " << maContentSel.nStartPara
+             << ", Pos: " << maContentSel.nStartPos << ") to (Para: " << maContentSel.nEndPara
+             << ", Pos: " << maContentSel.nEndPos ")\n");
     return pOutliner->CreateParaObject();
 }
 
@@ -213,10 +211,10 @@ OutlinerParaObject *OFlowChainedText::InsertOverflowingText(Outliner *pOutliner,
         return NULL;
 
     if (mbIsDeepMerge) {
-        fprintf(stderr, "[TEXTCHAINFLOW - OF] Deep merging paras\n" );
+        SAL_INFO("editeng.chaining", "[TEXTCHAINFLOW - OF] Deep merging paras" );
         return mpOverflowingTxt->DeeplyMergeParaObject(pOutliner, pTextToBeMerged );
     } else {
-        fprintf(stderr, "[TEXTCHAINFLOW - OF] Juxtaposing paras\n" );
+        SAL_INFO("editeng.chaining", "[TEXTCHAINFLOW - OF] Juxtaposing paras" );
         return mpOverflowingTxt->JuxtaposeParaObject(pOutliner, pTextToBeMerged );
     }
 }
@@ -249,11 +247,11 @@ OutlinerParaObject *UFlowChainedText::CreateMergedUnderflowParaObject(Outliner *
     OutlinerParaObject *pNewText = NULL;
 
     if (mbIsDeepMerge) {
-        fprintf(stderr, "[TEXTCHAINFLOW - UF] Deep merging paras\n" );
+        SAL_INFO("editeng.chaining", "[TEXTCHAINFLOW - UF] Deep merging paras" );
         pNewText = TextChainingUtils::DeeplyMergeParaObject(mxUnderflowingTxt, pOutl, pNextLinkWholeText);
     } else {
         // NewTextForCurBox = Txt(CurBox) ++ Txt(NextBox)
-        fprintf(stderr, "[TEXTCHAINFLOW - UF] Juxtaposing paras\n" );
+        SAL_INFO("editeng.chaining", "[TEXTCHAINFLOW - UF] Juxtaposing paras" );
         pNewText = TextChainingUtils::JuxtaposeParaObject(mxUnderflowingTxt, pOutl, pNextLinkWholeText);
     }
 
commit d8c7e8b68bcd71925d5849e3d8a7cbd999b6980d
Author: matteocam <matteo.campanelli at gmail.com>
Date:   Mon Sep 7 20:01:35 2015 +0200

    chained editeng: Handle chaining for cutting and pasting
    
    Change-Id: Iec08e339a7f06c5fa56e67b42206b31c766f845b

diff --git a/editeng/source/outliner/outlvw.cxx b/editeng/source/outliner/outlvw.cxx
index 4a0d96e..edf617f 100644
--- a/editeng/source/outliner/outlvw.cxx
+++ b/editeng/source/outliner/outlvw.cxx
@@ -675,8 +675,12 @@ void OutlinerView::InsertText( const OutlinerParaObject& rParaObj )
 
 void OutlinerView::Cut()
 {
-    if ( !ImpCalcSelectedPages( false ) || pOwner->ImpCanDeleteSelectedPages( this ) )
+    if ( !ImpCalcSelectedPages( false ) || pOwner->ImpCanDeleteSelectedPages( this ) ) {
         pEditView->Cut();
+        // Chaining handling
+        if (aEndCutPasteLink.IsSet())
+            aEndCutPasteLink.Call(NULL);
+    }
 }
 
 void OutlinerView::Paste()
@@ -705,6 +709,11 @@ void OutlinerView::PasteSpecial()
         pEditView->SetEditEngineUpdateMode( true );
         pOwner->UndoActionEnd( OLUNDO_INSERT );
         pEditView->ShowCursor( true );
+
+        // Chaining handling
+        // NOTE: We need to do this last because it pEditView may be deleted if a switch of box occurs
+        if (aEndCutPasteLink.IsSet())
+            aEndCutPasteLink.Call(NULL);
     }
 }
 
commit edd3273fcb8ef1a3efab256722cc8c5ca7283e60
Author: matteocam <matteo.campanelli at gmail.com>
Date:   Mon Sep 7 19:58:16 2015 +0200

    chained editeng: Handle DEL key for chaining
    
    Change-Id: I124b1adf6df3c42a58d45eaeb0e1e053c0eea4c9

diff --git a/sd/source/ui/view/drviewse.cxx b/sd/source/ui/view/drviewse.cxx
index da65984..d9e0a99 100644
--- a/sd/source/ui/view/drviewse.cxx
+++ b/sd/source/ui/view/drviewse.cxx
@@ -950,7 +950,10 @@ void DrawViewShell::FuSupport(SfxRequest& rReq)
                 {
                     vcl::KeyCode aKCode(KEY_DELETE);
                     KeyEvent aKEvt( 0, aKCode);
-                    pOLV->PostKeyEvent(aKEvt);
+                    //pOLV->PostKeyEvent(aKEvt);
+                    // We use SdrObjEditView to handle DEL for underflow handling
+                    mpDrawView->KeyInput(aKEvt, NULL);
+
                 }
             }
             else
commit ca385fa6de8f72e638880116621b41a0fa216db3
Author: matteocam <matteo.campanelli at gmail.com>
Date:   Mon Sep 7 16:37:56 2015 +0200

    chained editeng: Enable chaining after a key is pressed
    
    Change-Id: I64351619dd0886f3bb0c080557864c46a17d737d

diff --git a/svx/source/svdraw/svdedxv.cxx b/svx/source/svdraw/svdedxv.cxx
index 288b5e4..19f1b46 100644
--- a/svx/source/svdraw/svdedxv.cxx
+++ b/svx/source/svdraw/svdedxv.cxx
@@ -1325,6 +1325,15 @@ bool SdrObjEditView::KeyInput(const KeyEvent& rKEvt, vcl::Window* pWin)
 {
     if(pTextEditOutlinerView)
     {
+        /* Start special handling of keys within a chain */
+        // We possibly move to another box before any handling
+        bool bHandled = false;
+        TextChainCursorManager *pCursorManager =
+            ImpHandleMotionThroughBoxesKeyInput(rKEvt, pWin, &bHandled);
+        if (bHandled)
+            return true;
+        /* End special handling of keys within a chain */
+
         if (pTextEditOutlinerView->PostKeyEvent(rKEvt, pWin))
         {
             if( mpModel )
@@ -1333,6 +1342,11 @@ bool SdrObjEditView::KeyInput(const KeyEvent& rKEvt, vcl::Window* pWin)
                     mpModel->SetChanged();
             }
 
+            /* Start chaining processing */
+            ImpChainingEventHdl();
+            ImpMoveCursorAfterChainingEvent(pCursorManager);
+            /* End chaining processing */
+
             if (pWin!=NULL && pWin!=pTextEditWin) SetTextEditWin(pWin);
 #ifdef DBG_UTIL
             if (mpItemBrowser!=nullptr) mpItemBrowser->SetDirty();
commit 6f3bc537f00ff5c8dd6af847b4c9caa8c35569e5
Author: matteocam <matteo.campanelli at gmail.com>
Date:   Mon Sep 7 16:33:39 2015 +0200

    chained editeng: Add methods and basic setup for editing-mode chaining
    
    Change-Id: I8065bebaf2a54170bc7b3ddbd35740bcca42298d

diff --git a/include/svx/svdedxv.hxx b/include/svx/svdedxv.hxx
index 2aa9f89..c388941 100644
--- a/include/svx/svdedxv.hxx
+++ b/include/svx/svdedxv.hxx
@@ -34,6 +34,7 @@ class EditFieldInfo;
 class ImpSdrEditPara;
 struct PasteOrDropInfos;
 class SdrUndoManager;
+class TextChainCursorManager;
 
 namespace com { namespace sun { namespace star { namespace uno {
     class Any;
@@ -101,6 +102,10 @@ protected:
     // provide their document UndoManager and derive it from SdrUndoManager.
     virtual SdrUndoManager* getSdrUndoManagerForEnhancedTextEdit() const;
 
+    void ImpMoveCursorAfterChainingEvent(TextChainCursorManager *pCursorManager);
+    TextChainCursorManager *ImpHandleMotionThroughBoxesKeyInput(const KeyEvent& rKEvt, vcl::Window* pWin, bool *bOutHandled);
+
+
     OutlinerView* ImpFindOutlinerView(vcl::Window* pWin) const;
 
     // Create a new OutlinerView at the heap and initialize all required parameters.
@@ -109,6 +114,11 @@ protected:
     void ImpPaintOutlinerView(OutlinerView& rOutlView, const Rectangle& rRect, OutputDevice& rTargetDevice) const;
     void ImpInvalidateOutlinerView(OutlinerView& rOutlView) const;
 
+    // Chaining
+    void ImpChainingEventHdl();
+    DECL_LINK(ImpAfterCutOrPasteChainingEventHdl,void*);
+
+
     // Check if the whole text is selected.
     // Still returns sal_True if there is no text present.
     bool ImpIsTextEditAllSelected() const;
diff --git a/sd/source/ui/view/outlview.cxx b/sd/source/ui/view/outlview.cxx
index 17fe875..c2687f6 100644
--- a/sd/source/ui/view/outlview.cxx
+++ b/sd/source/ui/view/outlview.cxx
@@ -1375,6 +1375,7 @@ void OutlineView::ResetLinks() const
     mrOutliner.SetDrawPortionHdl(Link<DrawPortionInfo*,void>());
     mrOutliner.SetBeginPasteOrDropHdl(Link<PasteOrDropInfos*,void>());
     mrOutliner.SetEndPasteOrDropHdl(Link<PasteOrDropInfos*,void>());
+    mrOutliner.SetChainingEventHdl(aEmptyLink);
 }
 
 sal_Int8 OutlineView::AcceptDrop( const AcceptDropEvent&, DropTargetHelper&, ::sd::Window*, sal_uInt16, sal_uInt16)
diff --git a/sd/source/ui/view/sdview.cxx b/sd/source/ui/view/sdview.cxx
index 18fbf2e..524faba 100644
--- a/sd/source/ui/view/sdview.cxx
+++ b/sd/source/ui/view/sdview.cxx
@@ -1204,6 +1204,7 @@ void View::OnBeginPasteOrDrop( PasteOrDropInfos* /*pInfos*/ )
     get the correct style sheet. */
 void View::OnEndPasteOrDrop( PasteOrDropInfos* pInfos )
 {
+    /* Style Sheet handling */
     SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( GetTextEditObject() );
     SdrOutliner* pOutliner = GetTextEditOutliner();
     if( pOutliner && pTextObj && pTextObj->GetPage() )
diff --git a/svx/source/svdraw/svdedxv.cxx b/svx/source/svdraw/svdedxv.cxx
index f38d33f..288b5e4 100644
--- a/svx/source/svdraw/svdedxv.cxx
+++ b/svx/source/svdraw/svdedxv.cxx
@@ -51,6 +51,8 @@
 #include "svx/svdstr.hrc"
 #include "svdglob.hxx"
 #include "svx/globl3d.hxx"
+#include <svx/textchain.hxx>
+#include <svx/textchaincursor.hxx>
 #include <editeng/outliner.hxx>
 #include <editeng/adjustitem.hxx>
 #include <svtools/colorcfg.hxx>
@@ -489,6 +491,102 @@ IMPL_LINK(SdrObjEditView,ImpOutlinerStatusEventHdl,EditStatus*,pEditStat)
     return 0;
 }
 
+void SdrObjEditView::ImpChainingEventHdl()
+{
+    if(pTextEditOutliner )
+    {
+        SdrTextObj* pTextObj = dynamic_cast< SdrTextObj * >( mxTextEditObj.get() );
+        OutlinerView* pOLV = GetTextEditOutlinerView();
+        if( pTextObj && pOLV)
+        {
+            TextChain *pTextChain = pTextObj->GetTextChain();
+
+             // XXX: IsChainable and GetNilChainingEvent are a bit mixed up atm
+            if (!pTextObj->IsChainable()) {
+                return;
+            }
+            // This is true during an underflow-caused overflow (with pEdtOutl->SetText())
+            if (pTextChain->GetNilChainingEvent(pTextObj)) {
+                return;
+            }
+
+            // We prevent to trigger further handling of overflow/underflow for pTextObj
+            pTextChain->SetNilChainingEvent(pTextObj, true); // XXX
+
+            // Save previous selection pos // NOTE: It must be done to have the right CursorEvent in KeyInput
+            pTextChain->SetPreChainingSel(pTextObj, pOLV->GetSelection());
+            //maPreChainingSel = new ESelection(pOLV->GetSelection());
+
+            // Handling Undo
+            const int nText = 0; // XXX: hardcoded index (SdrTextObj::getText handles only 0)
+
+            SdrUndoObjSetText *pTxtUndo  = dynamic_cast< SdrUndoObjSetText* >
+                ( GetModel()->GetSdrUndoFactory().CreateUndoObjectSetText(*pTextObj, nText ) );
+
+            // trigger actual chaining
+            pTextObj->onChainingEvent();
+
+           if (pTxtUndo!=NULL)
+            {
+                pTxtUndo->AfterSetText();
+                if (!pTxtUndo->IsDifferent())
+                {
+                    delete pTxtUndo;
+                    pTxtUndo=NULL;
+                }
+            }
+
+            if (pTxtUndo)
+                AddUndo(pTxtUndo);
+
+            //maCursorEvent = new CursorChainingEvent(pTextChain->GetCursorEvent(pTextObj));
+            //SdrTextObj *pNextLink = pTextObj->GetNextLinkInChain();
+
+            // NOTE: Must be called. Don't let the function return if you set it to true and not reset it
+            pTextChain->SetNilChainingEvent(pTextObj, false);
+        } else {
+            // XXX
+            fprintf(stderr, "[OnChaining] No Edit Outliner View\n");
+        }
+    }
+
+}
+
+IMPL_LINK_NOARG(SdrObjEditView,ImpAfterCutOrPasteChainingEventHdl)
+{
+    SdrTextObj* pTextObj = dynamic_cast< SdrTextObj * >( GetTextEditObject());
+    if (!pTextObj)
+        return 0;
+    ImpChainingEventHdl();
+    TextChainCursorManager *pCursorManager = new TextChainCursorManager(this, pTextObj);
+    ImpMoveCursorAfterChainingEvent(pCursorManager);
+    return 0;
+}
+
+void SdrObjEditView::ImpMoveCursorAfterChainingEvent(TextChainCursorManager *pCursorManager)
+{
+    if (!mxTextEditObj.is() || !pCursorManager)
+        return;
+
+    SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>(mxTextEditObj.get());
+
+    // Check if it has links to move it to
+    if (!pTextObj->IsChainable())
+        return;
+
+    TextChain *pTextChain = pTextObj->GetTextChain();
+    ESelection aNewSel = pTextChain->GetPostChainingSel(pTextObj);
+
+
+    pCursorManager->HandleCursorEventAfterChaining(
+        pTextChain->GetCursorEvent(pTextObj),
+        aNewSel);
+
+    // Reset event
+    pTextChain->SetCursorEvent(pTextObj, CursorChainingEvent::NULL_EVENT);
+}
+
+
 IMPL_LINK_TYPED(SdrObjEditView,ImpOutlinerCalcFieldValueHdl,EditFieldInfo*,pFI,void)
 {
     bool bOk=false;
@@ -728,6 +826,10 @@ bool SdrObjEditView::SdrBeginTextEdit(
 
             pTextEditOutlinerView->ShowCursor();
             pTextEditOutliner->SetStatusEventHdl(LINK(this,SdrObjEditView,ImpOutlinerStatusEventHdl));
+            if (pTextObj->IsChainable()) {
+                pTextEditOutlinerView->SetEndCutPasteLinkHdl(LINK(this,SdrObjEditView,ImpAfterCutOrPasteChainingEventHdl) );
+            }
+
 #ifdef DBG_UTIL
             if (mpItemBrowser!=nullptr) mpItemBrowser->SetDirty();
 #endif
@@ -917,6 +1019,8 @@ SdrEndTextEditKind SdrObjEditView::SdrEndTextEdit(bool bDontDeleteReally)
             pTEOutliner->SetBeginPasteOrDropHdl(Link<PasteOrDropInfos*,void>());
             pTEOutliner->SetEndPasteOrDropHdl(Link<PasteOrDropInfos*,void>());
 
+            pTEOutliner->SetChainingEventHdl(Link<>());
+
             const bool bUndo = IsUndoEnabled();
             if( bUndo )
             {
@@ -1189,6 +1293,32 @@ bool SdrObjEditView::IsTextEditFrameHit(const Point& rHit) const
     return bOk;
 }
 
+TextChainCursorManager *SdrObjEditView::ImpHandleMotionThroughBoxesKeyInput(
+                                            const KeyEvent& rKEvt,
+                                            vcl::Window*,
+                                            bool *bOutHandled)
+{
+    *bOutHandled = false;
+
+    SdrTextObj* pTextObj = NULL;
+    if (mxTextEditObj.is())
+        pTextObj= dynamic_cast<SdrTextObj*>(mxTextEditObj.get());
+    else
+        return NULL;
+
+    if (!pTextObj->GetNextLinkInChain() && !pTextObj->GetPrevLinkInChain())
+        return NULL;
+
+    TextChainCursorManager *pCursorManager = new TextChainCursorManager(this, pTextObj);
+    if( pCursorManager->HandleKeyEvent(rKEvt) ) {
+        // Possibly do other stuff here if necessary...
+        // XXX: Careful with the checks below (in KeyInput) for pWin and co. You should do them here I guess.
+        *bOutHandled = true;
+    }
+
+    return pCursorManager;
+}
+
 
 
 bool SdrObjEditView::KeyInput(const KeyEvent& rKEvt, vcl::Window* pWin)
commit 225e72233de96b1216e688d35ccc49aaebf61b17
Author: matteocam <matteo.campanelli at gmail.com>
Date:   Mon Sep 7 12:44:37 2015 +0200

    chained editeng: Change EndTextEdit behavior to support recursive overflow
    
    Change-Id: I14009fa2e91b19a850e45484de7cd234e872689a

diff --git a/svx/source/svdraw/svdotxed.cxx b/svx/source/svdraw/svdotxed.cxx
index c68b085..4e07027 100644
--- a/svx/source/svdraw/svdotxed.cxx
+++ b/svx/source/svdraw/svdotxed.cxx
@@ -23,10 +23,12 @@
 #include <svx/svdoutl.hxx>
 #include <editeng/editdata.hxx>
 #include <editeng/outliner.hxx>
+#include <editeng/overflowingtxt.hxx>
 #include <editeng/editstat.hxx>
 #include <svl/itemset.hxx>
 #include <editeng/eeitem.hxx>
 #include <svx/sdtfchim.hxx>
+#include <svx/textchain.hxx>
 
 
 bool SdrTextObj::HasTextEdit() const
@@ -126,6 +128,19 @@ bool SdrTextObj::BegTextEdit(SdrOutliner& rOutl)
     return true;
 }
 
+void ImpUpdateOutlParamsForOverflow(SdrOutliner *pOutl, SdrTextObj *pTextObj)
+{
+     // Code from ImpSetTextEditParams
+    Size aPaperMin;
+    Size aPaperMax;
+    Rectangle aEditArea;
+    pTextObj->TakeTextEditArea(&aPaperMin,&aPaperMax,&aEditArea,NULL);
+
+    pOutl->SetMinAutoPaperSize(aPaperMin);
+    pOutl->SetMaxAutoPaperSize(aPaperMax);
+    pOutl->SetPaperSize(Size());
+}
+
 void SdrTextObj::TakeTextEditArea(Size* pPaperMin, Size* pPaperMax, Rectangle* pViewInit, Rectangle* pViewMin) const
 {
     bool bFitToSize(IsFitToSize());
@@ -263,9 +278,10 @@ void SdrTextObj::TakeTextEditArea(Size* pPaperMin, Size* pPaperMax, Rectangle* p
 
 void SdrTextObj::EndTextEdit(SdrOutliner& rOutl)
 {
+    OutlinerParaObject* pNewText = NULL;
+
     if(rOutl.IsModified())
     {
-        OutlinerParaObject* pNewText = NULL;
 
         // to make the gray field background vanish again
         rOutl.UpdateFields();
@@ -277,8 +293,39 @@ void SdrTextObj::EndTextEdit(SdrOutliner& rOutl)
         // uses GetCurrentBoundRect() which needs to take the text into account
         // to work correct
         mbInEditMode = false;
-        SetOutlinerParaObject(pNewText);
+
+        // We don't want broadcasting if we are merely trying to move to next box (this prevents infinite loops)
+        if (IsChainable() && GetTextChain()->GetSwitchingToNextBox(this)) {
+            GetTextChain()->SetSwitchingToNextBox(this, false);
+            if( getActiveText() )
+                getActiveText()->SetOutlinerParaObject( pNewText);
+        } else { // If we are not doing in-chaining switching just set the ParaObject
+            SetOutlinerParaObject(pNewText);
+        }
+    }
+
+    /* Beginning Chaining-related code */
+    rOutl.ClearOverflowingParaNum();
+
+    /* Flush overflow for next textbox - Necessary for recursive chaining */
+    if (false &&
+        IsChainable() &&
+        GetNextLinkInChain() &&
+        GetTextChain()->GetPendingOverflowCheck(GetNextLinkInChain()) )
+    {
+        GetTextChain()->SetPendingOverflowCheck(GetNextLinkInChain(), false);
+
+        SdrOutliner rDrawOutl = GetNextLinkInChain()->ImpGetDrawOutliner();
+        // Prepare Outliner for overflow check
+        ImpUpdateOutlParamsForOverflow(&rDrawOutl, GetNextLinkInChain());
+        const OutlinerParaObject *pObj = GetNextLinkInChain()->GetOutlinerParaObject();
+        rDrawOutl.SetText(*pObj);
+
+        rDrawOutl.SetUpdateMode(true);
+        // XXX: Change name of method below to impHandleChainingEventsNonEditMode
+        GetNextLinkInChain()->impHandleChainingEventsDuringDecomposition(rDrawOutl);
     }
+    /* End Chaining-related code */
 
     pEdtOutl = NULL;
     rOutl.Clear();
commit 6f344c67c38611f2914e12cafb8b9719ecf563c4
Author: matteocam <matteo.campanelli at gmail.com>
Date:   Mon Sep 7 12:32:14 2015 +0200

    chained editeng: Change size settings if box is chainable
    
    Change-Id: I3717324b3be36b9503cae195fd42249d92d2c685

diff --git a/svx/source/svdraw/svdotext.cxx b/svx/source/svdraw/svdotext.cxx
index 8fd7bc2..55948aa 100644
--- a/svx/source/svdraw/svdotext.cxx
+++ b/svx/source/svdraw/svdotext.cxx
@@ -755,14 +755,19 @@ void SdrTextObj::TakeTextRect( SdrOutliner& rOutliner, Rectangle& rTextRect, boo
                 if (eAniDirection==SDRTEXTANI_UP || eAniDirection==SDRTEXTANI_DOWN) nHgt=1000000;
             }
 
-            // #i119885# Do not limit/force height to geometrical frame (vice versa for vertical writing)
-            if(IsVerticalWriting())
-            {
-                nWdt = 1000000;
-            }
-            else
-            {
-                nHgt = 1000000;
+            bool bChainedFrame = IsChainable();
+            // Might be required for overflow check working: do limit height to frame if box is chainable.
+            if (!bChainedFrame) {
+                // #i119885# Do not limit/force height to geometrical frame (vice versa for vertical writing)
+
+                if(IsVerticalWriting())
+                {
+                    nWdt = 1000000;
+                }
+                else
+                {
+                    nHgt = 1000000;
+                }
             }
 
             rOutliner.SetMaxAutoPaperSize(Size(nWdt,nHgt));
diff --git a/svx/source/svdraw/svdotxed.cxx b/svx/source/svdraw/svdotxed.cxx
index b0b2ccc..c68b085 100644
--- a/svx/source/svdraw/svdotxed.cxx
+++ b/svx/source/svdraw/svdotxed.cxx
@@ -62,6 +62,14 @@ bool SdrTextObj::BegTextEdit(SdrOutliner& rOutl)
         rOutl.SetControlWord(nStat);
     }
 
+    // disable AUTOPAGESIZE if IsChainable (might be required for overflow check)
+    if ( IsChainable() ) {
+        EEControlBits nStat1=rOutl.GetControlWord();
+        nStat1 &=~EEControlBits::AUTOPAGESIZE;
+        rOutl.SetControlWord(nStat1);
+    }
+
+
     OutlinerParaObject* pOutlinerParaObject = GetOutlinerParaObject();
     if(pOutlinerParaObject!=NULL)
     {
@@ -181,14 +189,18 @@ void SdrTextObj::TakeTextEditArea(Size* pPaperMin, Size* pPaperMax, Rectangle* p
                 if (eAniDirection==SDRTEXTANI_UP || eAniDirection==SDRTEXTANI_DOWN) nMaxHgt=1000000;
             }
 
-            // #i119885# Do not limit/force height to geometrical frame (vice versa for vertical writing)
-            if(IsVerticalWriting())
-            {
-                nMaxWdt = 1000000;
-            }
-            else
-            {
-                nMaxHgt = 1000000;
+            bool bChainedFrame = IsChainable();
+            // Might be required for overflow check working: do limit height to frame if box is chainable.
+            if (!bChainedFrame) {
+                // #i119885# Do not limit/force height to geometrical frame (vice versa for vertical writing)
+                if(IsVerticalWriting())
+                {
+                    nMaxWdt = 1000000;
+                }
+                else
+                {
+                    nMaxHgt = 1000000;
+                }
             }
 
             aPaperMax.Width()=nMaxWdt;
commit 7c3362c9fb7c053e0e198c1223bb7519fb049644
Author: matteocam <matteo.campanelli at gmail.com>
Date:   Mon Sep 7 12:17:30 2015 +0200

    chained editeng: Add Chaining-related UNO attribute
    
    Definition and mechanisms for UNO API.
    
    Change-Id: I7fd3969804ca9b04881ced0b1e43ab6236cbefcc

diff --git a/include/editeng/unoprnms.hxx b/include/editeng/unoprnms.hxx
index 0566288..498d417 100644
--- a/include/editeng/unoprnms.hxx
+++ b/include/editeng/unoprnms.hxx
@@ -113,6 +113,7 @@
 #define UNO_NAME_TEXT_WRITINGMODE               "TextWritingMode"
 #define UNO_NAME_TEXT_FONTINDEPENDENTLINESPACING "FontIndependentLineSpacing"
 #define UNO_NAME_TEXT_WORDWRAP                  "TextWordWrap"
+#define UNO_NAME_TEXT_CHAINNEXTNAME              "TextChainNextName"
 
 #define UNO_NAME_MEASUREKIND                    "MeasureKind"
 #define UNO_NAME_MEASURETEXTHPOS                "MeasureTextHorizontalPosition"
diff --git a/include/svx/svdstr.hrc b/include/svx/svdstr.hrc
index 6663f01..d6bc94b 100644
--- a/include/svx/svdstr.hrc
+++ b/include/svx/svdstr.hrc
@@ -714,5 +714,7 @@
 #define STR_TABLE_STYLE_SETTINGS            (SIP_Begin + 275)
 #define SIP_SA_CROP_MARKERS                 (SIP_Begin + 276)
 #define STR_TABLE_DELETE_CELL_CONTENTS      (SIP_Begin + 277)
+#define SIP_SA_CHAINNEXTNAME                (SIP_Begin + 278)
+
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/svx/unoshprp.hxx b/include/svx/unoshprp.hxx
index b7a95be..2f8e35e 100644
--- a/include/svx/unoshprp.hxx
+++ b/include/svx/unoshprp.hxx
@@ -291,6 +291,7 @@
     { OUString(UNO_NAME_TEXT_FONTINDEPENDENTLINESPACING),SDRATTR_TEXT_USEFIXEDCELLHEIGHT,cppu::UnoType<bool>::get(),                   0,      0},               \
     { OUString(UNO_NAME_TEXT_VERTADJUST),       SDRATTR_TEXT_VERTADJUST,        cppu::UnoType<css::drawing::TextVerticalAdjust>::get(),    0,      0},\
     { OUString(UNO_NAME_TEXT_WORDWRAP),         SDRATTR_TEXT_WORDWRAP,          cppu::UnoType<bool>::get(),        0,      0}, \
+    { OUString(UNO_NAME_TEXT_CHAINNEXTNAME),    SDRATTR_TEXT_CHAINNEXTNAME,     ::cppu::UnoType<OUString>::get(),        0,      0}, \
     SVX_UNOEDIT_CHAR_PROPERTIES, \
     SVX_UNOEDIT_PARA_PROPERTIES,
 
diff --git a/svx/source/svdraw/svdattr.cxx b/svx/source/svdraw/svdattr.cxx
index 69fc2b5..0447ca8 100644
--- a/svx/source/svdraw/svdattr.cxx
+++ b/svx/source/svdraw/svdattr.cxx
@@ -162,6 +162,7 @@ SdrItemPool::SdrItemPool(
     mppLocalPoolDefaults[SDRATTR_TEXT_CONTOURFRAME  -SDRATTR_START]=new SdrOnOffItem(SDRATTR_TEXT_CONTOURFRAME, false);
     mppLocalPoolDefaults[SDRATTR_CUSTOMSHAPE_ADJUSTMENT -SDRATTR_START]=new SdrCustomShapeAdjustmentItem;
     mppLocalPoolDefaults[SDRATTR_XMLATTRIBUTES -SDRATTR_START]=new SvXMLAttrContainerItem( SDRATTR_XMLATTRIBUTES );
+    mppLocalPoolDefaults[SDRATTR_TEXT_CHAINNEXTNAME    -SDRATTR_START]=new SfxStringItem(SDRATTR_TEXT_CHAINNEXTNAME, "");
     mppLocalPoolDefaults[SDRATTR_TEXT_USEFIXEDCELLHEIGHT -SDRATTR_START]=new SdrTextFixedCellHeightItem;
     mppLocalPoolDefaults[SDRATTR_TEXT_WORDWRAP         -SDRATTR_START]=new SdrOnOffItem(SDRATTR_TEXT_WORDWRAP, true);
     mppLocalPoolDefaults[SDRATTR_TEXT_AUTOGROWSIZE     -SDRATTR_START]=new SdrOnOffItem(SDRATTR_TEXT_AUTOGROWSIZE, false);
@@ -499,6 +500,7 @@ void SdrItemPool::TakeItemName(sal_uInt16 nWhich, OUString& rItemName)
         case SDRATTR_XMLATTRIBUTES          : nResId = SIP_SA_XMLATTRIBUTES;break;
         case SDRATTR_TEXT_USEFIXEDCELLHEIGHT: nResId = SIP_SA_TEXT_USEFIXEDCELLHEIGHT;break;
         case SDRATTR_TEXT_WORDWRAP          : nResId = SIP_SA_WORDWRAP;break;
+        case SDRATTR_TEXT_CHAINNEXTNAME     : nResId = SIP_SA_CHAINNEXTNAME;break;
         case SDRATTR_TEXT_AUTOGROWSIZE      : nResId = SIP_SA_AUTOGROWSIZE;break;
 
         case SDRATTR_EDGEKIND           : nResId = SIP_SA_EDGEKIND;break;
diff --git a/svx/source/svdraw/svdstr.src b/svx/source/svdraw/svdstr.src
index f790f00..16383f8 100644
--- a/svx/source/svdraw/svdstr.src
+++ b/svx/source/svdraw/svdstr.src
@@ -2114,6 +2114,12 @@ String SIP_SA_WORDWRAP
     Text[ en-US ] = "Word wrap text in shape";
 };
 
+String SIP_SA_CHAINNEXTNAME
+{
+    Text[ en-US ] = "Next link in text chain";
+};
+
+
 String SIP_SA_AUTOGROWSIZE
 {
     Text[ en-US ] = "Auto grow shape to fit text";
diff --git a/svx/source/unodraw/unoshap2.cxx b/svx/source/unodraw/unoshap2.cxx
index 63b29ea..103ec4e 100644
--- a/svx/source/unodraw/unoshap2.cxx
+++ b/svx/source/unodraw/unoshap2.cxx
@@ -670,6 +670,7 @@ SvxShapeControlPropertyMapping[] =
     { RTL_CONSTASCII_STRINGPARAM(UNO_NAME_EDIT_CHAR_COLOR),   RTL_CONSTASCII_STRINGPARAM("TextColor") },
     { RTL_CONSTASCII_STRINGPARAM("CharBackColor"), RTL_CONSTASCII_STRINGPARAM("CharBackColor") },
     { RTL_CONSTASCII_STRINGPARAM("CharBackTransparent"), RTL_CONSTASCII_STRINGPARAM("CharBackTransparent") },
+    { RTL_CONSTASCII_STRINGPARAM(UNO_NAME_TEXT_CHAINNEXTNAME), RTL_CONSTASCII_STRINGPARAM(UNO_NAME_TEXT_CHAINNEXTNAME) },
     { RTL_CONSTASCII_STRINGPARAM("CharRelief"),   RTL_CONSTASCII_STRINGPARAM("FontRelief") },
     { RTL_CONSTASCII_STRINGPARAM("CharUnderlineColor"),   RTL_CONSTASCII_STRINGPARAM("TextLineColor") },
     { RTL_CONSTASCII_STRINGPARAM(UNO_NAME_EDIT_PARA_ADJUST), RTL_CONSTASCII_STRINGPARAM("Align") },
diff --git a/xmloff/source/draw/sdpropls.cxx b/xmloff/source/draw/sdpropls.cxx
index 442e5db..5896cc8 100644
--- a/xmloff/source/draw/sdpropls.cxx
+++ b/xmloff/source/draw/sdpropls.cxx
@@ -146,6 +146,7 @@ const XMLPropertyMapEntry aXMLSDProperties[] =
     GMAP( "NumberingRules",                 XML_NAMESPACE_TEXT, XML_LIST_STYLE,             XML_SD_TYPE_NUMBULLET|MID_FLAG_ELEMENT_ITEM, CTF_NUMBERINGRULES ),
     GMAP( "NumberingRules",                 XML_NAMESPACE_TEXT, XML_LIST_STYLE_NAME,        XML_TYPE_STRING, CTF_SD_NUMBERINGRULES_NAME ),
     GMAP( "TextWordWrap",                   XML_NAMESPACE_FO,   XML_WRAP_OPTION,            XML_TYPE_WRAP_OPTION, 0 ),
+    GMAP( "TextChainNextName",              XML_NAMESPACE_DRAW,   XML_CHAIN_NEXT_NAME,      XML_TYPE_STRING, 0 ),
 
     // shadow attributes
     GMAP( "Shadow",                         XML_NAMESPACE_DRAW, XML_SHADOW,                 XML_SD_TYPE_SHADOW, 0 ),
diff --git a/xmloff/source/draw/ximpshap.cxx b/xmloff/source/draw/ximpshap.cxx
index e5eb4a6..8a067f6 100644
--- a/xmloff/source/draw/ximpshap.cxx
+++ b/xmloff/source/draw/ximpshap.cxx
@@ -1600,7 +1600,8 @@ SdXMLTextBoxShapeContext::SdXMLTextBoxShapeContext(
     uno::Reference< drawing::XShapes >& rShapes,
     bool bTemporaryShape)
 :   SdXMLShapeContext( rImport, nPrfx, rLocalName, xAttrList, rShapes, bTemporaryShape ),
-    mnRadius(0)
+    mnRadius(0),
+    maChainNextName("")
 {
 }
 
@@ -1619,6 +1620,13 @@ void SdXMLTextBoxShapeContext::processAttribute( sal_uInt16 nPrefix, const OUStr
                     mnRadius, rValue);
             return;
         }
+
+        if( IsXMLToken( rLocalName, XML_CHAIN_NEXT_NAME ) )
+        {
+            maChainNextName = rValue;
+            return;
+        }
+
     }
 
     SdXMLShapeContext::processAttribute( nPrefix, rLocalName, rValue );
@@ -1752,6 +1760,23 @@ void SdXMLTextBoxShapeContext::StartElement(const uno::Reference< xml::sax::XAtt
             }
         }
 
+        if(maChainNextName != "")
+        {
+            uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY);
+            if(xPropSet.is())
+            {
+                try
+                {
+                    xPropSet->setPropertyValue("TextChainNextName",
+                                               uno::makeAny( maChainNextName ) );
+                }
+                catch(const uno::Exception&)
+                {
+                    OSL_FAIL( "exception during setting of name of next chain link!");
+                }
+            }
+        }
+
         SdXMLShapeContext::StartElement(mxAttrList);
     }
 }
diff --git a/xmloff/source/draw/ximpshap.hxx b/xmloff/source/draw/ximpshap.hxx
index 73c9d8c..fdf1e70 100644
--- a/xmloff/source/draw/ximpshap.hxx
+++ b/xmloff/source/draw/ximpshap.hxx
@@ -247,6 +247,7 @@ public:
 class SdXMLTextBoxShapeContext : public SdXMLShapeContext
 {
     sal_Int32                   mnRadius;
+    OUString                    maChainNextName;
 
 public:
     TYPEINFO_OVERRIDE();
commit aa5946b1b04aeff5487ea21b4ffd9c3579a8d3e0
Author: matteocam <matteo.campanelli at gmail.com>
Date:   Mon Sep 7 11:37:27 2015 +0200

    chained editeng: Add chaining attributes and chaining primitive creation logic
    
    Change-Id: I957d5261dd847fe5e950441585e879cfd5ae2fb2

diff --git a/include/svx/sdr/attribute/sdrtextattribute.hxx b/include/svx/sdr/attribute/sdrtextattribute.hxx
index 66e3e7a..7d5de1d 100644
--- a/include/svx/sdr/attribute/sdrtextattribute.hxx
+++ b/include/svx/sdr/attribute/sdrtextattribute.hxx
@@ -76,7 +76,10 @@ namespace drawinglayer
                 bool bScroll,
                 bool bInEditMode,
                 bool bFixedCellHeight,
-                bool bWrongSpell);
+                bool bWrongSpell,
+                bool bToBeChained,
+                bool bChainable);
+
             SdrTextAttribute();
             SdrTextAttribute(const SdrTextAttribute& rCandidate);
             SdrTextAttribute& operator=(const SdrTextAttribute& rCandidate);
@@ -107,6 +110,10 @@ namespace drawinglayer
             SdrTextHorzAdjust getSdrTextHorzAdjust() const;
             SdrTextVertAdjust getSdrTextVertAdjust() const;
 
+            bool isToBeChained() const;
+            bool isChainable() const;
+
+
             // helpers: animation timing generators
             void getBlinkTextTiming(
                 drawinglayer::animation::AnimationEntryList& rAnimList) const;
diff --git a/svx/source/sdr/attribute/sdrtextattribute.cxx b/svx/source/sdr/attribute/sdrtextattribute.cxx
index ddd1ce1..cefefb1 100644
--- a/svx/source/sdr/attribute/sdrtextattribute.cxx
+++ b/svx/source/sdr/attribute/sdrtextattribute.cxx
@@ -67,6 +67,10 @@ namespace drawinglayer
             bool                                mbFixedCellHeight : 1;
             bool                                mbWrongSpell : 1;
 
+            bool                                mbToBeChained : 1;
+            bool                                mbChainable : 1;
+
+
         public:
             ImpSdrTextAttribute(
                 const SdrText* pSdrText,
@@ -86,7 +90,9 @@ namespace drawinglayer
                 bool bScroll,
                 bool bInEditMode,
                 bool bFixedCellHeight,
-                bool bWrongSpell)
+                bool bWrongSpell,
+                bool bToBeChained,
+                bool bChainable)
             :   mpSdrText(pSdrText),
                 mxOutlinerParaObject(new OutlinerParaObject(rOutlinerParaObject)),
                 maSdrFormTextAttribute(),
@@ -105,7 +111,9 @@ namespace drawinglayer
                 mbScroll(bScroll),
                 mbInEditMode(bInEditMode),
                 mbFixedCellHeight(bFixedCellHeight),
-                mbWrongSpell(bWrongSpell)
+                mbWrongSpell(bWrongSpell),
+                mbToBeChained(bToBeChained),
+                mbChainable(bChainable)
             {
                 if(pSdrText)
                 {
@@ -141,7 +149,9 @@ namespace drawinglayer
                 mbScroll(false),
                 mbInEditMode(false),
                 mbFixedCellHeight(false),
-                mbWrongSpell(false)
+                mbWrongSpell(false),
+                mbToBeChained(false),
+                mbChainable(false)
             {
             }
 
@@ -167,6 +177,8 @@ namespace drawinglayer
             bool isInEditMode() const { return mbInEditMode; }
             bool isFixedCellHeight() const { return mbFixedCellHeight; }
             bool isWrongSpell() const { return mbWrongSpell; }
+            bool isToBeChained() const { return mbToBeChained; }
+            bool isChainable() const { return mbChainable; }
             const SdrFormTextAttribute& getSdrFormTextAttribute() const { return maSdrFormTextAttribute; }
             sal_Int32 getTextLeftDistance() const { return maTextLeftDistance; }
             sal_Int32 getTextUpperDistance() const { return maTextUpperDistance; }
@@ -225,7 +237,8 @@ namespace drawinglayer
                     && isScroll() == rCandidate.isScroll()
                     && isInEditMode() == rCandidate.isInEditMode()
                     && isFixedCellHeight() == rCandidate.isFixedCellHeight()
-                    && isWrongSpell() == rCandidate.isWrongSpell());
+                    && isWrongSpell() == rCandidate.isWrongSpell()
+                    && isToBeChained() == rCandidate.isToBeChained() );
             }
         };
 
@@ -253,13 +266,16 @@ namespace drawinglayer
             bool bScroll,
             bool bInEditMode,
             bool bFixedCellHeight,
-            bool bWrongSpell)
+            bool bWrongSpell,
+            bool bIsToBeChained,
+            bool bChainable)
         :   mpSdrTextAttribute(
                 ImpSdrTextAttribute(
                     &rSdrText, rOutlinerParaObject, eFormTextStyle, aTextLeftDistance,
                     aTextUpperDistance, aTextRightDistance, aTextLowerDistance,
                     aSdrTextHorzAdjust, aSdrTextVertAdjust, bContour, bFitToSize, bAutoFit,
-                    bHideContour, bBlink, bScroll, bInEditMode, bFixedCellHeight, bWrongSpell))
+                    bHideContour, bBlink, bScroll, bInEditMode, bFixedCellHeight, bWrongSpell,
+                    bIsToBeChained, bChainable))
         {
         }
 
@@ -342,6 +358,17 @@ namespace drawinglayer
             return mpSdrTextAttribute->isInEditMode();
         }
 
+        bool SdrTextAttribute::isToBeChained() const
+        {
+            return mpSdrTextAttribute->isToBeChained();
+        }
+
+        bool SdrTextAttribute::isChainable() const
+        {
+            return mpSdrTextAttribute->isChainable();
+        }
+
+
         bool SdrTextAttribute::isFixedCellHeight() const
         {
             return mpSdrTextAttribute->isFixedCellHeight();
diff --git a/svx/source/sdr/primitive2d/sdrattributecreator.cxx b/svx/source/sdr/primitive2d/sdrattributecreator.cxx
index 5222367..2ec29ed 100644
--- a/svx/source/sdr/primitive2d/sdrattributecreator.cxx
+++ b/svx/source/sdr/primitive2d/sdrattributecreator.cxx
@@ -520,6 +520,11 @@ namespace drawinglayer
         {
             const SdrTextObj& rTextObj = rText.GetObject();
 
+            // Save chaining attributes
+            bool bToBeChained = rTextObj.IsToBeChained();
+            bool bChainable = rTextObj.IsChainable();
+
+
             if(rText.GetOutlinerParaObject() && rText.GetModel())
             {
                 // added TextEdit text suppression
@@ -578,7 +583,9 @@ namespace drawinglayer
                     SDRTEXTANI_SCROLL == eAniKind || SDRTEXTANI_ALTERNATE == eAniKind || SDRTEXTANI_SLIDE == eAniKind,
                     bInEditMode,
                     static_cast<const SdrTextFixedCellHeightItem&>(rSet.Get(SDRATTR_TEXT_USEFIXEDCELLHEIGHT)).GetValue(),
-                    bWrongSpell);
+                    bWrongSpell,
+                    bToBeChained,
+                    bChainable);
             }
 
             return attribute::SdrTextAttribute();
diff --git a/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx b/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx
index ddc6608..390683f 100644
--- a/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx
+++ b/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx
@@ -307,7 +307,18 @@ namespace drawinglayer
                 else if(rText.isAutoFit())
                 {
                     // isotrophically scaled text in range
-                    pNew = new SdrAutoFitTextPrimitive2D(&rText.getSdrText(), rText.getOutlinerParaObject(), aAnchorTransform, bWordWrap);
+                    pNew = new SdrAutoFitTextPrimitive2D(
+                                    &rText.getSdrText(),
+                                    rText.getOutlinerParaObject(),
+                                    aAnchorTransform,
+                                    bWordWrap);
+                }
+                else if( rText.isChainable() && !rText.isInEditMode() )
+                {
+                    pNew = new SdrChainedTextPrimitive2D(
+                                    &rText.getSdrText(),
+                                    rText.getOutlinerParaObject(),
+                                    aAnchorTransform );
                 }
                 else // text in range
                 {
commit fa98c3b4c51d9ea84cd380069b5e5bed8fbce0a3
Author: matteocam <matteo.campanelli at gmail.com>
Date:   Sun Sep 6 12:06:47 2015 +0200

    chained editeng: Enhance existing svx classes with chaining-related methods
    
    Change-Id: I10829d8f07f8881af6d1a9422cbdae00e83a7ac8

diff --git a/include/svx/sdr/primitive2d/svx_primitivetypes2d.hxx b/include/svx/sdr/primitive2d/svx_primitivetypes2d.hxx
index 0fae52a..1161f2c 100644
--- a/include/svx/sdr/primitive2d/svx_primitivetypes2d.hxx
+++ b/include/svx/sdr/primitive2d/svx_primitivetypes2d.hxx
@@ -48,6 +48,7 @@
 #define PRIMITIVE2D_ID_SDRCONTROLPRIMITIVE2D            (PRIMITIVE2D_ID_RANGE_SVX| 21)
 #define PRIMITIVE2D_ID_SDROLECONTENTPRIMITIVE2D         (PRIMITIVE2D_ID_RANGE_SVX| 22)
 #define PRIMITIVE2D_ID_SDRAUTOFITTEXTPRIMITIVE2D        (PRIMITIVE2D_ID_RANGE_SVX| 23)
+#define PRIMITIVE2D_ID_SDRCHAINEDTEXTPRIMITIVE2D        (PRIMITIVE2D_ID_RANGE_SVX| 24)
 
 
 
diff --git a/include/svx/svddef.hxx b/include/svx/svddef.hxx
index 0e92e7f..5b3e5e9 100644
--- a/include/svx/svddef.hxx
+++ b/include/svx/svddef.hxx
@@ -112,7 +112,8 @@
 #define SDRATTR_TEXT_USEFIXEDCELLHEIGHT (SDRATTR_MISC_FIRST +24)   /*   1121 */ /*   1121 */ /*   1104 */             /* Pool V2 */
 #define SDRATTR_TEXT_WORDWRAP           (SDRATTR_MISC_FIRST +25)   /*   1122 */ /*   1122 */ /*   1105 */             /* Pool V2 */
 #define SDRATTR_TEXT_AUTOGROWSIZE       (SDRATTR_MISC_FIRST +26)   /*   1123 */ /*   1123 */ /*   1106 */             /* Pool V2 */
-#define SDRATTR_MISC_LAST               (SDRATTR_TEXT_AUTOGROWSIZE)        /* 1125   */ /* 1125   */ /* 1108   */ /* Pool V1: 1056 */
+#define SDRATTR_TEXT_CHAINNEXTNAME      (SDRATTR_MISC_FIRST + 27)   /*  1124 */ /*   11124 */
+#define SDRATTR_MISC_LAST               (SDRATTR_TEXT_CHAINNEXTNAME)        /* 1125   */ /* 1125   */ /* 1108   */ /* Pool V1: 1056 */
 
 #define SDRATTR_EDGE_FIRST              (SDRATTR_MISC_LAST + 1)      /* 1127   */ /* Pool V4 */
 #define SDRATTR_EDGEKIND                (SDRATTR_EDGE_FIRST + 0)   /*   1127 */ /* Pool V4 */
diff --git a/include/svx/svdmodel.hxx b/include/svx/svdmodel.hxx
index 2c9eb47..a296dc6 100644
--- a/include/svx/svdmodel.hxx
+++ b/include/svx/svdmodel.hxx
@@ -76,6 +76,7 @@ class SvNumberFormatter;
 class SdrOutlinerCache;
 class SdrUndoFactory;
 class ImageMap;
+class TextChain;
 namespace comphelper
 {
     class IEmbeddedHelper;
@@ -173,6 +174,7 @@ protected:
                     m_pEmbeddedHelper; // helper for embedded objects to get rid of the SfxObjectShell
     SdrOutliner*    pDrawOutliner;  // an Outliner for outputting text
     SdrOutliner*    pHitTestOutliner;// an Outliner for the HitTest
+    SdrOutliner*    pChainingOutliner; // an Outliner for chaining overflowing text
     sal_uIntPtr           nDefTextHgt;    // Default text height in logical units
     VclPtr<OutputDevice>  pRefOutDev;     // ReferenceDevice for the EditEngine
     /// Set if we are doing tiled rendering.
@@ -216,6 +218,7 @@ protected:
     sal_uInt16          nDefaultTabulator;
     sal_uInt32          nMaxUndoCount;
 
+    TextChain*          pTextChain;
 
 
 // sdr::Comment interface
@@ -328,6 +331,10 @@ public:
     void                 SetTextDefaults() const;
     static void          SetTextDefaults( SfxItemPool* pItemPool, sal_uIntPtr nDefTextHgt );
 
+    SdrOutliner&         GetChainingOutliner(const SdrTextObj* pObj=NULL) const;
+    TextChain *GetTextChain() const;
+    void SetNextLinkInTextChain(SdrTextObj *pPrev, SdrTextObj *pNext);
+
     // ReferenceDevice for the EditEngine
     void                 SetRefDevice(OutputDevice* pDev);
     OutputDevice*        GetRefDevice() const                   { return pRefOutDev.get(); }
diff --git a/include/svx/svdotext.hxx b/include/svx/svdotext.hxx
index 0b62bab..82950f0f 100644
--- a/include/svx/svdotext.hxx
+++ b/include/svx/svdotext.hxx
@@ -38,12 +38,16 @@
 
 
 class OutlinerParaObject;
+class OverflowingText;
 class SdrOutliner;
 class SdrTextObj;
 class SdrTextObjTest;
 class SvxFieldItem;
 class ImpSdrObjTextLink;
 class EditStatus;
+class TextChain;
+class TextChainFlow;
+
 
 namespace sdr { namespace properties {
     class TextProperties;
@@ -55,6 +59,7 @@ namespace drawinglayer { namespace primitive2d {
     class SdrBlockTextPrimitive2D;
     class SdrAutoFitTextPrimitive2D;
     class SdrStretchTextPrimitive2D;
+    class SdrChainedTextPrimitive2D;
 }}
 
 namespace drawinglayer { namespace animation {
@@ -133,6 +138,11 @@ private:
     friend class                sdr::table::SdrTableRtfExporter;
     friend class                sdr::table::SdrTableRTFParser;
 
+    friend class                TextChain;
+    friend class                TextChainFlow;
+    friend class                EditingTextChainFlow;
+
+
     // CustomShapeproperties need to access the "bTextFrame" member:
     friend class sdr::properties::CustomShapeProperties;
 
@@ -209,11 +219,24 @@ protected:
     // position of the virtual object. This offset is used when setting up
     // and maintaining the OutlinerView.
     Point                       maTextEditOffset;
+
+    virtual SdrObject* getFullDragClone() const SAL_OVERRIDE;
+
 public:
     const Point& GetTextEditOffset() const { return maTextEditOffset; }
     void SetTextEditOffset(const Point& rNew) { maTextEditOffset = rNew; }
 
 protected:
+    OverflowingText *mpOverflowingText = NULL;
+    bool mbIsUnchainableClone = false;
+
+    // the successor in a chain
+    SdrTextObj *mpNextInChain = NULL;
+    SdrTextObj *mpPrevInChain = NULL;
+
+    // indicating the for its text to be chained to another text box
+    bool mbToBeChained : 1;
+
     // Fuer beschriftete Zeichenobjekte ist bTextFrame=FALSE. Der Textblock
     // wird dann hoizontal und vertikal an aRect zentriert. Bei bTextFrame=
     // sal_True wird der Text in aRect hineinformatiert. Der eigentliche Textrahmen
@@ -343,6 +366,17 @@ public:
     bool IsAutoFit() const;
     /// returns true if the old feature for fitting shape content should into shape is enabled. implies IsAutoFit()==false!
     bool IsFitToSize() const;
+
+    // Chaining
+    bool IsToBeChained() const;
+    SdrTextObj *GetNextLinkInChain() const;
+    void SetNextLinkInChain(SdrTextObj *);
+    SdrTextObj *GetPrevLinkInChain() const;
+    bool IsChainable() const;
+    void SetPreventChainable();
+    bool GetPreventChainable() const;
+    TextChain *GetTextChain() const;
+
     SdrObjKind GetTextKind() const { return eTextKind; }
 
     // #i121917#
@@ -491,6 +525,8 @@ public:
 
     void SetTextEditOutliner(SdrOutliner* pOutl) { pEdtOutl=pOutl; }
 
+    void SetToBeChained(bool bToBeChained);
+
     /** Setup given Outliner equivalently to SdrTextObj::Paint()
 
         To setup an arbitrary Outliner in the same way as the draw
@@ -529,6 +565,10 @@ public:
     /** called from the SdrObjEditView during text edit when the status of the edit outliner changes */
     virtual void onEditOutlinerStatusEvent( EditStatus* pEditStatus );
 
+    /** called from the SdrObjEditView during text edit when a chain of boxes is to be updated */
+    virtual void onChainingEvent();
+
+
 
 
     // transformation interface for StarOfficeAPI. This implements support for
@@ -588,6 +628,11 @@ public:
         drawinglayer::primitive2d::Primitive2DSequence& rTarget,
         const drawinglayer::primitive2d::SdrStretchTextPrimitive2D& rSdrStretchTextPrimitive,
         const drawinglayer::geometry::ViewInformation2D& aViewInformation) const;
+    void impDecomposeChainedTextPrimitive(
+        drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+        const drawinglayer::primitive2d::SdrChainedTextPrimitive2D& rSdrChainedTextPrimitive,
+        const drawinglayer::geometry::ViewInformation2D& aViewInformation) const;
+    void impHandleChainingEventsDuringDecomposition(SdrOutliner &rOutliner) const;
 
 
     // timing generators
diff --git a/svx/inc/sdr/primitive2d/sdrtextprimitive2d.hxx b/svx/inc/sdr/primitive2d/sdrtextprimitive2d.hxx
index e31bac9..db10e08 100644
--- a/svx/inc/sdr/primitive2d/sdrtextprimitive2d.hxx
+++ b/svx/inc/sdr/primitive2d/sdrtextprimitive2d.hxx
@@ -331,6 +331,43 @@ namespace drawinglayer
     } // end of namespace primitive2d
 } // end of namespace drawinglayer
 
+namespace drawinglayer
+{
+    namespace primitive2d
+    {
+        class SdrChainedTextPrimitive2D : public SdrTextPrimitive2D
+        {
+        private:
+            // XXX: might have position of overflowing text
+
+            ::basegfx::B2DHomMatrix maTextRangeTransform;   // text range transformation from unit range ([0.0 .. 1.0]) to text range
+        protected:
+            // local decomposition.
+            virtual Primitive2DSequence create2DDecomposition(const geometry::ViewInformation2D& aViewInformation) const SAL_OVERRIDE;
+
+        public:
+            SdrChainedTextPrimitive2D(
+                const SdrText* pSdrText,
+                const OutlinerParaObject& rOutlinerParaObjectPtrs,
+                const ::basegfx::B2DHomMatrix& rTextRangeTransform);
+
+            // get data
+            const basegfx::B2DHomMatrix& getTextRangeTransform() const { return maTextRangeTransform; }
+            //bool getWordWrap() const { return true; } // XXX: Hack! Should have a proper implementation//
+
+            // compare operator
+            virtual bool operator==(const BasePrimitive2D& rPrimitive) const SAL_OVERRIDE;
+
+            // transformed clone operator
+            virtual SdrTextPrimitive2D* createTransformedClone(const basegfx::B2DHomMatrix& rTransform) const SAL_OVERRIDE;
+
+            // provide unique ID
+            DeclPrimitive2DIDBlock()
+        };
+    } // end of namespace primitive2d
+} // end of namespace drawinglayer
+
+
 
 
 #endif // INCLUDED_SVX_INC_SDR_PRIMITIVE2D_SDRTEXTPRIMITIVE2D_HXX
diff --git a/svx/source/sdr/primitive2d/sdrtextprimitive2d.cxx b/svx/source/sdr/primitive2d/sdrtextprimitive2d.cxx
index 385de99..ac7815d 100644
--- a/svx/source/sdr/primitive2d/sdrtextprimitive2d.cxx
+++ b/svx/source/sdr/primitive2d/sdrtextprimitive2d.cxx
@@ -480,6 +480,48 @@ namespace drawinglayer
      } // end of namespace primitive2d
  } // end of namespace drawinglayer
 
+namespace drawinglayer
+{
+    namespace primitive2d
+    {
+
+        SdrChainedTextPrimitive2D::SdrChainedTextPrimitive2D(
+            const SdrText* pSdrText,
+            const OutlinerParaObject& rOutlinerParaObject,
+            const basegfx::B2DHomMatrix& rTextRangeTransform)
+        : SdrTextPrimitive2D(pSdrText, rOutlinerParaObject),
+          maTextRangeTransform(rTextRangeTransform)
+        { }
+
+        Primitive2DSequence SdrChainedTextPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& aViewInformation) const
+        {
+            Primitive2DSequence aRetval;
+            getSdrText()->GetObject().impDecomposeChainedTextPrimitive(aRetval, *this, aViewInformation);
+
+            return encapsulateWithTextHierarchyBlockPrimitive2D(aRetval);
+        }
+
+        bool SdrChainedTextPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
+         {
+             if(SdrTextPrimitive2D::operator==(rPrimitive))
+             {
+                 const SdrBlockTextPrimitive2D& rCompare = (SdrBlockTextPrimitive2D&)rPrimitive;
+
+                 return (getTextRangeTransform() == rCompare.getTextRangeTransform());
+             }
+
+             return false;
+         }
+
+        SdrTextPrimitive2D* SdrChainedTextPrimitive2D::createTransformedClone(const basegfx::B2DHomMatrix& rTransform) const
+        {
+            return new SdrChainedTextPrimitive2D(getSdrText(), getOutlinerParaObject(), rTransform * getTextRangeTransform());
+        }
+
+        // provide unique ID
+        ImplPrimitive2DIDBlock(SdrChainedTextPrimitive2D, PRIMITIVE2D_ID_SDRCHAINEDTEXTPRIMITIVE2D)
+    } // end of namespace primitive2d
+} // end of namespace drawinglayer
 
 
  namespace drawinglayer
diff --git a/svx/source/svdraw/svdmodel.cxx b/svx/source/svdraw/svdmodel.cxx
index 5478cdc..942d623 100644
--- a/svx/source/svdraw/svdmodel.cxx
+++ b/svx/source/svdraw/svdmodel.cxx
@@ -56,6 +56,7 @@
 #include <svx/svdpool.hxx>
 #include <svx/svdobj.hxx>
 #include <svx/svdotext.hxx>
+#include <svx/textchain.hxx>
 #include <svx/svdetc.hxx>
 #include <svx/svdoutl.hxx>
 #include <svx/svdoole2.hxx>
@@ -221,6 +222,15 @@ void SdrModel::ImpCtor(SfxItemPool* pPool, ::comphelper::IEmbeddedHelper* _pEmbe
     pHitTestOutliner = SdrMakeOutliner(OUTLINERMODE_TEXTOBJECT, *this);
     ImpSetOutlinerDefaults(pHitTestOutliner, true);
 
+    /* Start Text Chaining related code */
+    // Initialize Chaining Outliner
+    pChainingOutliner = SdrMakeOutliner( OUTLINERMODE_TEXTOBJECT, *this );
+    ImpSetOutlinerDefaults(pChainingOutliner, true);
+
+    // Make a TextChain
+    pTextChain = new TextChain;
+    /* End Text Chaining related code */
+
     ImpCreateTables();
 }
 
@@ -763,6 +773,12 @@ SdrOutliner& SdrModel::GetDrawOutliner(const SdrTextObj* pObj) const
     return *pDrawOutliner;
 }
 
+SdrOutliner& SdrModel::GetChainingOutliner(const SdrTextObj* pObj) const
+{
+    pChainingOutliner->SetTextObj(pObj);
+    return *pChainingOutliner;
+}
+
 const SdrTextObj* SdrModel::GetFormattingTextObj() const
 {
     if (pDrawOutliner!=NULL) {
@@ -1994,6 +2010,17 @@ void SdrModel::PageListChanged()
 {
 }
 
+TextChain *SdrModel::GetTextChain() const
+{
+    return pTextChain;
+}
+
+void SdrModel::SetNextLinkInTextChain(SdrTextObj *pPrev, SdrTextObj *pNext)
+{
+    // Delegate to SdrTextObj
+    pPrev->SetNextLinkInChain(pNext);
+}
+
 const SdrPage* SdrModel::GetMasterPage(sal_uInt16 nPgNum) const
 {
     DBG_ASSERT(nPgNum < maMaPag.size(), "SdrModel::GetMasterPage: Access out of range (!)");
diff --git a/svx/source/svdraw/svdotext.cxx b/svx/source/svdraw/svdotext.cxx
index 6feb877..8fd7bc2 100644
--- a/svx/source/svdraw/svdotext.cxx
+++ b/svx/source/svdraw/svdotext.cxx
@@ -38,6 +38,8 @@
 #include <editeng/editobj.hxx>
 #include <editeng/outliner.hxx>
 #include <editeng/fhgtitem.hxx>
+#include <svx/textchain.hxx>
+#include <svx/textchainflow.hxx>
 #include <svl/itempool.hxx>
 #include <editeng/adjustitem.hxx>
 #include <editeng/flditem.hxx>
@@ -102,6 +104,9 @@ SdrTextObj::SdrTextObj()
     mbTextAnimationAllowed = true;
     maTextEditOffset = Point(0, 0);
 
+    // chaining
+    mbToBeChained = false;
+
     // #i25616#
     mbSupportTextIndentingOnLineWidthChange = true;
     mbInDownScale = false;
@@ -130,6 +135,9 @@ SdrTextObj::SdrTextObj(const Rectangle& rNewRect)
     mbInDownScale = false;
     maTextEditOffset = Point(0, 0);
 
+    // chaining
+    mbToBeChained = false;
+
     // #i25616#
     mbSupportTextIndentingOnLineWidthChange = true;
 }
@@ -155,6 +163,9 @@ SdrTextObj::SdrTextObj(SdrObjKind eNewTextKind)
     mbInDownScale = false;
     maTextEditOffset = Point(0, 0);
 
+    // chaining
+    mbToBeChained = false;
+
     // #i25616#
     mbSupportTextIndentingOnLineWidthChange = true;
 }
@@ -176,6 +187,9 @@ SdrTextObj::SdrTextObj(SdrObjKind eNewTextKind, const Rectangle& rNewRect)
     bDisableAutoWidthOnDragging=false;
     ImpJustifyRect(maRect);
 
+    // chaining
+    mbToBeChained = false;
+
     mbInEditMode = false;
     mbTextHidden = false;
     mbTextAnimationAllowed = true;
@@ -1520,6 +1534,25 @@ void SdrTextObj::ForceOutlinerParaObject()
     }
 }
 
+// chaining
+bool SdrTextObj::IsToBeChained() const
+{
+    return mbToBeChained;
+}
+
+void SdrTextObj::SetToBeChained(bool bToBeChained)
+{
+    mbToBeChained = bToBeChained;
+}
+
+TextChain *SdrTextObj::GetTextChain() const
+{
+    //if (!IsChainable())
+    //    return NULL;
+
+    return pModel->GetTextChain();
+}
+
 bool SdrTextObj::IsVerticalWriting() const
 {
     if(pEdtOutl)
@@ -1948,6 +1981,179 @@ void SdrTextObj::onEditOutlinerStatusEvent( EditStatus* pEditStatus )
     }
 }
 
+/* Begin chaining code */
+
+// XXX: Make it a method somewhere?
+SdrObject *ImpGetObjByName(SdrObjList *pObjList, OUString aObjName)
+{
+    // scan the whole list
+    size_t nObjCount = pObjList->GetObjCount();
+    for (unsigned i = 0; i < nObjCount; i++) {
+        SdrObject *pCurObj = pObjList->GetObj(i);
+
+        if (pCurObj->GetName() == aObjName) {
+            return pCurObj;
+        }
+    }
+    // not found
+    return NULL;
+}
+
+// XXX: Make it a (private) method of SdrTextObj
+void ImpUpdateChainLinks(SdrTextObj *pTextObj, OUString aNextLinkName)
+{
+    // XXX: Current implementation constraints text boxes to be on the same page
+
+    // No next link
+    if (aNextLinkName == "") {
+        pTextObj->SetNextLinkInChain(NULL);
+        return;
+    }
+
+    SdrPage *pPage = pTextObj->GetPage();
+    assert(pPage);
+    SdrTextObj *pNextTextObj = dynamic_cast< SdrTextObj * >
+                                (ImpGetObjByName(pPage, aNextLinkName));
+    if (!pNextTextObj) {
+        fprintf(stderr, "[CHAINING] Can't find object as next link.\n");
+        return;
+    }
+
+    pTextObj->SetNextLinkInChain(pNextTextObj);
+}
+
+bool SdrTextObj::IsChainable() const
+{
+    // Read it as item
+    const SfxItemSet& rSet = GetObjectItemSet();
+    OUString aNextLinkName = static_cast<const SfxStringItem&>(rSet.Get(SDRATTR_TEXT_CHAINNEXTNAME)).GetValue();
+
+    // Update links if any inconsistency is found
+    bool bNextLinkUnsetYet = (aNextLinkName != "") && !mpNextInChain;
+    bool bInconsistentNextLink = mpNextInChain && mpNextInChain->GetName() != aNextLinkName;
+    // if the link is not set despite there should be one OR if it has changed
+    if (bNextLinkUnsetYet || bInconsistentNextLink) {
+        ImpUpdateChainLinks(const_cast<SdrTextObj *>(this), aNextLinkName);
+    }
+
+    return aNextLinkName != ""; // XXX: Should we also check for GetNilChainingEvent? (see old code below)
+
+/*
+    // Check that no overflow is going on
+    if (!GetTextChain() || GetTextChain()->GetNilChainingEvent(this))
+        return false;
+*/
+}
+
+void SdrTextObj::onChainingEvent()
+{
+    if (!pEdtOutl)
+        return;
+
+    // Outliner for text transfer
+    SdrOutliner &aDrawOutliner = ImpGetDrawOutliner();
+
+    EditingTextChainFlow aTxtChainFlow(this);
+    aTxtChainFlow.CheckForFlowEvents(pEdtOutl);
+
+
+    if (aTxtChainFlow.IsOverflow()) {
+        fprintf(stderr, "[CHAINING] Overflow going on\n");
+        // One outliner is for non-overflowing text, the other for overflowing text
+        // We remove text directly from the editing outliner
+        aTxtChainFlow.ExecuteOverflow(pEdtOutl, &aDrawOutliner);
+    } else if (aTxtChainFlow.IsUnderflow()) {
+        fprintf(stderr, "[CHAINING] Underflow going on\n");
+        // underflow-induced overflow
+        aTxtChainFlow.ExecuteUnderflow(&aDrawOutliner);
+        bool bIsOverflowFromUnderflow = aTxtChainFlow.IsOverflow();
+        // handle overflow
+        if (bIsOverflowFromUnderflow) {
+            fprintf(stderr, "[CHAINING] Overflow going on (underflow induced)\n");
+            // prevents infinite loops when setting text for editing outliner
+
+
+            aTxtChainFlow.ExecuteOverflow(&aDrawOutliner, &aDrawOutliner);
+
+        }
+    }
+}
+
+SdrTextObj* SdrTextObj::GetNextLinkInChain() const
+{
+    /*
+    if (GetTextChain())
+        return GetTextChain()->GetNextLink(this);
+
+    return NULL;
+    */
+
+    return mpNextInChain;
+}
+
+void SdrTextObj::SetNextLinkInChain(SdrTextObj *pNextObj)
+{
+    // Basically a doubly linked list implementation
+
+    SdrTextObj *pOldNextObj = mpNextInChain;
+
+    // Replace next link
+    mpNextInChain = pNextObj;
+    // Deal with old next link's prev link
+    if (pOldNextObj) {
+        pOldNextObj->mpPrevInChain = NULL;
+    }
+
+    // Deal with new next link's prev link
+    if (mpNextInChain) {
+        // If there is a prev already at all and this is not already the current object
+        if (mpNextInChain->mpPrevInChain &&
+            mpNextInChain->mpPrevInChain != this)
+            mpNextInChain->mpPrevInChain->mpNextInChain = NULL;
+        mpNextInChain->mpPrevInChain = this;
+    }
+
+    // TODO: Introduce check for circular chains
+
+}
+
+SdrTextObj* SdrTextObj::GetPrevLinkInChain() const
+{
+    /*
+    if (GetTextChain())
+        return GetTextChain()->GetPrevLink(this);
+
+    return NULL;
+    */
+
+    return mpPrevInChain;
+}
+
+void SdrTextObj::SetPreventChainable()
+{
+    mbIsUnchainableClone = true;
+}
+
+bool SdrTextObj::GetPreventChainable() const
+{
+    // Prevent chaining it 1) during dragging && 2) when we are editing next link
+    return mbIsUnchainableClone || (GetNextLinkInChain() && GetNextLinkInChain()->IsInEditMode());
+}
+
+ SdrObject* SdrTextObj::getFullDragClone() const
+ {
+    SdrObject *pClone = SdrAttrObj::getFullDragClone();
+    SdrTextObj *pTextObjClone = dynamic_cast<SdrTextObj *>(pClone);
+    if (pTextObjClone != NULL) {
+        // Avoid transferring of text for chainable object during dragging
+        pTextObjClone->SetPreventChainable();
+    }
+
+    return pClone;
+ }
+
+/* End chaining code */
+
 /** returns the currently active text. */
 SdrText* SdrTextObj::getActiveText() const
 {
diff --git a/svx/source/svdraw/svdotextdecomposition.cxx b/svx/source/svdraw/svdotextdecomposition.cxx
index 74eebf0..be19e39 100644
--- a/svx/source/svdraw/svdotextdecomposition.cxx
+++ b/svx/source/svdraw/svdotextdecomposition.cxx
@@ -22,6 +22,9 @@
 #include <svx/svdoutl.hxx>
 #include <svx/svdpage.hxx>
 #include <svx/svdotext.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/textchain.hxx>
+#include <svx/textchainflow.hxx>
 #include <basegfx/vector/b2dvector.hxx>
 #include <sdr/primitive2d/sdrtextprimitive2d.hxx>
 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
@@ -48,6 +51,8 @@
 #include <svx/unoapi.hxx>
 #include <drawinglayer/geometry/viewinformation2d.hxx>
 #include <editeng/outlobj.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/overflowingtxt.hxx>
 #include <basegfx/matrix/b2dhommatrixtools.hxx>
 
 using namespace com::sun::star;
@@ -1404,5 +1409,194 @@ void SdrTextObj::impGetScrollTextTiming(drawinglayer::animation::AnimationEntryL
     }
 }
 
+void SdrTextObj::impHandleChainingEventsDuringDecomposition(SdrOutliner &rOutliner) const
+{
+    if (GetTextChain()->GetNilChainingEvent(this))
+        return;
+
+    GetTextChain()->SetNilChainingEvent(this, true);
+
+    TextChainFlow aTxtChainFlow(const_cast<SdrTextObj*>(this));
+    bool bIsOverflow;
+
+    // Some debug output
+    size_t nObjCount = pPage->GetObjCount();
+    for (unsigned i = 0; i < nObjCount; i++) {
+        SdrTextObj *pCurObj = (SdrTextObj *) pPage->GetObj(i);
+
+        if (pCurObj == this) {
+            fprintf(stderr, "Working on TextBox %d\n", i);
+            break;
+        }
+    }
+
+    aTxtChainFlow.CheckForFlowEvents(&rOutliner);
+
+    if (aTxtChainFlow.IsUnderflow() && !IsInEditMode())
+    {
+        // underflow-induced overflow
+        aTxtChainFlow.ExecuteUnderflow(&rOutliner);
+        bIsOverflow = aTxtChainFlow.IsOverflow();
+    } else {
+        // standard overflow (no underlow before)
+        bIsOverflow = aTxtChainFlow.IsOverflow();
+    }
+
+    if (bIsOverflow && !IsInEditMode()) {
+        // Initialize Chaining Outliner
+        SdrOutliner &rChainingOutl = pModel->GetChainingOutliner(this);
+        ImpInitDrawOutliner( rChainingOutl );
+        rChainingOutl.SetUpdateMode(true);
+        // We must pass the chaining outliner otherwise we would mess up decomposition
+        aTxtChainFlow.ExecuteOverflow(&rOutliner, &rChainingOutl);
+    }
+
+    GetTextChain()->SetNilChainingEvent(this, false);
+}
+
+void SdrTextObj::impDecomposeChainedTextPrimitive(
+        drawinglayer::primitive2d::Primitive2DSequence& rTarget,
+        const drawinglayer::primitive2d::SdrChainedTextPrimitive2D& rSdrChainedTextPrimitive,
+        const drawinglayer::geometry::ViewInformation2D& aViewInformation) const
+{
+    // decompose matrix to have position and size of text
+    basegfx::B2DVector aScale, aTranslate;
+    double fRotate, fShearX;
+    rSdrChainedTextPrimitive.getTextRangeTransform().decompose(aScale, aTranslate, fRotate, fShearX);
+
+    // use B2DRange aAnchorTextRange for calculations
+    basegfx::B2DRange aAnchorTextRange(aTranslate);
+    aAnchorTextRange.expand(aTranslate + aScale);
+
+    // prepare outliner
+    const SfxItemSet& rTextItemSet = rSdrChainedTextPrimitive.getSdrText()->GetItemSet();
+    SdrOutliner& rOutliner = ImpGetDrawOutliner();
+
+    SdrTextVertAdjust eVAdj = GetTextVerticalAdjust(rTextItemSet);
+    SdrTextHorzAdjust eHAdj = GetTextHorizontalAdjust(rTextItemSet);
+    const EEControlBits nOriginalControlWord(rOutliner.GetControlWord());
+    const Size aNullSize;
+
+    // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
+    rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
+
+    rOutliner.SetControlWord(nOriginalControlWord|EEControlBits::AUTOPAGESIZE|EEControlBits::STRETCHING);
+    rOutliner.SetMinAutoPaperSize(aNullSize);
+    rOutliner.SetMaxAutoPaperSize(Size(1000000,1000000));
+
+    // add one to rage sizes to get back to the old Rectangle and outliner measurements
+    const sal_uInt32 nAnchorTextWidth(FRound(aAnchorTextRange.getWidth() + 1L));
+    const sal_uInt32 nAnchorTextHeight(FRound(aAnchorTextRange.getHeight() + 1L));
+
+    // Text
+    const OutlinerParaObject* pOutlinerParaObject = rSdrChainedTextPrimitive.getSdrText()->GetOutlinerParaObject();
+    OSL_ENSURE(pOutlinerParaObject, "impDecomposeBlockTextPrimitive used with no OutlinerParaObject (!)");
+
+    const bool bVerticalWritintg(pOutlinerParaObject->IsVertical());
+    const Size aAnchorTextSize(Size(nAnchorTextWidth, nAnchorTextHeight));
+
+    if(IsTextFrame())
+    {
+        rOutliner.SetMaxAutoPaperSize(aAnchorTextSize);
+    }
+
+    if(SDRTEXTHORZADJUST_BLOCK == eHAdj && !bVerticalWritintg)
+    {
+        rOutliner.SetMinAutoPaperSize(Size(nAnchorTextWidth, 0));
+    }
+
+    if(SDRTEXTVERTADJUST_BLOCK == eVAdj && bVerticalWritintg)
+    {
+        rOutliner.SetMinAutoPaperSize(Size(0, nAnchorTextHeight));
+    }
+
+    rOutliner.SetPaperSize(aNullSize);
+    rOutliner.SetUpdateMode(true);
+    // Sets original text
+    rOutliner.SetText(*pOutlinerParaObject);
+
+    /* Begin overflow/underflow handling */
+
+    impHandleChainingEventsDuringDecomposition(rOutliner);
+
+    /* End overflow/underflow handling */
+
+    // set visualizing page at Outliner; needed e.g. for PageNumberField decomposition
+    rOutliner.setVisualizedPage(GetSdrPageFromXDrawPage(aViewInformation.getVisualizedPage()));
+
+    // now get back the layouted text size from outliner
+    const Size aOutlinerTextSize(rOutliner.GetPaperSize());
+    const basegfx::B2DVector aOutlinerScale(aOutlinerTextSize.Width(), aOutlinerTextSize.Height());
+    basegfx::B2DVector aAdjustTranslate(0.0, 0.0);
+
+    // correct horizontal translation using the now known text size
+    if(SDRTEXTHORZADJUST_CENTER == eHAdj || SDRTEXTHORZADJUST_RIGHT == eHAdj)
+    {
+        const double fFree(aAnchorTextRange.getWidth() - aOutlinerScale.getX());
+
+        if(SDRTEXTHORZADJUST_CENTER == eHAdj)
+        {
+            aAdjustTranslate.setX(fFree / 2.0);
+        }
+
+        if(SDRTEXTHORZADJUST_RIGHT == eHAdj)
+        {
+            aAdjustTranslate.setX(fFree);
+        }
+    }
+
+    // correct vertical translation using the now known text size
+    if(SDRTEXTVERTADJUST_CENTER == eVAdj || SDRTEXTVERTADJUST_BOTTOM == eVAdj)
+    {
+        const double fFree(aAnchorTextRange.getHeight() - aOutlinerScale.getY());
+
+        if(SDRTEXTVERTADJUST_CENTER == eVAdj)
+        {
+            aAdjustTranslate.setY(fFree / 2.0);
+        }
+
+        if(SDRTEXTVERTADJUST_BOTTOM == eVAdj)
+        {
+            aAdjustTranslate.setY(fFree);
+        }
+    }
+
+    // prepare matrices to apply to newly created primitives. aNewTransformA
+    // will get coordinates in aOutlinerScale size and positive in X, Y.
+    basegfx::B2DHomMatrix aNewTransformA;
+    basegfx::B2DHomMatrix aNewTransformB;
+
+    // translate relative to given primitive to get same rotation and shear
+    // as the master shape we are working on. For vertical, use the top-right
+    // corner
+    const double fStartInX(bVerticalWritintg ? aAdjustTranslate.getX() + aOutlinerScale.getX() : aAdjustTranslate.getX());
+    aNewTransformA.translate(fStartInX, aAdjustTranslate.getY());
+
+    // mirroring. We are now in aAnchorTextRange sizes. When mirroring in X and Y,
+    // move the null point which was top left to bottom right.
+    const bool bMirrorX(basegfx::fTools::less(aScale.getX(), 0.0));
+    const bool bMirrorY(basegfx::fTools::less(aScale.getY(), 0.0));
+    aNewTransformB.scale(bMirrorX ? -1.0 : 1.0, bMirrorY ? -1.0 : 1.0);
+
+    // in-between the translations of the single primitives will take place. Afterwards,
+    // the object's transformations need to be applied
+    aNewTransformB.shearX(fShearX);
+    aNewTransformB.rotate(fRotate);
+    aNewTransformB.translate(aTranslate.getX(), aTranslate.getY());
+
+    basegfx::B2DRange aClipRange;
+
+    // now break up text primitives.
+    impTextBreakupHandler aConverter(rOutliner);
+    aConverter.decomposeBlockTextPrimitive(aNewTransformA, aNewTransformB, aClipRange);
+
+    // cleanup outliner
+    rOutliner.Clear();
+    rOutliner.setVisualizedPage(0);
+    rOutliner.SetControlWord(nOriginalControlWord);
+
+    rTarget = aConverter.getPrimitive2DSequence();
+}
+
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/textchainflow.cxx b/svx/source/svdraw/textchainflow.cxx
index 922cfb3..3286b86 100644
--- a/svx/source/svdraw/textchainflow.cxx
+++ b/svx/source/svdraw/textchainflow.cxx
@@ -170,14 +170,14 @@ void TextChainFlow::ExecuteUnderflow(SdrOutliner *pOutl)
         mpNextLink->NbcSetOutlinerParaObject(pOutl->GetEmptyParaObject());
 
     // We store the size since NbcSetOutlinerParaObject can change it
-    Size aOldSize = pOutl->GetMaxAutoPaperSize();
+    //Size aOldSize = pOutl->GetMaxAutoPaperSize();
 
     // This should not be done in editing mode!! //XXX
     if (!mpTargetLink->IsInEditMode())
         mpTargetLink->NbcSetOutlinerParaObject(pNewText);
 
     // Restore size and set new text
-    //pOutl->SetMaxAutoPaperSize(aOldSize); // XXX
+    //pOutl->SetMaxAutoPaperSize(aOldSize); // XXX (it seems to be working anyway without this)
     pOutl->SetText(*pNewText);
 
     //GetTextChain()->SetNilChainingEvent(mpTargetLink, false);
commit f5f0a20b720d341ca14fc013ccb642ec430cacd4
Author: matteocam <matteo.campanelli at gmail.com>
Date:   Sun Sep 6 11:30:31 2015 +0200

    chained editeng: Add TextChainCursor related files
    
    Change-Id: I6c98a28ae800197d58df8791e72a00b6490a2e2e

diff --git a/include/svx/textchaincursor.hxx b/include/svx/textchaincursor.hxx
new file mode 100644
index 0000000..61e6939
--- /dev/null
+++ b/include/svx/textchaincursor.hxx
@@ -0,0 +1,64 @@
+/* -*- 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 .
+ */
+
+#ifndef INCLUDED_SVX_TEXTCHAINCURSOR_HXX
+#define INCLUDED_SVX_TEXTCHAINCURSOR_HXX
+
+#include <svx/svxdllapi.h>
+
+class SdrObjEditView;
+class SdrTextObj;
+class KeyEvent;
+class SdrOutliner;
+
+
+class SVX_DLLPUBLIC TextChainCursorManager
+{
+public:
+    TextChainCursorManager(SdrObjEditView *pEditView, const SdrTextObj *pTextObj);
+
+    bool HandleKeyEvent( const KeyEvent& rKEvt );
+
+    // Used by HandledKeyEvent and basic building block for handling cursor event
+    void HandleCursorEvent(const CursorChainingEvent aCurEvt,
+                           const ESelection  aNewSel);
+
+    // To be used after chaining event to deal with some nuisances
+    void  HandleCursorEventAfterChaining(const CursorChainingEvent aCurEvt,
+                                         const ESelection  aNewSel);
+
+private:
+    SdrObjEditView *mpEditView;
+    const SdrTextObj *mpTextObj;
+
+    // flag for handling of CANC which is kind of an exceptional case
+    bool mbHandlingDel;
+
+    void impChangeEditingTextObj(SdrTextObj *pTargetTextObj, ESelection aNewSel);
+    void impDetectEvent(const KeyEvent& rKEvt,
+                        CursorChainingEvent *pOutCursorEvt,
+                        ESelection *pOutSel,
+                        bool *bOutHandled);
+};
+
+
+#endif // INCLUDED_SVX_TEXTCHAINCURSOR_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/svx/Library_svxcore.mk b/svx/Library_svxcore.mk
index ffbcf01..ca9e5c5 100644
--- a/svx/Library_svxcore.mk
+++ b/svx/Library_svxcore.mk
@@ -341,6 +341,7 @@ $(eval $(call gb_Library_add_exception_objects,svxcore,\
     svx/source/svdraw/svdxcgv \
     svx/source/svdraw/textchain \
     svx/source/svdraw/textchainflow \
+    svx/source/svdraw/textchaincursor \
     svx/source/styles/CommonStylePreviewRenderer \
     svx/source/styles/CommonStyleManager \
     svx/source/styles/ColorSets \
diff --git a/svx/source/svdraw/textchaincursor.cxx b/svx/source/svdraw/textchaincursor.cxx
new file mode 100644
index 0000000..23bd8f5
--- /dev/null
+++ b/svx/source/svdraw/textchaincursor.cxx
@@ -0,0 +1,210 @@
+/* -*- 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 .
+ */
+
+#include <svx/textchain.hxx>
+#include <svx/textchaincursor.hxx>
+#include <svx/svdedxv.hxx>
+#include <svx/svdoutl.hxx>
+
+// XXX: Possible duplication of code in behavior with stuff in ImpEditView (or ImpEditEngine) and OutlinerView
+
+// XXX: We violate Demeter's Law several times here, I'm afraid
+
+TextChainCursorManager::TextChainCursorManager(SdrObjEditView *pEditView, const SdrTextObj *pTextObj) :
+    mpEditView(pEditView),
+    mpTextObj(pTextObj),
+    mbHandlingDel(false)
+{
+    assert(mpEditView);
+    assert(mpTextObj);
+
+}
+
+bool TextChainCursorManager::HandleKeyEvent( const KeyEvent& rKEvt )
+{
+    ESelection aNewSel;
+    CursorChainingEvent aCursorEvent;
+
+    // check what the cursor/event situation looks like
+    bool bCompletelyHandled = false;
+    impDetectEvent(rKEvt, &aCursorEvent, &aNewSel, &bCompletelyHandled);
+
+    if (aCursorEvent == CursorChainingEvent::NULL_EVENT)
+        return false;
+    else {
+        HandleCursorEvent(aCursorEvent, aNewSel);
+        // return value depends on the situation we are in
+        return bCompletelyHandled;
+    }
+}
+
+void TextChainCursorManager::impDetectEvent(const KeyEvent& rKEvt,
+                                            CursorChainingEvent *pOutCursorEvt,
+                                            ESelection *pOutSel,
+                                            bool *bOutHandled)
+{
+    SdrOutliner *pOutl = mpEditView->GetTextEditOutliner();
+    OutlinerView *pOLV = mpEditView->GetTextEditOutlinerView();
+
+    SdrTextObj *pNextLink = mpTextObj->GetNextLinkInChain();
+    SdrTextObj *pPrevLink = mpTextObj->GetPrevLinkInChain();
+
+    KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction();
+
+    // We need to have this KeyFuncType
+    if (eFunc !=  KeyFuncType::DONTKNOW && eFunc != KeyFuncType::DELETE)
+    {
+        *pOutCursorEvt = CursorChainingEvent::NULL_EVENT;
+        return;
+    }
+
+    sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
+    ESelection aCurSel = pOLV->GetSelection();
+
+    ESelection aEndSelPrevBox(100000, 100000);
+
+    sal_Int32 nLastPara = pOutl->GetParagraphCount()-1;
+    OUString aLastParaText = pOutl->GetText(pOutl->GetParagraph(nLastPara));
+    sal_Int32 nLastParaLen = aLastParaText.getLength();
+
+    ESelection aEndSel = ESelection(nLastPara, nLastParaLen);
+    bool bAtEndOfTextContent = aCurSel.IsEqual(aEndSel);
+
+    // Possibility: Are we "pushing" at the end of the object?
+    if (nCode == KEY_RIGHT && bAtEndOfTextContent && pNextLink)
+    {
+        *pOutCursorEvt = CursorChainingEvent::TO_NEXT_LINK;
+        // Selection unchanged: we are at the beginning of the box
+        *bOutHandled = true; // Nothing more to do than move cursor
+        return;
+    }
+
+    // Possibility: Are we "pushing" at the end of the object?
+    if (eFunc == KeyFuncType::DELETE && bAtEndOfTextContent && pNextLink)
+    {
+        *pOutCursorEvt = CursorChainingEvent::TO_NEXT_LINK;
+        // Selection unchanged: we are at the beginning of the box
+        *bOutHandled = false; // We still need to delete the characters
+        mbHandlingDel = true;
+        return;
+    }
+
+    ESelection aStartSel = ESelection(0, 0);
+    bool bAtStartOfTextContent = aCurSel.IsEqual(aStartSel);
+
+    // Possibility: Are we "pushing" at the start of the object?
+    if (nCode == KEY_LEFT && bAtStartOfTextContent && pPrevLink)
+    {
+        *pOutCursorEvt = CursorChainingEvent::TO_PREV_LINK;
+        *pOutSel = aEndSelPrevBox; // Set at end of selection
+        *bOutHandled = true; // Nothing more to do than move cursor
+        return;
+    }
+
+    // Possibility: Are we "pushing" at the start of the object and deleting left?
+    if (nCode == KEY_BACKSPACE && bAtStartOfTextContent && pPrevLink)
+    {
+        *pOutCursorEvt = CursorChainingEvent::TO_PREV_LINK;
+        *pOutSel = aEndSelPrevBox; // Set at end of selection
+        *bOutHandled = false; // We need to delete characters after moving cursor
+        return;
+    }
+
+    // If arrived here there is no event detected
+    *pOutCursorEvt = CursorChainingEvent::NULL_EVENT;
+
+}
+
+void TextChainCursorManager::HandleCursorEventAfterChaining(
+                            const CursorChainingEvent aCurEvt,
+                            const ESelection  aNewSel)
+
+{
+     // Special case for DELETE handling: we need to get back at the end of the prev box
+    if (mbHandlingDel) {
+        // reset flag
+        mbHandlingDel = false;
+
+        // Move to end of prev box
+        SdrTextObj *pPrevLink = mpTextObj->GetPrevLinkInChain();
+        ESelection aEndSel(100000, 100000);
+        impChangeEditingTextObj(pPrevLink, aEndSel);
+        return;
+    }
+
+    // Standard handling
+    HandleCursorEvent(aCurEvt, aNewSel);
+}
+
+
+void TextChainCursorManager::HandleCursorEvent(
+                            const CursorChainingEvent aCurEvt,
+                            const ESelection  aNewSel)
+
+{
+
+    OutlinerView* pOLV = mpEditView->GetTextEditOutlinerView();
+    SdrTextObj *pNextLink = mpTextObj->GetNextLinkInChain();
+    SdrTextObj *pPrevLink = mpTextObj->GetPrevLinkInChain();
+
+
+
+    switch ( aCurEvt ) {
+            case CursorChainingEvent::UNCHANGED:
+                // Set same selection as before the chaining (which is saved as PostChainingSel)
+                // We need an explicit set because the Outliner is messed up
+                //    after text transfer and otherwise it brings us at arbitrary positions.
+                pOLV->SetSelection(aNewSel);
+                break;
+            case CursorChainingEvent::TO_NEXT_LINK:
+                mpTextObj->GetTextChain()->SetSwitchingToNextBox(mpTextObj, true);
+                impChangeEditingTextObj(pNextLink, aNewSel);
+                break;
+            case CursorChainingEvent::TO_PREV_LINK:
+                impChangeEditingTextObj(pPrevLink, aNewSel);
+                break;
+            case CursorChainingEvent::NULL_EVENT:
+                // Do nothing here
+                break;
+    }
+
+}
+
+void TextChainCursorManager::impChangeEditingTextObj(SdrTextObj *pTargetTextObj, ESelection aNewSel)
+{
+    assert(pTargetTextObj);
+
+    // To ensure that we check for overflow in the next box // This is handled in SdrTextObj::EndTextEdit
+    SdrTextObj *pNextLink = mpTextObj->GetNextLinkInChain();
+    TextChain *pTextChain = mpTextObj->GetTextChain();
+    // If we are moving forward
+    if (pNextLink && pTargetTextObj == pNextLink)
+        pTextChain->SetPendingOverflowCheck(pNextLink, true);
+
+    mpEditView->SdrEndTextEdit();
+    mpEditView->SdrBeginTextEdit(pTargetTextObj);
+    // OutlinerView has changed, so we update the pointer
+    OutlinerView *pOLV = mpEditView->GetTextEditOutlinerView();
+    pOLV->SetSelection(aNewSel);
+
+    // Update reference text obj
+    mpTextObj = pTargetTextObj;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 68346af9ad9f3c88cc6c6335b80f916849054f29
Author: matteocam <matteo.campanelli at gmail.com>
Date:   Sun Sep 6 11:29:03 2015 +0200

    chained editeng: Add TextChainFlow related files
    
    Change-Id: I0e4155391fff29dc4484c7aedd4e62f02c4afd25

diff --git a/include/svx/textchainflow.hxx b/include/svx/textchainflow.hxx
new file mode 100644
index 0000000..60afe75
--- /dev/null
+++ b/include/svx/textchainflow.hxx
@@ -0,0 +1,134 @@
+/* -*- 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 .
+ */
+
+#ifndef INCLUDED_SVX_TEXTCHAINFLOW_HXX
+#define INCLUDED_SVX_TEXTCHAINFLOW_HXX
+
+
+#include <svx/textchain.hxx>
+
+class SdrTextObj;
+class SdrOutliner;
+class NonOverflowingText;
+class OverflowingText;
+class TextChain;
+class OutlinerParaObject;
+class OFlowChainedText;
+class UFlowChainedText;
+
+// XXX: const qualifiers?
+
+class TextChainFlow {
+
+    //  -- Public Members --
+    public:
+    TextChainFlow(SdrTextObj *pChainTarget);
+    virtual ~TextChainFlow();
+
+    // Check for flow events in Outliner
+    virtual void CheckForFlowEvents(SdrOutliner *);
+
+    virtual void ExecuteUnderflow(SdrOutliner *);
+
+    // Uses two outliners: one for the non-overfl text and one for overflowing (might be the same)
+    virtual void ExecuteOverflow(SdrOutliner *, SdrOutliner *);
+
+    // Getters
+
+    bool IsOverflow() const;
+    bool IsUnderflow() const;
+
+    SdrTextObj *GetLinkTarget() const;
+    SdrTextObj *GetNextLink() const;
+
+    OFlowChainedText *GetOverflowChainedText() const;
+    UFlowChainedText *GetUnderflowChainedText() const;
+
+    //  -- Protected Members --
+    protected:
+
+    // Cursor related
+    bool mbPossiblyCursorOut;
+    CursorChainingEvent maCursorEvent;
+    ESelection maOverflowPosSel;
+    ESelection maPostChainingSel;
+
+    OFlowChainedText *mpOverflChText;
+    UFlowChainedText *mpUnderflChText;
+
+
+
+    void impCheckForFlowEvents(SdrOutliner *, SdrOutliner *);
+
+    TextChain *GetTextChain() const;
+
+    virtual void impLeaveOnlyNonOverflowingText(SdrOutliner *);
+    virtual void impMoveChainedTextToNextLink(SdrOutliner *);
+
+    virtual void impSetFlowOutlinerParams(SdrOutliner *, SdrOutliner *);
+
+    OutlinerParaObject *impGetOverflowingParaObject(SdrOutliner *pOutliner);
+    // impGetMergedUnderflowingParaObject merges underflowing text with the one in the next box
+    OutlinerParaObject *impGetMergedUnderflowParaObject(SdrOutliner *pOutliner);
+
+    //  -- Private Members --
+    private:
+    // XXX: It would be nice to get rid of this
+    bool mbOFisUFinduced;
+
+    void impUpdateCursorInfo();
+
+    SdrTextObj *mpTargetLink;
+    SdrTextObj *mpNextLink;
+
+    TextChain *mpTextChain;
+
+    bool bCheckedFlowEvents;
+
+    bool bUnderflow;
+    bool bOverflow;
+
+};
+
+
+// NOTE: EditingTextChainFlow might be strongly coupled with behavior in SdrTextObj::onChainingEvent
+class EditingTextChainFlow : public TextChainFlow
+{
+public:
+    EditingTextChainFlow(SdrTextObj *);
+    virtual void CheckForFlowEvents(SdrOutliner *) SAL_OVERRIDE;
+
+    //virtual void ExecuteOverflow(SdrOutliner *, SdrOutliner *) SAL_OVERRIDE;
+
+protected:
+    virtual void impLeaveOnlyNonOverflowingText(SdrOutliner *) SAL_OVERRIDE;
+
+    virtual void impSetTextForEditingOutliner(OutlinerParaObject *);
+
+    virtual void impSetFlowOutlinerParams(SdrOutliner *, SdrOutliner *) SAL_OVERRIDE;
+
+private:
+    void impBroadcastCursorInfo() const;
+
+};
+
+#endif // INCLUDED_SVX_TEXTCHAINFLOW_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/svx/Library_svxcore.mk b/svx/Library_svxcore.mk
index 9c22634..ffbcf01 100644
--- a/svx/Library_svxcore.mk
+++ b/svx/Library_svxcore.mk
@@ -340,6 +340,7 @@ $(eval $(call gb_Library_add_exception_objects,svxcore,\
     svx/source/svdraw/svdviter \
     svx/source/svdraw/svdxcgv \
     svx/source/svdraw/textchain \
+    svx/source/svdraw/textchainflow \
     svx/source/styles/CommonStylePreviewRenderer \
     svx/source/styles/CommonStyleManager \
     svx/source/styles/ColorSets \
diff --git a/svx/source/svdraw/textchainflow.cxx b/svx/source/svdraw/textchainflow.cxx
new file mode 100644
index 0000000..922cfb3
--- /dev/null
+++ b/svx/source/svdraw/textchainflow.cxx
@@ -0,0 +1,353 @@
+/* -*- 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 .
+ */
+
+
+#include <svx/svdotext.hxx>
+#include <svx/svdoutl.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/overflowingtxt.hxx>
+#include <svx/textchainflow.hxx>
+
+TextChainFlow::TextChainFlow(SdrTextObj *pChainTarget)
+    : mpTargetLink(pChainTarget)
+{
+    fprintf(stderr, "\n[TEXTCHAINFLOW] Creating a new TextChainFlow\n");
+
+    mpTextChain = mpTargetLink->GetTextChain();
+    mpNextLink = mpTargetLink->GetNextLinkInChain();
+    bCheckedFlowEvents = false;
+
+    bUnderflow = bOverflow = false;
+
+    mbOFisUFinduced = false;
+
+    mpOverflChText = NULL;
+    mpUnderflChText = NULL;
+
+    maCursorEvent = CursorChainingEvent::NULL_EVENT;
+    mbPossiblyCursorOut = false;
+
+}
+
+
+TextChainFlow::~TextChainFlow()
+{
+    if (mpOverflChText)
+        delete mpOverflChText;
+    if (mpUnderflChText)
+        delete mpUnderflChText;
+}
+
+void TextChainFlow::impSetFlowOutlinerParams(SdrOutliner *, SdrOutliner *)
+{
+    // Nothing to do if not in editing mode
+}
+
+/*
+ * Check for overflow in the state of pFlowOutl.
+ * If pParamOutl is not NULL sets some parameters from there.
+ * This is useful in case the outliner is not set for overflow
+ * (e.g. in editing mode we check for overflow in drawing outl but
+ *  parameters come from editing outliner)
+*/
+void TextChainFlow::impCheckForFlowEvents(SdrOutliner *pFlowOutl, SdrOutliner *pParamOutl)
+{
+    bool bOldUpdateMode = pFlowOutl->GetUpdateMode();
+
+    // XXX: This could be reorganized moving most of this stuff inside EditingTextChainFlow
+    if (pParamOutl != NULL)
+    {
+        // We need this since it's required to check overflow
+        pFlowOutl->SetUpdateMode(true);
+
+        // XXX: does this work if you do it before setting the text? Seems so.
+        impSetFlowOutlinerParams(pFlowOutl, pParamOutl);
+    }
+
+    bool bIsPageOverflow = pFlowOutl->IsPageOverflow();
+
+    // NOTE: overflow and underflow cannot be both true
+    bOverflow = bIsPageOverflow && mpNextLink;
+    bUnderflow = !bIsPageOverflow &&  mpNextLink && mpNextLink->HasText();
+
+    // Get old state on whether to merge para-s or not
+    // NOTE: We handle UF/OF using the _old_ state. The new one is simply saved
+    bool bMustMergeParaAmongLinks = GetTextChain()->GetIsPartOfLastParaInNextLink(mpTargetLink);
+
+    // Set (Non)OverflowingTxt here (if any)
+
+    // If we had an underflow before we have to deep merge paras anyway
+    bool bMustMergeParaOF = bMustMergeParaAmongLinks || mbOFisUFinduced;
+
+    // XXX
+    bMustMergeParaOF = true; // XXX: Experiment: no deep merging.
+
+    mpOverflChText = bOverflow ?
+                     new OFlowChainedText(pFlowOutl, bMustMergeParaOF) :
+                     NULL;
+
+    // Set current underflowing text (if any)
+    mpUnderflChText = bUnderflow ?
+                      new UFlowChainedText(pFlowOutl, bMustMergeParaAmongLinks) :
+                      NULL;
+
+    // Reset update mode // Reset it here because we use WriteRTF (needing updatemode = true) in the two constructors above
+    if (!bOldUpdateMode) // Reset only if the old value was false
+        pFlowOutl->SetUpdateMode(bOldUpdateMode);
+
+    // NOTE: Must be called after mp*ChText abd b*flow have been set but before mbOFisUFinduced is reset
+    impUpdateCursorInfo();
+
+    // To check whether an overflow is underflow induced or not (useful in cursor checking)
+    mbOFisUFinduced = bUnderflow;
+}
+
+void TextChainFlow::impUpdateCursorInfo()
+{
+    // XXX: Maybe we can get rid of mbOFisUFinduced by not allowing handling of more than one event by the same TextChainFlow
+    // if this is not an OF triggered during an UF
+
+    mbPossiblyCursorOut = bOverflow;
+
+    if(mbPossiblyCursorOut ) {
+        maOverflowPosSel = ESelection(mpOverflChText->GetOverflowPointSel());
+        ESelection aSelAtUFTime = GetTextChain()->GetPreChainingSel(GetLinkTarget());
+        // Might be an invalid selection if the cursor at UF time was before
+        //   the (possibly UF-induced) Overflowing point but we don't use it in that case
+        maPostChainingSel = ESelection(aSelAtUFTime.nStartPara-maOverflowPosSel.nStartPara,
+                                       aSelAtUFTime.nStartPos-maOverflowPosSel.nStartPos );
+    }
+
+    // XXX: It may not be necessary anymore to keep this method separated from EditingTextChainFlow::impBroadcastCursorInfo
+}
+
+void TextChainFlow::CheckForFlowEvents(SdrOutliner *pFlowOutl)
+{
+    impCheckForFlowEvents(pFlowOutl, NULL);
+}
+
+
+bool TextChainFlow::IsOverflow() const
+{
+    return bOverflow;
+}
+
+bool TextChainFlow::IsUnderflow() const
+{
+    return bUnderflow;
+}
+
+
+// XXX: In editing mode you need to get "underflowing" text from editing outliner, so it's kinda separate from the drawing one!
+
+// XXX:Would it be possible to unify undeflow and its possibly following overrflow?
+void TextChainFlow::ExecuteUnderflow(SdrOutliner *pOutl)
+{
+
+    //GetTextChain()->SetNilChainingEvent(mpTargetLink, true);
+    // making whole text
+    OutlinerParaObject *pNewText = impGetMergedUnderflowParaObject(pOutl);
+
+    // Set the other box empty; it will be replaced by the rest of the text if overflow occurs
+    if (!mpTargetLink->GetPreventChainable())
+        mpNextLink->NbcSetOutlinerParaObject(pOutl->GetEmptyParaObject());
+
+    // We store the size since NbcSetOutlinerParaObject can change it
+    Size aOldSize = pOutl->GetMaxAutoPaperSize();
+
+    // This should not be done in editing mode!! //XXX
+    if (!mpTargetLink->IsInEditMode())
+        mpTargetLink->NbcSetOutlinerParaObject(pNewText);
+
+    // Restore size and set new text
+    //pOutl->SetMaxAutoPaperSize(aOldSize); // XXX
+    pOutl->SetText(*pNewText);
+
+    //GetTextChain()->SetNilChainingEvent(mpTargetLink, false);
+
+    // Check for new overflow
+    CheckForFlowEvents(pOutl);
+}
+
+void TextChainFlow::ExecuteOverflow(SdrOutliner *pNonOverflOutl, SdrOutliner *pOverflOutl)
+{
+    //GetTextChain()->SetNilChainingEvent(mpTargetLink, true);
+    // Leave only non overflowing text
+    impLeaveOnlyNonOverflowingText(pNonOverflOutl);
+
+    // Transfer of text to next link
+    if (!mpTargetLink->GetPreventChainable() ) // we don't transfer text while dragging because of resizing
+    {
+        impMoveChainedTextToNextLink(pOverflOutl);
+    }
+
+    //GetTextChain()->SetNilChainingEvent(mpTargetLink, false);
+}
+
+void TextChainFlow::impLeaveOnlyNonOverflowingText(SdrOutliner *pNonOverflOutl)
+{
+    OutlinerParaObject *pNewText = mpOverflChText->RemoveOverflowingText(pNonOverflOutl);
+
+    fprintf(stderr, "[TEXTCHAINFLOW - OF] SOURCE box set to %d paras \n", pNewText->GetTextObject().GetParagraphCount());
+
+    // adds it to current outliner anyway (useful in static decomposition)
+    pNonOverflOutl->SetText(*pNewText);
+
+    mpTargetLink->NbcSetOutlinerParaObject(pNewText);
+    // For some reason the paper size is lost after last instruction, so we set it.
+    pNonOverflOutl->SetPaperSize(Size(pNonOverflOutl->GetPaperSize().Width(),
+                                      pNonOverflOutl->GetTextHeight()));
+
+}
+
+void TextChainFlow::impMoveChainedTextToNextLink(SdrOutliner *pOverflOutl)
+{
+    // prevent copying text in same box
+    if ( mpNextLink ==  mpTargetLink ) {
+        fprintf(stderr, "[CHAINING] Trying to copy text for next link in same object\n");
+        return;
+    }
+
+    OutlinerParaObject *pNewText =
+        mpOverflChText->InsertOverflowingText(pOverflOutl,
+                                              mpNextLink->GetOutlinerParaObject());
+    fprintf(stderr, "[TEXTCHAINFLOW - OF] DEST box set to %d paras \n", pNewText->GetTextObject().GetParagraphCount());
+
+    if (pNewText)
+        mpNextLink->NbcSetOutlinerParaObject(pNewText);
+
+    // Set Deep Merge status
+    fprintf(stderr, "[DEEPMERGE] Setting deepMerge to %d\n", mpOverflChText->IsLastParaInterrupted());
+    GetTextChain()->SetIsPartOfLastParaInNextLink(
+                          mpTargetLink,
+                          mpOverflChText->IsLastParaInterrupted());
+}
+
+SdrTextObj *TextChainFlow::GetLinkTarget() const
+{
+    return mpTargetLink;
+}
+
+SdrTextObj *TextChainFlow::GetNextLink() const
+{
+    return mpNextLink;
+}
+
+OutlinerParaObject *TextChainFlow::impGetOverflowingParaObject(SdrOutliner *)
+{   // XXX: Should never be called (to be deleted)
+    assert(0);
+    return NULL;
+    //return mpOverflChText->CreateOverflowingParaObject(pOutliner,
+//                                                      mpNextLink->GetOutlinerParaObject());
+}
+
+OutlinerParaObject *TextChainFlow::impGetMergedUnderflowParaObject(SdrOutliner *pOutliner)
+{

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list