xref: /aoo41x/main/vcl/source/app/help.cxx (revision cdf0e10c)
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