[Libreoffice-commits] core.git: include/oox oox/source writerfilter/source

Justin Luth justin_luth at sil.org
Thu Jul 2 03:07:46 PDT 2015


 include/oox/vml/vmlshape.hxx                      |    1 
 include/oox/vml/vmltextbox.hxx                    |    1 
 oox/source/vml/vmlshape.cxx                       |   77 ++++++++++++++++++++--
 oox/source/vml/vmlshapecontext.cxx                |    1 
 oox/source/vml/vmltextboxcontext.cxx              |    2 
 writerfilter/source/dmapper/DomainMapper_Impl.cxx |   77 +++++++++++++++++++++-
 6 files changed, 151 insertions(+), 8 deletions(-)

New commits:
commit 091fe76b6329b4bb974987554369cbfadd8f2401
Author: Justin Luth <justin_luth at sil.org>
Date:   Tue Jun 30 12:55:18 2015 +0300

    tdf#87348 implement mso-next-textbox vml-style textbox chaining import
    
    Change-Id: Ic62769cf5bb1589dd4de3a66b3d7dd896e5b5711
    Reviewed-on: https://gerrit.libreoffice.org/16366
    Reviewed-by: Justin Luth <justin_luth at sil.org>
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>

diff --git a/include/oox/vml/vmlshape.hxx b/include/oox/vml/vmlshape.hxx
index 6cc180c..e4b5c92 100644
--- a/include/oox/vml/vmlshape.hxx
+++ b/include/oox/vml/vmlshape.hxx
@@ -58,6 +58,7 @@ const sal_Int32 VML_CLIENTDATA_FORMULA          = 4;
 struct OOX_DLLPUBLIC ShapeTypeModel
 {
     OUString     maShapeId;              ///< Unique identifier of the shape.
+    OUString     maLegacyId;             ///< Plaintext identifier of the shape.
     OUString     maShapeName;            ///< Name of the shape, if present.
     OptValue< sal_Int32 > moShapeType;          ///< Builtin shape type identifier.
 
diff --git a/include/oox/vml/vmltextbox.hxx b/include/oox/vml/vmltextbox.hxx
index 3ff88d4..6b14c4c 100644
--- a/include/oox/vml/vmltextbox.hxx
+++ b/include/oox/vml/vmltextbox.hxx
@@ -95,6 +95,7 @@ public:
     bool borderDistanceSet;
     int borderDistanceLeft, borderDistanceTop, borderDistanceRight, borderDistanceBottom;
     OUString maLayoutFlow;
+    OUString msNextTextbox;
 
 private:
     typedef ::std::vector< TextPortionModel > PortionVector;
diff --git a/oox/source/vml/vmlshape.cxx b/oox/source/vml/vmlshape.cxx
index 55b17d9..2c2f6eb 100644
--- a/oox/source/vml/vmlshape.cxx
+++ b/oox/source/vml/vmlshape.cxx
@@ -312,21 +312,64 @@ Reference< XShape > ShapeBase::convertAndInsert( const Reference< XShapes >& rxS
                 if( aShapeProp.hasProperty( PROP_Name ) )
                     aShapeProp.setProperty( PROP_Name, getShapeName() );
                 uno::Reference< lang::XServiceInfo > xSInfo( xShape, uno::UNO_QUERY_THROW );
+
+                OUString sLinkChainName = getTypeModel().maLegacyId;
+                sal_Int32 id = 0;
+                sal_Int32 idPos = sLinkChainName.indexOf("_x");
+                sal_Int32 seq = 0;
+                sal_Int32 seqPos = sLinkChainName.indexOf("_s",idPos);
+                if( idPos >= 0 && idPos < seqPos )
+                {
+                    id = sLinkChainName.copy(idPos+2,seqPos-idPos+2).toInt32();
+                    seq = sLinkChainName.copy(seqPos+2).toInt32();
+                }
+
+                OUString s_mso_next_textbox;
+                if( getTextBox() )
+                    s_mso_next_textbox = getTextBox()->msNextTextbox;
+                if( s_mso_next_textbox.startsWith("#") )
+                    s_mso_next_textbox = s_mso_next_textbox.copy(1);
+
                 if (xSInfo->supportsService("com.sun.star.text.TextFrame"))
                 {
                     uno::Sequence<beans::PropertyValue> aGrabBag;
                     uno::Reference<beans::XPropertySet> propertySet (xShape, uno::UNO_QUERY);
                     propertySet->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag;
-                    sal_Int32 length = aGrabBag.getLength();
+                    sal_Int32 length;
 
+                    length = aGrabBag.getLength();
                     aGrabBag.realloc( length+1 );
                     aGrabBag[length].Name = "VML-Z-ORDER";
                     aGrabBag[length].Value = uno::makeAny( maTypeModel.maZIndex.toInt32() );
+
+                    if( !s_mso_next_textbox.isEmpty() )
+                    {
+                        length = aGrabBag.getLength();
+                        aGrabBag.realloc( length+1 );
+                        aGrabBag[length].Name = "mso-next-textbox";
+                        aGrabBag[length].Value = uno::makeAny( s_mso_next_textbox );
+                    }
+
+                    if( !sLinkChainName.isEmpty() )
+                    {
+                        length = aGrabBag.getLength();
+                        aGrabBag.realloc( length+4 );
+                        aGrabBag[length].Name   = "TxbxHasLink";
+                        aGrabBag[length].Value   = uno::makeAny( true );
+                        aGrabBag[length+1].Name = "Txbx-Id";
+                        aGrabBag[length+1].Value = uno::makeAny( id );
+                        aGrabBag[length+2].Name = "Txbx-Seq";
+                        aGrabBag[length+2].Value = uno::makeAny( seq );
+                        aGrabBag[length+3].Name = "LinkChainName";
+                        aGrabBag[length+3].Value = uno::makeAny( sLinkChainName );
+                    }
+
                     if(!(maTypeModel.maRotation).isEmpty())
                     {
-                        aGrabBag.realloc( length+2 );
-                        aGrabBag[length+1].Name = "mso-rotation-angle";
-                        aGrabBag[length+1].Value = uno::makeAny(sal_Int32(NormAngle360((maTypeModel.maRotation.toInt32()) * -100)));
+                        length = aGrabBag.getLength();
+                        aGrabBag.realloc( length+1 );
+                        aGrabBag[length].Name = "mso-rotation-angle";
+                        aGrabBag[length].Value = uno::makeAny(sal_Int32(NormAngle360((maTypeModel.maRotation.toInt32()) * -100)));
                     }
                     propertySet->setPropertyValue( "FrameInteropGrabBag", uno::makeAny(aGrabBag) );
                     sal_Int32 backColorTransparency = 0;
@@ -346,10 +389,34 @@ Reference< XShape > ShapeBase::convertAndInsert( const Reference< XShapes >& rxS
                         uno::Sequence<beans::PropertyValue> aGrabBag;
                         uno::Reference<beans::XPropertySet> propertySet (xShape, uno::UNO_QUERY);
                         propertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag;
-                        sal_Int32 length = aGrabBag.getLength();
+                        sal_Int32 length;
+
+                        length = aGrabBag.getLength();
                         aGrabBag.realloc( length+1 );
                         aGrabBag[length].Name = "VML-Z-ORDER";
                         aGrabBag[length].Value = uno::makeAny( maTypeModel.maZIndex.toInt32() );
+
+                        if( !s_mso_next_textbox.isEmpty() )
+                        {
+                            length = aGrabBag.getLength();
+                            aGrabBag.realloc( length+1 );
+                            aGrabBag[length].Name = "mso-next-textbox";
+                            aGrabBag[length].Value = uno::makeAny( s_mso_next_textbox );
+                        }
+
+                        if( !sLinkChainName.isEmpty() )
+                        {
+                            length = aGrabBag.getLength();
+                            aGrabBag.realloc( length+4 );
+                            aGrabBag[length].Name   = "TxbxHasLink";
+                            aGrabBag[length].Value   = uno::makeAny( true );
+                            aGrabBag[length+1].Name = "Txbx-Id";
+                            aGrabBag[length+1].Value = uno::makeAny( id );
+                            aGrabBag[length+2].Name = "Txbx-Seq";
+                            aGrabBag[length+2].Value = uno::makeAny( seq );
+                            aGrabBag[length+3].Name = "LinkChainName";
+                            aGrabBag[length+3].Value = uno::makeAny( sLinkChainName );
+                        }
                         propertySet->setPropertyValue( "InteropGrabBag", uno::makeAny(aGrabBag) );
                     }
                 }
diff --git a/oox/source/vml/vmlshapecontext.cxx b/oox/source/vml/vmlshapecontext.cxx
index 2f69efe..4ea10e8 100644
--- a/oox/source/vml/vmlshapecontext.cxx
+++ b/oox/source/vml/vmlshapecontext.cxx
@@ -269,6 +269,7 @@ ShapeTypeContext::ShapeTypeContext( ContextHandler2Helper& rParent, ShapeType& r
     // shape identifier and shape name
     bool bHasOspid = rAttribs.hasAttribute( O_TOKEN( spid ) );
     mrTypeModel.maShapeId = rAttribs.getXString( bHasOspid ? O_TOKEN( spid ) : XML_id, OUString() );
+    mrTypeModel.maLegacyId = rAttribs.getString( XML_id, OUString() );
     OSL_ENSURE( !mrTypeModel.maShapeId.isEmpty(), "ShapeTypeContext::ShapeTypeContext - missing shape identifier" );
     // if the o:spid attribute exists, the id attribute contains the user-defined shape name
     if( bHasOspid )
diff --git a/oox/source/vml/vmltextboxcontext.cxx b/oox/source/vml/vmltextboxcontext.cxx
index 8a1d5fb..d1a8b12 100644
--- a/oox/source/vml/vmltextboxcontext.cxx
+++ b/oox/source/vml/vmltextboxcontext.cxx
@@ -212,6 +212,8 @@ TextBoxContext::TextBoxContext( ContextHandler2Helper& rParent, TextBox& rTextBo
                 rTextBox.mrTypeModel.mbAutoHeight = true;
             else if (aName == "mso-layout-flow-alt")
                 rTextBox.mrTypeModel.maLayoutFlowAlt = aValue;
+            else if (aName == "mso-next-textbox")
+                rTextBox.msNextTextbox = aValue;
             else
                 SAL_WARN("oox", "unhandled style property: " << aName);
         }
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 38a4c07..3354057 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -2457,7 +2457,9 @@ void DomainMapper_Impl::ChainTextFrames()
         css::uno::Reference< css::drawing::XShape > xShape;
         sal_Int32 nId;
         sal_Int32 nSeq;
-        TextFramesForChaining(): xShape(0), nId(0), nSeq(0) {}
+        OUString s_mso_next_textbox;
+        bool bShapeNameSet;
+        TextFramesForChaining(): xShape(0), nId(0), nSeq(0), bShapeNameSet(false) {}
     } ;
     typedef std::map <OUString, TextFramesForChaining> ChainMap;
 
@@ -2472,12 +2474,18 @@ void DomainMapper_Impl::ChainTextFrames()
         {
             uno::Reference<text::XTextContent>  xTextContent(*iter, uno::UNO_QUERY_THROW);
             uno::Reference<beans::XPropertySet> xPropertySet(xTextContent, uno::UNO_QUERY);
+            uno::Reference<beans::XPropertySetInfo> xPropertySetInfo;
+            if( xPropertySet.is() )
+                xPropertySetInfo = xPropertySet->getPropertySetInfo();
             uno::Sequence<beans::PropertyValue> aGrabBag;
             uno::Reference<lang::XServiceInfo> xServiceInfo(xPropertySet, uno::UNO_QUERY);
 
             TextFramesForChaining aChainStruct = TextFramesForChaining();
             OUString sShapeName;
+            OUString sLinkChainName;
 
+            //The chaining name and the shape name CAN be different in .docx.
+            //MUST use LinkDisplayName/ChainName as the shape name for establishing links.
             if ( xServiceInfo->supportsService("com.sun.star.text.TextFrame") )
             {
                 xPropertySet->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag;
@@ -2491,8 +2499,68 @@ void DomainMapper_Impl::ChainTextFrames()
 
             lcl_getGrabBagValue( aGrabBag, "Txbx-Id")  >>= aChainStruct.nId;
             lcl_getGrabBagValue( aGrabBag, "Txbx-Seq") >>= aChainStruct.nSeq;
-            aChainStruct.xShape = *iter;
-            aTextFramesForChainingHelper[sShapeName] = aChainStruct;
+            lcl_getGrabBagValue( aGrabBag, "LinkChainName") >>= sLinkChainName;
+            lcl_getGrabBagValue( aGrabBag, "mso-next-textbox") >>= aChainStruct.s_mso_next_textbox;
+
+            //Sometimes the shape names have not been imported.  If not, we may have a fallback name.
+            //Set name later, only if required for linking.
+            if( sShapeName.isEmpty() )
+                aChainStruct.bShapeNameSet = false;
+            else
+            {
+                aChainStruct.bShapeNameSet = true;
+                sLinkChainName = sShapeName;
+            }
+
+            if( !sLinkChainName.isEmpty() )
+            {
+                aChainStruct.xShape = *iter;
+                aTextFramesForChainingHelper[sLinkChainName] = aChainStruct;
+            }
+        }
+
+        //if mso-next-textbox tags are provided, create those vml-style links first. Afterwards we will make dml-style id/seq links.
+        for (ChainMap::iterator msoIter= aTextFramesForChainingHelper.begin(); msoIter != aTextFramesForChainingHelper.end(); ++msoIter)
+        {
+            //if no mso-next-textbox, we are done.
+            //if it points to itself, we are done.
+            if( !msoIter->second.s_mso_next_textbox.isEmpty()
+                && !msoIter->second.s_mso_next_textbox.equals(msoIter->first) )
+            {
+                ChainMap::iterator nextFinder=aTextFramesForChainingHelper.find(msoIter->second.s_mso_next_textbox);
+                if( nextFinder != aTextFramesForChainingHelper.end() )
+                {
+                    //if the frames have no name yet, then set them.  LinkDisplayName / ChainName are read-only.
+                    if( !msoIter->second.bShapeNameSet )
+                    {
+                        uno::Reference< container::XNamed > xNamed( msoIter->second.xShape, uno::UNO_QUERY );
+                        if ( xNamed.is() )
+                        {
+                            xNamed->setName( msoIter->first );
+                            msoIter->second.bShapeNameSet = true;
+                        }
+                    }
+                    if( !nextFinder->second.bShapeNameSet )
+                    {
+                        uno::Reference< container::XNamed > xNamed( nextFinder->second.xShape, uno::UNO_QUERY );
+                        if ( xNamed.is() )
+                        {
+                            xNamed->setName( nextFinder->first );
+                            nextFinder->second.bShapeNameSet = true;
+                        }
+                    }
+
+                    uno::Reference<text::XTextContent>  xTextContent(msoIter->second.xShape, uno::UNO_QUERY_THROW);
+                    uno::Reference<beans::XPropertySet> xPropertySet(xTextContent, uno::UNO_QUERY);
+
+                    //The reverse chaining happens automatically, so only one direction needs to be set
+                    xPropertySet->setPropertyValue(sChainNextName, uno::makeAny(nextFinder->first));
+
+                    //the last item in an mso-next-textbox chain is indistinguishable from id/seq items.  Now that it is handled, remove it.
+                    if( nextFinder->second.s_mso_next_textbox.isEmpty() )
+                        aTextFramesForChainingHelper.erase(nextFinder->first);
+                }
+            }
         }
 
         //TODO: Perhaps allow reverse sequences when mso-layout-flow-alt = "bottom-to-top"
@@ -2501,6 +2569,8 @@ void DomainMapper_Impl::ChainTextFrames()
         //Finally - go through and attach the chains based on matching ID and incremented sequence number (dml-style).
         for (ChainMap::iterator outer_iter= aTextFramesForChainingHelper.begin(); outer_iter != aTextFramesForChainingHelper.end(); ++outer_iter)
         {
+            if( outer_iter->second.s_mso_next_textbox.isEmpty() )  //non-empty ones already handled earlier - so skipping them now.
+            {
                 for (ChainMap::iterator inner_iter=aTextFramesForChainingHelper.begin(); inner_iter != aTextFramesForChainingHelper.end(); ++inner_iter)
                 {
                     if ( inner_iter->second.nId == outer_iter->second.nId )
@@ -2516,6 +2586,7 @@ void DomainMapper_Impl::ChainTextFrames()
                         }
                     }
                 }
+            }
         }
         m_vTextFramesForChaining.clear(); //clear the vector
     }


More information about the Libreoffice-commits mailing list