xref: /trunk/main/vcl/source/app/help.cxx (revision 7670ab779549d7913098aa9e18e66c33b446cb8b)
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 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_vcl.hxx"
24 
25 #include "tools/debug.hxx"
26 #include "tools/diagnose_ex.h"
27 #include "tools/time.hxx"
28 
29 #include "vcl/window.hxx"
30 #include "vcl/event.hxx"
31 #include "vcl/svapp.hxx"
32 #include "vcl/wrkwin.hxx"
33 #include "vcl/help.hxx"
34 
35 #include "helpwin.hxx"
36 #include "svdata.hxx"
37 
38 // =======================================================================
39 
40 #define HELPWINSTYLE_QUICK      0
41 #define HELPWINSTYLE_BALLOON    1
42 
43 #define HELPTEXTMARGIN_QUICK    4
44 #define HELPTEXTMARGIN_BALLOON  4 // same margin as quickhelp
45 #define HELPTEXTMAXLEN 100
46 
47 #define HELPDELAY_NORMAL        1
48 #define HELPDELAY_SHORT         2
49 #define HELPDELAY_NONE          3
50 
51 // =======================================================================
52 
53 Help::Help()
54 {
55 }
56 
57 Help::~Help()
58 {
59 }
60 
61 // -----------------------------------------------------------------------
62 
63 void Help::OpenHelpAgent( const rtl::OString& )
64 {
65 }
66 
67 // -----------------------------------------------------------------------
68 
69 sal_Bool Help::Start( const XubString&, const Window* )
70 {
71     return sal_False;
72 }
73 
74 sal_Bool Help::SearchKeyword( const XubString& )
75 {
76     return sal_False;
77 }
78 
79 // -----------------------------------------------------------------------
80 
81 XubString Help::GetHelpText( const String&, const Window* )
82 {
83     return ImplGetSVEmptyStr();
84 }
85 
86 // -----------------------------------------------------------------------
87 
88 void Help::EnableContextHelp()
89 {
90     ImplGetSVData()->maHelpData.mbContextHelp = sal_True;
91 }
92 
93 // -----------------------------------------------------------------------
94 
95 void Help::DisableContextHelp()
96 {
97     ImplGetSVData()->maHelpData.mbContextHelp = sal_False;
98 }
99 
100 // -----------------------------------------------------------------------
101 
102 sal_Bool Help::IsContextHelpEnabled()
103 {
104     return ImplGetSVData()->maHelpData.mbContextHelp;
105 }
106 
107 // -----------------------------------------------------------------------
108 
109 sal_Bool Help::StartContextHelp()
110 {
111     ImplSVData* pSVData = ImplGetSVData();
112 
113     if ( pSVData->maHelpData.mbContextHelp )
114     {
115         Window* pWindow = pSVData->maWinData.mpFocusWin;
116         if ( pWindow )
117         {
118             Point       aMousePos = pWindow->OutputToScreenPixel( pWindow->GetPointerPosPixel() );
119             HelpEvent   aHelpEvent( aMousePos, HELPMODE_CONTEXT );
120             pWindow->RequestHelp( aHelpEvent );
121             return sal_True;
122         }
123     }
124 
125     return sal_False;
126 }
127 
128 // -----------------------------------------------------------------------
129 
130 void Help::EnableExtHelp()
131 {
132     ImplGetSVData()->maHelpData.mbExtHelp = sal_True;
133 }
134 
135 // -----------------------------------------------------------------------
136 
137 void Help::DisableExtHelp()
138 {
139     ImplGetSVData()->maHelpData.mbExtHelp = sal_False;
140 }
141 
142 // -----------------------------------------------------------------------
143 
144 sal_Bool Help::IsExtHelpEnabled()
145 {
146     return ImplGetSVData()->maHelpData.mbExtHelp;
147 }
148 
149 // -----------------------------------------------------------------------
150 
151 sal_Bool Help::StartExtHelp()
152 {
153     ImplSVData* pSVData = ImplGetSVData();
154 
155     if ( pSVData->maHelpData.mbExtHelp && !pSVData->maHelpData.mbExtHelpMode )
156     {
157         pSVData->maHelpData.mbExtHelpMode = sal_True;
158         pSVData->maHelpData.mbOldBalloonMode = pSVData->maHelpData.mbBalloonHelp;
159         pSVData->maHelpData.mbBalloonHelp = sal_True;
160         if ( pSVData->maWinData.mpAppWin )
161             pSVData->maWinData.mpAppWin->ImplGenerateMouseMove();
162         return sal_True;
163     }
164 
165     return sal_False;
166 }
167 
168 // -----------------------------------------------------------------------
169 
170 sal_Bool Help::EndExtHelp()
171 {
172     ImplSVData* pSVData = ImplGetSVData();
173 
174     if ( pSVData->maHelpData.mbExtHelp && pSVData->maHelpData.mbExtHelpMode )
175     {
176         pSVData->maHelpData.mbExtHelpMode = sal_False;
177         pSVData->maHelpData.mbBalloonHelp = pSVData->maHelpData.mbOldBalloonMode;
178         if ( pSVData->maWinData.mpAppWin )
179             pSVData->maWinData.mpAppWin->ImplGenerateMouseMove();
180         return sal_True;
181     }
182 
183     return sal_False;
184 }
185 
186 // -----------------------------------------------------------------------
187 
188 sal_Bool Help::IsExtHelpActive()
189 {
190     return ImplGetSVData()->maHelpData.mbExtHelpMode;
191 }
192 
193 // -----------------------------------------------------------------------
194 
195 void Help::EnableBalloonHelp()
196 {
197     ImplGetSVData()->maHelpData.mbBalloonHelp = sal_True;
198 }
199 
200 // -----------------------------------------------------------------------
201 
202 void Help::DisableBalloonHelp()
203 {
204     ImplGetSVData()->maHelpData.mbBalloonHelp = sal_False;
205 }
206 
207 // -----------------------------------------------------------------------
208 
209 sal_Bool Help::IsBalloonHelpEnabled()
210 {
211     return ImplGetSVData()->maHelpData.mbBalloonHelp;
212 }
213 
214 // -----------------------------------------------------------------------
215 
216 sal_Bool Help::ShowBalloon( Window* pParent,
217                         const Point& rScreenPos,
218                         const XubString& rHelpText )
219 {
220     ImplShowHelpWindow( pParent, HELPWINSTYLE_BALLOON, 0,
221                         rHelpText, ImplGetSVEmptyStr(), rScreenPos );
222 
223     return sal_True;
224 }
225 
226 // -----------------------------------------------------------------------
227 
228 sal_Bool Help::ShowBalloon( Window* pParent,
229                         const Point& rScreenPos, const Rectangle& rRect,
230                         const XubString& rHelpText )
231 {
232     ImplShowHelpWindow( pParent, HELPWINSTYLE_BALLOON, 0,
233                         rHelpText, ImplGetSVEmptyStr(), rScreenPos, &rRect );
234 
235     return sal_True;
236 }
237 
238 // -----------------------------------------------------------------------
239 
240 void Help::EnableQuickHelp()
241 {
242     ImplGetSVData()->maHelpData.mbQuickHelp = sal_True;
243 }
244 
245 // -----------------------------------------------------------------------
246 
247 void Help::DisableQuickHelp()
248 {
249     ImplGetSVData()->maHelpData.mbQuickHelp = sal_False;
250 }
251 
252 // -----------------------------------------------------------------------
253 
254 sal_Bool Help::IsQuickHelpEnabled()
255 {
256     return ImplGetSVData()->maHelpData.mbQuickHelp;
257 }
258 
259 // -----------------------------------------------------------------------
260 
261 sal_Bool Help::ShowQuickHelp( Window* pParent,
262                           const Rectangle& rScreenRect,
263                           const XubString& rHelpText,
264                           const XubString& rLongHelpText,
265                           sal_uInt16 nStyle )
266 {
267     ImplShowHelpWindow( pParent, HELPWINSTYLE_QUICK, nStyle,
268                         rHelpText, rLongHelpText,
269                         pParent->OutputToScreenPixel( pParent->GetPointerPosPixel() ), &rScreenRect );
270     return sal_True;
271 }
272 
273 // -----------------------------------------------------------------------
274 
275 void Help::HideBalloonAndQuickHelp()
276 {
277     HelpTextWindow const * pHelpWin = ImplGetSVData()->maHelpData.mpHelpWin;
278     bool const bIsVisible = ( pHelpWin != NULL ) && pHelpWin->IsVisible();
279     ImplDestroyHelpWindow( bIsVisible );
280 }
281 
282 // -----------------------------------------------------------------------
283 
284 sal_uIntPtr Help::ShowTip( Window* pParent, const Rectangle& rScreenRect,
285                      const XubString& rText, sal_uInt16 nStyle )
286 {
287     sal_uInt16 nHelpWinStyle = ( ( nStyle & QUICKHELP_TIP_STYLE_BALLOON ) != 0 ) ? HELPWINSTYLE_BALLOON : HELPWINSTYLE_QUICK;
288     HelpTextWindow* pHelpWin = new HelpTextWindow( pParent, rText, nHelpWinStyle, nStyle );
289 
290     sal_uIntPtr nId = reinterpret_cast< sal_uIntPtr >( pHelpWin );
291     UpdateTip( nId, pParent, rScreenRect, rText );
292 
293     pHelpWin->ShowHelp( HELPDELAY_NONE );
294     return nId;
295 }
296 
297 // -----------------------------------------------------------------------
298 
299 void Help::UpdateTip( sal_uIntPtr nId, Window* pParent, const Rectangle& rScreenRect, const XubString& rText )
300 {
301     HelpTextWindow* pHelpWin = reinterpret_cast< HelpTextWindow* >( nId );
302     ENSURE_OR_RETURN_VOID( pHelpWin != NULL, "Help::UpdateTip: invalid ID!" );
303 
304     Size aSz = pHelpWin->CalcOutSize();
305     pHelpWin->SetOutputSizePixel( aSz );
306     ImplSetHelpWindowPos( pHelpWin, pHelpWin->GetWinStyle(), pHelpWin->GetStyle(),
307         pParent->OutputToScreenPixel( pParent->GetPointerPosPixel() ), &rScreenRect );
308 
309     pHelpWin->SetHelpText( rText );
310     pHelpWin->Invalidate();
311 }
312 
313 // -----------------------------------------------------------------------
314 
315 void Help::HideTip( sal_uLong nId )
316 {
317     HelpTextWindow* pHelpWin = (HelpTextWindow*)nId;
318     Window* pFrameWindow = pHelpWin->ImplGetFrameWindow();
319     pHelpWin->Hide();
320     // Update auslösen, damit ein Paint sofort ausgelöst wird, da
321     // wir den Hintergrund nicht sichern
322     pFrameWindow->ImplUpdateAll();
323     delete pHelpWin;
324     ImplGetSVData()->maHelpData.mnLastHelpHideTime = Time::GetSystemTicks();
325 }
326 
327 // =======================================================================
328 
329 HelpTextWindow::HelpTextWindow( Window* pParent, const XubString& rText, sal_uInt16 nHelpWinStyle, sal_uInt16 nStyle ) :
330     //FloatingWindow( pParent->ImplGetFrameWindow(), WB_SYSTEMWINDOW ),
331     FloatingWindow( pParent, WB_SYSTEMWINDOW|WB_TOOLTIPWIN ), // #105827# if we change the parent, mirroring will not work correctly when positioning this window
332     maHelpText( rText )
333 {
334     SetType( WINDOW_HELPTEXTWINDOW );
335     ImplSetMouseTransparent( sal_True );
336     mnHelpWinStyle = nHelpWinStyle;
337     mnStyle = nStyle;
338 // On Windows this will raise the application window, because help windows are system windows now
339 //  EnableAlwaysOnTop();
340     EnableSaveBackground();
341 
342     const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
343     SetPointFont( rStyleSettings.GetHelpFont() );
344     SetTextColor( rStyleSettings.GetHelpTextColor() );
345     SetTextAlign( ALIGN_TOP );
346     if ( IsNativeControlSupported( CTRL_TOOLTIP, PART_ENTIRE_CONTROL ) )
347     {
348         EnableChildTransparentMode( sal_True );
349         SetParentClipMode( PARENTCLIPMODE_NOCLIP );
350         SetPaintTransparent( sal_True );
351         SetBackground();
352     }
353     else
354         SetBackground( Wallpaper( rStyleSettings.GetHelpColor() ) );
355     if( rStyleSettings.GetHelpColor().IsDark() )
356         SetLineColor( COL_YELLOW );
357     else
358         SetLineColor( COL_BLACK );
359     SetFillColor();
360 
361     if( mnStyle & QUICKHELP_BIDI_RTL )
362     {
363         sal_uLong nLayoutMode = GetLayoutMode();
364         nLayoutMode |= TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_LEFT;
365         SetLayoutMode( nLayoutMode );
366     }
367     SetHelpText( rText );
368     Window::SetHelpText( rText );
369 
370     ImplSVData* pSVData = ImplGetSVData();
371     if ( pSVData->maHelpData.mbSetKeyboardHelp )
372         pSVData->maHelpData.mbKeyboardHelp = sal_True;
373 
374     const HelpSettings& rHelpSettings = pParent->GetSettings().GetHelpSettings();
375     maShowTimer.SetTimeoutHdl( LINK( this, HelpTextWindow, TimerHdl ) );
376     maHideTimer.SetTimeoutHdl( LINK( this, HelpTextWindow, TimerHdl ) );
377     maHideTimer.SetTimeout( rHelpSettings.GetTipTimeout() );
378 }
379 
380 // -----------------------------------------------------------------------
381 
382 HelpTextWindow::~HelpTextWindow()
383 {
384     maShowTimer.Stop();
385     maHideTimer.Stop();
386 
387     if( this == ImplGetSVData()->maHelpData.mpHelpWin )
388         ImplGetSVData()->maHelpData.mpHelpWin = NULL;
389 
390     if ( maStatusText.Len() )
391     {
392         ImplSVData* pSVData = ImplGetSVData();
393         pSVData->mpApp->HideHelpStatusText();
394     }
395 }
396 
397 // -----------------------------------------------------------------------
398 
399 void HelpTextWindow::SetHelpText( const String& rHelpText )
400 {
401     maHelpText = rHelpText;
402     if ( mnHelpWinStyle == HELPWINSTYLE_QUICK && maHelpText.Len() < HELPTEXTMAXLEN )
403     {
404         Size aSize;
405         aSize.Height() = GetTextHeight();
406         if ( mnStyle & QUICKHELP_CTRLTEXT )
407             aSize.Width() = GetCtrlTextWidth( maHelpText );
408         else
409             aSize.Width() = GetTextWidth( maHelpText );
410         maTextRect = Rectangle( Point( HELPTEXTMARGIN_QUICK, HELPTEXTMARGIN_QUICK ), aSize );
411     }
412     else // HELPWINSTYLE_BALLOON
413     {
414         Point       aTmpPoint;
415         sal_uInt16      nCharsInLine = 35 + ((maHelpText.Len()/100)*5);
416         XubString   aXXX;
417         aXXX.Fill( nCharsInLine, 'x' ); // average width for all windows
418         long nWidth = GetTextWidth( aXXX );
419         Size aTmpSize( nWidth, 0x7FFFFFFF );
420         Rectangle aTry1( aTmpPoint, aTmpSize );
421         sal_uInt16 nDrawFlags = TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK |
422                             TEXT_DRAW_LEFT | TEXT_DRAW_TOP;
423         if ( mnStyle & QUICKHELP_CTRLTEXT )
424             nDrawFlags |= TEXT_DRAW_MNEMONIC;
425         Rectangle aTextRect = GetTextRect( aTry1, maHelpText, nDrawFlags );
426 
427         // Später mal eine geeignete Breite ermitteln...
428         maTextRect = aTextRect;
429 
430         // Sicherheitsabstand...
431         maTextRect.SetPos( Point( HELPTEXTMARGIN_BALLOON, HELPTEXTMARGIN_BALLOON ) );
432     }
433 
434     Size aSize( CalcOutSize() );
435     SetOutputSizePixel( aSize );
436 }
437 
438 // -----------------------------------------------------------------------
439 
440 void HelpTextWindow::ImplShow()
441 {
442     ImplDelData aDogTag( this );
443     if ( maStatusText.Len() )
444     {
445         ImplSVData* pSVData = ImplGetSVData();
446         pSVData->mpApp->ShowHelpStatusText( maStatusText );
447     }
448     Show( sal_True, SHOW_NOACTIVATE );
449     if( !aDogTag.IsDelete() )
450     Update();
451 }
452 
453 // -----------------------------------------------------------------------
454 
455 void HelpTextWindow::Paint( const Rectangle& )
456 {
457     // paint native background
458     bool bNativeOK = false;
459     if ( IsNativeControlSupported( CTRL_TOOLTIP, PART_ENTIRE_CONTROL ) )
460     {
461         // #i46472# workaround gcc3.3 temporary problem
462         Rectangle aCtrlRegion( Point( 0, 0 ), GetOutputSizePixel() );
463         ImplControlValue aControlValue;
464         bNativeOK = DrawNativeControl( CTRL_TOOLTIP, PART_ENTIRE_CONTROL, aCtrlRegion,
465                                        0, aControlValue, rtl::OUString() );
466     }
467 
468     // paint text
469     if ( mnHelpWinStyle == HELPWINSTYLE_QUICK && maHelpText.Len() < HELPTEXTMAXLEN )
470     {
471         if ( mnStyle & QUICKHELP_CTRLTEXT )
472             DrawCtrlText( maTextRect.TopLeft(), maHelpText );
473         else
474             DrawText( maTextRect.TopLeft(), maHelpText );
475     }
476     else // HELPWINSTYLE_BALLOON
477     {
478         sal_uInt16 nDrawFlags = TEXT_DRAW_MULTILINE|TEXT_DRAW_WORDBREAK|
479                                 TEXT_DRAW_LEFT|TEXT_DRAW_TOP;
480         if ( mnStyle & QUICKHELP_CTRLTEXT )
481             nDrawFlags |= TEXT_DRAW_MNEMONIC;
482         DrawText( maTextRect, maHelpText, nDrawFlags );
483     }
484 
485     // paint border
486     if( ! bNativeOK )
487     {
488         Size aSz = GetOutputSizePixel();
489         DrawRect( Rectangle( Point(), aSz ) );
490 //      if ( mnHelpWinStyle == HELPWINSTYLE_BALLOON ) // same border as quickhelp
491 //      {
492 //          aSz.Width() -= 2;
493 //          aSz.Height() -= 2;
494 //          Color aColor( GetLineColor() );
495 //          SetLineColor( ( COL_GRAY ) );
496 //          DrawRect( Rectangle( Point( 1, 1 ), aSz ) );
497 //          SetLineColor( aColor );
498 //      }
499     }
500 }
501 
502 // -----------------------------------------------------------------------
503 
504 void HelpTextWindow::ShowHelp( sal_uInt16 nDelayMode )
505 {
506     sal_uLong nTimeout = 0;
507     if ( nDelayMode != HELPDELAY_NONE )
508     {
509         // Im ExtendedHelp-Fall die Hilfe schneller anzeigen
510         if ( ImplGetSVData()->maHelpData.mbExtHelpMode )
511             nTimeout = 15;
512         else
513         {
514             const HelpSettings& rHelpSettings = GetSettings().GetHelpSettings();
515             if ( mnHelpWinStyle == HELPWINSTYLE_QUICK )
516                 nTimeout = rHelpSettings.GetTipDelay();
517             else
518                 nTimeout = rHelpSettings.GetBalloonDelay();
519         }
520 
521         if ( nDelayMode == HELPDELAY_SHORT )
522             nTimeout /= 3;
523     }
524 
525     maShowTimer.SetTimeout( nTimeout );
526     maShowTimer.Start();
527 }
528 
529 // -----------------------------------------------------------------------
530 
531 IMPL_LINK( HelpTextWindow, TimerHdl, Timer*, pTimer)
532 {
533     if ( pTimer == &maShowTimer )
534     {
535         if ( mnHelpWinStyle == HELPWINSTYLE_QUICK )
536         {
537             // start auto-hide-timer for non-ShowTip windows
538             ImplSVData* pSVData = ImplGetSVData();
539             if ( this == pSVData->maHelpData.mpHelpWin )
540                 maHideTimer.Start();
541         }
542         ImplShow();
543     }
544     else
545     {
546         DBG_ASSERT( pTimer == &maHideTimer, "HelpTextWindow::TimerHdl with bad Timer" );
547         ImplDestroyHelpWindow( true );
548     }
549 
550     return 1;
551 }
552 
553 // -----------------------------------------------------------------------
554 
555 Size HelpTextWindow::CalcOutSize() const
556 {
557     Size aSz = maTextRect.GetSize();
558     aSz.Width() += 2*maTextRect.Left();
559     aSz.Height() += 2*maTextRect.Top();
560     return aSz;
561 }
562 
563 // -----------------------------------------------------------------------
564 
565 void HelpTextWindow::RequestHelp( const HelpEvent& /*rHEvt*/ )
566 {
567     // Nur damit nicht von Window::RequestHelp() ein
568     // ShowQuickHelp/ShowBalloonHelp am HelpTextWindow aufgerufen wird.
569 }
570 
571 // -----------------------------------------------------------------------
572 
573 String HelpTextWindow::GetText() const
574 {
575     return maHelpText;
576 }
577 
578 // -----------------------------------------------------------------------
579 
580 ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > HelpTextWindow::CreateAccessible()
581 {
582     return FloatingWindow::CreateAccessible();
583 }
584 
585 // -----------------------------------------------------------------------
586 
587 sal_Bool HelpTextWindow::RegisterAccessibleParent()
588 {
589         return sal_False;
590 }
591 
592 // -----------------------------------------------------------------------
593 
594 void HelpTextWindow::RevokeAccessibleParent()
595 {
596 }
597 
598 // =======================================================================
599 
600 void ImplShowHelpWindow( Window* pParent, sal_uInt16 nHelpWinStyle, sal_uInt16 nStyle,
601                          const XubString& rHelpText, const XubString& rStatusText,
602                          const Point& rScreenPos, const Rectangle* pHelpArea )
603 {
604     ImplSVData* pSVData = ImplGetSVData();
605 
606     if( !rHelpText.Len() && !pSVData->maHelpData.mbRequestingHelp )
607         return;
608 
609     HelpTextWindow* pHelpWin = pSVData->maHelpData.mpHelpWin;
610     sal_uInt16 nDelayMode = HELPDELAY_NORMAL;
611     if ( pHelpWin )
612     {
613         DBG_ASSERT( pHelpWin != pParent, "HelpInHelp ?!" );
614 
615         if  (   (   ( pHelpWin->GetHelpText() != rHelpText )
616                 ||  ( pHelpWin->GetWinStyle() != nHelpWinStyle )
617                 ||  (   pHelpArea
618                     &&  ( pHelpWin->GetHelpArea() != *pHelpArea )
619                     )
620                 )
621             &&  pSVData->maHelpData.mbRequestingHelp
622             )
623         {
624             // remove help window if no HelpText or other HelpText or
625             // other help mode. but keep it if we are scrolling, i.e. not requesting help
626             bool bWasVisible = pHelpWin->IsVisible();
627             if ( bWasVisible )
628                 nDelayMode = HELPDELAY_NONE; // display it quickly if we were already in quick help mode
629             pHelpWin = NULL;
630             ImplDestroyHelpWindow( bWasVisible );
631         }
632         else
633         {
634             bool const bTextChanged = rHelpText != pHelpWin->GetHelpText();
635             if ( bTextChanged || ( ( nStyle & QUICKHELP_FORCE_REPOSITION ) != 0 ) )
636             {
637                 Window * pWindow = pHelpWin->GetParent()->ImplGetFrameWindow();
638                 Rectangle aInvRect( pHelpWin->GetWindowExtentsRelative( pWindow ) );
639                 if( pHelpWin->IsVisible() )
640                     pWindow->Invalidate( aInvRect );
641 
642                 pHelpWin->SetHelpText( rHelpText );
643                 // approach mouse position
644                 ImplSetHelpWindowPos( pHelpWin, nHelpWinStyle, nStyle, rScreenPos, pHelpArea );
645                 if( pHelpWin->IsVisible() )
646                     pHelpWin->Invalidate();
647             }
648         }
649     }
650 
651     if ( !pHelpWin && rHelpText.Len() )
652     {
653         sal_uLong nCurTime = Time::GetSystemTicks();
654         if  (   ( ( nCurTime - pSVData->maHelpData.mnLastHelpHideTime ) < pParent->GetSettings().GetHelpSettings().GetTipDelay() )
655             ||  ( ( nStyle & QUICKHELP_NO_DELAY ) != 0 )
656             )
657             nDelayMode = HELPDELAY_NONE;
658 
659         DBG_ASSERT( !pHelpWin, "Another HelpWin?!" );
660         pHelpWin = new HelpTextWindow( pParent, rHelpText, nHelpWinStyle, nStyle );
661         pSVData->maHelpData.mpHelpWin = pHelpWin;
662         pHelpWin->SetStatusText( rStatusText );
663         if ( pHelpArea )
664             pHelpWin->SetHelpArea( *pHelpArea );
665 
666         // positioning
667         Size aSz = pHelpWin->CalcOutSize();
668         pHelpWin->SetOutputSizePixel( aSz );
669         ImplSetHelpWindowPos( pHelpWin, nHelpWinStyle, nStyle, rScreenPos, pHelpArea );
670         // if not called from Window::RequestHelp, then without delay...
671         if ( !pSVData->maHelpData.mbRequestingHelp )
672             nDelayMode = HELPDELAY_NONE;
673         pHelpWin->ShowHelp( nDelayMode );
674     }
675 }
676 
677 // -----------------------------------------------------------------------
678 
679 void ImplDestroyHelpWindow( bool bUpdateHideTime )
680 {
681     ImplSVData* pSVData = ImplGetSVData();
682     HelpTextWindow* pHelpWin = pSVData->maHelpData.mpHelpWin;
683     if ( pHelpWin )
684     {
685         Window * pWindow = pHelpWin->GetParent()->ImplGetFrameWindow();
686         // find out screen area covered by system help window
687         Rectangle aInvRect( pHelpWin->GetWindowExtentsRelative( pWindow ) );
688         if( pHelpWin->IsVisible() )
689             pWindow->Invalidate( aInvRect );
690         pSVData->maHelpData.mpHelpWin = NULL;
691         pSVData->maHelpData.mbKeyboardHelp = sal_False;
692         pHelpWin->Hide();
693         delete pHelpWin;
694         if( bUpdateHideTime )
695             pSVData->maHelpData.mnLastHelpHideTime = Time::GetSystemTicks();
696     }
697 }
698 
699 // -----------------------------------------------------------------------
700 
701 void ImplSetHelpWindowPos( Window* pHelpWin, sal_uInt16 nHelpWinStyle, sal_uInt16 nStyle,
702                            const Point& rPos, const Rectangle* pHelpArea )
703 {
704     Point       aPos = rPos;
705     Size        aSz = pHelpWin->GetSizePixel();
706     Rectangle   aScreenRect = pHelpWin->ImplGetFrameWindow()->GetDesktopRectPixel();
707     aPos = pHelpWin->GetParent()->ImplGetFrameWindow()->OutputToAbsoluteScreenPixel( aPos );
708     // get mouse screen coordinates
709     Point mPos( pHelpWin->GetParent()->ImplGetFrameWindow()->GetPointerPosPixel() );
710     mPos = pHelpWin->GetParent()->ImplGetFrameWindow()->OutputToAbsoluteScreenPixel( mPos );
711 
712     if ( nHelpWinStyle == HELPWINSTYLE_QUICK )
713     {
714         if ( !(nStyle & QUICKHELP_NOAUTOPOS) )
715         {
716             long nScreenHeight = aScreenRect.GetHeight();
717             aPos.X() -= 4;
718             if ( aPos.Y() > aScreenRect.Top()+nScreenHeight-(nScreenHeight/4) )
719                 aPos.Y() -= aSz.Height()+4;
720             else
721                 aPos.Y() += 21;
722         }
723     }
724     else
725     {
726         // If it's the mouse position, move the window slightly
727         // so the mouse pointer does not cover it
728         if ( aPos == mPos )
729         {
730             aPos.X() += 12;
731             aPos.Y() += 16;
732         }
733     }
734 
735     if ( nStyle & QUICKHELP_NOAUTOPOS )
736     {
737         if ( pHelpArea )
738         {
739             // convert help area to screen coordinates
740             Rectangle devHelpArea(
741                 pHelpWin->GetParent()->ImplGetFrameWindow()->OutputToAbsoluteScreenPixel( pHelpArea->TopLeft() ),
742                 pHelpWin->GetParent()->ImplGetFrameWindow()->OutputToAbsoluteScreenPixel( pHelpArea->BottomRight() ) );
743 
744             // Welche Position vom Rechteck?
745             aPos = devHelpArea.Center();
746 
747             if ( nStyle & QUICKHELP_LEFT )
748                 aPos.X() = devHelpArea.Left();
749             else if ( nStyle & QUICKHELP_RIGHT )
750                 aPos.X() = devHelpArea.Right();
751 
752             if ( nStyle & QUICKHELP_TOP )
753                 aPos.Y() = devHelpArea.Top();
754             else if ( nStyle & QUICKHELP_BOTTOM )
755                 aPos.Y() = devHelpArea.Bottom();
756         }
757 
758         // Which direction?
759         if ( nStyle & QUICKHELP_LEFT )
760             ;
761         else if ( nStyle & QUICKHELP_RIGHT )
762             aPos.X() -= aSz.Width();
763         else
764             aPos.X() -= aSz.Width() / 2;
765 
766         if ( nStyle & QUICKHELP_TOP )
767             ;
768         else if ( nStyle & QUICKHELP_BOTTOM )
769             aPos.Y() -= aSz.Height();
770         else
771             aPos.Y() -= aSz.Height() / 2;
772     }
773 
774     if ( aPos.X() < aScreenRect.Left() )
775         aPos.X() = aScreenRect.Left();
776     else if ( ( aPos.X() + aSz.Width() ) > aScreenRect.Right() )
777         aPos.X() = aScreenRect.Right() - aSz.Width();
778     if ( aPos.Y() < aScreenRect.Top() )
779         aPos.Y() = aScreenRect.Top();
780     else if ( ( aPos.Y() + aSz.Height() ) > aScreenRect.Bottom() )
781         aPos.Y() = aScreenRect.Bottom() - aSz.Height();
782 
783     if( ! (nStyle & QUICKHELP_NOEVADEPOINTER) )
784     {
785         /* the remark below should be obsolete by now as the helpwindow should
786         not be focusable, leaving it as a hint. However it is sensible in most
787         conditions to evade the mouse pointer so the content window is fully visible.
788 
789         // the popup must not appear under the mouse
790         // otherwise it would directly be closed due to a focus change...
791         */
792         Rectangle aHelpRect( aPos, aSz );
793         if( aHelpRect.IsInside( mPos ) )
794         {
795             Point delta(2,2);
796             Point pSize( aSz.Width(), aSz.Height() );
797             Point pTest( mPos - pSize - delta );
798             if( pTest.X() > aScreenRect.Left() && pTest.Y() > aScreenRect.Top() )
799                 aPos = pTest;
800             else
801                 aPos = mPos + delta;
802         }
803     }
804 
805     Window* pWindow = pHelpWin->GetParent()->ImplGetFrameWindow();
806     aPos = pWindow->AbsoluteScreenToOutputPixel( aPos );
807     pHelpWin->SetPosPixel( aPos );
808 }
809 
810 /* vim: set noet sw=4 ts=4: */
811