xref: /aoo41x/main/vcl/source/control/ctrl.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include <comphelper/processfactory.hxx>
32 
33 #include <tools/diagnose_ex.h>
34 #include <tools/rc.h>
35 
36 #include <vcl/svapp.hxx>
37 #include <vcl/event.hxx>
38 #include <vcl/ctrl.hxx>
39 #include <vcl/decoview.hxx>
40 #include <vcl/salnativewidgets.hxx>
41 
42 #include <textlayout.hxx>
43 #include <svdata.hxx>
44 #include <controldata.hxx>
45 
46 
47 using namespace vcl;
48 
49 // =======================================================================
50 
51 void Control::ImplInitControlData()
52 {
53     mbHasControlFocus	    = sal_False;
54     mpControlData   = new ImplControlData;
55 }
56 
57 // -----------------------------------------------------------------------
58 
59 Control::Control( WindowType nType ) :
60     Window( nType )
61 {
62     ImplInitControlData();
63 }
64 
65 // -----------------------------------------------------------------------
66 
67 Control::Control( Window* pParent, WinBits nStyle ) :
68     Window( WINDOW_CONTROL )
69 {
70     ImplInitControlData();
71     Window::ImplInit( pParent, nStyle, NULL );
72 }
73 
74 // -----------------------------------------------------------------------
75 
76 Control::Control( Window* pParent, const ResId& rResId ) :
77     Window( WINDOW_CONTROL )
78 {
79     ImplInitControlData();
80     rResId.SetRT( RSC_CONTROL );
81     WinBits nStyle = ImplInitRes( rResId );
82     ImplInit( pParent, nStyle, NULL );
83     ImplLoadRes( rResId );
84 
85     if ( !(nStyle & WB_HIDE) )
86         Show();
87 }
88 
89 // -----------------------------------------------------------------------
90 
91 Control::~Control()
92 {
93     delete mpControlData, mpControlData = NULL;
94 }
95 
96 // -----------------------------------------------------------------------
97 
98 void Control::GetFocus()
99 {
100     Window::GetFocus();
101 }
102 
103 // -----------------------------------------------------------------------
104 
105 void Control::LoseFocus()
106 {
107     Window::LoseFocus();
108 }
109 
110 // -----------------------------------------------------------------------
111 
112 void Control::Resize()
113 {
114     ImplClearLayoutData();
115     Window::Resize();
116 }
117 
118 // -----------------------------------------------------------------------
119 
120 void Control::FillLayoutData() const
121 {
122 }
123 
124 // -----------------------------------------------------------------------
125 
126 void Control::CreateLayoutData() const
127 {
128 	DBG_ASSERT( !mpControlData->mpLayoutData, "Control::CreateLayoutData: should be called with non-existent layout data only!" );
129 	mpControlData->mpLayoutData = new ::vcl::ControlLayoutData();
130 }
131 
132 // -----------------------------------------------------------------------
133 
134 bool Control::HasLayoutData() const
135 {
136     return mpControlData->mpLayoutData != NULL;
137 }
138 
139 // -----------------------------------------------------------------------
140 
141 ::vcl::ControlLayoutData* Control::GetLayoutData() const
142 {
143     return mpControlData->mpLayoutData;
144 }
145 
146 // -----------------------------------------------------------------------
147 
148 void Control::SetText( const String& rStr )
149 {
150     ImplClearLayoutData();
151     Window::SetText( rStr );
152 }
153 
154 // -----------------------------------------------------------------------
155 
156 Rectangle ControlLayoutData::GetCharacterBounds( long nIndex ) const
157 {
158     return (nIndex >= 0 && nIndex < (long) m_aUnicodeBoundRects.size()) ? m_aUnicodeBoundRects[ nIndex ] : Rectangle();
159 }
160 
161 
162 // -----------------------------------------------------------------------
163 
164 Rectangle Control::GetCharacterBounds( long nIndex ) const
165 {
166     if( !HasLayoutData() )
167         FillLayoutData();
168     return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->GetCharacterBounds( nIndex ) : Rectangle();
169 }
170 
171 // -----------------------------------------------------------------------
172 
173 long ControlLayoutData::GetIndexForPoint( const Point& rPoint ) const
174 {
175     long nIndex = -1;
176     for( long i = m_aUnicodeBoundRects.size()-1; i >= 0; i-- )
177     {
178         if( m_aUnicodeBoundRects[ i ].IsInside( rPoint ) )
179         {
180             nIndex = i;
181             break;
182         }
183     }
184     return nIndex;
185 }
186 
187 // -----------------------------------------------------------------------
188 
189 long Control::GetIndexForPoint( const Point& rPoint ) const
190 {
191     if( ! HasLayoutData() )
192         FillLayoutData();
193     return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->GetIndexForPoint( rPoint ) : -1;
194 }
195 
196 // -----------------------------------------------------------------------
197 
198 long ControlLayoutData::GetLineCount() const
199 {
200     long nLines = m_aLineIndices.size();
201     if( nLines == 0 && m_aDisplayText.Len() )
202         nLines = 1;
203     return nLines;
204 }
205 
206 // -----------------------------------------------------------------------
207 
208 long Control::GetLineCount() const
209 {
210     if( !HasLayoutData() )
211         FillLayoutData();
212     return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->GetLineCount() : 0;
213 }
214 
215 // -----------------------------------------------------------------------
216 
217 Pair ControlLayoutData::GetLineStartEnd( long nLine ) const
218 {
219     Pair aPair( -1, -1 );
220 
221     int nDisplayLines = m_aLineIndices.size();
222     if( nLine >= 0 && nLine < nDisplayLines )
223     {
224         aPair.A() = m_aLineIndices[nLine];
225         if( nLine+1 < nDisplayLines )
226             aPair.B() = m_aLineIndices[nLine+1]-1;
227         else
228             aPair.B() = m_aDisplayText.Len()-1;
229     }
230     else if( nLine == 0 && nDisplayLines == 0 && m_aDisplayText.Len() )
231     {
232         // special case for single line controls so the implementations
233         // in that case do not have to fill in the line indices
234         aPair.A() = 0;
235         aPair.B() = m_aDisplayText.Len()-1;
236     }
237     return aPair;
238 }
239 
240 // -----------------------------------------------------------------------
241 
242 Pair Control::GetLineStartEnd( long nLine ) const
243 {
244     if( !HasLayoutData() )
245         FillLayoutData();
246     return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->GetLineStartEnd( nLine ) : Pair( -1, -1 );
247 }
248 
249 // -----------------------------------------------------------------------
250 
251 long ControlLayoutData::ToRelativeLineIndex( long nIndex ) const
252 {
253     // is the index sensible at all ?
254     if( nIndex >= 0 && nIndex < m_aDisplayText.Len() )
255     {
256         int nDisplayLines = m_aLineIndices.size();
257         // if only 1 line exists, then absolute and relative index are
258         // identical -> do nothing
259         if( nDisplayLines > 1 )
260         {
261             int nLine;
262             for( nLine = nDisplayLines-1; nLine >= 0; nLine-- )
263             {
264                 if( m_aLineIndices[nLine] <= nIndex )
265                 {
266                     nIndex -= m_aLineIndices[nLine];
267                     break;
268                 }
269             }
270             if( nLine < 0 )
271             {
272                 DBG_ASSERT( nLine >= 0, "ToRelativeLineIndex failed" );
273                 nIndex = -1;
274             }
275         }
276     }
277     else
278         nIndex = -1;
279 
280     return nIndex;
281 }
282 
283 // -----------------------------------------------------------------------
284 
285 long Control::ToRelativeLineIndex( long nIndex ) const
286 {
287     if( !HasLayoutData() )
288         FillLayoutData();
289     return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->ToRelativeLineIndex( nIndex ) : -1;
290 }
291 
292 // -----------------------------------------------------------------------
293 
294 String Control::GetDisplayText() const
295 {
296     if( !HasLayoutData() )
297         FillLayoutData();
298     return mpControlData->mpLayoutData ? mpControlData->mpLayoutData->m_aDisplayText : GetText();
299 }
300 
301 // -----------------------------------------------------------------------
302 
303 long Control::Notify( NotifyEvent& rNEvt )
304 {
305     if ( rNEvt.GetType() == EVENT_GETFOCUS )
306     {
307         if ( !mbHasControlFocus )
308         {
309             mbHasControlFocus = sal_True;
310             StateChanged( STATE_CHANGE_CONTROL_FOCUS );
311             if ( ImplCallEventListenersAndHandler( VCLEVENT_CONTROL_GETFOCUS, maGetFocusHdl, this ) )
312                 // been destroyed within the handler
313                 return sal_True;
314         }
315     }
316     else
317     {
318         if ( rNEvt.GetType() == EVENT_LOSEFOCUS )
319         {
320             Window* pFocusWin = Application::GetFocusWindow();
321             if ( !pFocusWin || !ImplIsWindowOrChild( pFocusWin ) )
322             {
323                 mbHasControlFocus = sal_False;
324                 StateChanged( STATE_CHANGE_CONTROL_FOCUS );
325                 if ( ImplCallEventListenersAndHandler( VCLEVENT_CONTROL_LOSEFOCUS, maLoseFocusHdl, this ) )
326                     // been destroyed within the handler
327                     return sal_True;
328             }
329         }
330     }
331 
332     return Window::Notify( rNEvt );
333 }
334 
335 // -----------------------------------------------------------------------
336 
337 void Control::StateChanged( StateChangedType nStateChange )
338 {
339     if( nStateChange == STATE_CHANGE_INITSHOW	||
340         nStateChange == STATE_CHANGE_VISIBLE	||
341         nStateChange == STATE_CHANGE_FORMAT		||
342         nStateChange == STATE_CHANGE_ZOOM		||
343         nStateChange == STATE_CHANGE_BORDER		||
344         nStateChange == STATE_CHANGE_CONTROLFONT
345         )
346     {
347         ImplClearLayoutData();
348     }
349     Window::StateChanged( nStateChange );
350 }
351 
352 // -----------------------------------------------------------------------
353 
354 void Control::AppendLayoutData( const Control& rSubControl ) const
355 {
356     if( !rSubControl.HasLayoutData() )
357         rSubControl.FillLayoutData();
358     if( !rSubControl.HasLayoutData() || !rSubControl.mpControlData->mpLayoutData->m_aDisplayText.Len() )
359         return;
360 
361     long nCurrentIndex = mpControlData->mpLayoutData->m_aDisplayText.Len();
362     mpControlData->mpLayoutData->m_aDisplayText.Append( rSubControl.mpControlData->mpLayoutData->m_aDisplayText );
363     int nLines = rSubControl.mpControlData->mpLayoutData->m_aLineIndices.size();
364     int n;
365     mpControlData->mpLayoutData->m_aLineIndices.push_back( nCurrentIndex );
366     for( n = 1; n < nLines; n++ )
367         mpControlData->mpLayoutData->m_aLineIndices.push_back( rSubControl.mpControlData->mpLayoutData->m_aLineIndices[n] + nCurrentIndex );
368     int nRectangles = rSubControl.mpControlData->mpLayoutData->m_aUnicodeBoundRects.size();
369         Rectangle aRel = const_cast<Control&>(rSubControl).GetWindowExtentsRelative( const_cast<Control*>(this) );
370     for( n = 0; n < nRectangles; n++ )
371     {
372         Rectangle aRect = rSubControl.mpControlData->mpLayoutData->m_aUnicodeBoundRects[n];
373         aRect.Move( aRel.Left(), aRel.Top() );
374         mpControlData->mpLayoutData->m_aUnicodeBoundRects.push_back( aRect );
375     }
376 }
377 
378 // -----------------------------------------------------------------
379 
380 sal_Bool Control::ImplCallEventListenersAndHandler(  sal_uLong nEvent, const Link& rHandler, void* pCaller )
381 {
382     ImplDelData aCheckDelete;
383     ImplAddDel( &aCheckDelete );
384 
385     ImplCallEventListeners( nEvent );
386     if ( !aCheckDelete.IsDelete() )
387     {
388     	rHandler.Call( pCaller );
389 
390         if ( !aCheckDelete.IsDelete() )
391         {
392             ImplRemoveDel( &aCheckDelete );
393             return sal_False;
394         }
395     }
396     return sal_True;
397 }
398 
399 // -----------------------------------------------------------------
400 
401 void Control::SetLayoutDataParent( const Control* pParent ) const
402 {
403     if( HasLayoutData() )
404         mpControlData->mpLayoutData->m_pParent = pParent;
405 }
406 
407 // -----------------------------------------------------------------
408 
409 void Control::ImplClearLayoutData() const
410 {
411     delete mpControlData->mpLayoutData, mpControlData->mpLayoutData = NULL;
412 }
413 
414 // -----------------------------------------------------------------------
415 
416 void Control::ImplDrawFrame( OutputDevice* pDev, Rectangle& rRect )
417 {
418     // use a deco view to draw the frame
419     // However, since there happens a lot of magic there, we need to fake some (style) settings
420     // on the device
421     AllSettings aOriginalSettings( pDev->GetSettings() );
422 
423     AllSettings aNewSettings( aOriginalSettings );
424     StyleSettings aStyle( aNewSettings.GetStyleSettings() );
425 
426     // The *only known* clients of the Draw methods of the various VCL-controls are form controls:
427     // During print preview, and during printing, Draw is called. Thus, drawing always happens with a
428     // mono (colored) border
429     aStyle.SetOptions( aStyle.GetOptions() | STYLE_OPTION_MONO );
430     aStyle.SetMonoColor( GetSettings().GetStyleSettings().GetMonoColor() );
431 
432     aNewSettings.SetStyleSettings( aStyle );
433     // #i67023# do not call data changed listeners for this fake
434     // since they may understandably invalidate on settings changed
435     pDev->OutputDevice::SetSettings( aNewSettings );
436 
437     DecorationView aDecoView( pDev );
438     rRect = aDecoView.DrawFrame( rRect, FRAME_DRAW_WINDOWBORDER );
439 
440     pDev->OutputDevice::SetSettings( aOriginalSettings );
441 }
442 
443 // -----------------------------------------------------------------------
444 
445 void Control::DataChanged( const DataChangedEvent& rDCEvt)
446 {
447     // we don't want to loose some style settings for controls created with the
448     // toolkit
449     if ( IsCreatedWithToolkit() &&
450          (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
451          (rDCEvt.GetFlags() & SETTINGS_STYLE) )
452     {
453         AllSettings     aSettings = GetSettings();
454         StyleSettings   aStyleSettings = aSettings.GetStyleSettings();
455         sal_uLong           nOldOptions = rDCEvt.GetOldSettings()->GetStyleSettings().GetOptions();
456         sal_uLong           nNewOptions = aStyleSettings.GetOptions();
457 
458         if ( !(nNewOptions & STYLE_OPTION_MONO) && ( nOldOptions & STYLE_OPTION_MONO ) )
459         {
460             nNewOptions |= STYLE_OPTION_MONO;
461             aStyleSettings.SetOptions( nNewOptions );
462             aStyleSettings.SetMonoColor( rDCEvt.GetOldSettings()->GetStyleSettings().GetMonoColor() );
463             aSettings.SetStyleSettings( aStyleSettings );
464             SetSettings( aSettings );
465         }
466     }
467 }
468 
469 // -----------------------------------------------------------------
470 
471 ControlLayoutData::~ControlLayoutData()
472 {
473     if( m_pParent )
474         m_pParent->ImplClearLayoutData();
475 }
476 
477 // -----------------------------------------------------------------
478 
479 Size Control::GetOptimalSize(WindowSizeType eType) const
480 {
481     switch (eType) {
482     case WINDOWSIZE_MINIMUM:
483         return Size( GetTextWidth( GetText() ) + 2 * 12,
484                      GetTextHeight() + 2 * 6 );
485     case WINDOWSIZE_PREFERRED:
486         return GetOptimalSize( WINDOWSIZE_MINIMUM );
487     case WINDOWSIZE_MAXIMUM:
488     default:
489         return Size( LONG_MAX, LONG_MAX );
490     }
491 }
492 
493 // -----------------------------------------------------------------
494 
495 void Control::SetReferenceDevice( OutputDevice* _referenceDevice )
496 {
497     if ( mpControlData->mpReferenceDevice == _referenceDevice )
498         return;
499 
500     mpControlData->mpReferenceDevice = _referenceDevice;
501     Invalidate();
502 }
503 
504 // -----------------------------------------------------------------
505 
506 OutputDevice* Control::GetReferenceDevice() const
507 {
508     return mpControlData->mpReferenceDevice;
509 }
510 
511 // -----------------------------------------------------------------
512 
513 const Font& Control::GetCanonicalFont( const StyleSettings& _rStyle ) const
514 {
515     return _rStyle.GetLabelFont();
516 }
517 
518 // -----------------------------------------------------------------
519 const Color& Control::GetCanonicalTextColor( const StyleSettings& _rStyle ) const
520 {
521     return _rStyle.GetLabelTextColor();
522 }
523 
524 // -----------------------------------------------------------------
525 void Control::ImplInitSettings( const sal_Bool _bFont, const sal_Bool _bForeground )
526 {
527     const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
528 
529     if ( _bFont )
530     {
531         Font aFont( GetCanonicalFont( rStyleSettings ) );
532         if ( IsControlFont() )
533             aFont.Merge( GetControlFont() );
534         SetZoomedPointFont( aFont );
535     }
536 
537     if ( _bForeground || _bFont )
538     {
539         Color aColor;
540         if ( IsControlForeground() )
541             aColor = GetControlForeground();
542         else
543             aColor = GetCanonicalTextColor( rStyleSettings );
544         SetTextColor( aColor );
545         SetTextFillColor();
546     }
547 }
548 
549 // -----------------------------------------------------------------
550 
551 void Control::DrawControlText( OutputDevice& _rTargetDevice, Rectangle& _io_rRect, const XubString& _rStr,
552     sal_uInt16 _nStyle, MetricVector* _pVector, String* _pDisplayText ) const
553 {
554 #ifdef FS_DEBUG
555     if ( !_pVector )
556     {
557         static MetricVector aCharRects;
558         static String sDisplayText;
559         aCharRects.clear();
560         sDisplayText = String();
561         _pVector = &aCharRects;
562         _pDisplayText = &sDisplayText;
563     }
564 #endif
565 
566     if ( !mpControlData->mpReferenceDevice || ( mpControlData->mpReferenceDevice == &_rTargetDevice ) )
567     {
568         _io_rRect = _rTargetDevice.GetTextRect( _io_rRect, _rStr, _nStyle );
569         _rTargetDevice.DrawText( _io_rRect, _rStr, _nStyle, _pVector, _pDisplayText );
570     }
571     else
572     {
573         ControlTextRenderer aRenderer( *this, _rTargetDevice, *mpControlData->mpReferenceDevice );
574         _io_rRect = aRenderer.DrawText( _io_rRect, _rStr, _nStyle, _pVector, _pDisplayText );
575     }
576 
577 #ifdef FS_DEBUG
578     _rTargetDevice.Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
579     _rTargetDevice.SetLineColor( COL_LIGHTRED );
580     _rTargetDevice.SetFillColor();
581     for (   MetricVector::const_iterator cr = _pVector->begin();
582             cr != _pVector->end();
583             ++cr
584         )
585     {
586         _rTargetDevice.DrawRect( *cr );
587     }
588     _rTargetDevice.Pop();
589 #endif
590 }
591