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_svtools.hxx"
30 
31 #define _TASKBAR_CXX
32 
33 #include <tools/list.hxx>
34 #include <tools/debug.hxx>
35 #include <tools/date.hxx>
36 #include <vcl/image.hxx>
37 #include <vcl/help.hxx>
38 #include <vcl/svapp.hxx>
39 #include <unotools/calendarwrapper.hxx>
40 #include <unotools/syslocale.hxx>
41 #include <svtools/taskbar.hxx>
42 
43 // =======================================================================
44 
45 #define TASKSTATUSBAR_CLOCXOFFX     3
46 #define TASKSTATUSBAR_IMAGEOFFX     1
47 
48 // =======================================================================
49 
50 struct ImplTaskSBFldItem
51 {
52     TaskStatusFieldItem     maItem;
53     sal_uInt16                  mnId;
54     long                    mnOffX;
55 };
56 
57 DECLARE_LIST( ImplTaskSBItemList, ImplTaskSBFldItem* )
58 
59 // =======================================================================
60 
61 sal_Bool ITaskStatusNotify::MouseButtonDown( sal_uInt16, const MouseEvent& )
62 {
63     return sal_False;
64 }
65 
66 // -----------------------------------------------------------------------
67 
68 sal_Bool ITaskStatusNotify::MouseButtonUp( sal_uInt16, const MouseEvent& )
69 {
70     return sal_False;
71 }
72 
73 // -----------------------------------------------------------------------
74 
75 sal_Bool ITaskStatusNotify::MouseMove( sal_uInt16, const MouseEvent& )
76 {
77     return sal_False;
78 }
79 
80 // -----------------------------------------------------------------------
81 
82 sal_Bool ITaskStatusNotify::Command( sal_uInt16, const CommandEvent& )
83 {
84     return sal_False;
85 }
86 
87 // -----------------------------------------------------------------------
88 
89 sal_Bool ITaskStatusNotify::UpdateHelp( sal_uInt16 )
90 {
91     return sal_False;
92 }
93 
94 // =======================================================================
95 
96 TaskStatusFieldItem::TaskStatusFieldItem()
97 {
98     mpNotify        = NULL;
99     mnFlags         = 0;
100 }
101 
102 // -----------------------------------------------------------------------
103 
104 TaskStatusFieldItem::TaskStatusFieldItem( const TaskStatusFieldItem& rItem ) :
105     mpNotify( rItem.mpNotify ),
106     maImage( rItem.maImage ),
107     maQuickHelpText( rItem.maQuickHelpText ),
108     maHelpText( rItem.maHelpText ),
109     mnFlags( rItem.mnFlags )
110 {
111 }
112 
113 // -----------------------------------------------------------------------
114 
115 TaskStatusFieldItem::TaskStatusFieldItem( ITaskStatusNotify* pNotify,
116                                           const Image& rImage,
117                                           const XubString& rQuickHelpText,
118                                           const XubString& rHelpText,
119                                           sal_uInt16 nFlags ) :
120     mpNotify( pNotify ),
121     maImage( rImage ),
122     maQuickHelpText( rQuickHelpText ),
123     maHelpText( rHelpText ),
124     mnFlags( nFlags )
125 {
126 }
127 
128 // -----------------------------------------------------------------------
129 
130 TaskStatusFieldItem::~TaskStatusFieldItem()
131 {
132 }
133 
134 // -----------------------------------------------------------------------
135 
136 const TaskStatusFieldItem& TaskStatusFieldItem::operator=( const TaskStatusFieldItem& rItem )
137 {
138     mpNotify        = rItem.mpNotify;
139     maImage         = rItem.maImage;
140     maQuickHelpText = rItem.maQuickHelpText;
141     maHelpText      = rItem.maHelpText;
142     mnFlags         = rItem.mnFlags;
143     return *this;
144 }
145 
146 // =======================================================================
147 
148 TaskStatusBar::TaskStatusBar( Window* pParent, WinBits nWinStyle ) :
149     StatusBar( pParent, nWinStyle | WB_3DLOOK ),
150     maTime( 0, 0, 0 )
151 {
152     mpFieldItemList = NULL;
153     mpNotifyTaskBar = NULL;
154     mpNotify        = NULL;
155     mnClockWidth    = 0;
156     mnItemWidth     = 0;
157     mnFieldWidth    = 0;
158     mnFieldFlags    = 0;
159     mbFlashItems    = sal_False;
160     mbOutInterval   = sal_False;
161 
162     maTimer.SetTimeoutHdl( LINK( this, TaskStatusBar, ImplTimerHdl ) );
163 }
164 
165 // -----------------------------------------------------------------------
166 
167 TaskStatusBar::~TaskStatusBar()
168 {
169     if ( mpFieldItemList )
170     {
171         ImplTaskSBFldItem* pItem = mpFieldItemList->First();
172         while ( pItem )
173         {
174             delete pItem;
175             pItem = mpFieldItemList->Next();
176         }
177 
178         delete mpFieldItemList;
179     }
180 }
181 
182 // -----------------------------------------------------------------------
183 
184 IMPL_LINK( TaskStatusBar, ImplTimerHdl, Timer*, EMPTYARG )
185 {
186     sal_Bool bUpdate = ImplUpdateClock();
187     if ( ImplUpdateFlashItems() )
188         bUpdate = sal_True;
189     if ( bUpdate )
190         SetItemData( TASKSTATUSBAR_STATUSFIELDID, NULL );
191 
192     return 0;
193 }
194 
195 // -----------------------------------------------------------------------
196 
197 ImplTaskSBFldItem* TaskStatusBar::ImplGetFieldItem( sal_uInt16 nItemId ) const
198 {
199     if ( !mpFieldItemList )
200         return NULL;
201 
202     ImplTaskSBFldItem* pItem = mpFieldItemList->First();
203     while ( pItem )
204     {
205         if ( pItem->mnId == nItemId )
206             return pItem;
207 
208         pItem = mpFieldItemList->Next();
209     }
210 
211     return NULL;
212 }
213 
214 // -----------------------------------------------------------------------
215 
216 ImplTaskSBFldItem* TaskStatusBar::ImplGetFieldItem( const Point& rPos, sal_Bool& rFieldRect ) const
217 {
218     if ( GetItemId( rPos ) == TASKSTATUSBAR_STATUSFIELDID )
219     {
220         rFieldRect = sal_True;
221 
222         if ( mpFieldItemList )
223         {
224             long nX = rPos.X()-GetItemRect( TASKSTATUSBAR_STATUSFIELDID ).Left();
225             ImplTaskSBFldItem* pItem = mpFieldItemList->First();
226             while ( pItem )
227             {
228                 if ( nX < pItem->mnOffX+pItem->maItem.GetImage().GetSizePixel().Width() )
229                     return pItem;
230 
231                 pItem = mpFieldItemList->Next();
232             }
233         }
234     }
235     else
236         rFieldRect = sal_False;
237 
238     return NULL;
239 }
240 
241 // -----------------------------------------------------------------------
242 
243 sal_Bool TaskStatusBar::ImplUpdateClock()
244 {
245     if ( mnFieldFlags & TASKSTATUSFIELD_CLOCK )
246     {
247         Time aTime;
248         maTimer.SetTimeout( ((long)60000)-((aTime.GetSec()*1000)+(aTime.Get100Sec()*10)) );
249         if ( (aTime.GetMin()  != maTime.GetMin()) ||
250              (aTime.GetHour() != maTime.GetHour()) )
251         {
252             maTime = aTime;
253             maTimeText = SvtSysLocale().GetLocaleData().getTime( aTime, sal_False, sal_False );
254             return sal_True;
255         }
256     }
257 
258     return sal_False;
259 }
260 
261 // -----------------------------------------------------------------------
262 
263 sal_Bool TaskStatusBar::ImplUpdateFlashItems()
264 {
265     if ( mbFlashItems )
266     {
267         if ( mbOutInterval )
268         {
269             maTimer.SetTimeout( 900 );
270             mbOutInterval = sal_False;
271         }
272         else
273         {
274             maTimer.SetTimeout( 700 );
275             mbOutInterval = sal_True;
276         }
277 
278         return sal_True;
279     }
280 
281     return sal_False;
282 }
283 
284 // -----------------------------------------------------------------------
285 
286 void TaskStatusBar::ImplUpdateField( sal_Bool bItems )
287 {
288     maTimer.Stop();
289 
290     if ( bItems )
291     {
292         ImplTaskSBFldItem* pItem = mpFieldItemList->First();
293         mnItemWidth = 0;
294         mbFlashItems = sal_False;
295         mbOutInterval = sal_False;
296         while ( pItem )
297         {
298             mnItemWidth += TASKSTATUSBAR_IMAGEOFFX;
299             pItem->mnOffX = mnItemWidth;
300             mnItemWidth += pItem->maItem.GetImage().GetSizePixel().Width();
301             if ( pItem->maItem.GetFlags() & TASKSTATUSFIELDITEM_FLASH )
302                 mbFlashItems = sal_True;
303 
304             pItem = mpFieldItemList->Next();
305         }
306     }
307     else
308     {
309         if ( mnFieldFlags & TASKSTATUSFIELD_CLOCK )
310         {
311             XubString aStr = SvtSysLocale().GetLocaleData().getTime( Time( 23, 59, 59 ), sal_False, sal_False );
312             mnClockWidth = GetTextWidth( aStr )+(TASKSTATUSBAR_CLOCXOFFX*2);
313         }
314         else
315             mnClockWidth = 0;
316     }
317 
318     long nNewWidth = mnItemWidth+mnClockWidth;
319     if ( mnItemWidth && !mnClockWidth )
320         nNewWidth += TASKSTATUSBAR_IMAGEOFFX;
321     if ( nNewWidth != mnFieldWidth )
322     {
323         RemoveItem( TASKSTATUSBAR_STATUSFIELDID );
324 
325         if ( mnItemWidth || mnClockWidth )
326         {
327             mnFieldWidth = nNewWidth;
328             long    nOffset = GetItemOffset( TASKSTATUSBAR_STATUSFIELDID );
329             sal_uInt16  nItemPos = GetItemPos( TASKSTATUSBAR_STATUSFIELDID );
330             InsertItem( TASKSTATUSBAR_STATUSFIELDID, nNewWidth, SIB_RIGHT | SIB_IN | SIB_USERDRAW, nOffset, nItemPos );
331         }
332         else
333             mnFieldWidth = 0;
334 
335         if ( mpNotifyTaskBar )
336             mpNotifyTaskBar->Resize();
337     }
338     else
339         SetItemData( TASKSTATUSBAR_STATUSFIELDID, NULL );
340 
341     if ( mbFlashItems || (mnFieldFlags & TASKSTATUSFIELD_CLOCK) )
342     {
343         ImplUpdateClock();
344         mbOutInterval = sal_True;
345         ImplUpdateFlashItems();
346         maTimer.Start();
347     }
348 }
349 
350 // -----------------------------------------------------------------------
351 
352 void TaskStatusBar::MouseButtonDown( const MouseEvent& rMEvt )
353 {
354     sal_Bool bFieldRect;
355     sal_Bool bBaseClass = sal_False;
356     ImplTaskSBFldItem* pItem = ImplGetFieldItem( rMEvt.GetPosPixel(), bFieldRect );
357 
358     ITaskStatusNotify*  pNotify = mpNotify;
359     sal_uInt16              nItemId = 0;
360 
361     if ( bFieldRect )
362         nItemId = TASKSTATUSBAR_CLOCKID;
363 
364     if ( pItem )
365     {
366         pNotify = pItem->maItem.GetNotifyObject();
367         nItemId = pItem->mnId;
368     }
369 
370     if ( pNotify )
371         bBaseClass = pNotify->MouseButtonDown( nItemId, rMEvt );
372 
373     if ( bBaseClass )
374         StatusBar::MouseButtonDown( rMEvt );
375 }
376 
377 // -----------------------------------------------------------------------
378 
379 void TaskStatusBar::MouseButtonUp( const MouseEvent& rMEvt )
380 {
381     sal_Bool bFieldRect;
382     sal_Bool bBaseClass = sal_False;
383     ImplTaskSBFldItem* pItem = ImplGetFieldItem( rMEvt.GetPosPixel(), bFieldRect );
384 
385     ITaskStatusNotify*  pNotify = mpNotify;
386     sal_uInt16              nItemId = 0;
387 
388     if ( bFieldRect )
389         nItemId = TASKSTATUSBAR_CLOCKID;
390 
391     if ( pItem )
392     {
393         pNotify = pItem->maItem.GetNotifyObject();
394         nItemId = pItem->mnId;
395     }
396 
397     if ( pNotify )
398         bBaseClass = pNotify->MouseButtonUp( nItemId, rMEvt );
399 
400     if ( bBaseClass )
401         StatusBar::MouseButtonUp( rMEvt );
402 }
403 
404 // -----------------------------------------------------------------------
405 
406 void TaskStatusBar::MouseMove( const MouseEvent& rMEvt )
407 {
408     sal_Bool bFieldRect;
409     sal_Bool bBaseClass = sal_False;
410     ImplTaskSBFldItem* pItem = ImplGetFieldItem( rMEvt.GetPosPixel(), bFieldRect );
411 
412     ITaskStatusNotify*  pNotify = mpNotify;
413     sal_uInt16              nItemId = 0;
414 
415     if ( bFieldRect )
416         nItemId = TASKSTATUSBAR_CLOCKID;
417 
418     if ( pItem )
419     {
420         pNotify = pItem->maItem.GetNotifyObject();
421         nItemId = pItem->mnId;
422     }
423 
424     if ( pNotify )
425         bBaseClass = pNotify->MouseMove( nItemId, rMEvt );
426 
427     if ( bBaseClass )
428         StatusBar::MouseMove( rMEvt );
429 }
430 
431 // -----------------------------------------------------------------------
432 
433 void TaskStatusBar::Command( const CommandEvent& rCEvt )
434 {
435     sal_Bool bFieldRect;
436     sal_Bool bBaseClass = sal_False;
437     ImplTaskSBFldItem* pItem = ImplGetFieldItem( rCEvt.GetMousePosPixel(), bFieldRect );
438 
439     ITaskStatusNotify*  pNotify = mpNotify;
440     sal_uInt16              nItemId = 0;
441 
442     if ( bFieldRect )
443         nItemId = TASKSTATUSBAR_CLOCKID;
444 
445     if ( pItem )
446     {
447         pNotify = pItem->maItem.GetNotifyObject();
448         nItemId = pItem->mnId;
449     }
450 
451     if ( pNotify )
452         bBaseClass = pNotify->Command( nItemId, rCEvt );
453 
454     if ( bBaseClass )
455         StatusBar::Command( rCEvt );
456 }
457 
458 // -----------------------------------------------------------------------
459 
460 void TaskStatusBar::RequestHelp( const HelpEvent& rHEvt )
461 {
462     sal_Bool bFieldRect;
463     ImplTaskSBFldItem* pItem = ImplGetFieldItem( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ), bFieldRect );
464     if ( bFieldRect )
465     {
466         ITaskStatusNotify*  pNotify = mpNotify;
467         sal_uInt16              nItemId = 0;
468 
469         if ( pItem )
470         {
471             pNotify = pItem->maItem.GetNotifyObject();
472             nItemId = pItem->mnId;
473         }
474 
475         if ( pNotify )
476             pNotify->UpdateHelp( nItemId );
477 
478         if ( rHEvt.GetMode() & (HELPMODE_BALLOON | HELPMODE_QUICK) )
479         {
480             Rectangle aItemRect = GetItemRect( TASKSTATUSBAR_STATUSFIELDID );
481             Point aPt = OutputToScreenPixel( aItemRect.TopLeft() );
482             aItemRect.Left()   = aPt.X();
483             aItemRect.Top()    = aPt.Y();
484             aPt = OutputToScreenPixel( aItemRect.BottomRight() );
485             aItemRect.Right()  = aPt.X();
486             aItemRect.Bottom() = aPt.Y();
487             if ( pItem )
488             {
489                 if ( rHEvt.GetMode() & HELPMODE_BALLOON )
490                 {
491                     XubString aStr = pItem->maItem.GetHelpText();
492                     if ( !aStr.Len() )
493                         aStr = pItem->maItem.GetQuickHelpText();
494                     Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aStr );
495                 }
496                 else
497                     Help::ShowQuickHelp( this, aItemRect, pItem->maItem.GetQuickHelpText() );
498             }
499             else
500             {
501                 SvtSysLocale aSL;
502                 const LocaleDataWrapper& rLDW = aSL.GetLocaleData();
503                 CalendarWrapper aCal( rLDW.getServiceFactory());
504                 aCal.loadDefaultCalendar( rLDW.getLoadedLocale());
505                 XubString aStr = rLDW.getLongDate( Date(), aCal );
506                 if ( rHEvt.GetMode() & HELPMODE_BALLOON )
507                     Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aStr );
508                 else
509                     Help::ShowQuickHelp( this, aItemRect, aStr );
510             }
511             return;
512         }
513         else if ( rHEvt.GetMode() & HELPMODE_EXTENDED )
514         {
515             if ( pItem )
516             {
517                 rtl::OUString aHelpId( rtl::OStringToOUString( pItem->maItem.GetHelpId(), RTL_TEXTENCODING_UTF8 ) );
518                 if ( aHelpId.getLength() )
519                 {
520                     // Wenn eine Hilfe existiert, dann ausloesen
521                     Help* pHelp = Application::GetHelp();
522                     if ( pHelp )
523                         pHelp->Start( aHelpId, this );
524                     return;
525                 }
526             }
527         }
528     }
529 
530     StatusBar::RequestHelp( rHEvt );
531 }
532 
533 // -----------------------------------------------------------------------
534 
535 void TaskStatusBar::UserDraw( const UserDrawEvent& rUDEvt )
536 {
537     if ( rUDEvt.GetItemId() == TASKSTATUSBAR_STATUSFIELDID )
538     {
539         OutputDevice*   pDev = rUDEvt.GetDevice();
540         Rectangle       aRect = rUDEvt.GetRect();
541 
542         if ( mpFieldItemList )
543         {
544             ImplTaskSBFldItem* pItem = mpFieldItemList->First();
545             while ( pItem )
546             {
547                 if ( !mbOutInterval || !(pItem->maItem.GetFlags() & TASKSTATUSFIELDITEM_FLASH) )
548                 {
549                     const Image& rImage = pItem->maItem.GetImage();
550                     Size aImgSize = rImage.GetSizePixel();
551                     pDev->DrawImage( Point( aRect.Left()+pItem->mnOffX,
552                                             aRect.Top()+((aRect.GetHeight()-aImgSize.Width())/2) ),
553                                      rImage );
554                 }
555 
556                 pItem = mpFieldItemList->Next();
557             }
558         }
559 
560         if ( mnFieldFlags & TASKSTATUSFIELD_CLOCK )
561         {
562             long nX = mnItemWidth+TASKSTATUSBAR_CLOCXOFFX;
563             Point aPos = GetItemTextPos( TASKSTATUSBAR_STATUSFIELDID );
564             aPos.X() = aRect.Left()+nX;
565             pDev->DrawText( aPos, maTimeText );
566         }
567     }
568     else
569         StatusBar::UserDraw( rUDEvt );
570 }
571 
572 // -----------------------------------------------------------------------
573 
574 void TaskStatusBar::InsertStatusField( long, sal_uInt16,
575                                        sal_uInt16 nFlags )
576 {
577     mnFieldFlags = nFlags;
578     ImplUpdateField( sal_False );
579 }
580 
581 // -----------------------------------------------------------------------
582 
583 void TaskStatusBar::SetFieldFlags( sal_uInt16 nFlags )
584 {
585     if ( mnFieldFlags != nFlags )
586     {
587         mnFieldFlags = nFlags;
588         ImplUpdateField( sal_False );
589     }
590 }
591 
592 // -----------------------------------------------------------------------
593 
594 void TaskStatusBar::AddStatusFieldItem( sal_uInt16 nItemId, const TaskStatusFieldItem& rItem,
595                                         sal_uInt16 nPos )
596 {
597     DBG_ASSERT( nItemId, "TaskStatusBar::AddStatusFieldItem() - Item is 0" );
598     DBG_ASSERT( !ImplGetFieldItem( nItemId ), "TaskStatusBar::AddStatusFieldItem() - Item-Id already exist" );
599 
600     if ( !mpFieldItemList )
601         mpFieldItemList = new ImplTaskSBItemList;
602 
603     ImplTaskSBFldItem* pItem = new ImplTaskSBFldItem;
604     pItem->maItem   = rItem;
605     pItem->mnId     = nItemId;
606     pItem->mnOffX   = 0;
607     mpFieldItemList->Insert( pItem, (sal_uLong)nPos );
608 
609     ImplUpdateField( sal_True );
610 }
611 
612 // -----------------------------------------------------------------------
613 
614 void TaskStatusBar::ModifyStatusFieldItem( sal_uInt16 nItemId, const TaskStatusFieldItem& rItem )
615 {
616     ImplTaskSBFldItem* pItem = ImplGetFieldItem( nItemId );
617     if ( pItem )
618     {
619         sal_Bool bUpdate = (pItem->maItem.GetImage() != rItem.GetImage()) ||
620                        (pItem->maItem.GetFlags() != rItem.GetFlags());
621         pItem->maItem = rItem;
622         if ( bUpdate )
623             ImplUpdateField( sal_True );
624     }
625 }
626 
627 // -----------------------------------------------------------------------
628 
629 void TaskStatusBar::RemoveStatusFieldItem( sal_uInt16 nItemId )
630 {
631     ImplTaskSBFldItem* pItem = ImplGetFieldItem( nItemId );
632     if ( pItem )
633     {
634         mpFieldItemList->Remove( pItem );
635         delete pItem;
636         ImplUpdateField( sal_True );
637     }
638 }
639 
640 // -----------------------------------------------------------------------
641 
642 sal_Bool TaskStatusBar::GetStatusFieldItem( sal_uInt16 nItemId, TaskStatusFieldItem& rItem ) const
643 {
644     ImplTaskSBFldItem* pItem = ImplGetFieldItem( nItemId );
645     if ( pItem )
646     {
647         rItem = pItem->maItem;
648         return sal_True;
649     }
650 
651     return sal_False;
652 }
653 
654