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