1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "comphelper/anytostring.hxx"
29 #include "cppuhelper/exc_hlp.hxx"
30 
31 #include <com/sun/star/drawing/XMasterPagesSupplier.hpp>
32 #include <com/sun/star/drawing/XDrawPages.hpp>
33 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
34 #include <com/sun/star/drawing/XMasterPageTarget.hpp>
35 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
36 #include <com/sun/star/style/XStyle.hpp>
37 #include <com/sun/star/presentation/XPresentationPage.hpp>
38 #include <com/sun/star/task/XStatusIndicator.hpp>
39 
40 #include "oox/drawingml/theme.hxx"
41 #include "oox/drawingml/drawingmltypes.hxx"
42 #include "oox/drawingml/themefragmenthandler.hxx"
43 #include "oox/drawingml/textliststylecontext.hxx"
44 #include "oox/ppt/pptshape.hxx"
45 #include "oox/ppt/presentationfragmenthandler.hxx"
46 #include "oox/ppt/slidefragmenthandler.hxx"
47 #include "oox/ppt/layoutfragmenthandler.hxx"
48 #include "oox/ppt/pptimport.hxx"
49 
50 using rtl::OUString;
51 using namespace ::com::sun::star;
52 using namespace ::oox::core;
53 using namespace ::oox::drawingml;
54 using namespace ::com::sun::star::uno;
55 using namespace ::com::sun::star::beans;
56 using namespace ::com::sun::star::drawing;
57 using namespace ::com::sun::star::presentation;
58 using namespace ::com::sun::star::xml::sax;
59 
60 namespace oox { namespace ppt {
61 
62 PresentationFragmentHandler::PresentationFragmentHandler( XmlFilterBase& rFilter, const OUString& rFragmentPath ) throw()
63 : FragmentHandler( rFilter, rFragmentPath )
64 , mpTextListStyle( new TextListStyle )
65 {
66 	TextParagraphPropertiesVector& rParagraphDefaulsVector( mpTextListStyle->getListStyle() );
67 	TextParagraphPropertiesVector::iterator aParagraphDefaultIter( rParagraphDefaulsVector.begin() );
68 	while( aParagraphDefaultIter != rParagraphDefaulsVector.end() )
69 	{
70 		// ppt is having zero bottom margin per default, whereas OOo is 0,5cm,
71 		// so this attribute needs to be set always
72 		(*aParagraphDefaultIter++)->getParaBottomMargin() = TextSpacing( 0 );
73 	}
74 }
75 
76 PresentationFragmentHandler::~PresentationFragmentHandler() throw()
77 {
78 
79 }
80 void PresentationFragmentHandler::startDocument() throw (SAXException, RuntimeException)
81 {
82 }
83 
84 void ResolveTextFields( XmlFilterBase& rFilter )
85 {
86 	const oox::core::TextFieldStack& rTextFields = rFilter.getTextFieldStack();
87 	if ( rTextFields.size() )
88 	{
89 		Reference< frame::XModel > xModel( rFilter.getModel() );
90 		oox::core::TextFieldStack::const_iterator aIter( rTextFields.begin() );
91 		while( aIter != rTextFields.end() )
92 		{
93 	        const OUString sURL = CREATE_OUSTRING( "URL" );
94 			Reference< drawing::XDrawPagesSupplier > xDPS( xModel, uno::UNO_QUERY_THROW );
95 			Reference< drawing::XDrawPages > xDrawPages( xDPS->getDrawPages(), uno::UNO_QUERY_THROW );
96 
97 			const oox::core::TextField& rTextField( *aIter++ );
98 			Reference< XPropertySet > xPropSet( rTextField.xTextField, UNO_QUERY );
99 	        Reference< XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
100 			if ( xPropSetInfo->hasPropertyByName( sURL ) )
101 			{
102 				rtl::OUString aURL;
103 				if ( xPropSet->getPropertyValue( sURL ) >>= aURL )
104 				{
105 					const OUString sSlide = CREATE_OUSTRING( "#Slide " );
106 					const OUString sNotes = CREATE_OUSTRING( "#Notes " );
107 					sal_Bool bNotes = sal_False;
108 					sal_Int32 nPageNumber = 0;
109 					if ( aURL.match( sSlide ) )
110 						nPageNumber = aURL.copy( sSlide.getLength() ).toInt32();
111 					else if ( aURL.match( sNotes ) )
112 					{
113 						nPageNumber = aURL.copy( sNotes.getLength() ).toInt32();
114 						bNotes = sal_True;
115 					}
116 					if ( nPageNumber )
117 					{
118 						try
119 						{
120 							Reference< XDrawPage > xDrawPage;
121 							xDrawPages->getByIndex( nPageNumber - 1 ) >>= xDrawPage;
122 							if ( bNotes )
123 							{
124 								Reference< ::com::sun::star::presentation::XPresentationPage > xPresentationPage( xDrawPage, UNO_QUERY_THROW );
125 					            xDrawPage = xPresentationPage->getNotesPage();
126 							}
127 							Reference< container::XNamed > xNamed( xDrawPage, UNO_QUERY_THROW );
128 							aURL = CREATE_OUSTRING( "#" ).concat( xNamed->getName() );
129 							xPropSet->setPropertyValue( sURL, Any( aURL ) );
130 							Reference< text::XTextContent > xContent( rTextField.xTextField, UNO_QUERY);
131 							Reference< text::XTextRange > xTextRange( rTextField.xTextCursor, UNO_QUERY );
132 							rTextField.xText->insertTextContent( xTextRange, xContent, sal_True );
133 						}
134 						catch( uno::Exception& )
135 						{
136 						}
137 					}
138 				}
139 			}
140 		}
141 	}
142 }
143 
144 void PresentationFragmentHandler::endDocument() throw (SAXException, RuntimeException)
145 {
146 	// todo: localized progress bar text
147 	const Reference< task::XStatusIndicator >& rxStatusIndicator( getFilter().getStatusIndicator() );
148 	if ( rxStatusIndicator.is() )
149 		rxStatusIndicator->start( rtl::OUString(), 10000 );
150 
151 	try
152 	{
153         PowerPointImport& rFilter = dynamic_cast< PowerPointImport& >( getFilter() );
154 
155         Reference< frame::XModel > xModel( rFilter.getModel() );
156 		Reference< drawing::XDrawPage > xSlide;
157 		sal_uInt32 nSlide;
158 
159 		// importing slide pages and its corresponding notes page
160 		Reference< drawing::XDrawPagesSupplier > xDPS( xModel, uno::UNO_QUERY_THROW );
161 		Reference< drawing::XDrawPages > xDrawPages( xDPS->getDrawPages(), uno::UNO_QUERY_THROW );
162 
163 		for( nSlide = 0; nSlide < maSlidesVector.size(); nSlide++ )
164 		{
165 			if ( rxStatusIndicator.is() )
166 				rxStatusIndicator->setValue( ( nSlide * 10000 ) / maSlidesVector.size() );
167 
168 			if( nSlide == 0 )
169 				xDrawPages->getByIndex( 0 ) >>= xSlide;
170 			else
171 				xSlide = xDrawPages->insertNewByIndex( nSlide );
172 
173             OUString aSlideFragmentPath = getFragmentPathFromRelId( maSlidesVector[ nSlide ] );
174             if( aSlideFragmentPath.getLength() > 0 )
175 			{
176 				rtl::OUString aMasterFragmentPath;
177 				SlidePersistPtr pMasterPersistPtr;
178                 SlidePersistPtr pSlidePersistPtr( new SlidePersist( rFilter, sal_False, sal_False, xSlide,
179 									ShapePtr( new PPTShape( Slide, "com.sun.star.drawing.GroupShape" ) ), mpTextListStyle ) );
180 
181                 FragmentHandlerRef xSlideFragmentHandler( new SlideFragmentHandler( rFilter, aSlideFragmentPath, pSlidePersistPtr, Slide ) );
182 
183 				// importing the corresponding masterpage/layout
184                 OUString aLayoutFragmentPath = xSlideFragmentHandler->getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "slideLayout" ) );
185                 if ( aLayoutFragmentPath.getLength() > 0 )
186 				{
187 					// importing layout
188                     RelationsRef xLayoutRelations = rFilter.importRelations( aLayoutFragmentPath );
189                     aMasterFragmentPath = xLayoutRelations->getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "slideMaster" ) );
190                     if( aMasterFragmentPath.getLength() )
191                     {
192                         // check if the corresponding masterpage+layout has already been imported
193                         std::vector< SlidePersistPtr >& rMasterPages( rFilter.getMasterPages() );
194                         std::vector< SlidePersistPtr >::iterator aIter( rMasterPages.begin() );
195                         while( aIter != rMasterPages.end() )
196                         {
197                             if ( ( (*aIter)->getPath() == aMasterFragmentPath ) && ( (*aIter)->getLayoutPath() == aLayoutFragmentPath ) )
198                             {
199                                 pMasterPersistPtr = *aIter;
200                                 break;
201                             }
202                             aIter++;
203                         }
204 					}
205 				}
206 
207                 if ( !pMasterPersistPtr.get() )
208                 {   // masterpersist not found, we have to load it
209                     Reference< drawing::XDrawPage > xMasterPage;
210                     Reference< drawing::XMasterPagesSupplier > xMPS( xModel, uno::UNO_QUERY_THROW );
211                     Reference< drawing::XDrawPages > xMasterPages( xMPS->getMasterPages(), uno::UNO_QUERY_THROW );
212 
213                     if( !(rFilter.getMasterPages().size() ))
214                         xMasterPages->getByIndex( 0 ) >>= xMasterPage;
215                     else
216                         xMasterPage = xMasterPages->insertNewByIndex( xMasterPages->getCount() );
217 
218                     pMasterPersistPtr = SlidePersistPtr( new SlidePersist( rFilter, sal_True, sal_False, xMasterPage,
219                         ShapePtr( new PPTShape( Master, "com.sun.star.drawing.GroupShape" ) ), mpTextListStyle ) );
220                     pMasterPersistPtr->setLayoutPath( aLayoutFragmentPath );
221                     rFilter.getMasterPages().push_back( pMasterPersistPtr );
222                     rFilter.setActualSlidePersist( pMasterPersistPtr );
223 
224                     FragmentHandlerRef xMasterFragmentHandler( new SlideFragmentHandler( rFilter, aMasterFragmentPath, pMasterPersistPtr, Master ) );
225 
226                     // set the correct theme
227                     OUString aThemeFragmentPath = xMasterFragmentHandler->getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "theme" ) );
228                     if( aThemeFragmentPath.getLength() > 0 )
229                     {
230                         std::map< OUString, oox::drawingml::ThemePtr >& rThemes( rFilter.getThemes() );
231                         std::map< OUString, oox::drawingml::ThemePtr >::iterator aIter2( rThemes.find( aThemeFragmentPath ) );
232                         if( aIter2 == rThemes.end() )
233                         {
234                             oox::drawingml::ThemePtr pThemePtr( new oox::drawingml::Theme() );
235                             pMasterPersistPtr->setTheme( pThemePtr );
236                             rFilter.importFragment( new ThemeFragmentHandler( rFilter, aThemeFragmentPath, *pThemePtr ) );
237                             rThemes[ aThemeFragmentPath ] = pThemePtr;
238                         }
239                         else
240                         {
241                             pMasterPersistPtr->setTheme( (*aIter2).second );
242                         }
243                     }
244                     importSlide( xMasterFragmentHandler, pMasterPersistPtr );
245                     rFilter.importFragment( new LayoutFragmentHandler( rFilter, aLayoutFragmentPath, pMasterPersistPtr ) );
246                     pMasterPersistPtr->createBackground( rFilter );
247                     pMasterPersistPtr->createXShapes( rFilter );
248                 }
249 
250 				// importing slide page
251 				pSlidePersistPtr->setMasterPersist( pMasterPersistPtr );
252 				pSlidePersistPtr->setTheme( pMasterPersistPtr->getTheme() );
253 				Reference< drawing::XMasterPageTarget > xMasterPageTarget( pSlidePersistPtr->getPage(), UNO_QUERY );
254 				if( xMasterPageTarget.is() )
255 					xMasterPageTarget->setMasterPage( pMasterPersistPtr->getPage() );
256                 rFilter.getDrawPages().push_back( pSlidePersistPtr );
257                 rFilter.setActualSlidePersist( pSlidePersistPtr );
258                 importSlide( xSlideFragmentHandler, pSlidePersistPtr );
259                 pSlidePersistPtr->createBackground( rFilter );
260                 pSlidePersistPtr->createXShapes( rFilter );
261 
262 				// now importing the notes page
263                 OUString aNotesFragmentPath = xSlideFragmentHandler->getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "notesSlide" ) );
264                 if( aNotesFragmentPath.getLength() > 0 )
265                 {
266 					Reference< XPresentationPage > xPresentationPage( xSlide, UNO_QUERY );
267 					if ( xPresentationPage.is() )
268 					{
269 						Reference< XDrawPage > xNotesPage( xPresentationPage->getNotesPage() );
270 						if ( xNotesPage.is() )
271 						{
272                             SlidePersistPtr pNotesPersistPtr( new SlidePersist( rFilter, sal_False, sal_True, xNotesPage,
273 								ShapePtr( new PPTShape( Slide, "com.sun.star.drawing.GroupShape" ) ), mpTextListStyle ) );
274                             FragmentHandlerRef xNotesFragmentHandler( new SlideFragmentHandler( getFilter(), aNotesFragmentPath, pNotesPersistPtr, Slide ) );
275                             rFilter.getNotesPages().push_back( pNotesPersistPtr );
276                             rFilter.setActualSlidePersist( pNotesPersistPtr );
277                             importSlide( xNotesFragmentHandler, pNotesPersistPtr );
278                             pNotesPersistPtr->createBackground( rFilter );
279                             pNotesPersistPtr->createXShapes( rFilter );
280 						}
281 					}
282 				}
283 			}
284 		}
285 		ResolveTextFields( rFilter );
286 	}
287 	catch( uno::Exception& )
288 	{
289         OSL_ENSURE( false,
290 			(rtl::OString("oox::ppt::PresentationFragmentHandler::EndDocument(), "
291 					"exception caught: ") +
292 			rtl::OUStringToOString(
293 				comphelper::anyToString( cppu::getCaughtException() ),
294 				RTL_TEXTENCODING_UTF8 )).getStr() );
295 
296 	}
297 
298 	// todo	error handling;
299 	if ( rxStatusIndicator.is() )
300 		rxStatusIndicator->end();
301 }
302 
303 // CT_Presentation
304 Reference< XFastContextHandler > PresentationFragmentHandler::createFastChildContext( sal_Int32 aElementToken, const Reference< XFastAttributeList >& xAttribs ) throw (SAXException, RuntimeException)
305 {
306 	Reference< XFastContextHandler > xRet;
307 	switch( aElementToken )
308 	{
309 	case PPT_TOKEN( presentation ):
310 	case PPT_TOKEN( sldMasterIdLst ):
311 	case PPT_TOKEN( notesMasterIdLst ):
312 	case PPT_TOKEN( sldIdLst ):
313 		break;
314 	case PPT_TOKEN( sldMasterId ):
315 		maSlideMasterVector.push_back( xAttribs->getOptionalValue( R_TOKEN( id ) ) );
316 		break;
317 	case PPT_TOKEN( sldId ):
318 		maSlidesVector.push_back( xAttribs->getOptionalValue( R_TOKEN( id ) ) );
319 		break;
320 	case PPT_TOKEN( notesMasterId ):
321 		maNotesMasterVector.push_back( xAttribs->getOptionalValue(R_TOKEN( id ) ) );
322 		break;
323 	case PPT_TOKEN( sldSz ):
324 		maSlideSize = GetSize2D( xAttribs );
325 		break;
326 	case PPT_TOKEN( notesSz ):
327 		maNotesSize = GetSize2D( xAttribs );
328 		break;
329 	case PPT_TOKEN( custShowLst ):
330         xRet.set( new CustomShowListContext( *this, maCustomShowList ) );
331 		break;
332 	case PPT_TOKEN( defaultTextStyle ):
333         xRet.set( new TextListStyleContext( *this, *mpTextListStyle ) );
334 		break;
335 	}
336 	if ( !xRet.is() )
337         xRet = getFastContextHandler();
338 	return xRet;
339 }
340 
341 bool PresentationFragmentHandler::importSlide( const FragmentHandlerRef& rxSlideFragmentHandler,
342         const SlidePersistPtr pSlidePersistPtr )
343 {
344 	Reference< drawing::XDrawPage > xSlide( pSlidePersistPtr->getPage() );
345 	SlidePersistPtr pMasterPersistPtr( pSlidePersistPtr->getMasterPersist() );
346 	if ( pMasterPersistPtr.get() )
347 	{
348         const OUString sLayout = CREATE_OUSTRING( "Layout" );
349 		uno::Reference< beans::XPropertySet > xSet( xSlide, uno::UNO_QUERY_THROW );
350 		xSet->setPropertyValue(	sLayout, Any( pMasterPersistPtr->getLayoutFromValueToken() ) );
351 	}
352 	while( xSlide->getCount() )
353 	{
354 		Reference< drawing::XShape > xShape;
355 		xSlide->getByIndex(0) >>= xShape;
356 		xSlide->remove( xShape );
357 	}
358 
359 	Reference< XPropertySet > xPropertySet( xSlide, UNO_QUERY );
360 	if ( xPropertySet.is() )
361 	{
362         static const OUString sWidth = CREATE_OUSTRING( "Width" );
363         static const OUString sHeight = CREATE_OUSTRING( "Height" );
364 		awt::Size& rPageSize( pSlidePersistPtr->isNotesPage() ? maNotesSize : maSlideSize );
365 		xPropertySet->setPropertyValue( sWidth, Any( rPageSize.Width ) );
366 		xPropertySet->setPropertyValue( sHeight, Any( rPageSize.Height ) );
367 
368 		oox::ppt::HeaderFooter aHeaderFooter( pSlidePersistPtr->getHeaderFooter() );
369 		if ( !pSlidePersistPtr->isMasterPage() )
370 			aHeaderFooter.mbSlideNumber = aHeaderFooter.mbHeader = aHeaderFooter.mbFooter = aHeaderFooter.mbDateTime = sal_False;
371 		try
372 		{
373 			static const OUString sIsHeaderVisible = CREATE_OUSTRING( "IsHeaderVisible" );
374 			static const OUString sIsFooterVisible = CREATE_OUSTRING( "IsFooterVisible" );
375 			static const OUString sIsDateTimeVisible = CREATE_OUSTRING( "IsDateTimeVisible" );
376 			static const OUString sIsPageNumberVisible = CREATE_OUSTRING( "IsPageNumberVisible" );
377 
378 			if ( pSlidePersistPtr->isNotesPage() )
379 				xPropertySet->setPropertyValue( sIsHeaderVisible, Any( aHeaderFooter.mbHeader ) );
380 			xPropertySet->setPropertyValue( sIsFooterVisible, Any( aHeaderFooter.mbFooter ) );
381 			xPropertySet->setPropertyValue( sIsDateTimeVisible, Any( aHeaderFooter.mbDateTime ) );
382 			xPropertySet->setPropertyValue( sIsPageNumberVisible, Any( aHeaderFooter.mbSlideNumber ) );
383 		}
384 		catch( uno::Exception& )
385 		{
386 		}
387 	}
388     pSlidePersistPtr->setPath( rxSlideFragmentHandler->getFragmentPath() );
389     return getFilter().importFragment( rxSlideFragmentHandler );
390 }
391 
392 } }
393 
394