Kaydet (Commit) d5c934d1 authored tarafından Miklos Vajna's avatar Miklos Vajna

n#792778 DOCX import: parse group shapes in oox only

Previously textframes inside groupshapes were tried to be imported as
TextFrames, but then their addition to a GroupShape failed, so the text
simply ended up as a normal paragraph. Fix this by importing members of
groupshapes as drawinglayer objects, just like how the WW8 import does.

Also fix two testcases, which implicitely tested that the groupshape VML
element is ignored on import.

Change-Id: I1a9fba8a5fd532203a825e55b1d5996277ea12fa
üst 2bbb4b9c
...@@ -202,7 +202,7 @@ struct ShapeModel ...@@ -202,7 +202,7 @@ struct ShapeModel
~ShapeModel(); ~ShapeModel();
/** Creates and returns a new shape textbox structure. */ /** Creates and returns a new shape textbox structure. */
TextBox& createTextBox(); TextBox& createTextBox(ShapeTypeModel& rModel);
/** Creates and returns a new shape client data structure. */ /** Creates and returns a new shape client data structure. */
ClientData& createClientData(); ClientData& createClientData();
}; };
......
...@@ -24,10 +24,17 @@ ...@@ -24,10 +24,17 @@
#include <rtl/ustring.hxx> #include <rtl/ustring.hxx>
#include "oox/helper/helper.hxx" #include "oox/helper/helper.hxx"
#include "oox/dllapi.h" #include "oox/dllapi.h"
#include <com/sun/star/uno/Reference.h>
namespace com { namespace sun { namespace star {
namespace drawing { class XShape; }
} } }
namespace oox { namespace oox {
namespace vml { namespace vml {
class ShapeTypeModel;
// ============================================================================ // ============================================================================
/** Font settings for a text portion in a textbox. */ /** Font settings for a text portion in a textbox. */
...@@ -62,7 +69,7 @@ struct TextPortionModel ...@@ -62,7 +69,7 @@ struct TextPortionModel
class OOX_DLLPUBLIC TextBox class OOX_DLLPUBLIC TextBox
{ {
public: public:
explicit TextBox(); explicit TextBox(ShapeTypeModel& rTypeModel);
/** Appends a new text portion to the textbox. */ /** Appends a new text portion to the textbox. */
void appendPortion( const TextFontModel& rFont, const ::rtl::OUString& rText ); void appendPortion( const TextFontModel& rFont, const ::rtl::OUString& rText );
...@@ -73,7 +80,9 @@ public: ...@@ -73,7 +80,9 @@ public:
const TextFontModel* getFirstFont() const; const TextFontModel* getFirstFont() const;
/** Returns the entire text of all text portions. */ /** Returns the entire text of all text portions. */
::rtl::OUString getText() const; ::rtl::OUString getText() const;
void convert(com::sun::star::uno::Reference<com::sun::star::drawing::XShape> xShape) const;
ShapeTypeModel& mrTypeModel;
/// Text distance from the border (inset attribute of v:textbox), valid only if set. /// Text distance from the border (inset attribute of v:textbox), valid only if set.
bool borderDistanceSet; bool borderDistanceSet;
int borderDistanceLeft, borderDistanceTop, borderDistanceRight, borderDistanceBottom; int borderDistanceLeft, borderDistanceTop, borderDistanceRight, borderDistanceBottom;
......
...@@ -41,6 +41,7 @@ public: ...@@ -41,6 +41,7 @@ public:
virtual ::oox::core::ContextHandlerRef virtual ::oox::core::ContextHandlerRef
onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ); onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs );
virtual void onCharacters( const ::rtl::OUString& rChars ); virtual void onCharacters( const ::rtl::OUString& rChars );
virtual void onStartElement(const AttributeList& rAttribs);
virtual void onEndElement(); virtual void onEndElement();
private: private:
......
...@@ -233,9 +233,9 @@ ShapeModel::~ShapeModel() ...@@ -233,9 +233,9 @@ ShapeModel::~ShapeModel()
{ {
} }
TextBox& ShapeModel::createTextBox() TextBox& ShapeModel::createTextBox(ShapeTypeModel& rModel)
{ {
mxTextBox.reset( new TextBox ); mxTextBox.reset( new TextBox(rModel) );
return *mxTextBox; return *mxTextBox;
} }
...@@ -486,6 +486,9 @@ Reference< XShape > SimpleShape::implConvertAndInsert( const Reference< XShapes ...@@ -486,6 +486,9 @@ Reference< XShape > SimpleShape::implConvertAndInsert( const Reference< XShapes
PropertySet( xShape ).setAnyProperty(PROP_RelativeHeight, makeAny( nHeight ) ); PropertySet( xShape ).setAnyProperty(PROP_RelativeHeight, makeAny( nHeight ) );
} }
} }
if (getTextBox())
getTextBox()->convert(xShape);
} }
// Import Legacy Fragments (if any) // Import Legacy Fragments (if any)
...@@ -522,8 +525,9 @@ Reference< XShape > SimpleShape::createPictureObject( const Reference< XShapes > ...@@ -522,8 +525,9 @@ Reference< XShape > SimpleShape::createPictureObject( const Reference< XShapes >
{ {
aPropSet.setProperty( PROP_GraphicURL, aGraphicUrl ); aPropSet.setProperty( PROP_GraphicURL, aGraphicUrl );
} }
// If the shape has an absolute position, set the properties accordingly. uno::Reference< lang::XServiceInfo > xServiceInfo(rxShapes, uno::UNO_QUERY);
if ( maTypeModel.maPosition == "absolute" ) // If the shape has an absolute position, set the properties accordingly, unless we're inside a group shape.
if ( maTypeModel.maPosition == "absolute" && !xServiceInfo->supportsService("com.sun.star.drawing.GroupShape"))
{ {
aPropSet.setProperty(PROP_HoriOrientPosition, rShapeRect.X); aPropSet.setProperty(PROP_HoriOrientPosition, rShapeRect.X);
aPropSet.setProperty(PROP_VertOrientPosition, rShapeRect.Y); aPropSet.setProperty(PROP_VertOrientPosition, rShapeRect.Y);
...@@ -866,6 +870,9 @@ Reference< XShape > GroupShape::implConvertAndInsert( const Reference< XShapes > ...@@ -866,6 +870,9 @@ Reference< XShape > GroupShape::implConvertAndInsert( const Reference< XShapes >
catch( Exception& ) catch( Exception& )
{ {
} }
// Make sure group shapes are inline as well, unless there is an explicit different style.
PropertySet aPropertySet(xGroupShape);
lcl_SetAnchorType(aPropertySet, maTypeModel);
return xGroupShape; return xGroupShape;
} }
......
...@@ -404,10 +404,13 @@ ContextHandlerRef ShapeContext::onCreateContext( sal_Int32 nElement, const Attri ...@@ -404,10 +404,13 @@ ContextHandlerRef ShapeContext::onCreateContext( sal_Int32 nElement, const Attri
if( isRootElement() ) switch( nElement ) if( isRootElement() ) switch( nElement )
{ {
case VML_TOKEN( textbox ): case VML_TOKEN( textbox ):
// Custom shape in Writer with a textbox are transformed into a frame if (getParentElement() != VML_TOKEN( group ))
dynamic_cast<SimpleShape&>( mrShape ).setService( {
"com.sun.star.text.TextFrame"); // Custom shape in Writer with a textbox are transformed into a frame
return new TextBoxContext( *this, mrShapeModel.createTextBox(), rAttribs, dynamic_cast<SimpleShape&>( mrShape ).setService(
"com.sun.star.text.TextFrame");
}
return new TextBoxContext( *this, mrShapeModel.createTextBox(mrShape.getTypeModel()), rAttribs,
mrShape.getDrawing().getFilter().getGraphicHelper()); mrShape.getDrawing().getFilter().getGraphicHelper());
case VMLX_TOKEN( ClientData ): case VMLX_TOKEN( ClientData ):
return new ClientDataContext( *this, mrShapeModel.createClientData(), rAttribs ); return new ClientDataContext( *this, mrShapeModel.createClientData(), rAttribs );
......
...@@ -20,12 +20,15 @@ ...@@ -20,12 +20,15 @@
#include "oox/vml/vmltextbox.hxx" #include "oox/vml/vmltextbox.hxx"
#include <rtl/ustrbuf.hxx> #include <rtl/ustrbuf.hxx>
#include <com/sun/star/awt/FontWeight.hpp>
#include <com/sun/star/text/XTextAppend.hpp>
namespace oox { namespace oox {
namespace vml { namespace vml {
using ::rtl::OUString; using ::rtl::OUString;
using ::rtl::OUStringBuffer; using ::rtl::OUStringBuffer;
using namespace com::sun::star;
TextFontModel::TextFontModel() TextFontModel::TextFontModel()
{ {
...@@ -37,8 +40,9 @@ TextPortionModel::TextPortionModel( const TextFontModel& rFont, const OUString& ...@@ -37,8 +40,9 @@ TextPortionModel::TextPortionModel( const TextFontModel& rFont, const OUString&
{ {
} }
TextBox::TextBox() TextBox::TextBox(ShapeTypeModel& rTypeModel)
: borderDistanceSet( false ) : mrTypeModel(rTypeModel),
borderDistanceSet( false )
{ {
} }
...@@ -60,6 +64,34 @@ OUString TextBox::getText() const ...@@ -60,6 +64,34 @@ OUString TextBox::getText() const
return aBuffer.makeStringAndClear(); return aBuffer.makeStringAndClear();
} }
void TextBox::convert(uno::Reference<drawing::XShape> xShape) const
{
uno::Reference<text::XTextAppend> xTextAppend(xShape, uno::UNO_QUERY);
for (PortionVector::const_iterator aIt = maPortions.begin(), aEnd = maPortions.end(); aIt != aEnd; ++aIt)
{
beans::PropertyValue aPropertyValue;
std::vector<beans::PropertyValue> aPropVec;
const TextFontModel& rFont = aIt->maFont;
if (rFont.mobBold.has())
{
aPropertyValue.Name = "CharWeight";
aPropertyValue.Value = uno::makeAny(rFont.mobBold.get() ? awt::FontWeight::BOLD : awt::FontWeight::NORMAL);
aPropVec.push_back(aPropertyValue);
}
if (rFont.monSize.has())
{
aPropertyValue.Name = "CharHeight";
aPropertyValue.Value = uno::makeAny(double(rFont.monSize.get()) / 2.);
aPropVec.push_back(aPropertyValue);
}
uno::Sequence<beans::PropertyValue> aPropSeq(aPropVec.size());
beans::PropertyValue* pValues = aPropSeq.getArray();
for (std::vector<beans::PropertyValue>::iterator i = aPropVec.begin(); i != aPropVec.end(); ++i)
*pValues++ = *i;
xTextAppend->appendTextPortion(aIt->maText, aPropSeq);
}
}
} // namespace vml } // namespace vml
} // namespace oox } // namespace oox
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#include "oox/vml/vmlformatting.hxx" #include "oox/vml/vmlformatting.hxx"
#include "oox/vml/vmltextboxcontext.hxx" #include "oox/vml/vmltextboxcontext.hxx"
#include "oox/vml/vmlshape.hxx"
#include <com/sun/star/drawing/XShape.hpp>
namespace oox { namespace oox {
namespace vml { namespace vml {
...@@ -68,7 +70,22 @@ TextPortionContext::TextPortionContext( ContextHandler2Helper& rParent, ...@@ -68,7 +70,22 @@ TextPortionContext::TextPortionContext( ContextHandler2Helper& rParent,
OSL_ENSURE( !maFont.mobStrikeout, "TextPortionContext::TextPortionContext - nested <s> elements" ); OSL_ENSURE( !maFont.mobStrikeout, "TextPortionContext::TextPortionContext - nested <s> elements" );
maFont.mobStrikeout = true; maFont.mobStrikeout = true;
break; break;
case OOX_TOKEN(dml, blip):
{
OptValue<OUString> oRelId = rAttribs.getString(R_TOKEN(embed));
if (oRelId.has())
mrTextBox.mrTypeModel.moGraphicPath = getFragmentPathFromRelId(oRelId.get());
}
break;
case VML_TOKEN(imagedata):
{
OptValue<OUString> oRelId = rAttribs.getString(R_TOKEN(id));
if (oRelId.has())
mrTextBox.mrTypeModel.moGraphicPath = getFragmentPathFromRelId(oRelId.get());
}
break;
case XML_span: case XML_span:
case OOX_TOKEN(doc, r):
break; break;
default: default:
OSL_ENSURE( false, "TextPortionContext::TextPortionContext - unknown element" ); OSL_ENSURE( false, "TextPortionContext::TextPortionContext - unknown element" );
...@@ -78,11 +95,16 @@ TextPortionContext::TextPortionContext( ContextHandler2Helper& rParent, ...@@ -78,11 +95,16 @@ TextPortionContext::TextPortionContext( ContextHandler2Helper& rParent,
ContextHandlerRef TextPortionContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) ContextHandlerRef TextPortionContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
{ {
OSL_ENSURE( nElement != XML_font, "TextPortionContext::onCreateContext - nested <font> elements" ); OSL_ENSURE( nElement != XML_font, "TextPortionContext::onCreateContext - nested <font> elements" );
if (getNamespace(getCurrentElement()) == NMSP_doc)
return this;
return new TextPortionContext( *this, mrTextBox, maFont, nElement, rAttribs ); return new TextPortionContext( *this, mrTextBox, maFont, nElement, rAttribs );
} }
void TextPortionContext::onCharacters( const OUString& rChars ) void TextPortionContext::onCharacters( const OUString& rChars )
{ {
if (getNamespace(getCurrentElement()) == NMSP_doc && getCurrentElement() != OOX_TOKEN(doc, t))
return;
switch( getCurrentElement() ) switch( getCurrentElement() )
{ {
case XML_span: case XML_span:
...@@ -94,8 +116,24 @@ void TextPortionContext::onCharacters( const OUString& rChars ) ...@@ -94,8 +116,24 @@ void TextPortionContext::onCharacters( const OUString& rChars )
} }
} }
void TextPortionContext::onStartElement(const AttributeList& rAttribs)
{
switch (getCurrentElement())
{
case OOX_TOKEN(doc, b):
maFont.mobBold = true;
break;
case OOX_TOKEN(doc, sz):
maFont.monSize = rAttribs.getInteger( OOX_TOKEN(doc, val) );
break;
}
}
void TextPortionContext::onEndElement() void TextPortionContext::onEndElement()
{ {
if (getNamespace(getCurrentElement()) == NMSP_doc && getCurrentElement() != OOX_TOKEN(doc, t))
return;
/* A child element without own child elements may contain a single space /* A child element without own child elements may contain a single space
character, for example: character, for example:
...@@ -149,10 +187,17 @@ ContextHandlerRef TextBoxContext::onCreateContext( sal_Int32 nElement, const Att ...@@ -149,10 +187,17 @@ ContextHandlerRef TextBoxContext::onCreateContext( sal_Int32 nElement, const Att
{ {
case VML_TOKEN( textbox ): case VML_TOKEN( textbox ):
if( nElement == XML_div ) return this; if( nElement == XML_div ) return this;
else if (nElement == OOX_TOKEN(doc, txbxContent)) return this;
break; break;
case XML_div: case XML_div:
if( nElement == XML_font ) return new TextPortionContext( *this, mrTextBox, TextFontModel(), nElement, rAttribs ); if( nElement == XML_font ) return new TextPortionContext( *this, mrTextBox, TextFontModel(), nElement, rAttribs );
break; break;
case OOX_TOKEN(doc, txbxContent):
if (nElement == OOX_TOKEN(doc, p)) return this;
break;
case OOX_TOKEN(doc, p):
if (nElement == OOX_TOKEN(doc, r)) return new TextPortionContext( *this, mrTextBox, TextFontModel(), nElement, rAttribs );
break;
} }
return 0; return 0;
} }
......
...@@ -317,26 +317,28 @@ void Test::testFdo49940() ...@@ -317,26 +317,28 @@ void Test::testFdo49940()
void Test::testN751077() void Test::testN751077()
{ {
/* /*
enum = ThisComponent.Text.createEnumeration xray ThisComponent.DrawPage(1).getByIndex(0).String
enum.NextElement xray ThisComponent.DrawPage(1).getByIndex(0).Anchor.PageStyleName
para = enum.NextElement
xray para.String
xray para.PageStyleName
*/ */
uno::Reference<uno::XInterface> paragraph(getParagraph( 2, "TEXT1" )); uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
// we want to test the paragraph is on the first page (it was put onto another page without the fix), uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(xTextDocument, uno::UNO_QUERY);
uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
uno::Reference<drawing::XShapes> xShapes(xDrawPage->getByIndex(1), uno::UNO_QUERY);
uno::Reference<text::XTextRange> xShape(xShapes->getByIndex(0), uno::UNO_QUERY);
CPPUNIT_ASSERT_EQUAL(OUString("TEXT1"), xShape->getString());
// we want to test the textbox is on the first page (it was put onto another page without the fix),
// use a small trick and instead of checking the page layout, check the page style // use a small trick and instead of checking the page layout, check the page style
OUString pageStyle = getProperty< OUString >( paragraph, "PageStyleName" ); uno::Reference<text::XTextContent> xTextContent(xShape, uno::UNO_QUERY);
CPPUNIT_ASSERT_EQUAL( OUString( "First Page" ), pageStyle ); CPPUNIT_ASSERT_EQUAL(OUString("First Page"), getProperty<OUString>(xTextContent->getAnchor(), "PageStyleName"));
} }
void Test::testN705956_1() void Test::testN705956_1()
{ {
/* /*
Get the first image in the document and check it's the one image in the document. Get the first image in the document and check it's the one image in the document.
It should be also anchored inline (as character). It should be also anchored inline (as character) and be inside a groupshape.
image = ThisComponent.DrawPage.getByIndex(0) image = ThisComponent.DrawPage.getByIndex(0)
graphic = image.Graphic graphic = image(0).Graphic
xray graphic.Size xray graphic.Size
xray image.AnchorType xray image.AnchorType
*/ */
...@@ -344,8 +346,9 @@ xray image.AnchorType ...@@ -344,8 +346,9 @@ xray image.AnchorType
uno::Reference<drawing::XDrawPageSupplier> drawPageSupplier(textDocument, uno::UNO_QUERY); uno::Reference<drawing::XDrawPageSupplier> drawPageSupplier(textDocument, uno::UNO_QUERY);
uno::Reference<drawing::XDrawPage> drawPage = drawPageSupplier->getDrawPage(); uno::Reference<drawing::XDrawPage> drawPage = drawPageSupplier->getDrawPage();
CPPUNIT_ASSERT_EQUAL( sal_Int32( 1 ), drawPage->getCount()); CPPUNIT_ASSERT_EQUAL( sal_Int32( 1 ), drawPage->getCount());
uno::Reference<drawing::XShapes> shapes(drawPage->getByIndex(0), uno::UNO_QUERY);
uno::Reference<drawing::XShape> image; uno::Reference<drawing::XShape> image;
drawPage->getByIndex(0) >>= image; shapes->getByIndex(0) >>= image;
uno::Reference<beans::XPropertySet> imageProperties(image, uno::UNO_QUERY); uno::Reference<beans::XPropertySet> imageProperties(image, uno::UNO_QUERY);
uno::Reference<graphic::XGraphic> graphic; uno::Reference<graphic::XGraphic> graphic;
imageProperties->getPropertyValue( "Graphic" ) >>= graphic; imageProperties->getPropertyValue( "Graphic" ) >>= graphic;
......
...@@ -2073,6 +2073,7 @@ OOXMLFastContextHandlerShape::lcl_createFastChildContext ...@@ -2073,6 +2073,7 @@ OOXMLFastContextHandlerShape::lcl_createFastChildContext
{ {
uno::Reference< xml::sax::XFastContextHandler > xContextHandler; uno::Reference< xml::sax::XFastContextHandler > xContextHandler;
bool bGroupShape = Element == Token_t(NS_vml | OOXML_group);
sal_uInt32 nNamespace = Element & 0xffff0000; sal_uInt32 nNamespace = Element & 0xffff0000;
switch (nNamespace) switch (nNamespace)
...@@ -2080,26 +2081,33 @@ OOXMLFastContextHandlerShape::lcl_createFastChildContext ...@@ -2080,26 +2081,33 @@ OOXMLFastContextHandlerShape::lcl_createFastChildContext
case NS_wordprocessingml: case NS_wordprocessingml:
case NS_vml_wordprocessingDrawing: case NS_vml_wordprocessingDrawing:
case NS_office: case NS_office:
xContextHandler.set(OOXMLFactory::getInstance()->createFastChildContextFromStart(this, Element)); if (!bGroupShape)
break; xContextHandler.set(OOXMLFactory::getInstance()->createFastChildContextFromStart(this, Element));
// no break;
default: default:
if (mrShapeContext.is()) if (!xContextHandler.is())
{ {
uno::Reference<XFastContextHandler> pChildContext = if (mrShapeContext.is())
mrShapeContext->createFastChildContext(Element, Attribs); {
uno::Reference<XFastContextHandler> pChildContext =
OOXMLFastContextHandlerWrapper * pWrapper = mrShapeContext->createFastChildContext(Element, Attribs);
new OOXMLFastContextHandlerWrapper(this, pChildContext);
OOXMLFastContextHandlerWrapper * pWrapper =
pWrapper->addNamespace(NS_wordprocessingml); new OOXMLFastContextHandlerWrapper(this, pChildContext);
pWrapper->addNamespace(NS_vml_wordprocessingDrawing);
pWrapper->addNamespace(NS_office); if (!bGroupShape)
pWrapper->addToken( NS_vml|OOXML_textbox ); {
pWrapper->addNamespace(NS_wordprocessingml);
xContextHandler.set(pWrapper); pWrapper->addNamespace(NS_vml_wordprocessingDrawing);
pWrapper->addNamespace(NS_office);
pWrapper->addToken( NS_vml|OOXML_textbox );
}
xContextHandler.set(pWrapper);
}
else
xContextHandler.set(this);
} }
else
xContextHandler.set(this);
break; break;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment