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