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