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 <com/sun/star/embed/Aspects.hpp>
21 #include <com/sun/star/frame/TaskCreator.hpp>
22 #include <com/sun/star/frame/XTitle.hpp>
23 #include <com/sun/star/frame/TerminationVetoException.hpp>
24 #include <com/sun/star/frame/XComponentLoader.hpp>
25 #include <com/sun/star/frame/XSynchronousFrameLoader.hpp>
26 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
27 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
28 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
29 #include <com/sun/star/util/XCloseBroadcaster.hpp>
30 #include <com/sun/star/util/XCloseable.hpp>
31 #include <com/sun/star/container/XNameAccess.hpp>
32 #include <com/sun/star/lang/XServiceInfo.hpp>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/beans/NamedValue.hpp>
35 #include <com/sun/star/frame/XModel.hpp>
36 #include <com/sun/star/frame/Desktop.hpp>
37 #include <com/sun/star/frame/XFramesSupplier.hpp>
38 #include <com/sun/star/frame/XDispatchHelper.hpp>
39 #include <com/sun/star/frame/FrameSearchFlag.hpp>
40 #include <com/sun/star/frame/XControllerBorder.hpp>
41 #include <com/sun/star/util/XModifyBroadcaster.hpp>
42 #include <com/sun/star/frame/XDispatchProviderInterception.hpp>
43 #include <com/sun/star/awt/Toolkit.hpp>
44 #include <com/sun/star/awt/XTopWindow.hpp>
45 #include <com/sun/star/awt/PosSize.hpp>
46 #include <com/sun/star/awt/XView.hpp>
47 #include <com/sun/star/awt/WindowAttribute.hpp>
48 #include <com/sun/star/awt/VclWindowPeerAttribute.hpp>
49 #include <com/sun/star/bridge/XBridgeSupplier2.hpp>
50 #include <com/sun/star/bridge/ModelDependent.hpp>
51 #include <com/sun/star/embed/XHatchWindow.hpp>
52 #include <com/sun/star/embed/HatchWindowFactory.hpp>
53 #include <com/sun/star/embed/XInplaceClient.hpp>
54 #include <com/sun/star/frame/XLayoutManager.hpp>
55 #include <com/sun/star/frame/XMenuBarMergingAcceptor.hpp>
56 #include <com/sun/star/frame/ModuleManager.hpp>
57 #include <com/sun/star/ui/XDockingAreaAcceptor.hpp>
58 #include <com/sun/star/ui/XUIElementSettings.hpp>
59 #include <com/sun/star/ui/XUIConfigurationManager.hpp>
60 #include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
61 #include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
62 #include <com/sun/star/embed/StateChangeInProgressException.hpp>
64 #include <com/sun/star/embed/EmbedMisc.hpp>
65 #include <com/sun/star/embed/EmbedStates.hpp>
66 #include <osl/diagnose.h>
67 #include <rtl/process.h>
68 #include <vcl/svapp.hxx>
69 #include <svtools/embedhlp.hxx>
70 #include <tools/resmgr.hxx>
71 #include <vcl/settings.hxx>
72 #include <sfx2/sfx.hrc>
74 #include <comphelper/processfactory.hxx>
75 #include <comphelper/namedvaluecollection.hxx>
77 #include "docholder.hxx"
78 #include "commonembobj.hxx"
79 #include "intercept.hxx"
81 #define HATCH_BORDER_WIDTH (((m_pEmbedObj->getStatus(embed::Aspects::MSOLE_CONTENT)&embed::EmbedMisc::MS_EMBED_ACTIVATEWHENVISIBLE) && \
82 m_pEmbedObj->getCurrentState()!=embed::EmbedStates::UI_ACTIVE) ? 0 : 4 )
84 using namespace ::com::sun::star
;
90 explicit IntCounterGuard(sal_Int32
& rFlag
)
103 static void InsertMenu_Impl( const uno::Reference
< container::XIndexContainer
>& xTargetMenu
,
104 sal_Int32 nTargetIndex
,
105 const uno::Reference
< container::XIndexAccess
>& xSourceMenu
,
106 sal_Int32 nSourceIndex
,
107 const OUString
& aContModuleName
,
108 const uno::Reference
< frame::XDispatchProvider
>& xSourceDisp
)
111 OUString
aModuleIdentPropName( "ModuleIdentifier" );
112 OUString
aDispProvPropName( "DispatchProvider" );
113 bool bModuleNameSet
= false;
114 bool bDispProvSet
= false;
116 uno::Sequence
< beans::PropertyValue
> aSourceProps
;
117 xSourceMenu
->getByIndex( nSourceIndex
) >>= aSourceProps
;
118 uno::Sequence
< beans::PropertyValue
> aTargetProps( aSourceProps
.getLength() );
119 for ( nInd
= 0; nInd
< aSourceProps
.getLength(); nInd
++ )
121 aTargetProps
[nInd
].Name
= aSourceProps
[nInd
].Name
;
122 if ( !aContModuleName
.isEmpty() && aTargetProps
[nInd
].Name
.equals( aModuleIdentPropName
) )
124 aTargetProps
[nInd
].Value
<<= aContModuleName
;
125 bModuleNameSet
= true;
127 else if ( aTargetProps
[nInd
].Name
.equals( aDispProvPropName
) )
129 aTargetProps
[nInd
].Value
<<= xSourceDisp
;
133 aTargetProps
[nInd
].Value
= aSourceProps
[nInd
].Value
;
136 if ( !bModuleNameSet
&& !aContModuleName
.isEmpty() )
138 aTargetProps
.realloc( ++nInd
);
139 aTargetProps
[nInd
-1].Name
= aModuleIdentPropName
;
140 aTargetProps
[nInd
-1].Value
<<= aContModuleName
;
143 if ( !bDispProvSet
&& xSourceDisp
.is() )
145 aTargetProps
.realloc( ++nInd
);
146 aTargetProps
[nInd
-1].Name
= aDispProvPropName
;
147 aTargetProps
[nInd
-1].Value
<<= xSourceDisp
;
150 xTargetMenu
->insertByIndex( nTargetIndex
, uno::makeAny( aTargetProps
) );
154 DocumentHolder::DocumentHolder( const uno::Reference
< uno::XComponentContext
>& xContext
,
155 OCommonEmbeddedObject
* pEmbObj
)
156 : m_pEmbedObj( pEmbObj
),
157 m_pInterceptor( nullptr ),
158 m_xContext( xContext
),
159 m_bReadOnly( false ),
160 m_bWaitForClose( false ),
161 m_bAllowClosing( false ),
162 m_bDesktopTerminated( false ),
163 m_nNoBorderResizeReact( 0 ),
164 m_nNoResizeReact( 0 )
166 m_aOutplaceFrameProps
.realloc( 3 );
167 beans::NamedValue aArg
;
169 aArg
.Name
= "TopWindow";
171 m_aOutplaceFrameProps
[0] <<= aArg
;
173 aArg
.Name
= "MakeVisible";
174 aArg
.Value
<<= false;
175 m_aOutplaceFrameProps
[1] <<= aArg
;
177 uno::Reference
< frame::XDesktop2
> xDesktop
= frame::Desktop::create( m_xContext
);
181 xDesktop
->addTerminateListener( this );
183 catch ( const uno::Exception
& )
188 aArg
.Name
= "ParentFrame";
189 aArg
.Value
<<= xDesktop
; //TODO/LATER: should use parent document frame
190 m_aOutplaceFrameProps
[2] <<= aArg
;
194 DocumentHolder::~DocumentHolder()
196 m_refCount
++; // to allow deregistration as a listener
201 if ( m_xComponent
.is() )
204 CloseDocument( true, false );
205 } catch( const uno::Exception
& ) {}
208 if ( m_pInterceptor
)
210 m_pInterceptor
->DisconnectDocHolder();
211 m_pInterceptor
->release();
214 if ( !m_bDesktopTerminated
)
219 void DocumentHolder::CloseFrame()
221 uno::Reference
< util::XCloseBroadcaster
> xCloseBroadcaster( m_xFrame
, uno::UNO_QUERY
);
222 if ( xCloseBroadcaster
.is() )
223 xCloseBroadcaster
->removeCloseListener( static_cast<util::XCloseListener
*>(this) );
225 uno::Reference
<util::XCloseable
> xCloseable(
226 m_xFrame
,uno::UNO_QUERY
);
227 if( xCloseable
.is() )
229 xCloseable
->close( true );
231 catch( const uno::Exception
& ) {
234 uno::Reference
<lang::XComponent
> xComp( m_xFrame
,uno::UNO_QUERY
);
239 uno::Reference
< lang::XComponent
> xComp( m_xHatchWindow
, uno::UNO_QUERY
);
243 m_xHatchWindow
.clear();
244 m_xOwnWindow
.clear();
249 void DocumentHolder::FreeOffice()
251 uno::Reference
< frame::XDesktop2
> xDesktop
= frame::Desktop::create( m_xContext
);
252 xDesktop
->removeTerminateListener( this );
254 // the following code is commented out since for now there is still no completely correct way to detect
255 // whether the office can be terminated, so it is better to have unnecessary process running than
258 // uno::Reference< frame::XFramesSupplier > xFramesSupplier( xDesktop, uno::UNO_QUERY );
259 // if ( xFramesSupplier.is() )
261 // uno::Reference< frame::XFrames > xFrames = xFramesSupplier->getFrames();
262 // if ( xFrames.is() && !xFrames->hasElements() )
266 // xDesktop->terminate();
268 // catch( uno::Exception & )
275 void DocumentHolder::CloseDocument( bool bDeliverOwnership
, bool bWaitForClose
)
277 uno::Reference
< util::XCloseBroadcaster
> xBroadcaster( m_xComponent
, uno::UNO_QUERY
);
278 if ( xBroadcaster
.is() )
280 uno::Reference
< document::XEventBroadcaster
> xEventBroadcaster( m_xComponent
, uno::UNO_QUERY
);
281 if ( xEventBroadcaster
.is() )
282 xEventBroadcaster
->removeEventListener( static_cast<document::XEventListener
*>(this) );
285 // the object does not support document::XEventBroadcaster interface
286 // use the workaround, register for modified events
287 uno::Reference
< util::XModifyBroadcaster
> xModifyBroadcaster( m_xComponent
, uno::UNO_QUERY
);
288 if ( xModifyBroadcaster
.is() )
289 xModifyBroadcaster
->removeModifyListener( static_cast<util::XModifyListener
*>(this) );
292 uno::Reference
< util::XCloseable
> xCloseable( xBroadcaster
, uno::UNO_QUERY
);
293 if ( xCloseable
.is() )
295 m_bAllowClosing
= true;
296 m_bWaitForClose
= bWaitForClose
;
297 xCloseable
->close( bDeliverOwnership
);
301 m_xComponent
= nullptr;
305 void DocumentHolder::PlaceFrame( const awt::Rectangle
& aNewRect
)
307 OSL_ENSURE( m_xFrame
.is() && m_xOwnWindow
.is(),
308 "The object does not have windows required for inplace mode!" );
310 //TODO: may need mutex locking???
311 if ( m_xFrame
.is() && m_xOwnWindow
.is() )
313 // the frame can be replaced only in inplace mode
314 frame::BorderWidths aOldWidths
;
315 IntCounterGuard
aGuard( m_nNoBorderResizeReact
);
319 aOldWidths
= m_aBorderWidths
;
321 awt::Rectangle aHatchRect
= AddBorderToArea( aNewRect
);
323 ResizeWindows_Impl( aHatchRect
);
325 } while ( aOldWidths
.Left
!= m_aBorderWidths
.Left
326 || aOldWidths
.Top
!= m_aBorderWidths
.Top
327 || aOldWidths
.Right
!= m_aBorderWidths
.Right
328 || aOldWidths
.Bottom
!= m_aBorderWidths
.Bottom
);
330 m_aObjRect
= aNewRect
;
335 void DocumentHolder::ResizeWindows_Impl( const awt::Rectangle
& aHatchRect
)
337 OSL_ENSURE( m_xFrame
.is() && m_xOwnWindow
.is() /*&& m_xHatchWindow.is()*/,
338 "The object does not have windows required for inplace mode!" );
339 if ( m_xHatchWindow
.is() )
341 m_xOwnWindow
->setPosSize( HATCH_BORDER_WIDTH
,
343 aHatchRect
.Width
- 2*HATCH_BORDER_WIDTH
,
344 aHatchRect
.Height
- 2*HATCH_BORDER_WIDTH
,
345 awt::PosSize::POSSIZE
);
348 m_xHatchWindow
->setPosSize( aHatchRect
.X
,
352 awt::PosSize::POSSIZE
);
355 m_xOwnWindow
->setPosSize( aHatchRect
.X
+ HATCH_BORDER_WIDTH
,
356 aHatchRect
.Y
+ HATCH_BORDER_WIDTH
,
357 aHatchRect
.Width
- 2*HATCH_BORDER_WIDTH
,
358 aHatchRect
.Height
- 2*HATCH_BORDER_WIDTH
,
359 awt::PosSize::POSSIZE
);
363 bool DocumentHolder::SetFrameLMVisibility( const uno::Reference
< frame::XFrame
>& xFrame
, bool bVisible
)
365 bool bResult
= false;
369 uno::Reference
< css::frame::XLayoutManager
> xLayoutManager
;
370 uno::Reference
< beans::XPropertySet
> xPropSet( xFrame
, uno::UNO_QUERY_THROW
);
371 xPropSet
->getPropertyValue("LayoutManager") >>= xLayoutManager
;
372 if ( xLayoutManager
.is() )
374 xLayoutManager
->setVisible( bVisible
);
376 // MBA: locking is done only on the container LM, because it is not about hiding windows, it's about
377 // giving up control over the component window (and stopping to listen for resize events of the container window)
379 xLayoutManager
->unlock();
381 xLayoutManager
->lock();
386 catch( const uno::Exception
& )
393 bool DocumentHolder::ShowInplace( const uno::Reference
< awt::XWindowPeer
>& xParent
,
394 const awt::Rectangle
& aRectangleToShow
,
395 const uno::Reference
< frame::XDispatchProvider
>& xContDisp
)
397 OSL_ENSURE( !m_xFrame
.is(), "A frame exists already!" );
399 if ( !m_xFrame
.is() )
401 uno::Reference
< frame::XModel
> xModel( GetComponent(), uno::UNO_QUERY
);
402 awt::Rectangle aHatchRectangle
= AddBorderToArea( aRectangleToShow
);
404 awt::Rectangle
aOwnRectangle( HATCH_BORDER_WIDTH
,
406 aHatchRectangle
.Width
- 2*HATCH_BORDER_WIDTH
,
407 aHatchRectangle
.Height
- 2*HATCH_BORDER_WIDTH
);
408 uno::Reference
< awt::XWindow
> xHWindow
;
409 uno::Reference
< awt::XWindowPeer
> xMyParent( xParent
);
414 uno::Reference
< embed::XHatchWindowFactory
> xHatchFactory
=
415 embed::HatchWindowFactory::create(m_xContext
);
417 uno::Reference
< embed::XHatchWindow
> xHatchWindow
=
418 xHatchFactory
->createHatchWindowInstance( xParent
,
420 awt::Size( HATCH_BORDER_WIDTH
, HATCH_BORDER_WIDTH
) );
422 uno::Reference
< awt::XWindowPeer
> xHatchWinPeer( xHatchWindow
, uno::UNO_QUERY
);
423 xHWindow
.set( xHatchWinPeer
, uno::UNO_QUERY
);
424 if ( !xHWindow
.is() )
425 throw uno::RuntimeException(); // TODO: can not create own window
427 xHatchWindow
->setController( uno::Reference
< embed::XHatchWindowController
>(
428 static_cast< embed::XHatchWindowController
* >( this ) ) );
430 xMyParent
= xHatchWinPeer
;
434 aOwnRectangle
.X
+= aHatchRectangle
.X
;
435 aOwnRectangle
.Y
+= aHatchRectangle
.Y
;
438 awt::WindowDescriptor
aOwnWinDescriptor( awt::WindowClass_TOP
,
439 OUString("dockingwindow"),
442 awt::Rectangle(),//aOwnRectangle,
443 awt::WindowAttribute::SHOW
| awt::VclWindowPeerAttribute::CLIPCHILDREN
);
445 uno::Reference
< awt::XToolkit2
> xToolkit
= awt::Toolkit::create(m_xContext
);
447 uno::Reference
< awt::XWindowPeer
> xNewWinPeer
= xToolkit
->createWindow( aOwnWinDescriptor
);
448 uno::Reference
< awt::XWindow
> xOwnWindow( xNewWinPeer
, uno::UNO_QUERY
);
449 if ( !xOwnWindow
.is() )
450 throw uno::RuntimeException(); // TODO: can not create own window
452 // create a frame based on the specified window
453 uno::Reference
< lang::XSingleServiceFactory
> xFrameFact
= frame::TaskCreator::create(m_xContext
);
455 uno::Sequence
< uno::Any
> aArgs( 2 );
456 beans::NamedValue aArg
;
458 aArg
.Name
= "ContainerWindow";
459 aArg
.Value
<<= xOwnWindow
;
462 uno::Reference
< frame::XFrame
> xContFrame( xContDisp
, uno::UNO_QUERY
);
463 if ( xContFrame
.is() )
465 aArg
.Name
= "ParentFrame";
466 aArg
.Value
<<= xContFrame
;
472 // the call will create, initialize the frame, and register it in the parent
473 m_xFrame
.set( xFrameFact
->createInstanceWithArguments( aArgs
), uno::UNO_QUERY_THROW
);
475 m_xHatchWindow
= xHWindow
;
476 m_xOwnWindow
= xOwnWindow
;
478 if ( !SetFrameLMVisibility( m_xFrame
, false ) )
480 OSL_FAIL( "Can't deactivate LayoutManager!\n" );
481 // TODO/LATER: error handling?
484 // m_bIsInplace = sal_True; TODO: ?
486 uno::Reference
< util::XCloseBroadcaster
> xCloseBroadcaster( m_xFrame
, uno::UNO_QUERY
);
487 if ( xCloseBroadcaster
.is() )
488 xCloseBroadcaster
->addCloseListener( static_cast<util::XCloseListener
*>(this) );
490 // TODO: some listeners to the frame and the window ( resize for example )
493 if ( m_xComponent
.is() )
495 if ( !LoadDocToFrame( true ) )
501 uno::Reference
< frame::XControllerBorder
> xControllerBorder( m_xFrame
->getController(), uno::UNO_QUERY
);
502 if ( xControllerBorder
.is() )
504 m_aBorderWidths
= xControllerBorder
->getBorder();
505 xControllerBorder
->addBorderResizeListener( static_cast<frame::XBorderResizeListener
*>(this) );
508 PlaceFrame( aRectangleToShow
);
510 if ( m_xHatchWindow
.is() )
511 m_xHatchWindow
->setVisible( true );
520 uno::Reference
< container::XIndexAccess
> DocumentHolder::RetrieveOwnMenu_Impl()
522 uno::Reference
< container::XIndexAccess
> xResult
;
524 uno::Reference
< css::ui::XUIConfigurationManagerSupplier
> xUIConfSupplier(
527 uno::Reference
< css::ui::XUIConfigurationManager
> xUIConfigManager
;
528 if( xUIConfSupplier
.is())
530 xUIConfigManager
.set(
531 xUIConfSupplier
->getUIConfigurationManager(),
532 uno::UNO_QUERY_THROW
);
537 if( xUIConfigManager
.is())
539 xResult
= xUIConfigManager
->getSettings(
540 "private:resource/menubar/menubar",
544 catch( const uno::Exception
& )
549 // no internal document configuration, use the one from the module
550 uno::Reference
< frame::XModuleManager2
> xModuleMan
= frame::ModuleManager::create(m_xContext
);
551 OUString aModuleIdent
=
552 xModuleMan
->identify( uno::Reference
< uno::XInterface
>( m_xComponent
, uno::UNO_QUERY
) );
554 if ( !aModuleIdent
.isEmpty() )
556 uno::Reference
< ui::XModuleUIConfigurationManagerSupplier
> xModConfSupplier
=
557 ui::theModuleUIConfigurationManagerSupplier::get(m_xContext
);
558 uno::Reference
< css::ui::XUIConfigurationManager
> xModUIConfMan(
559 xModConfSupplier
->getUIConfigurationManager( aModuleIdent
),
560 uno::UNO_QUERY_THROW
);
561 xResult
= xModUIConfMan
->getSettings(
562 "private:resource/menubar/menubar",
568 throw uno::RuntimeException();
574 void DocumentHolder::FindConnectPoints(
575 const uno::Reference
< container::XIndexAccess
>& xMenu
,
576 sal_Int32 nConnectPoints
[2] )
577 throw ( uno::Exception
)
579 nConnectPoints
[0] = -1;
580 nConnectPoints
[1] = -1;
581 for ( sal_Int32 nInd
= 0; nInd
< xMenu
->getCount(); nInd
++ )
583 uno::Sequence
< beans::PropertyValue
> aProps
;
584 xMenu
->getByIndex( nInd
) >>= aProps
;
586 for ( sal_Int32 nSeqInd
= 0; nSeqInd
< aProps
.getLength(); nSeqInd
++ )
587 if ( aProps
[nSeqInd
].Name
== "CommandURL" )
589 aProps
[nSeqInd
].Value
>>= aCommand
;
593 if ( aCommand
.isEmpty() )
594 throw uno::RuntimeException();
596 if ( aCommand
== ".uno:PickList" )
597 nConnectPoints
[0] = nInd
;
598 else if ( aCommand
== ".uno:WindowList" )
599 nConnectPoints
[1] = nInd
;
604 uno::Reference
< container::XIndexAccess
> DocumentHolder::MergeMenusForInplace(
605 const uno::Reference
< container::XIndexAccess
>& xContMenu
,
606 const uno::Reference
< frame::XDispatchProvider
>& xContDisp
,
607 const OUString
& aContModuleName
,
608 const uno::Reference
< container::XIndexAccess
>& xOwnMenu
,
609 const uno::Reference
< frame::XDispatchProvider
>& xOwnDisp
)
610 throw ( uno::Exception
)
612 // TODO/LATER: use dispatch providers on merge
614 sal_Int32 nContPoints
[2];
615 sal_Int32 nOwnPoints
[2];
617 uno::Reference
< lang::XSingleComponentFactory
> xIndAccessFact( xContMenu
, uno::UNO_QUERY_THROW
);
619 uno::Reference
< container::XIndexContainer
> xMergedMenu(
620 xIndAccessFact
->createInstanceWithContext(
621 comphelper::getProcessComponentContext() ),
622 uno::UNO_QUERY_THROW
);
624 FindConnectPoints( xContMenu
, nContPoints
);
625 FindConnectPoints( xOwnMenu
, nOwnPoints
);
627 for ( sal_Int32 nInd
= 0; nInd
< xOwnMenu
->getCount(); nInd
++ )
629 if ( nOwnPoints
[0] == nInd
)
631 if ( nContPoints
[0] >= 0 && nContPoints
[0] < xContMenu
->getCount() )
633 InsertMenu_Impl( xMergedMenu
, nInd
, xContMenu
, nContPoints
[0], aContModuleName
, xContDisp
);
636 else if ( nOwnPoints
[1] == nInd
)
638 if ( nContPoints
[1] >= 0 && nContPoints
[1] < xContMenu
->getCount() )
640 InsertMenu_Impl( xMergedMenu
, nInd
, xContMenu
, nContPoints
[1], aContModuleName
, xContDisp
);
644 InsertMenu_Impl( xMergedMenu
, nInd
, xOwnMenu
, nInd
, OUString(), xOwnDisp
);
647 return uno::Reference
< container::XIndexAccess
>( xMergedMenu
, uno::UNO_QUERY_THROW
);
651 bool DocumentHolder::MergeMenus_Impl( const uno::Reference
< css::frame::XLayoutManager
>& xOwnLM
,
652 const uno::Reference
< css::frame::XLayoutManager
>& xContLM
,
653 const uno::Reference
< frame::XDispatchProvider
>& xContDisp
,
654 const OUString
& aContModuleName
)
656 bool bMenuMerged
= false;
659 uno::Reference
< css::ui::XUIElementSettings
> xUISettings(
660 xContLM
->getElement( "private:resource/menubar/menubar" ),
661 uno::UNO_QUERY_THROW
);
662 uno::Reference
< container::XIndexAccess
> xContMenu
= xUISettings
->getSettings( true );
663 if ( !xContMenu
.is() )
664 throw uno::RuntimeException();
666 uno::Reference
< container::XIndexAccess
> xOwnMenu
= RetrieveOwnMenu_Impl();
667 uno::Reference
< frame::XDispatchProvider
> xOwnDisp( m_xFrame
, uno::UNO_QUERY_THROW
);
669 uno::Reference
< container::XIndexAccess
> xMergedMenu
= MergeMenusForInplace( xContMenu
, xContDisp
, aContModuleName
, xOwnMenu
, xOwnDisp
);
670 uno::Reference
< css::frame::XMenuBarMergingAcceptor
> xMerge( xOwnLM
,
671 uno::UNO_QUERY_THROW
);
672 bMenuMerged
= xMerge
->setMergedMenuBar( xMergedMenu
);
674 catch( const uno::Exception
& )
680 bool DocumentHolder::ShowUI( const uno::Reference
< css::frame::XLayoutManager
>& xContainerLM
,
681 const uno::Reference
< frame::XDispatchProvider
>& xContainerDP
,
682 const OUString
& aContModuleName
)
684 bool bResult
= false;
685 if ( xContainerLM
.is() )
687 // the LM of the embedded frame and its current DockingAreaAcceptor
688 uno::Reference
< css::frame::XLayoutManager
> xOwnLM
;
689 uno::Reference
< css::ui::XDockingAreaAcceptor
> xDocAreaAcc
;
693 uno::Reference
< beans::XPropertySet
> xPropSet( m_xFrame
, uno::UNO_QUERY_THROW
);
694 xPropSet
->getPropertyValue("LayoutManager") >>= xOwnLM
;
695 xDocAreaAcc
= xContainerLM
->getDockingAreaAcceptor();
697 catch( const uno::Exception
& ){}
699 if ( xOwnLM
.is() && xDocAreaAcc
.is() )
701 // make sure that lock state of LM is correct even if an exception is thrown in between
702 bool bUnlock
= false;
706 // take over the control over the containers window
707 // as long as the LM is invisible and locked an empty tool space will be used on resizing
708 xOwnLM
->setDockingAreaAcceptor( xDocAreaAcc
);
710 // try to merge menus; don't do anything else if it fails
711 if ( MergeMenus_Impl( xOwnLM
, xContainerLM
, xContainerDP
, aContModuleName
) )
713 // make sure that the container LM does not control the size of the containers window anymore
714 // this must be done after merging menus as we won't get the container menu otherwise
715 xContainerLM
->setDockingAreaAcceptor( uno::Reference
< ui::XDockingAreaAcceptor
>() );
717 bool bIsChart
= false;
718 uno::Reference
< lang::XServiceInfo
> xServiceInfo(m_xComponent
, uno::UNO_QUERY
);
719 if (xServiceInfo
.is() && xServiceInfo
->supportsService("com.sun.star.chart2.ChartDocument"))
721 // prevent further changes at this LM
722 // TODO: moggi: why is this necessary?
725 xContainerLM
->setVisible( false );
726 xContainerLM
->lock();
730 // by unlocking the LM each layout change will now resize the containers window; pending layouts will be processed now
731 xOwnLM
->setVisible( true );
733 uno::Reference
< frame::XFramesSupplier
> xSupp( m_xFrame
->getCreator(), uno::UNO_QUERY
);
735 xSupp
->setActiveFrame( m_xFrame
);
741 // TODO/LATER: The following action should be done only if the window is not hidden
742 // otherwise the activation must fail, unfortunately currently it is not possible
743 // to detect whether the window is hidden using UNO API
744 m_xOwnWindow
->setFocus();
747 catch( const uno::Exception
& )
749 // activation failed; reestablish old state
752 uno::Reference
< frame::XFramesSupplier
> xSupp( m_xFrame
->getCreator(), uno::UNO_QUERY
);
754 xSupp
->setActiveFrame( nullptr );
756 // remove control about containers window from own LM
759 xOwnLM
->setVisible( false );
760 xOwnLM
->setDockingAreaAcceptor( uno::Reference
< css::ui::XDockingAreaAcceptor
>() );
763 uno::Reference
< css::frame::XMenuBarMergingAcceptor
> xMerge( xOwnLM
, uno::UNO_QUERY_THROW
);
764 xMerge
->removeMergedMenuBar();
766 catch( const uno::Exception
& ) {}
770 // reestablish control of containers window
771 xContainerLM
->setDockingAreaAcceptor( xDocAreaAcc
);
772 xContainerLM
->setVisible( true );
774 xContainerLM
->unlock();
776 catch( const uno::Exception
& ) {}
785 bool DocumentHolder::HideUI( const uno::Reference
< css::frame::XLayoutManager
>& xContainerLM
)
787 bool bResult
= false;
789 if ( xContainerLM
.is() )
791 uno::Reference
< css::frame::XLayoutManager
> xOwnLM
;
794 uno::Reference
< beans::XPropertySet
> xPropSet( m_xFrame
, uno::UNO_QUERY_THROW
);
795 xPropSet
->getPropertyValue("LayoutManager") >>= xOwnLM
;
796 } catch( const uno::Exception
& )
802 uno::Reference
< frame::XFramesSupplier
> xSupp( m_xFrame
->getCreator(), uno::UNO_QUERY
);
804 xSupp
->setActiveFrame( nullptr );
806 uno::Reference
< css::ui::XDockingAreaAcceptor
> xDocAreaAcc
= xOwnLM
->getDockingAreaAcceptor();
808 xOwnLM
->setDockingAreaAcceptor( uno::Reference
< ui::XDockingAreaAcceptor
>() );
810 xOwnLM
->setVisible( false );
812 uno::Reference
< css::frame::XMenuBarMergingAcceptor
> xMerge( xOwnLM
, uno::UNO_QUERY_THROW
);
813 xMerge
->removeMergedMenuBar();
815 xContainerLM
->setDockingAreaAcceptor( xDocAreaAcc
);
816 xContainerLM
->setVisible( true );
817 xContainerLM
->unlock();
819 xContainerLM
->doLayout();
822 catch( const uno::Exception
& )
824 SetFrameLMVisibility( m_xFrame
, true );
833 uno::Reference
< frame::XFrame
> const & DocumentHolder::GetDocFrame()
835 // the frame for outplace activation
836 if ( !m_xFrame
.is() )
838 uno::Reference
< lang::XSingleServiceFactory
> xFrameFact
= frame::TaskCreator::create(m_xContext
);
840 m_xFrame
.set(xFrameFact
->createInstanceWithArguments( m_aOutplaceFrameProps
), uno::UNO_QUERY_THROW
);
842 uno::Reference
< frame::XDispatchProviderInterception
> xInterception( m_xFrame
, uno::UNO_QUERY
);
843 if ( xInterception
.is() )
845 if ( m_pInterceptor
)
847 m_pInterceptor
->DisconnectDocHolder();
848 m_pInterceptor
->release();
849 m_pInterceptor
= nullptr;
852 m_pInterceptor
= new Interceptor( this );
853 m_pInterceptor
->acquire();
855 xInterception
->registerDispatchProviderInterceptor( m_pInterceptor
);
857 // register interceptor from outside
858 if ( m_xOutplaceInterceptor
.is() )
859 xInterception
->registerDispatchProviderInterceptor( m_xOutplaceInterceptor
);
862 uno::Reference
< util::XCloseBroadcaster
> xCloseBroadcaster( m_xFrame
, uno::UNO_QUERY
);
863 if ( xCloseBroadcaster
.is() )
864 xCloseBroadcaster
->addCloseListener( static_cast<util::XCloseListener
*>(this) );
867 if ( m_xComponent
.is() )
869 uno::Reference
< css::frame::XLayoutManager
> xOwnLM
;
871 uno::Reference
< beans::XPropertySet
> xPropSet( m_xFrame
, uno::UNO_QUERY_THROW
);
872 xPropSet
->getPropertyValue("LayoutManager") >>= xOwnLM
;
873 } catch( const uno::Exception
& )
879 // TODO/LATER: get it for the real aspect
881 LoadDocToFrame(false);
889 GetExtent( embed::Aspects::MSOLE_CONTENT
, &aSize
);
890 SetExtent( embed::Aspects::MSOLE_CONTENT
, aSize
);
898 uno::Reference
< awt::XWindow
> xHWindow
= m_xFrame
->getContainerWindow();
902 sal_Int32 nDisplay
= Application::GetDisplayBuiltInScreen();
904 Rectangle aWorkRect
= Application::GetScreenPosSizePixel( nDisplay
);
905 awt::Rectangle aWindowRect
= xHWindow
->getPosSize();
907 if (( aWindowRect
.Width
< aWorkRect
.GetWidth()) && ( aWindowRect
.Height
< aWorkRect
.GetHeight() ))
909 int OffsetX
= ( aWorkRect
.GetWidth() - aWindowRect
.Width
) / 2 + aWorkRect
.Left();
910 int OffsetY
= ( aWorkRect
.GetHeight() - aWindowRect
.Height
) /2 + aWorkRect
.Top();
911 xHWindow
->setPosSize( OffsetX
, OffsetY
, aWindowRect
.Width
, aWindowRect
.Height
, awt::PosSize::POS
);
915 xHWindow
->setPosSize( aWorkRect
.Left(), aWorkRect
.Top(), aWorkRect
.GetWidth(), aWorkRect
.GetHeight(), awt::PosSize::POSSIZE
);
918 xHWindow
->setVisible( true );
921 catch ( const uno::Exception
& )
929 void DocumentHolder::SetComponent( const uno::Reference
< util::XCloseable
>& xDoc
, bool bReadOnly
)
931 if ( m_xComponent
.is() )
933 // May be should be improved
935 CloseDocument( true, false );
936 } catch( const uno::Exception
& )
942 m_bReadOnly
= bReadOnly
;
943 m_bAllowClosing
= false;
945 uno::Reference
< util::XCloseBroadcaster
> xBroadcaster( m_xComponent
, uno::UNO_QUERY
);
946 if ( xBroadcaster
.is() )
947 xBroadcaster
->addCloseListener( static_cast<util::XCloseListener
*>(this) );
949 uno::Reference
< document::XEventBroadcaster
> xEventBroadcaster( m_xComponent
, uno::UNO_QUERY
);
950 if ( xEventBroadcaster
.is() )
951 xEventBroadcaster
->addEventListener( static_cast<document::XEventListener
*>(this) );
954 // the object does not support document::XEventBroadcaster interface
955 // use the workaround, register for modified events
956 uno::Reference
< util::XModifyBroadcaster
> xModifyBroadcaster( m_xComponent
, uno::UNO_QUERY
);
957 if ( xModifyBroadcaster
.is() )
958 xModifyBroadcaster
->addModifyListener( static_cast<util::XModifyListener
*>(this) );
962 LoadDocToFrame(false);
966 bool DocumentHolder::LoadDocToFrame( bool bInPlace
)
968 if ( m_xFrame
.is() && m_xComponent
.is() )
970 uno::Reference
< frame::XModel
> xDoc( m_xComponent
, uno::UNO_QUERY
);
973 // load new document in to the frame
974 uno::Reference
< frame::XComponentLoader
> xComponentLoader( m_xFrame
, uno::UNO_QUERY_THROW
);
976 ::comphelper::NamedValueCollection aArgs
;
977 aArgs
.put( "Model", m_xComponent
);
978 aArgs
.put( "ReadOnly", m_bReadOnly
);
980 // set document title to show in the title bar
981 css::uno::Reference
< css::frame::XTitle
> xModelTitle( xDoc
, css::uno::UNO_QUERY
);
982 if( xModelTitle
.is() )
984 LanguageTag
aLocale( Application::GetSettings().GetUILanguageTag() );
985 ResMgr
* pResMgr
= ResMgr::SearchCreateResMgr( "sfx", aLocale
);
986 OUString sEmbedded
= ResId( STR_EMBEDDED_TITLE
, *pResMgr
);
987 xModelTitle
->setTitle( m_pEmbedObj
->getContainerName() + sEmbedded
);
988 m_aContainerName
= m_pEmbedObj
->getContainerName();
989 // TODO: get real m_aDocumentNamePart
990 m_aDocumentNamePart
= sEmbedded
;
994 aArgs
.put( "PluginMode", sal_Int16(1) );
996 uno::Reference
< lang::XServiceInfo
> xServiceInfo(xDoc
,uno::UNO_QUERY
);
997 if ( xServiceInfo
.is()
998 && xServiceInfo
->supportsService("com.sun.star.report.ReportDefinition") )
1000 sUrl
= ".component:DB/ReportDesign";
1002 else if( xServiceInfo
.is()
1003 && xServiceInfo
->supportsService("com.sun.star.chart2.ChartDocument"))
1004 sUrl
= "private:factory/schart";
1006 sUrl
= "private:object";
1008 xComponentLoader
->loadComponentFromURL( sUrl
,
1011 aArgs
.getPropertyValues() );
1017 uno::Reference
< frame::XSynchronousFrameLoader
> xLoader( m_xComponent
, uno::UNO_QUERY
);
1019 return xLoader
->load( uno::Sequence
< beans::PropertyValue
>(), m_xFrame
);
1029 void DocumentHolder::Show()
1033 m_xFrame
->activate();
1034 uno::Reference
<awt::XTopWindow
> xTopWindow( m_xFrame
->getContainerWindow(), uno::UNO_QUERY
);
1035 if( xTopWindow
.is() )
1036 xTopWindow
->toFront();
1043 bool DocumentHolder::SetExtent( sal_Int64 nAspect
, const awt::Size
& aSize
)
1045 uno::Reference
< embed::XVisualObject
> xDocVis( m_xComponent
, uno::UNO_QUERY
);
1050 xDocVis
->setVisualAreaSize( nAspect
, aSize
);
1053 catch( const uno::Exception
& )
1055 // TODO: Error handling
1063 bool DocumentHolder::GetExtent( sal_Int64 nAspect
, awt::Size
*pSize
)
1065 uno::Reference
< embed::XVisualObject
> xDocVis( m_xComponent
, uno::UNO_QUERY
);
1066 if ( pSize
&& xDocVis
.is() )
1070 *pSize
= xDocVis
->getVisualAreaSize( nAspect
);
1073 catch( const uno::Exception
& )
1075 // TODO: Error handling
1083 sal_Int32
DocumentHolder::GetMapUnit( sal_Int64 nAspect
)
1085 uno::Reference
< embed::XVisualObject
> xDocVis( m_xComponent
, uno::UNO_QUERY
);
1090 return xDocVis
->getMapUnit( nAspect
);
1092 catch( const uno::Exception
& )
1094 // TODO: Error handling
1102 awt::Rectangle
DocumentHolder::CalculateBorderedArea( const awt::Rectangle
& aRect
)
1104 return awt::Rectangle( aRect
.X
+ m_aBorderWidths
.Left
+ HATCH_BORDER_WIDTH
,
1105 aRect
.Y
+ m_aBorderWidths
.Top
+ HATCH_BORDER_WIDTH
,
1106 aRect
.Width
- m_aBorderWidths
.Left
- m_aBorderWidths
.Right
- 2*HATCH_BORDER_WIDTH
,
1107 aRect
.Height
- m_aBorderWidths
.Top
- m_aBorderWidths
.Bottom
- 2*HATCH_BORDER_WIDTH
);
1111 awt::Rectangle
DocumentHolder::AddBorderToArea( const awt::Rectangle
& aRect
)
1113 return awt::Rectangle( aRect
.X
- m_aBorderWidths
.Left
- HATCH_BORDER_WIDTH
,
1114 aRect
.Y
- m_aBorderWidths
.Top
- HATCH_BORDER_WIDTH
,
1115 aRect
.Width
+ m_aBorderWidths
.Left
+ m_aBorderWidths
.Right
+ 2*HATCH_BORDER_WIDTH
,
1116 aRect
.Height
+ m_aBorderWidths
.Top
+ m_aBorderWidths
.Bottom
+ 2*HATCH_BORDER_WIDTH
);
1120 void SAL_CALL
DocumentHolder::disposing( const css::lang::EventObject
& aSource
)
1121 throw (uno::RuntimeException
, std::exception
)
1123 if ( m_xComponent
.is() && m_xComponent
== aSource
.Source
)
1125 m_xComponent
= nullptr;
1126 if ( m_bWaitForClose
)
1128 m_bWaitForClose
= false;
1133 if( m_xFrame
.is() && m_xFrame
== aSource
.Source
)
1135 m_xHatchWindow
.clear();
1136 m_xOwnWindow
.clear();
1142 void SAL_CALL
DocumentHolder::queryClosing( const lang::EventObject
& aSource
, sal_Bool
/*bGetsOwnership*/ )
1143 throw (util::CloseVetoException
, uno::RuntimeException
, std::exception
)
1145 if ( m_xComponent
.is() && m_xComponent
== aSource
.Source
&& !m_bAllowClosing
)
1146 throw util::CloseVetoException("To close an embedded document, close the document holder (document definition), not the document itself.", static_cast< ::cppu::OWeakObject
*>(this));
1150 void SAL_CALL
DocumentHolder::notifyClosing( const lang::EventObject
& aSource
)
1151 throw (uno::RuntimeException
, std::exception
)
1153 if ( m_xComponent
.is() && m_xComponent
== aSource
.Source
)
1155 m_xComponent
= nullptr;
1156 if ( m_bWaitForClose
)
1158 m_bWaitForClose
= false;
1163 if( m_xFrame
.is() && m_xFrame
== aSource
.Source
)
1165 m_xHatchWindow
.clear();
1166 m_xOwnWindow
.clear();
1172 void SAL_CALL
DocumentHolder::queryTermination( const lang::EventObject
& )
1173 throw (frame::TerminationVetoException
, uno::RuntimeException
, std::exception
)
1175 if ( m_bWaitForClose
)
1176 throw frame::TerminationVetoException();
1180 void SAL_CALL
DocumentHolder::notifyTermination( const lang::EventObject
& aSource
)
1181 throw (uno::RuntimeException
, std::exception
)
1183 OSL_ENSURE( !m_xComponent
.is(), "Just a disaster..." );
1185 uno::Reference
< frame::XDesktop
> xDesktop( aSource
.Source
, uno::UNO_QUERY
);
1186 m_bDesktopTerminated
= true;
1187 if ( xDesktop
.is() )
1188 xDesktop
->removeTerminateListener( static_cast<frame::XTerminateListener
*>(this) );
1192 void SAL_CALL
DocumentHolder::modified( const lang::EventObject
& aEvent
)
1193 throw ( uno::RuntimeException
, std::exception
)
1195 // if the component does not support document::XEventBroadcaster
1196 // the modify notifications are used as workaround, but only for running state
1197 if( aEvent
.Source
== m_xComponent
&& m_pEmbedObj
&& m_pEmbedObj
->getCurrentState() == embed::EmbedStates::RUNNING
)
1198 m_pEmbedObj
->PostEvent_Impl( "OnVisAreaChanged" );
1202 void SAL_CALL
DocumentHolder::notifyEvent( const document::EventObject
& Event
)
1203 throw ( uno::RuntimeException
, std::exception
)
1205 if( m_pEmbedObj
&& Event
.Source
== m_xComponent
)
1207 // for now the ignored events are not forwarded, but sent by the object itself
1208 if ( !Event
.EventName
.startsWith( "OnSave" )
1209 && !Event
.EventName
.startsWith( "OnSaveDone" )
1210 && !Event
.EventName
.startsWith( "OnSaveAs" )
1211 && !Event
.EventName
.startsWith( "OnSaveAsDone" )
1212 && !( Event
.EventName
.startsWith( "OnVisAreaChanged" ) && m_nNoResizeReact
) )
1213 m_pEmbedObj
->PostEvent_Impl( Event
.EventName
);
1218 void SAL_CALL
DocumentHolder::borderWidthsChanged( const uno::Reference
< uno::XInterface
>& aObject
,
1219 const frame::BorderWidths
& aNewSize
)
1220 throw ( uno::RuntimeException
, std::exception
)
1222 // TODO: may require mutex introduction ???
1223 if ( m_pEmbedObj
&& m_xFrame
.is() && aObject
== m_xFrame
->getController() )
1225 if ( m_aBorderWidths
.Left
!= aNewSize
.Left
1226 || m_aBorderWidths
.Right
!= aNewSize
.Right
1227 || m_aBorderWidths
.Top
!= aNewSize
.Top
1228 || m_aBorderWidths
.Bottom
!= aNewSize
.Bottom
)
1230 m_aBorderWidths
= aNewSize
;
1231 if ( !m_nNoBorderResizeReact
)
1232 PlaceFrame( m_aObjRect
);
1238 void SAL_CALL
DocumentHolder::requestPositioning( const awt::Rectangle
& aRect
)
1239 throw (uno::RuntimeException
, std::exception
)
1241 // TODO: may require mutex introduction ???
1244 // borders should not be counted
1245 awt::Rectangle aObjRect
= CalculateBorderedArea( aRect
);
1246 IntCounterGuard
aGuard( m_nNoResizeReact
);
1247 m_pEmbedObj
->requestPositioning( aObjRect
);
1252 awt::Rectangle SAL_CALL
DocumentHolder::calcAdjustedRectangle( const awt::Rectangle
& aRect
)
1253 throw (uno::RuntimeException
, std::exception
)
1255 // Solar mutex should be locked already since this is a call from HatchWindow with focus
1256 awt::Rectangle
aResult( aRect
);
1258 if ( m_xFrame
.is() )
1260 // borders should not be counted
1261 uno::Reference
< frame::XControllerBorder
> xControllerBorder( m_xFrame
->getController(), uno::UNO_QUERY
);
1262 if ( xControllerBorder
.is() )
1264 awt::Rectangle aObjRect
= CalculateBorderedArea( aRect
);
1265 aObjRect
= xControllerBorder
->queryBorderedArea( aObjRect
);
1266 aResult
= AddBorderToArea( aObjRect
);
1270 awt::Rectangle aMinRectangle
= AddBorderToArea( awt::Rectangle() );
1271 if ( aResult
.Width
< aMinRectangle
.Width
+ 2 )
1272 aResult
.Width
= aMinRectangle
.Width
+ 2;
1273 if ( aResult
.Height
< aMinRectangle
.Height
+ 2 )
1274 aResult
.Height
= aMinRectangle
.Height
+ 2;
1279 void SAL_CALL
DocumentHolder::activated( ) throw (css::uno::RuntimeException
, std::exception
)
1281 if ( (m_pEmbedObj
->getStatus(embed::Aspects::MSOLE_CONTENT
)&embed::EmbedMisc::MS_EMBED_ACTIVATEWHENVISIBLE
) ||
1282 svt::EmbeddedObjectRef::IsGLChart(m_pEmbedObj
) )
1284 if ( m_pEmbedObj
->getCurrentState() != embed::EmbedStates::UI_ACTIVE
&&
1285 !(m_pEmbedObj
->getStatus(embed::Aspects::MSOLE_CONTENT
)&embed::EmbedMisc::MS_EMBED_NOUIACTIVATE
) )
1289 m_pEmbedObj
->changeState( embed::EmbedStates::UI_ACTIVE
);
1291 catch ( const css::embed::StateChangeInProgressException
& )
1293 // must catch this exception because focus is grabbed while UI activation in doVerb()
1295 catch ( const css::uno::Exception
& )
1297 // no outgoing exceptions specified here
1302 uno::Reference
< frame::XFramesSupplier
> xSupp( m_xFrame
->getCreator(), uno::UNO_QUERY
);
1304 xSupp
->setActiveFrame( m_xFrame
);
1309 void DocumentHolder::ResizeHatchWindow()
1311 awt::Rectangle aHatchRect
= AddBorderToArea( m_aObjRect
);
1312 ResizeWindows_Impl( aHatchRect
);
1313 uno::Reference
< embed::XHatchWindow
> xHatchWindow( m_xHatchWindow
, uno::UNO_QUERY
);
1314 xHatchWindow
->setHatchBorderSize( awt::Size( HATCH_BORDER_WIDTH
, HATCH_BORDER_WIDTH
) );
1317 void SAL_CALL
DocumentHolder::deactivated( ) throw (css::uno::RuntimeException
, std::exception
)
1319 // deactivation is too unspecific to be useful; usually we only trigger code from activation
1320 // so UIDeactivation is actively triggered by the container
1323 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */