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