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