1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_forms.hxx"
26 #include "richtextimplcontrol.hxx"
27 #include "textattributelistener.hxx"
28 #include "richtextengine.hxx"
29 #include <editeng/editeng.hxx>
30 #include <editeng/editview.hxx>
31 #include <editeng/eeitem.hxx>
32 #include <editeng/editstat.hxx>
33 #ifndef _SVX_SVXIDS_HRC
34 #include <svx/svxids.hrc>
35 #endif
36 #include <editeng/scripttypeitem.hxx>
37 
38 #include <editeng/editobj.hxx>
39 #include <svl/itempool.hxx>
40 #include <svl/itemset.hxx>
41 #include <tools/mapunit.hxx>
42 #include <vcl/window.hxx>
43 #include <vcl/svapp.hxx>
44 
45 #include <memory>
46 
47 #define EMPTY_PAPER_SIZE    0x7FFFFFFF
48 
49 //........................................................................
50 namespace frm
51 {
52 //........................................................................
53     //====================================================================
54     //= RichTextControlImpl
55     //====================================================================
56     //--------------------------------------------------------------------
RichTextControlImpl(Control * _pAntiImpl,RichTextEngine * _pEngine,ITextAttributeListener * _pTextAttrListener,ITextSelectionListener * _pSelectionListener)57     RichTextControlImpl::RichTextControlImpl( Control* _pAntiImpl, RichTextEngine* _pEngine, ITextAttributeListener* _pTextAttrListener, ITextSelectionListener* _pSelectionListener )
58         :m_pAntiImpl            ( _pAntiImpl          )
59         ,m_pViewport            ( NULL                )
60         ,m_pHScroll             ( NULL                )
61         ,m_pVScroll             ( NULL                )
62         ,m_pScrollCorner        ( NULL                )
63         ,m_pEngine              ( _pEngine            )
64         ,m_pView                ( NULL                )
65         ,m_pTextAttrListener    ( _pTextAttrListener  )
66         ,m_pSelectionListener   ( _pSelectionListener )
67         ,m_bHasEverBeenShown    ( false               )
68     {
69         OSL_ENSURE( m_pAntiImpl, "RichTextControlImpl::RichTextControlImpl: invalid window!" );
70         OSL_ENSURE( m_pEngine,   "RichTextControlImpl::RichTextControlImpl: invalid edit engine! This will *definitely* crash!" );
71 
72         m_pViewport = new RichTextViewPort( m_pAntiImpl );
73         m_pViewport->setAttributeInvalidationHandler( LINK( this, RichTextControlImpl, OnInvalidateAllAttributes ) );
74         m_pViewport->Show();
75 
76         // ensure that both the window and the reference device have the same map unit
77         MapMode aRefDeviceMapMode( m_pEngine->GetRefDevice()->GetMapMode() );
78         m_pAntiImpl->SetMapMode( aRefDeviceMapMode );
79         m_pViewport->SetMapMode( aRefDeviceMapMode );
80 
81         m_pView = new EditView( m_pEngine, m_pViewport );
82         m_pEngine->InsertView( m_pView );
83         m_pViewport->setView( *m_pView );
84 
85         m_pEngine->registerEngineStatusListener( this );
86 
87         {
88             sal_uLong nViewControlWord = m_pView->GetControlWord();
89             nViewControlWord |= EV_CNTRL_AUTOSCROLL;
90             m_pView->SetControlWord( nViewControlWord );
91         }
92 
93         // ensure that it's initially scrolled to the upper left
94         m_pView->SetVisArea( Rectangle( Point( ), m_pViewport->GetOutputSize() ) );
95 
96         ensureScrollbars();
97 
98         m_pAntiImpl->SetBackground( Wallpaper( m_pAntiImpl->GetSettings().GetStyleSettings().GetFieldColor() ) );
99     }
100 
101     //--------------------------------------------------------------------
~RichTextControlImpl()102     RichTextControlImpl::~RichTextControlImpl( )
103     {
104         m_pEngine->RemoveView( m_pView );
105         m_pEngine->revokeEngineStatusListener( this );
106         delete m_pView;
107         delete m_pViewport;
108         delete m_pHScroll;
109         delete m_pVScroll;
110         delete m_pScrollCorner;
111     }
112 
113     //--------------------------------------------------------------------
implUpdateAttribute(AttributeHandlerPool::const_iterator _pHandler)114     void RichTextControlImpl::implUpdateAttribute( AttributeHandlerPool::const_iterator _pHandler )
115     {
116         if  (  ( _pHandler->first == SID_ATTR_CHAR_WEIGHT )
117             || ( _pHandler->first == SID_ATTR_CHAR_POSTURE )
118             || ( _pHandler->first == SID_ATTR_CHAR_FONT )
119             || ( _pHandler->first == SID_ATTR_CHAR_FONTHEIGHT )
120             )
121         {
122             // these are attributes whose value depends on the current script type.
123             // I.e., in real, there are *three* items in the ItemSet: One for each script
124             // type (Latin, Asian, Complex). However, if we have an observer who is interested
125             // in the state of this attribute, we have to kind of *merge* the three attributes
126             // to only one.
127             // This is useful in case the observer is for instance a toolbox which contains only
128             // an, e.g., "bold" slot, and thus not interested in the particular script type of the
129             // current selection.
130             SvxScriptSetItem aNormalizedSet( (WhichId)_pHandler->first, *m_pView->GetAttribs().GetPool() );
131             normalizeScriptDependentAttribute( aNormalizedSet );
132 
133             implCheckUpdateCache( _pHandler->first, _pHandler->second->getState( aNormalizedSet.GetItemSet() ) );
134         }
135         else
136             implCheckUpdateCache( _pHandler->first, _pHandler->second->getState( m_pView->GetAttribs() ) );
137     }
138 
139     //--------------------------------------------------------------------
updateAttribute(AttributeId _nAttribute)140     void RichTextControlImpl::updateAttribute( AttributeId _nAttribute )
141     {
142         AttributeHandlerPool::const_iterator pHandler = m_aAttributeHandlers.find( _nAttribute );
143         if ( pHandler != m_aAttributeHandlers.end() )
144             implUpdateAttribute( pHandler );
145     }
146 
147     //--------------------------------------------------------------------
updateAllAttributes()148     void RichTextControlImpl::updateAllAttributes( )
149     {
150         for (   AttributeHandlerPool::const_iterator pHandler = m_aAttributeHandlers.begin();
151                 pHandler != m_aAttributeHandlers.end();
152                 ++pHandler
153             )
154         {
155             implUpdateAttribute( pHandler );
156         }
157 
158         // notify changes of the selection, if necessary
159         if ( m_pSelectionListener && m_pView )
160         {
161             ESelection aCurrentSelection = m_pView->GetSelection();
162             if ( !aCurrentSelection.IsEqual( m_aLastKnownSelection ) )
163             {
164                 m_aLastKnownSelection = aCurrentSelection;
165                 m_pSelectionListener->onSelectionChanged( m_aLastKnownSelection );
166             }
167         }
168     }
169 
170     //--------------------------------------------------------------------
getAttributeState(AttributeId _nAttributeId) const171     AttributeState RichTextControlImpl::getAttributeState( AttributeId _nAttributeId ) const
172     {
173         StateCache::const_iterator aCachedStatePos = m_aLastKnownStates.find( _nAttributeId );
174         if ( aCachedStatePos == m_aLastKnownStates.end() )
175         {
176             OSL_ENSURE( sal_False, "RichTextControlImpl::getAttributeState: Don't ask for the state of an attribute which I never encountered!" );
177             return AttributeState( eIndetermined );
178         }
179         return aCachedStatePos->second;
180     }
181 
182     //--------------------------------------------------------------------
executeAttribute(const SfxItemSet & _rCurrentAttribs,SfxItemSet & _rAttribs,AttributeId _nAttribute,const SfxPoolItem * _pArgument,ScriptType _nForScriptType)183     bool RichTextControlImpl::executeAttribute( const SfxItemSet& _rCurrentAttribs, SfxItemSet& _rAttribs, AttributeId _nAttribute, const SfxPoolItem* _pArgument, ScriptType _nForScriptType )
184     {
185         // let's see whether we have a handler for this attribute
186         AttributeHandlerPool::const_iterator aHandlerPos = m_aAttributeHandlers.find( _nAttribute );
187         if ( aHandlerPos != m_aAttributeHandlers.end() )
188         {
189             aHandlerPos->second->executeAttribute( _rCurrentAttribs, _rAttribs, _pArgument, _nForScriptType );
190             return true;
191         }
192         return false;
193     }
194 
195     //--------------------------------------------------------------------
enableAttributeNotification(AttributeId _nAttributeId,ITextAttributeListener * _pListener)196     void RichTextControlImpl::enableAttributeNotification( AttributeId _nAttributeId, ITextAttributeListener* _pListener )
197     {
198         AttributeHandlerPool::const_iterator aHandlerPos = m_aAttributeHandlers.find( _nAttributeId  );
199         if ( aHandlerPos == m_aAttributeHandlers.end() )
200         {
201             ::rtl::Reference< IAttributeHandler > aHandler = AttributeHandlerFactory::getHandlerFor( _nAttributeId, *m_pEngine->GetEmptyItemSet().GetPool() );
202             OSL_ENSURE( aHandler.is(), "RichTextControlImpl::enableAttributeNotification: no handler available for this attribute!" );
203             if ( !aHandler.is() )
204                 return;
205             OSL_POSTCOND( _nAttributeId == aHandler->getAttributeId(), "RichTextControlImpl::enableAttributeNotification: suspicious handler!" );
206 
207             aHandlerPos = m_aAttributeHandlers.insert( AttributeHandlerPool::value_type( _nAttributeId , aHandler ) ).first;
208         }
209 
210         // remember the listener
211         if ( _pListener )
212             m_aAttributeListeners.insert( AttributeListenerPool::value_type( _nAttributeId, _pListener ) );
213 
214         // update (and broadcast) the state of this attribute
215         updateAttribute( _nAttributeId );
216     }
217 
218     //--------------------------------------------------------------------
disableAttributeNotification(AttributeId _nAttributeId)219     void RichTextControlImpl::disableAttributeNotification( AttributeId _nAttributeId )
220     {
221         // forget the handler for this attribute
222         AttributeHandlerPool::iterator aHandlerPos = m_aAttributeHandlers.find( _nAttributeId );
223         if ( aHandlerPos != m_aAttributeHandlers.end() )
224             m_aAttributeHandlers.erase( aHandlerPos );
225 
226         // as well as the listener
227         AttributeListenerPool::iterator aListenerPos = m_aAttributeListeners.find( _nAttributeId );
228         if ( aListenerPos != m_aAttributeListeners.end() )
229             m_aAttributeListeners.erase( aListenerPos );
230     }
231 
232     //--------------------------------------------------------------------
normalizeScriptDependentAttribute(SvxScriptSetItem & _rScriptSetItem)233     void RichTextControlImpl::normalizeScriptDependentAttribute( SvxScriptSetItem& _rScriptSetItem )
234     {
235         _rScriptSetItem.GetItemSet().Put( m_pView->GetAttribs(), sal_False );
236         const SfxPoolItem* pNormalizedItem = _rScriptSetItem.GetItemOfScript( getSelectedScriptType() );
237 
238         WhichId nNormalizedWhichId = _rScriptSetItem.GetItemSet().GetPool()->GetWhich( _rScriptSetItem.Which() );
239         if ( pNormalizedItem )
240         {
241             SfxPoolItem* pProperWhich = pNormalizedItem->Clone();
242             pProperWhich->SetWhich( nNormalizedWhichId );
243             _rScriptSetItem.GetItemSet().Put( *pProperWhich );
244             DELETEZ( pProperWhich );
245         }
246         else
247             _rScriptSetItem.GetItemSet().InvalidateItem( nNormalizedWhichId );
248     }
249 
250     //--------------------------------------------------------------------
implCheckUpdateCache(AttributeId _nAttribute,const AttributeState & _rState)251     void RichTextControlImpl::implCheckUpdateCache( AttributeId _nAttribute, const AttributeState& _rState )
252     {
253         StateCache::iterator aCachePos = m_aLastKnownStates.find( _nAttribute );
254         if ( aCachePos == m_aLastKnownStates.end() )
255         {   // nothing known about this attribute, yet
256             m_aLastKnownStates.insert( StateCache::value_type( _nAttribute, _rState ) );
257         }
258         else
259         {
260             if ( aCachePos->second == _rState )
261             {
262                 // nothing to do
263                 return;
264             }
265             aCachePos->second = _rState;
266         }
267 
268         // is there a dedicated listener for this particular attribute?
269         AttributeListenerPool::const_iterator aListenerPos = m_aAttributeListeners.find( _nAttribute );
270         if ( aListenerPos != m_aAttributeListeners.end( ) )
271             aListenerPos->second->onAttributeStateChanged( _nAttribute, _rState );
272 
273         // call our global listener, if there is one
274         if ( m_pTextAttrListener )
275             m_pTextAttrListener->onAttributeStateChanged( _nAttribute, _rState );
276     }
277 
278     //--------------------------------------------------------------------
getSelectedScriptType() const279     ScriptType RichTextControlImpl::getSelectedScriptType() const
280     {
281         ScriptType nScript = m_pView->GetSelectedScriptType();
282         if ( !nScript )
283             nScript = SvtLanguageOptions::GetScriptTypeOfLanguage( Application::GetSettings().GetLanguage() );
284         return nScript;
285     }
286 
287     //--------------------------------------------------------------------
EditEngineStatusChanged(const EditStatus & _rStatus)288     void RichTextControlImpl::EditEngineStatusChanged( const EditStatus& _rStatus )
289     {
290         sal_uLong nStatusWord( _rStatus.GetStatusWord() );
291         if  (   ( nStatusWord & EE_STAT_TEXTWIDTHCHANGED )
292             ||  ( nStatusWord & EE_STAT_TEXTHEIGHTCHANGED )
293             )
294         {
295             if ( ( nStatusWord & EE_STAT_TEXTHEIGHTCHANGED ) && windowHasAutomaticLineBreak() )
296                 m_pEngine->SetPaperSize( Size( m_pEngine->GetPaperSize().Width(), m_pEngine->GetTextHeight() ) );
297 
298             updateScrollbars();
299         }
300 
301         bool bHScroll = 0 != ( nStatusWord & EE_STAT_HSCROLL );
302         bool bVScroll = 0 != ( nStatusWord & EE_STAT_VSCROLL );
303 
304         // In case of *no* automatic line breaks, we also need to check for the *range* here.
305         // Normally, we would do this only after a EE_STAT_TEXTWIDTHCHANGED. However, due to a bug
306         // in the EditEngine (I believe so) this is not fired when the engine does not have
307         // the AutoPaperSize bits set.
308         // So in order to be properly notified, we would need the AutoPaperSize. But, with
309         // AutoPaperSize, other things do not work anymore: Either, when we set a MaxAutoPaperSize,
310         // then the view does automatic soft line breaks at the paper end - which we definitely do
311         // want. Or, if we did not set a MaxAutoPaperSize, then the view does not automatically scroll
312         // anymore in horizontal direction.
313         // So this is some kind of lose-lose situation ... :(
314         if ( !windowHasAutomaticLineBreak() && bHScroll )
315         {
316             updateScrollbars();
317             return;
318         }
319 
320         if ( bHScroll && m_pHScroll )
321             m_pHScroll->SetThumbPos( m_pView->GetVisArea().Left() );
322         if ( bVScroll && m_pVScroll )
323             m_pVScroll->SetThumbPos( m_pView->GetVisArea().Top() );
324     }
325 
326     //--------------------------------------------------------------------
327     IMPL_LINK( RichTextControlImpl, OnInvalidateAllAttributes, void*, /*_pNotInterestedIn*/ )
328     {
329         updateAllAttributes();
330         return 0L;
331     }
332 
333     //--------------------------------------------------------------------
IMPL_LINK(RichTextControlImpl,OnHScroll,ScrollBar *,_pScrollbar)334     IMPL_LINK( RichTextControlImpl, OnHScroll, ScrollBar*, _pScrollbar )
335     {
336         m_pView->Scroll( -_pScrollbar->GetDelta(), 0, RGCHK_PAPERSZ1 );
337         return 0L;
338     }
339 
340     //--------------------------------------------------------------------
IMPL_LINK(RichTextControlImpl,OnVScroll,ScrollBar *,_pScrollbar)341     IMPL_LINK( RichTextControlImpl, OnVScroll, ScrollBar*, _pScrollbar )
342     {
343         m_pView->Scroll( 0, -_pScrollbar->GetDelta(), RGCHK_PAPERSZ1 );
344         return 0L;
345     }
346 
347     //--------------------------------------------------------------------
ensureScrollbars()348     void RichTextControlImpl::ensureScrollbars()
349     {
350         bool bNeedVScroll = 0 != ( m_pAntiImpl->GetStyle() & WB_VSCROLL );
351         bool bNeedHScroll = 0 != ( m_pAntiImpl->GetStyle() & WB_HSCROLL );
352 
353         if ( ( bNeedVScroll == hasVScrollBar() ) && ( bNeedHScroll == hasHScrollBar( ) ) )
354             // nothing to do
355             return;
356 
357         // create or delete the scrollbars, as necessary
358         if ( !bNeedVScroll )
359         {
360             delete m_pVScroll;
361             m_pVScroll = NULL;
362         }
363         else
364         {
365             m_pVScroll = new ScrollBar( m_pAntiImpl, WB_VSCROLL | WB_DRAG | WB_REPEAT );
366             m_pVScroll->SetScrollHdl ( LINK( this, RichTextControlImpl, OnVScroll ) );
367             m_pVScroll->Show();
368         }
369 
370         if ( !bNeedHScroll )
371         {
372             delete m_pHScroll;
373             m_pHScroll = NULL;
374         }
375         else
376         {
377             m_pHScroll = new ScrollBar( m_pAntiImpl, WB_HSCROLL | WB_DRAG | WB_REPEAT );
378             m_pHScroll->SetScrollHdl ( LINK( this, RichTextControlImpl, OnHScroll ) );
379             m_pHScroll->Show();
380         }
381 
382         if ( m_pHScroll && m_pVScroll )
383         {
384             delete m_pScrollCorner;
385             m_pScrollCorner = new ScrollBarBox( m_pAntiImpl );
386             m_pScrollCorner->Show();
387         }
388         else
389         {
390             delete m_pScrollCorner;
391             m_pScrollCorner = NULL;
392         }
393 
394         layoutWindow();
395     }
396 
397     //--------------------------------------------------------------------
ensureLineBreakSetting()398     void RichTextControlImpl::ensureLineBreakSetting()
399     {
400         if ( !windowHasAutomaticLineBreak() )
401             m_pEngine->SetPaperSize( Size( EMPTY_PAPER_SIZE, EMPTY_PAPER_SIZE ) );
402 
403         layoutWindow();
404     }
405 
406     //--------------------------------------------------------------------
layoutWindow()407     void RichTextControlImpl::layoutWindow()
408     {
409         if ( !m_bHasEverBeenShown )
410             // no need to do anything. Especially, no need to set the paper size on the
411             // EditEngine to anything ....
412             return;
413 
414         const StyleSettings& rStyleSettings = m_pAntiImpl->GetSettings().GetStyleSettings();
415 
416         long nScrollBarWidth = m_pVScroll ? rStyleSettings.GetScrollBarSize() : 0;
417         long nScrollBarHeight = m_pHScroll ? rStyleSettings.GetScrollBarSize() : 0;
418 
419         if ( m_pAntiImpl->IsZoom() )
420         {
421             nScrollBarWidth = m_pAntiImpl->CalcZoom( nScrollBarWidth );
422             nScrollBarHeight = m_pAntiImpl->CalcZoom( nScrollBarHeight );
423         }
424 
425         // the overall size we can use
426         Size aPlaygroundSizePixel( m_pAntiImpl->GetOutputSizePixel() );
427 
428         // the size of the viewport - note that the viewport does *not* occupy all the place
429         // which is left when subtracting the scrollbar width/height
430         Size aViewportPlaygroundPixel( aPlaygroundSizePixel );
431         aViewportPlaygroundPixel.Width() = ::std::max( long( 10 ), long( aViewportPlaygroundPixel.Width() - nScrollBarWidth ) );
432         aViewportPlaygroundPixel.Height() = ::std::max( long( 10 ), long( aViewportPlaygroundPixel.Height() - nScrollBarHeight ) );
433         Size aViewportPlaygroundLogic( m_pViewport->PixelToLogic( aViewportPlaygroundPixel ) );
434 
435         const long nOffset = 2;
436         Size aViewportSizePixel( aViewportPlaygroundPixel.Width() - 2 * nOffset, aViewportPlaygroundPixel.Height() - 2 * nOffset );
437         Size aViewportSizeLogic( m_pViewport->PixelToLogic( aViewportSizePixel ) );
438 
439         // position the viewport
440         m_pViewport->SetPosSizePixel( Point( nOffset, nOffset ), aViewportSizePixel );
441         // position the scrollbars
442         if ( m_pVScroll )
443             m_pVScroll->SetPosSizePixel( Point( aViewportPlaygroundPixel.Width(), 0 ), Size( nScrollBarWidth, aViewportPlaygroundPixel.Height() ) );
444         if ( m_pHScroll )
445             m_pHScroll->SetPosSizePixel( Point( 0, aViewportPlaygroundPixel.Height() ), Size( aViewportPlaygroundPixel.Width(), nScrollBarHeight ) );
446         if ( m_pScrollCorner )
447             m_pScrollCorner->SetPosSizePixel( Point( aViewportPlaygroundPixel.Width(), aViewportPlaygroundPixel.Height() ), Size( nScrollBarWidth, nScrollBarHeight ) );
448 
449         // paper size
450         if ( windowHasAutomaticLineBreak() )
451             m_pEngine->SetPaperSize( Size( aViewportSizeLogic.Width(), m_pEngine->GetTextHeight() ) );
452 
453         // output area of the view
454         m_pView->SetOutputArea( Rectangle( Point( ), aViewportSizeLogic ) );
455         m_pView->SetVisArea( Rectangle( Point( ), aViewportSizeLogic ) );
456 
457         if ( m_pVScroll )
458         {
459             m_pVScroll->SetVisibleSize( aViewportPlaygroundLogic.Height() );
460 
461             // the default height of a text line ....
462             long nFontHeight = m_pEngine->GetStandardFont(0).GetSize().Height();
463             // ... is the scroll size for the vertical scrollbar
464             m_pVScroll->SetLineSize( nFontHeight );
465             // the viewport width, minus one line, is the page scroll size
466             m_pVScroll->SetPageSize( ::std::max( nFontHeight, aViewportPlaygroundLogic.Height() - nFontHeight ) );
467         }
468 
469         // the font width
470         if ( m_pHScroll )
471         {
472             m_pHScroll->SetVisibleSize( aViewportPlaygroundLogic.Width() );
473 
474             long nFontWidth = m_pEngine->GetStandardFont(0).GetSize().Width();
475             if ( !nFontWidth )
476             {
477                 m_pViewport->Push( PUSH_FONT );
478                 m_pViewport->SetFont( m_pEngine->GetStandardFont(0) );
479                 nFontWidth = m_pViewport->GetTextWidth( String( RTL_CONSTASCII_USTRINGPARAM( "x" ) ) );
480                 m_pViewport->Pop();
481             }
482             // ... is the scroll size for the horizontal scrollbar
483             m_pHScroll->SetLineSize( 5 * nFontWidth );
484             // the viewport height, minus one character, is the page scroll size
485             m_pHScroll->SetPageSize( ::std::max( nFontWidth, aViewportPlaygroundLogic.Width() - nFontWidth ) );
486         }
487 
488         // update range and position of the scrollbars
489         updateScrollbars();
490     }
491 
492     //--------------------------------------------------------------------
updateScrollbars()493     void RichTextControlImpl::updateScrollbars()
494     {
495         if ( m_pVScroll )
496         {
497             long nOverallTextHeight = m_pEngine->GetTextHeight();
498             m_pVScroll->SetRange( Range( 0, nOverallTextHeight ) );
499             m_pVScroll->SetThumbPos( m_pView->GetVisArea().Top() );
500         }
501 
502         if ( m_pHScroll )
503         {
504             Size aPaperSize( m_pEngine->GetPaperSize() );
505             long nOverallTextWidth = ( aPaperSize.Width() == EMPTY_PAPER_SIZE ) ? m_pEngine->CalcTextWidth() : aPaperSize.Width();
506             m_pHScroll->SetRange( Range( 0, nOverallTextWidth ) );
507             m_pHScroll->SetThumbPos( m_pView->GetVisArea().Left() );
508         }
509     }
510 
511     //--------------------------------------------------------------------
notifyInitShow()512     void RichTextControlImpl::notifyInitShow()
513     {
514         if ( !m_bHasEverBeenShown )
515         {
516             m_bHasEverBeenShown = true;
517             layoutWindow();
518         }
519     }
520 
521     //--------------------------------------------------------------------
notifyStyleChanged()522     void RichTextControlImpl::notifyStyleChanged()
523     {
524         ensureScrollbars();
525         ensureLineBreakSetting();
526     }
527 
528     //--------------------------------------------------------------------
notifyZoomChanged()529     void RichTextControlImpl::notifyZoomChanged()
530     {
531         const Fraction& rZoom = m_pAntiImpl->GetZoom();
532 
533         MapMode aMapMode( m_pAntiImpl->GetMapMode() );
534         aMapMode.SetScaleX( rZoom );
535         aMapMode.SetScaleY( rZoom );
536         m_pAntiImpl->SetMapMode( aMapMode );
537 
538         m_pViewport->SetZoom( rZoom );
539         m_pViewport->SetMapMode( aMapMode );
540 
541         layoutWindow();
542     }
543 
544     //--------------------------------------------------------------------
windowHasAutomaticLineBreak()545     bool RichTextControlImpl::windowHasAutomaticLineBreak()
546     {
547         return ( m_pAntiImpl->GetStyle() & WB_WORDBREAK ) != 0;
548     }
549 
550     //--------------------------------------------------------------------
SetReadOnly(bool _bReadOnly)551     void RichTextControlImpl::SetReadOnly( bool _bReadOnly )
552     {
553         m_pView->SetReadOnly( _bReadOnly );
554     }
555 
556     //--------------------------------------------------------------------
IsReadOnly() const557     bool RichTextControlImpl::IsReadOnly() const
558     {
559         return m_pView->IsReadOnly( );
560     }
561 
562     //--------------------------------------------------------------------
563     namespace
564     {
lcl_inflate(Rectangle & _rRect,long _nInflateX,long _nInflateY)565         static void lcl_inflate( Rectangle& _rRect, long _nInflateX, long _nInflateY )
566         {
567             _rRect.Left() -= _nInflateX;
568             _rRect.Right() += _nInflateX;
569             _rRect.Top() -= _nInflateY;
570             _rRect.Bottom() += _nInflateY;
571         }
572     }
573     //--------------------------------------------------------------------
HandleCommand(const CommandEvent & _rEvent)574     long RichTextControlImpl::HandleCommand( const CommandEvent& _rEvent )
575     {
576         if (  ( _rEvent.GetCommand() == COMMAND_WHEEL )
577            || ( _rEvent.GetCommand() == COMMAND_STARTAUTOSCROLL )
578            || ( _rEvent.GetCommand() == COMMAND_AUTOSCROLL )
579            )
580         {
581             m_pAntiImpl->HandleScrollCommand( _rEvent, m_pHScroll, m_pVScroll );
582             return 1;
583         }
584         return 0;
585     }
586 
587     //--------------------------------------------------------------------
Draw(OutputDevice * _pDev,const Point & _rPos,const Size & _rSize,sal_uLong)588     void RichTextControlImpl::Draw( OutputDevice* _pDev, const Point& _rPos, const Size& _rSize, sal_uLong /*_nFlags*/ )
589     {
590         // need to normalize the map mode of the device - every paint operation on any device needs
591         // to use the same map mode
592         _pDev->Push( PUSH_MAPMODE | PUSH_LINECOLOR | PUSH_FILLCOLOR );
593 
594         // enforce our "normalize map mode" on the device
595         MapMode aRefMapMode( m_pEngine->GetRefDevice()->GetMapMode() );
596         MapMode aOriginalMapMode( _pDev->GetMapMode() );
597         MapMode aNormalizedMapMode( aRefMapMode.GetMapUnit(), aRefMapMode.GetOrigin(), aOriginalMapMode.GetScaleX(), aOriginalMapMode.GetScaleY() );
598         _pDev->SetMapMode( aNormalizedMapMode );
599 
600         // translate coordinates
601         Point aPos( _rPos );
602         Size aSize( _rSize );
603         if ( aOriginalMapMode.GetMapUnit() == MAP_PIXEL )
604         {
605             aPos = _pDev->PixelToLogic( _rPos, aNormalizedMapMode );
606             aSize = _pDev->PixelToLogic( _rSize, aNormalizedMapMode );
607         }
608         else
609         {
610             aPos = OutputDevice::LogicToLogic( _rPos, aOriginalMapMode, aNormalizedMapMode );
611             aSize = OutputDevice::LogicToLogic( _rSize, aOriginalMapMode, aNormalizedMapMode );
612         }
613 
614         Rectangle aPlayground( aPos, aSize );
615         Size aOnePixel( _pDev->PixelToLogic( Size( 1, 1 ) ) );
616         aPlayground.Right() -= aOnePixel.Width();
617         aPlayground.Bottom() -= aOnePixel.Height();
618 
619         // background
620         _pDev->SetLineColor();
621         _pDev->DrawRect( aPlayground );
622 
623         // do we need to draw a border?
624         bool bBorder = ( m_pAntiImpl->GetStyle() & WB_BORDER );
625         if ( bBorder )
626             _pDev->SetLineColor( m_pAntiImpl->GetSettings().GetStyleSettings().GetMonoColor() );
627         else
628             _pDev->SetLineColor();
629         _pDev->SetFillColor( m_pAntiImpl->GetBackground().GetColor() );
630         _pDev->DrawRect( aPlayground );
631 
632         if ( bBorder )
633             // don't draw the text over the border
634             lcl_inflate( aPlayground, -aOnePixel.Width(), -aOnePixel.Height() );
635 
636         // leave a space of one pixel between the "surroundings" of the control
637         // and the content
638         lcl_inflate( aPlayground, -aOnePixel.Width(), -aOnePixel.Height() );
639         lcl_inflate( aPlayground, -aOnePixel.Width(), -aOnePixel.Height() );
640 
641         // actually draw the content
642         m_pEngine->Draw( _pDev, aPlayground, Point(), sal_True );
643 
644         _pDev->Pop();
645     }
646 
647     //--------------------------------------------------------------------
SetBackgroundColor()648     void RichTextControlImpl::SetBackgroundColor( )
649     {
650         SetBackgroundColor( Application::GetSettings().GetStyleSettings().GetFieldColor() );
651     }
652 
653     //--------------------------------------------------------------------
SetBackgroundColor(const Color & _rColor)654     void RichTextControlImpl::SetBackgroundColor( const Color& _rColor )
655     {
656         Wallpaper aWallpaper( _rColor );
657         m_pAntiImpl->SetBackground( aWallpaper );
658         m_pViewport->SetBackground( aWallpaper );
659     }
660 
661     //--------------------------------------------------------------------
SetHideInactiveSelection(bool _bHide)662     void RichTextControlImpl::SetHideInactiveSelection( bool _bHide )
663     {
664         m_pViewport->SetHideInactiveSelection( _bHide );
665     }
666 
667     //--------------------------------------------------------------------
GetHideInactiveSelection() const668     bool RichTextControlImpl::GetHideInactiveSelection() const
669     {
670         return m_pViewport->GetHideInactiveSelection( );
671     }
672 
673 //........................................................................
674 }   // namespace frm
675 //........................................................................
676 
677