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