1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: slideshowviewimpl.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sd.hxx"
33 #include <slideshowviewimpl.hxx>
34 #include <slideshowimpl.hxx>
35 #include <vos/mutex.hxx>
37 #include <com/sun/star/beans/XPropertySet.hpp>
39 #include <basegfx/polygon/b2dpolygon.hxx>
40 #include <basegfx/polygon/b2dpolygontools.hxx>
41 #include <cppcanvas/vclfactory.hxx>
42 #include <cppcanvas/basegfxfactory.hxx>
45 using ::com::sun::star::uno::UNO_QUERY
;
46 using ::com::sun::star::uno::XInterface
;
47 using ::com::sun::star::uno::Reference
;
48 using ::com::sun::star::uno::WeakReference
;
49 using ::com::sun::star::uno::RuntimeException
;
50 using ::com::sun::star::lang::XComponent
;
51 using ::com::sun::star::uno::Exception
;
52 using ::com::sun::star::presentation::XSlideShow
;
53 using ::com::sun::star::presentation::XSlideShowView
;
54 using ::com::sun::star::presentation::XShapeEventListener
;
55 using ::com::sun::star::presentation::XSlideShowListener
;
56 using ::comphelper::ImplementationReference
;
58 using ::rtl::OUString
;
59 using namespace ::com::sun::star
;
60 using namespace ::com::sun::star
;
65 ///////////////////////////////////////////////////////////////////////
66 // SlideShowViewListeners
67 ///////////////////////////////////////////////////////////////////////
69 SlideShowViewListeners::SlideShowViewListeners( ::osl::Mutex
& rMutex
)
74 void SlideShowViewListeners::addListener( const Reference
< util::XModifyListener
>& _rxListener
)
76 ::osl::MutexGuard
aGuard( mrMutex
);
78 WeakReference
< util::XModifyListener
> xWeak( _rxListener
);
79 if( std::find( maListeners
.begin(), maListeners
.end(), xWeak
) == maListeners
.end() )
80 maListeners
.push_back( xWeak
);
83 void SlideShowViewListeners::removeListener( const Reference
< util::XModifyListener
>& _rxListener
)
85 ::osl::MutexGuard
aGuard( mrMutex
);
87 WeakReference
< util::XModifyListener
> xWeak( _rxListener
);
88 ViewListenerVector::iterator
aIter( std::find( maListeners
.begin(), maListeners
.end(), xWeak
) );
89 if( aIter
!= maListeners
.end() )
90 maListeners
.erase( aIter
);
93 bool SlideShowViewListeners::notify( const lang::EventObject
& _rEvent
) throw( com::sun::star::uno::Exception
)
95 ::osl::MutexGuard
aGuard( mrMutex
);
97 ViewListenerVector::iterator
aIter( maListeners
.begin() );
98 while( aIter
!= maListeners
.end() )
100 Reference
< util::XModifyListener
> xListener( (*aIter
) );
103 xListener
->modified( _rEvent
);
108 aIter
= maListeners
.erase( aIter
);
114 void SlideShowViewListeners::disposing( const lang::EventObject
& _rEventSource
)
116 ::osl::MutexGuard
aGuard( mrMutex
);
118 ViewListenerVector::iterator
aIter( maListeners
.begin() );
119 while( aIter
!= maListeners
.end() )
121 Reference
< util::XModifyListener
> xListener( (*aIter
++) );
123 xListener
->disposing( _rEventSource
);
129 ///////////////////////////////////////////////////////////////////////
130 // SlideShowViewPaintListeners
131 ///////////////////////////////////////////////////////////////////////
133 SlideShowViewPaintListeners::SlideShowViewPaintListeners( ::osl::Mutex
& rMutex
)
134 : SlideShowViewPaintListeners_Base( rMutex
)
138 bool SlideShowViewPaintListeners::implTypedNotify( const Reference
< awt::XPaintListener
>& rListener
,
139 const awt::PaintEvent
& rEvent
) throw( uno::Exception
)
141 rListener
->windowPaint( rEvent
);
142 return true; // continue calling listeners
145 ///////////////////////////////////////////////////////////////////////
146 // SlideShowViewMouseListeners
147 ///////////////////////////////////////////////////////////////////////
149 SlideShowViewMouseListeners::SlideShowViewMouseListeners( ::osl::Mutex
& rMutex
) :
150 SlideShowViewMouseListeners_Base( rMutex
)
154 bool SlideShowViewMouseListeners::implTypedNotify( const Reference
< awt::XMouseListener
>& rListener
,
155 const WrappedMouseEvent
& rEvent
) throw( uno::Exception
)
157 switch( rEvent
.meType
)
159 case WrappedMouseEvent::PRESSED
:
160 rListener
->mousePressed( rEvent
.maEvent
);
163 case WrappedMouseEvent::RELEASED
:
164 rListener
->mouseReleased( rEvent
.maEvent
);
167 case WrappedMouseEvent::ENTERED
:
168 rListener
->mouseEntered( rEvent
.maEvent
);
171 case WrappedMouseEvent::EXITED
:
172 rListener
->mouseExited( rEvent
.maEvent
);
176 return true; // continue calling listeners
179 ///////////////////////////////////////////////////////////////////////
180 // SlideShowViewMouseMotionListeners
181 ///////////////////////////////////////////////////////////////////////
183 SlideShowViewMouseMotionListeners::SlideShowViewMouseMotionListeners( ::osl::Mutex
& rMutex
) :
184 SlideShowViewMouseMotionListeners_Base( rMutex
)
188 bool SlideShowViewMouseMotionListeners::implTypedNotify( const Reference
< awt::XMouseMotionListener
>& rListener
,
189 const WrappedMouseMotionEvent
& rEvent
) throw( uno::Exception
)
191 switch( rEvent
.meType
)
193 case WrappedMouseMotionEvent::DRAGGED
:
194 rListener
->mouseDragged( rEvent
.maEvent
);
197 case WrappedMouseMotionEvent::MOVED
:
198 rListener
->mouseMoved( rEvent
.maEvent
);
202 return true; // continue calling listeners
205 ///////////////////////////////////////////////////////////////////////
207 ///////////////////////////////////////////////////////////////////////
209 SlideShowView::SlideShowView( ShowWindow
& rOutputWindow
,
210 SdDrawDocument
* pDoc
,
211 AnimationMode eAnimationMode
,
212 SlideshowImpl
* pSlideShow
,
214 : SlideShowView_Base( m_aMutex
),
215 mpCanvas( ::cppcanvas::VCLFactory::getInstance().createSpriteCanvas( rOutputWindow
) ),
216 mxWindow( VCLUnoHelper::GetInterface( &rOutputWindow
), uno::UNO_QUERY_THROW
),
217 mxWindowPeer( mxWindow
, uno::UNO_QUERY_THROW
),
219 mpSlideShow( pSlideShow
),
220 mrOutputWindow( rOutputWindow
),
221 mpViewListeners( new SlideShowViewListeners( m_aMutex
) ),
222 mpPaintListeners( new SlideShowViewPaintListeners( m_aMutex
) ),
223 mpMouseListeners( new SlideShowViewMouseListeners( m_aMutex
) ),
224 mpMouseMotionListeners( new SlideShowViewMouseMotionListeners( m_aMutex
) ),
226 mbIsMouseMotionListener( false ),
227 meAnimationMode( eAnimationMode
),
228 mbFirstPaint( true ),
229 mbFullScreen( bFullScreen
),
230 mbMousePressedEaten( false )
235 /// Dispose all internal references
236 void SAL_CALL
SlideShowView::dispose() throw (RuntimeException
)
238 ::osl::MutexGuard
aGuard( m_aMutex
);
242 // deregister listeners
245 mxWindow
->removeWindowListener( this );
246 mxWindow
->removeMouseListener( this );
248 if( mbIsMouseMotionListener
)
249 mxWindow
->removeMouseMotionListener( this );
255 // clear all listener containers
256 disposing( lang::EventObject() );
259 WeakComponentImplHelperBase::dispose();
262 /// Disposing our broadcaster
263 void SAL_CALL
SlideShowView::disposing( const lang::EventObject
& ) throw(RuntimeException
)
265 ::osl::MutexGuard
aGuard( m_aMutex
);
267 // notify all listeners that _we_ are going down (send a disposing()),
268 // then delete listener containers:
269 lang::EventObject
const evt( static_cast<OWeakObject
*>(this) );
270 if (mpViewListeners
.get() != 0) {
271 mpViewListeners
->disposing( evt
);
272 mpViewListeners
.reset();
274 if (mpPaintListeners
.get() != 0) {
275 mpPaintListeners
->disposing( evt
);
276 mpPaintListeners
.reset();
278 if (mpMouseListeners
.get() != 0) {
279 mpMouseListeners
->disposing( evt
);
280 mpMouseListeners
.reset();
282 if (mpMouseMotionListeners
.get() != 0) {
283 mpMouseMotionListeners
->disposing( evt
);
284 mpMouseMotionListeners
.reset();
288 void SAL_CALL
SlideShowView::paint( const awt::PaintEvent
& e
) throw (RuntimeException
)
290 ::osl::ClearableMutexGuard
aGuard( m_aMutex
);
294 mbFirstPaint
= false;
295 SlideshowImpl
* pSlideShow
= mpSlideShow
;
298 pSlideShow
->onFirstPaint();
302 // Change event source, to enable listeners to match event
304 awt::PaintEvent
aEvent( e
);
305 aEvent
.Source
= static_cast< ::cppu::OWeakObject
* >( this );
306 mpPaintListeners
->notify( aEvent
);
307 updateimpl( aGuard
, mpSlideShow
); // warning: clears guard!
311 // XSlideShowView methods
312 Reference
< rendering::XSpriteCanvas
> SAL_CALL
SlideShowView::getCanvas( ) throw (RuntimeException
)
314 ::osl::MutexGuard
aGuard( m_aMutex
);
316 return mpCanvas
.get() ? mpCanvas
->getUNOSpriteCanvas() : Reference
< rendering::XSpriteCanvas
>();
319 void SAL_CALL
SlideShowView::clear() throw (::com::sun::star::uno::RuntimeException
)
321 // paint background in black
322 ::osl::MutexGuard
aGuard( m_aMutex
);
323 ::vos::OGuard
aSolarGuard( Application::GetSolarMutex() );
325 // fill the bounds rectangle in black
326 // ----------------------------------
328 const Size
aWindowSize( mrOutputWindow
.GetSizePixel() );
330 ::basegfx::B2DPolygon
aPoly( ::basegfx::tools::createPolygonFromRect(
331 ::basegfx::B2DRectangle(0.0,0.0,
333 aWindowSize
.Height() ) ) );
334 ::cppcanvas::PolyPolygonSharedPtr
pPolyPoly(
335 ::cppcanvas::BaseGfxFactory::getInstance().createPolyPolygon( mpCanvas
, aPoly
) );
337 if( pPolyPoly
.get() )
339 pPolyPoly
->setRGBAFillColor( 0x000000FFU
);
344 geometry::AffineMatrix2D SAL_CALL
SlideShowView::getTransformation( ) throw (RuntimeException
)
346 ::osl::MutexGuard
aGuard( m_aMutex
);
347 ::vos::OGuard
aSolarGuard( Application::GetSolarMutex() );
349 const Size
& rTmpSize( mrOutputWindow
.GetSizePixel() );
351 if (rTmpSize
.Width()<=0 || rTmpSize
.Height()<=0)
353 return geometry::AffineMatrix2D (1,0,0,0,1,0);
356 const Size
aWindowSize( mrOutputWindow
.GetSizePixel() );
357 Size
aOutputSize( aWindowSize
);
359 if( meAnimationMode
!= ANIMATIONMODE_SHOW
)
361 aOutputSize
.Width() = (long)( aOutputSize
.Width() / 1.03 );
362 aOutputSize
.Height() = (long)( aOutputSize
.Height() / 1.03 );
365 SdPage
* pP
= mpDoc
->GetSdPage( 0, PK_STANDARD
);
366 Size
aPageSize( pP
->GetSize() );
368 const double page_ratio
= (double)aPageSize
.Width() / (double)aPageSize
.Height();
369 const double output_ratio
= (double)aOutputSize
.Width() / (double)aOutputSize
.Height();
371 if( page_ratio
> output_ratio
)
373 aOutputSize
.Height() = ( aOutputSize
.Width() * aPageSize
.Height() ) / aPageSize
.Width();
375 else if( page_ratio
< output_ratio
)
377 aOutputSize
.Width() = ( aOutputSize
.Height() * aPageSize
.Width() ) / aPageSize
.Height();
380 Point
aOutputOffset( ( aWindowSize
.Width() - aOutputSize
.Width() ) >> 1,
381 ( aWindowSize
.Height() - aOutputSize
.Height() ) >> 1 );
383 // Reduce available width by one, as the slides might actually
384 // render one pixel wider and higher as aPageSize below specifies
385 // (when shapes of page size have visible border lines)
386 aOutputSize
.Width() --;
387 aOutputSize
.Height() --;
389 ::basegfx::B2DHomMatrix aMatrix
;
391 maPresentationArea
= Rectangle( aOutputOffset
, aOutputSize
);
392 mrOutputWindow
.SetPresentationArea( maPresentationArea
);
394 // scale presentation into available window rect (minus 10%)
395 aMatrix
.scale( aOutputSize
.Width(), aOutputSize
.Height() );
397 // center in the window
398 aMatrix
.translate( aOutputOffset
.X(), aOutputOffset
.Y() );
400 geometry::AffineMatrix2D aRes
;
402 return ::basegfx::unotools::affineMatrixFromHomMatrix( aRes
, aMatrix
);
405 void SAL_CALL
SlideShowView::addTransformationChangedListener( const Reference
< util::XModifyListener
>& xListener
) throw (RuntimeException
)
407 ::osl::MutexGuard
aGuard( m_aMutex
);
409 if( mpViewListeners
.get() )
410 mpViewListeners
->addListener( xListener
);
413 void SAL_CALL
SlideShowView::removeTransformationChangedListener( const Reference
< util::XModifyListener
>& xListener
) throw (RuntimeException
)
415 ::osl::MutexGuard
aGuard( m_aMutex
);
417 if( mpViewListeners
.get() )
418 mpViewListeners
->removeListener( xListener
);
421 void SAL_CALL
SlideShowView::addPaintListener( const Reference
< awt::XPaintListener
>& xListener
) throw (RuntimeException
)
423 ::osl::MutexGuard
aGuard( m_aMutex
);
425 if( mpPaintListeners
.get() )
426 mpPaintListeners
->addTypedListener( xListener
);
429 void SAL_CALL
SlideShowView::removePaintListener( const Reference
< awt::XPaintListener
>& xListener
) throw (RuntimeException
)
431 ::osl::MutexGuard
aGuard( m_aMutex
);
433 if( mpPaintListeners
.get() )
434 mpPaintListeners
->removeTypedListener( xListener
);
437 void SAL_CALL
SlideShowView::addMouseListener( const Reference
< awt::XMouseListener
>& xListener
) throw (RuntimeException
)
439 ::osl::MutexGuard
aGuard( m_aMutex
);
441 if( mpMouseListeners
.get() )
442 mpMouseListeners
->addTypedListener( xListener
);
445 void SAL_CALL
SlideShowView::removeMouseListener( const Reference
< awt::XMouseListener
>& xListener
) throw (RuntimeException
)
447 ::osl::MutexGuard
aGuard( m_aMutex
);
449 if( mpMouseListeners
.get() )
450 mpMouseListeners
->removeTypedListener( xListener
);
453 void SAL_CALL
SlideShowView::addMouseMotionListener( const Reference
< awt::XMouseMotionListener
>& xListener
) throw (RuntimeException
)
455 ::osl::MutexGuard
aGuard( m_aMutex
);
457 if( !mbIsMouseMotionListener
&& mxWindow
.is() )
459 // delay motion event registration, until we really
461 mbIsMouseMotionListener
= true;
462 mxWindow
->addMouseMotionListener( this );
465 if( mpMouseMotionListeners
.get() )
466 mpMouseMotionListeners
->addTypedListener( xListener
);
469 void SAL_CALL
SlideShowView::removeMouseMotionListener( const Reference
< awt::XMouseMotionListener
>& xListener
) throw (RuntimeException
)
471 ::osl::MutexGuard
aGuard( m_aMutex
);
473 if( mpMouseMotionListeners
.get() )
474 mpMouseMotionListeners
->removeTypedListener( xListener
);
476 // TODO(P1): Might be nice to deregister for mouse motion
477 // events, when the last listener is gone.
480 void SAL_CALL
SlideShowView::setMouseCursor( sal_Int16 nPointerShape
) throw (RuntimeException
)
482 ::osl::MutexGuard
aGuard( m_aMutex
);
486 mxPointer
->setType( nPointerShape
);
488 if( mxWindowPeer
.is() )
489 mxWindowPeer
->setPointer( mxPointer
);
492 awt::Rectangle SAL_CALL
SlideShowView::getCanvasArea( ) throw (RuntimeException
)
494 awt::Rectangle aRectangle
;
497 return mxWindow
->getPosSize();
499 aRectangle
.X
= aRectangle
.Y
= aRectangle
.Width
= aRectangle
.Height
= 0;
504 void SlideShowView::updateimpl( ::osl::ClearableMutexGuard
& rGuard
, SlideshowImpl
* pSlideShow
)
508 ::rtl::Reference
< SlideshowImpl
> aSLGuard( pSlideShow
);
510 pSlideShow
->startUpdateTimer();
514 // XWindowListener methods
515 void SAL_CALL
SlideShowView::windowResized( const awt::WindowEvent
& e
) throw (RuntimeException
)
517 ::osl::ClearableMutexGuard
aGuard( m_aMutex
);
519 if( mpViewListeners
.get() )
521 // Change event source, to enable listeners to match event
523 awt::WindowEvent
aEvent( e
);
524 aEvent
.Source
= static_cast< ::cppu::OWeakObject
* >( this );
526 mpViewListeners
->notify( aEvent
);
527 updateimpl( aGuard
, mpSlideShow
); // warning: clears guard!
531 void SAL_CALL
SlideShowView::windowMoved( const awt::WindowEvent
& ) throw (RuntimeException
)
536 void SAL_CALL
SlideShowView::windowShown( const lang::EventObject
& ) throw (RuntimeException
)
541 void SAL_CALL
SlideShowView::windowHidden( const lang::EventObject
& ) throw (RuntimeException
)
546 // XMouseListener implementation
547 void SAL_CALL
SlideShowView::mousePressed( const awt::MouseEvent
& e
) throw (uno::RuntimeException
)
549 ::osl::ClearableMutexGuard
aGuard( m_aMutex
);
550 if( mpSlideShow
&& mpSlideShow
->isInputFreezed() )
552 mbMousePressedEaten
= true;
556 mbMousePressedEaten
= false;
558 // Change event source, to enable listeners to match event
560 WrappedMouseEvent aEvent
;
561 aEvent
.meType
= WrappedMouseEvent::PRESSED
;
563 aEvent
.maEvent
.Source
= static_cast< ::cppu::OWeakObject
* >( this );
565 if( mpMouseListeners
.get() )
566 mpMouseListeners
->notify( aEvent
);
567 updateimpl( aGuard
, mpSlideShow
); // warning: clears guard!
571 void SAL_CALL
SlideShowView::mouseReleased( const awt::MouseEvent
& e
) throw (uno::RuntimeException
)
573 ::osl::ClearableMutexGuard
aGuard( m_aMutex
);
574 if( mbMousePressedEaten
)
576 // if mouse button down was ignored, also ignore mouse button up
577 mbMousePressedEaten
= false;
579 else if( mpSlideShow
&& !mpSlideShow
->isInputFreezed() )
581 // Change event source, to enable listeners to match event
583 WrappedMouseEvent aEvent
;
584 aEvent
.meType
= WrappedMouseEvent::RELEASED
;
586 aEvent
.maEvent
.Source
= static_cast< ::cppu::OWeakObject
* >( this );
588 if( mpMouseListeners
.get() )
589 mpMouseListeners
->notify( aEvent
);
590 updateimpl( aGuard
, mpSlideShow
); // warning: clears guard!
594 void SAL_CALL
SlideShowView::mouseEntered( const awt::MouseEvent
& e
) throw (uno::RuntimeException
)
596 ::osl::ClearableMutexGuard
aGuard( m_aMutex
);
598 // Change event source, to enable listeners to match event
600 WrappedMouseEvent aEvent
;
601 aEvent
.meType
= WrappedMouseEvent::ENTERED
;
603 aEvent
.maEvent
.Source
= static_cast< ::cppu::OWeakObject
* >( this );
605 if( mpMouseListeners
.get() )
606 mpMouseListeners
->notify( aEvent
);
607 updateimpl( aGuard
, mpSlideShow
); // warning: clears guard!
610 void SAL_CALL
SlideShowView::mouseExited( const awt::MouseEvent
& e
) throw (uno::RuntimeException
)
612 ::osl::ClearableMutexGuard
aGuard( m_aMutex
);
614 // Change event source, to enable listeners to match event
616 WrappedMouseEvent aEvent
;
617 aEvent
.meType
= WrappedMouseEvent::EXITED
;
619 aEvent
.maEvent
.Source
= static_cast< ::cppu::OWeakObject
* >( this );
621 if( mpMouseListeners
.get() )
622 mpMouseListeners
->notify( aEvent
);
623 updateimpl( aGuard
, mpSlideShow
); // warning: clears guard!
626 // XMouseMotionListener implementation
627 void SAL_CALL
SlideShowView::mouseDragged( const awt::MouseEvent
& e
) throw (uno::RuntimeException
)
629 ::osl::ClearableMutexGuard
aGuard( m_aMutex
);
631 // Change event source, to enable listeners to match event
633 WrappedMouseMotionEvent aEvent
;
634 aEvent
.meType
= WrappedMouseMotionEvent::DRAGGED
;
636 aEvent
.maEvent
.Source
= static_cast< ::cppu::OWeakObject
* >( this );
638 if( mpMouseMotionListeners
.get() )
639 mpMouseMotionListeners
->notify( aEvent
);
640 updateimpl( aGuard
, mpSlideShow
); // warning: clears guard!
643 void SAL_CALL
SlideShowView::mouseMoved( const awt::MouseEvent
& e
) throw (uno::RuntimeException
)
645 ::osl::ClearableMutexGuard
aGuard( m_aMutex
);
647 // Change event source, to enable listeners to match event
649 WrappedMouseMotionEvent aEvent
;
650 aEvent
.meType
= WrappedMouseMotionEvent::MOVED
;
652 aEvent
.maEvent
.Source
= static_cast< ::cppu::OWeakObject
* >( this );
654 if( mpMouseMotionListeners
.get() )
655 mpMouseMotionListeners
->notify( aEvent
);
656 updateimpl( aGuard
, mpSlideShow
); // warning: clears guard!
659 void SlideShowView::init()
661 mxWindow
->addWindowListener( this );
662 mxWindow
->addMouseListener( this );
664 Reference
< lang::XMultiServiceFactory
> xFactory( ::comphelper::getProcessServiceFactory(),
665 uno::UNO_QUERY_THROW
);
668 mxPointer
.set( xFactory
->createInstance( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.awt.Pointer")) ),
673 // #i48939# only switch on kind of hacky scroll optimisation, when
674 // running fullscreen. this minimizes the probability that other
675 // windows partially cover the show.
680 Reference
< beans::XPropertySet
> xCanvasProps( getCanvas(),
681 uno::UNO_QUERY_THROW
);
682 xCanvasProps
->setPropertyValue(
683 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("UnsafeScrolling")),
684 uno::makeAny( true ) );
686 catch( uno::Exception
& )