1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
24 #include <comphelper/propertyvalue.hxx>
25 #include <osl/diagnose.h>
26 #include <osl/file.hxx>
27 #include <sfx2/bindings.hxx>
28 #include <sfx2/request.hxx>
29 #include <sfx2/docfilt.hxx>
30 #include <sfx2/fcontnr.hxx>
31 #include <sfx2/docfile.hxx>
32 #include <sfx2/sfxsids.hrc>
33 #include <vcl/outdev.hxx>
34 #include <vcl/pdfread.hxx>
35 #include <vcl/svapp.hxx>
36 #include <vcl/weld.hxx>
37 #include <svx/svdpagv.hxx>
38 #include <svx/xbtmpit.hxx>
39 #include <svx/svdundo.hxx>
40 #include <svx/xfillit0.hxx>
41 #include <svx/svdograf.hxx>
42 #include <svx/svdomedia.hxx>
43 #include <svx/svdoole2.hxx>
44 #include <svx/ImageMapInfo.hxx>
45 #include <sfx2/app.hxx>
46 #include <avmedia/mediawindow.hxx>
47 #include <svtools/ehdl.hxx>
48 #include <svtools/sfxecode.hxx>
49 #include <svtools/embedhlp.hxx>
50 #include <vcl/graphicfilter.hxx>
53 #include <DrawDocShell.hxx>
54 #include <DrawViewShell.hxx>
55 #include <fuinsfil.hxx>
56 #include <drawdoc.hxx>
57 #include <sdresid.hxx>
58 #include <strings.hrc>
60 #include <view/SlideSorterView.hxx>
61 #include <com/sun/star/embed/XEmbedPersist.hpp>
62 #include <com/sun/star/embed/Aspects.hpp>
63 #include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
64 #include <com/sun/star/embed/XEmbeddedObject.hpp>
65 #include <com/sun/star/media/XPlayer.hpp>
66 #include <svtools/soerr.hxx>
67 #include <sfx2/ipclient.hxx>
68 #include <tools/debug.hxx>
70 using namespace com::sun::star
;
75 * If an empty graphic object is provided, we fill it. Otherwise we fill an
76 * existing object at the specified position. If there is no object at the
77 * position, we create a new object and return a pointer to it.
79 SdrGrafObj
* View::InsertGraphic( const Graphic
& rGraphic
, sal_Int8
& rAction
,
80 const Point
& rPos
, SdrObject
* pObj
, ImageMap
const * pImageMap
)
85 // Is there an object at the position rPos?
86 rtl::Reference
<SdrGrafObj
> pNewGrafObj
;
87 SdrPageView
* pPV
= GetSdrPageView();
88 SdrObject
* pPickObj
= pObj
;
89 const bool bOnMaster
= pPV
&& pPV
->GetPage() && pPV
->GetPage()->IsMasterPage();
91 if(pPV
&& dynamic_cast< const ::sd::slidesorter::view::SlideSorterView
* >(this) != nullptr)
93 if(!pPV
->GetPageRect().Contains(rPos
))
97 if( !pPickObj
&& pPV
)
99 SdrPageView
* pPageView
= pPV
;
100 pPickObj
= PickObj(rPos
, getHitTolLog(), pPageView
);
103 const bool bIsGraphic(dynamic_cast< const SdrGrafObj
* >(pPickObj
) != nullptr);
105 if (DND_ACTION_LINK
== mnAction
108 && (bIsGraphic
|| (pPickObj
->IsEmptyPresObj() && !bOnMaster
))) // #121603# Do not use pObj, it may be NULL
110 // hit on SdrGrafObj with wanted new linked graphic (or PresObj placeholder hit)
111 if( IsUndoEnabled() )
112 BegUndo(SdResId(STR_INSERTGRAPHIC
));
114 SdPage
* pPage
= static_cast<SdPage
*>( pPickObj
->getSdrPageFromSdrObject() );
118 // We fill the object with the Bitmap
119 pNewGrafObj
= SdrObject::Clone(static_cast<SdrGrafObj
&>(*pPickObj
), pPickObj
->getSdrModelFromSdrObject());
120 pNewGrafObj
->SetGraphic(rGraphic
);
124 pNewGrafObj
= new SdrGrafObj(
125 getSdrModelFromSdrView(),
127 pPickObj
->GetLogicRect());
128 pNewGrafObj
->SetEmptyPresObj(true);
131 if ( pNewGrafObj
->IsEmptyPresObj() )
133 ::tools::Rectangle
aRect( pNewGrafObj
->GetLogicRect() );
134 pNewGrafObj
->AdjustToMaxRect( aRect
);
135 pNewGrafObj
->SetOutlinerParaObject(std::nullopt
);
136 pNewGrafObj
->SetEmptyPresObj(false);
139 if (pPage
&& pPage
->IsPresObj(pPickObj
))
141 // Insert new PresObj into the list
142 pPage
->InsertPresObj( pNewGrafObj
.get(), PresObjKind::Graphic
);
143 pNewGrafObj
->SetUserCall(pPickObj
->GetUserCall());
147 pNewGrafObj
->AppendUserData(std::unique_ptr
<SdrObjUserData
>(new SvxIMapInfo(*pImageMap
)));
149 ReplaceObjectAtView(pPickObj
, *pPV
, pNewGrafObj
.get()); // maybe ReplaceObjectAtView
151 if( IsUndoEnabled() )
154 else if (DND_ACTION_LINK
== mnAction
157 && pPickObj
->IsClosedObj()
158 && !dynamic_cast< const SdrOle2Obj
* >(pPickObj
))
160 // fill style change (fill object with graphic), independent of mnAction
161 // and thus of DND_ACTION_LINK or DND_ACTION_MOVE
162 if( IsUndoEnabled() )
164 BegUndo(SdResId(STR_UNDO_DRAGDROP
));
165 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoAttrObject(*pPickObj
));
169 SfxItemSetFixed
<XATTR_FILLSTYLE
, XATTR_FILLBITMAP
> aSet(mpDocSh
->GetPool());
171 aSet
.Put(XFillStyleItem(drawing::FillStyle_BITMAP
));
172 aSet
.Put(XFillBitmapItem(rGraphic
));
173 pPickObj
->SetMergedItemSetAndBroadcast(aSet
);
178 Size aSizePixel
= rGraphic
.GetSizePixel();
183 if ( rGraphic
.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel
)
185 ::OutputDevice
* pOutDev
= nullptr;
187 pOutDev
= mpViewSh
->GetActiveWindow()->GetOutDev();
190 pOutDev
= Application::GetDefaultDevice();
193 aSize
= pOutDev
->PixelToLogic(rGraphic
.GetPrefSize(), MapMode(MapUnit::Map100thMM
));
197 aSize
= OutputDevice::LogicToLogic( rGraphic
.GetPrefSize(),
198 rGraphic
.GetPrefMapMode(),
199 MapMode( MapUnit::Map100thMM
) );
202 sal_Int32 nPreferredDPI
= mrDoc
.getImagePreferredDPI();
204 if (rGraphic
.GetGfxLink().GetType() == GfxLinkType::NativePdf
&& nPreferredDPI
== 0 && vcl::PDF_INSERT_MAGIC_SCALE_FACTOR
> 1)
205 nPreferredDPI
= Application::GetDefaultDevice()->GetDPIX() * vcl::PDF_INSERT_MAGIC_SCALE_FACTOR
;
207 if (nPreferredDPI
> 0)
209 auto nWidth
= o3tl::convert(aSizePixel
.Width() / double(nPreferredDPI
), o3tl::Length::in
, o3tl::Length::mm100
);
210 auto nHeight
= o3tl::convert(aSizePixel
.Height() / double(nPreferredDPI
), o3tl::Length::in
, o3tl::Length::mm100
);
211 if (nWidth
> 0 && nHeight
> 0)
212 aSize
= Size(nWidth
, nHeight
);
215 pNewGrafObj
= new SdrGrafObj(getSdrModelFromSdrView(), rGraphic
, ::tools::Rectangle(rPos
, aSize
));
217 if (nPreferredDPI
> 0)
219 // move to the center of insertion point
220 pNewGrafObj
->NbcMove(Size(-aSize
.Width() / 2, -aSize
.Height() / 2));
224 SdrPage
* pPage
= pPV
->GetPage();
225 Size
aPageSize( pPage
->GetSize() );
226 aPageSize
.AdjustWidth( -(pPage
->GetLeftBorder() + pPage
->GetRightBorder()) );
227 aPageSize
.AdjustHeight( -(pPage
->GetUpperBorder() + pPage
->GetLowerBorder()) );
228 pNewGrafObj
->AdjustToMaxRect( ::tools::Rectangle( Point(), aPageSize
), true );
231 SdrInsertFlags nOptions
= SdrInsertFlags::SETDEFLAYER
;
232 bool bIsPresTarget
= false;
235 && mpViewSh
->GetViewShell()!=nullptr
236 && mpViewSh
->GetViewShell()->GetIPClient()
237 && mpViewSh
->GetViewShell()->GetIPClient()->IsObjectInPlaceActive())
238 || dynamic_cast<const ::sd::slidesorter::view::SlideSorterView
* >(this))
239 nOptions
|= SdrInsertFlags::DONTMARK
;
241 if( ( mnAction
& DND_ACTION_MOVE
) && pPickObj
&& (pPickObj
->IsEmptyPresObj() || pPickObj
->GetUserCall()) )
243 SdPage
* pP
= static_cast< SdPage
* >( pPickObj
->getSdrPageFromSdrObject() );
245 if ( pP
&& pP
->IsMasterPage() )
246 bIsPresTarget
= pP
->IsPresObj(pPickObj
);
249 if( ( mnAction
& DND_ACTION_MOVE
) && pPickObj
&& !bIsPresTarget
)
253 pNewGrafObj
->AppendUserData(std::unique_ptr
<SdrObjUserData
>(new SvxIMapInfo(*pImageMap
)));
255 ::tools::Rectangle
aPickObjRect(pPickObj
->GetCurrentBoundRect());
256 Size
aPickObjSize(aPickObjRect
.GetSize());
257 ::tools::Rectangle
aObjRect(pNewGrafObj
->GetCurrentBoundRect());
258 Size
aObjSize(aObjRect
.GetSize());
260 Fraction
aScaleWidth(aPickObjSize
.Width(), aObjSize
.Width());
261 Fraction
aScaleHeight(aPickObjSize
.Height(), aObjSize
.Height());
262 pNewGrafObj
->NbcResize(aObjRect
.TopLeft(), aScaleWidth
, aScaleHeight
);
264 Point aVec
= aPickObjRect
.TopLeft() - aObjRect
.TopLeft();
265 pNewGrafObj
->NbcMove(Size(aVec
.X(), aVec
.Y()));
267 const bool bUndo
= IsUndoEnabled();
270 BegUndo(SdResId(STR_UNDO_DRAGDROP
));
271 pNewGrafObj
->NbcSetLayer(pPickObj
->GetLayer());
272 SdrPage
* pP
= pPV
->GetPage();
273 pP
->InsertObject(pNewGrafObj
.get());
276 AddUndo(mrDoc
.GetSdrUndoFactory().CreateUndoNewObject(*pNewGrafObj
));
277 AddUndo(mrDoc
.GetSdrUndoFactory().CreateUndoDeleteObject(*pPickObj
));
279 pP
->RemoveObject(pPickObj
->GetOrdNum());
285 mnAction
= DND_ACTION_COPY
;
289 bool bSuccess
= InsertObjectAtView(pNewGrafObj
.get(), *pPV
, nOptions
);
291 pNewGrafObj
= nullptr;
293 pNewGrafObj
->AppendUserData(std::unique_ptr
<SdrObjUserData
>(new SvxIMapInfo(*pImageMap
)));
299 return pNewGrafObj
.get();
302 void View::InsertMediaURL( const OUString
& rMediaURL
, sal_Int8
& rAction
,
303 const Point
& rPos
, const Size
& rSize
,
313 uno::Reference
<frame::XModel
> const xModel(
314 GetDoc().GetObjectShell()->GetModel());
315 #if HAVE_FEATURE_AVMEDIA
316 bool const bRet
= ::avmedia::EmbedMedia(xModel
, rMediaURL
, realURL
);
317 if (!bRet
) { return; }
323 InsertMediaObj(realURL
, rAction
, rPos
, rSize
);
326 SdrMediaObj
* View::InsertMediaObj( const OUString
& rMediaURL
, sal_Int8
& rAction
,
327 const Point
& rPos
, const Size
& rSize
)
332 rtl::Reference
<SdrMediaObj
> pNewMediaObj
;
333 SdrPageView
* pPV
= GetSdrPageView();
334 SdrObject
* pPickObj
= GetEmptyPresentationObject( PresObjKind::Media
);
336 if(pPV
&& dynamic_cast<const ::sd::slidesorter::view::SlideSorterView
* >(this) )
338 if(!pPV
->GetPageRect().Contains(rPos
))
342 if( mnAction
== DND_ACTION_LINK
&& pPV
&& dynamic_cast< SdrMediaObj
*>( pPickObj
) )
344 pNewMediaObj
= SdrObject::Clone(static_cast<SdrMediaObj
&>(*pPickObj
), pPickObj
->getSdrModelFromSdrObject());
345 pNewMediaObj
->setURL(rMediaURL
, u
""_ustr
/*TODO?*/);
347 BegUndo(SdResId(STR_UNDO_DRAGDROP
));
348 ReplaceObjectAtView(pPickObj
, *pPV
, pNewMediaObj
.get());
353 ::tools::Rectangle
aRect( rPos
, rSize
);
354 SdrObjUserCall
* pUserCall
= nullptr;
357 aRect
= pPickObj
->GetLogicRect();
358 pUserCall
= pPickObj
->GetUserCall(); // ReplaceObjectAtView can free pPickObj
361 pNewMediaObj
= new SdrMediaObj(
362 getSdrModelFromSdrView(),
365 bool bIsPres
= false;
368 SdPage
* pPage
= static_cast< SdPage
* >(pPickObj
->getSdrPageFromSdrObject());
369 bIsPres
= pPage
&& pPage
->IsPresObj(pPickObj
);
372 pPage
->InsertPresObj( pNewMediaObj
.get(), PresObjKind::Media
);
377 ReplaceObjectAtView(pPickObj
, *pPV
, pNewMediaObj
.get());
380 if (!InsertObjectAtView(pNewMediaObj
.get(), *pPV
, SdrInsertFlags::SETDEFLAYER
))
381 pNewMediaObj
= nullptr;
385 DrawDocShell
* sh
= GetDocSh();
386 if (sh
!= nullptr && sh
->HasName()) {
387 referer
= sh
->GetMedium()->GetName();
392 pNewMediaObj
->setURL(rMediaURL
, referer
);
396 pNewMediaObj
->AdjustToMaxRect( aRect
);
398 pNewMediaObj
->SetUserCall( pUserCall
);
405 return pNewMediaObj
.get();
409 * Timer handler for InsertFile at Drop()
411 IMPL_LINK_NOARG(View
, DropInsertFileHdl
, Timer
*, void)
413 DBG_ASSERT( mpViewSh
, "sd::View::DropInsertFileHdl(), I need a view shell to work!" );
417 SfxErrorContext
aEc( ERRCTX_ERROR
, mpViewSh
->GetFrameWeld(), RID_SO_ERRCTX
);
418 ErrCode nError
= ERRCODE_NONE
;
420 ::std::vector
< OUString
>::const_iterator
aIter( maDropFileVector
.begin() );
422 while( (aIter
!= maDropFileVector
.end()) && !nError
)
424 OUString
aCurrentDropFile( *aIter
);
425 INetURLObject
aURL( aCurrentDropFile
);
426 bool bHandled
= false;
428 if( aURL
.GetProtocol() == INetProtocol::NotValid
)
431 osl::FileBase::getFileURLFromSystemPath( aCurrentDropFile
, aURLStr
);
432 aURL
= INetURLObject( aURLStr
);
435 GraphicFilter
& rGraphicFilter
= GraphicFilter::GetGraphicFilter();
438 aCurrentDropFile
= aURL
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
440 #if HAVE_FEATURE_AVMEDIA
441 if( !::avmedia::MediaWindow::isMediaURL( aCurrentDropFile
, u
""_ustr
/*TODO?*/ ) )
445 if( !rGraphicFilter
.ImportGraphic( aGraphic
, aURL
) )
447 sal_Int8 nTempAction
= ( aIter
== maDropFileVector
.begin() ) ? mnAction
: 0;
448 const bool bLink
= ( ( nTempAction
& DND_ACTION_LINK
) != 0 );
449 SdrGrafObj
* pGrafObj
= InsertGraphic( aGraphic
, nTempAction
, maDropPos
, nullptr, nullptr );
450 if(pGrafObj
&& bLink
)
452 pGrafObj
->SetGraphicLink( aCurrentDropFile
);
455 // return action from first inserted graphic
456 if( aIter
== maDropFileVector
.begin() )
457 mnAction
= nTempAction
;
463 std::shared_ptr
<const SfxFilter
> pFoundFilter
;
464 SfxMedium
aSfxMedium( aCurrentDropFile
, StreamMode::READ
| StreamMode::SHARE_DENYNONE
);
465 ErrCode nErr
= SfxGetpApp()->GetFilterMatcher().GuessFilter( aSfxMedium
, pFoundFilter
);
467 if( pFoundFilter
&& !nErr
)
469 ::std::vector
< OUString
> aFilterVector
;
470 OUString aFilterName
= pFoundFilter
->GetFilterName();
471 OUString aLowerAsciiFileName
= aCurrentDropFile
.toAsciiLowerCase();
473 FuInsertFile::GetSupportedFilterVector( aFilterVector
);
475 if( ( ::std::find( aFilterVector
.begin(), aFilterVector
.end(), pFoundFilter
->GetMimeType() ) != aFilterVector
.end() ) ||
476 aFilterName
.indexOf( "Text" ) != -1 ||
477 aFilterName
.indexOf( "Rich" ) != -1 ||
478 aFilterName
.indexOf( "RTF" ) != -1 ||
479 aFilterName
.indexOf( "HTML" ) != -1 ||
480 aLowerAsciiFileName
.indexOf(".sdd") != -1 ||
481 aLowerAsciiFileName
.indexOf(".sda") != -1 ||
482 aLowerAsciiFileName
.indexOf(".sxd") != -1 ||
483 aLowerAsciiFileName
.indexOf(".sxi") != -1 ||
484 aLowerAsciiFileName
.indexOf(".std") != -1 ||
485 aLowerAsciiFileName
.indexOf(".sti") != -1 )
487 ::sd::Window
* pWin
= mpViewSh
->GetActiveWindow();
488 SfxRequest
aReq(SID_INSERTFILE
, ::SfxCallMode::SLOT
, mrDoc
.GetItemPool());
489 SfxStringItem
aItem1( ID_VAL_DUMMY0
, aCurrentDropFile
), aItem2( ID_VAL_DUMMY1
, pFoundFilter
->GetFilterName() );
491 aReq
.AppendItem( aItem1
);
492 aReq
.AppendItem( aItem2
);
493 FuInsertFile::Create( mpViewSh
, pWin
, this, &mrDoc
, aReq
);
500 #if HAVE_FEATURE_AVMEDIA
503 bool bShallowDetect
= ::avmedia::MediaWindow::isMediaURL(aCurrentDropFile
, u
""_ustr
/*TODO?*/);
506 mxDropMediaSizeListener
.set(new avmedia::PlayerListener(
507 [this, aCurrentDropFile
](const css::uno::Reference
<css::media::XPlayer
>& rPlayer
){
510 css::awt::Size aSize
= rPlayer
->getPreferredPlayerWindowSize();
511 Size
aPrefSize(aSize
.Width
, aSize
.Height
);
513 if (aPrefSize
.Width() && aPrefSize
.Height())
515 ::sd::Window
* pWin
= mpViewSh
->GetActiveWindow();
518 aPrefSize
= pWin
->PixelToLogic(aPrefSize
, MapMode(MapUnit::Map100thMM
));
520 aPrefSize
= Application::GetDefaultDevice()->PixelToLogic(aPrefSize
, MapMode(MapUnit::Map100thMM
));
523 aPrefSize
= Size( 5000, 5000 );
525 InsertMediaURL(aCurrentDropFile
, mnAction
, maDropPos
, aPrefSize
, true);
527 mxDropMediaSizeListener
.clear();
530 bHandled
= bShallowDetect
&& ::avmedia::MediaWindow::isMediaURL(aCurrentDropFile
, u
""_ustr
/*TODO?*/, true, mxDropMediaSizeListener
);
536 if( mnAction
& DND_ACTION_LINK
)
537 static_cast< DrawViewShell
* >( mpViewSh
)->InsertURLButton( aCurrentDropFile
, aCurrentDropFile
, OUString(), &maDropPos
);
546 uno::Sequence
< beans::PropertyValue
> aMedium
{ comphelper::makePropertyValue(
547 u
"URL"_ustr
, aCurrentDropFile
) };
549 uno::Reference
< embed::XEmbeddedObject
> xObj
= mpDocSh
->GetEmbeddedObjectContainer().
550 InsertEmbeddedObject( aMedium
, aName
);
552 uno::Reference
< embed::XEmbedPersist
> xPersist( xObj
, uno::UNO_QUERY
);
555 // TODO/LEAN: VisualArea access can switch the object to running state
556 sal_Int64 nAspect
= embed::Aspects::MSOLE_CONTENT
;
558 xPersist
->storeOwn();
563 aSz
= xObj
->getVisualAreaSize( nAspect
);
565 catch( embed::NoVisualAreaSizeException
& )
567 // the default size will be set later
570 Size
aSize( aSz
.Width
, aSz
.Height
);
571 ::tools::Rectangle aRect
;
573 if (!aSize
.Width() || !aSize
.Height())
575 aSize
.setWidth( 1410 );
576 aSize
.setHeight( 1000 );
579 aRect
= ::tools::Rectangle( maDropPos
, aSize
);
581 rtl::Reference
<SdrOle2Obj
> pOleObj
= new SdrOle2Obj(
582 getSdrModelFromSdrView(),
583 svt::EmbeddedObjectRef(xObj
, nAspect
),
586 SdrInsertFlags nOptions
= SdrInsertFlags::SETDEFLAYER
;
588 if (mpViewSh
!= nullptr)
590 OSL_ASSERT (mpViewSh
->GetViewShell()!=nullptr);
591 SfxInPlaceClient
* pIpClient
=
592 mpViewSh
->GetViewShell()->GetIPClient();
593 if (pIpClient
!=nullptr && pIpClient
->IsObjectInPlaceActive())
594 nOptions
|= SdrInsertFlags::DONTMARK
;
597 if (InsertObjectAtView( pOleObj
.get(), *GetSdrPageView(), nOptions
))
598 pOleObj
->SetLogicRect( aRect
);
599 aSz
.Width
= aRect
.GetWidth();
600 aSz
.Height
= aRect
.GetHeight();
601 xObj
->setVisualAreaSize( nAspect
,aSz
);
604 catch( uno::Exception
& )
606 nError
= ERRCODE_IO_GENERAL
;
607 // TODO/LATER: better error handling
617 ErrorHandler::HandleError( nError
);
621 * Timer handler for Errorhandling at Drop()
623 IMPL_LINK_NOARG(View
, DropErrorHdl
, Timer
*, void)
625 vcl::Window
* pWin
= mpViewSh
? mpViewSh
->GetActiveWindow() : nullptr;
626 std::unique_ptr
<weld::MessageDialog
> xInfoBox(Application::CreateMessageDialog(pWin
? pWin
->GetFrameWeld() : nullptr,
627 VclMessageType::Info
, VclButtonsType::Ok
,
628 SdResId(STR_ACTION_NOTPOSSIBLE
)));
633 * @returns StyleSheet from selection
635 SfxStyleSheet
* View::GetStyleSheet() const
637 return SdrView::GetStyleSheet();
640 } // end of namespace sd
642 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */