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 #include "wrapper.hxx"
29 
30 #include <com/sun/star/awt/PosSize.hpp>
31 #include <com/sun/star/awt/XActionListener.hpp>
32 #include <com/sun/star/awt/XButton.hpp>
33 #include <com/sun/star/awt/XCheckBox.hpp>
34 #include <com/sun/star/awt/XRadioButton.hpp>
35 #include <com/sun/star/graphic/XGraphic.hpp>
36 #include <cppuhelper/implbase1.hxx>
37 #include <toolkit/awt/vclxwindow.hxx>
38 #include <toolkit/awt/vclxwindows.hxx>
39 #include <toolkit/helper/convert.hxx>
40 #include <vcl/button.hxx>
41 #include <vcl/event.hxx>
42 #include <vcl/msgbox.hxx>
43 #include <vcl/svapp.hxx>
44 #include <vcl/window.hxx>
45 
46 #include <list>
47 
48 #include <layout/core/helper.hxx>
49 
50 using namespace ::com::sun::star;
51 
52 using rtl::OUString;
53 
54 namespace layout
55 {
56 
57 class ImageImpl
58 {
59   public:
60     uno::Reference< graphic::XGraphic > mxGraphic;
61     ImageImpl( const char *pName )
62         : mxGraphic( layoutimpl::loadGraphic( pName ) )
63     {
64         if ( !mxGraphic.is() )
65         {
66             DBG_ERROR1( "ERROR: failed to load image: `%s'\n", pName );
67         }
68     }
69 };
70 
71 Image::Image( const char *pName )
72     : pImpl( new ImageImpl( pName ) )
73 {
74 }
75 
76 Image::~Image()
77 {
78     delete pImpl;
79 }
80 
81 class ButtonImpl : public ControlImpl
82                  , public ::cppu::WeakImplHelper1< awt::XActionListener >
83 {
84     Link maClickHdl;
85 
86 public:
87     uno::Reference< awt::XButton > mxButton;
88     ButtonImpl( Context *context, const PeerHandle &peer, Window *window )
89         : ControlImpl( context, peer, window )
90         , mxButton( peer, uno::UNO_QUERY )
91     {
92         /* We have default action when clicked, always listen. */
93         mxButton->addActionListener( this );
94     }
95 
96     ~ButtonImpl()
97     {
98     }
99 
100     virtual void Click() { /* make me pure virtual? */ };
101 
102     Link& GetClickHdl ()
103     {
104         return maClickHdl;
105     }
106 
107     virtual void SetClickHdl( Link const& link )
108     {
109         maClickHdl = link;
110     }
111 
112     void SAL_CALL disposing( lang::EventObject const& e )
113         throw (uno::RuntimeException)
114     {
115         mxButton->removeActionListener( this );
116         ControlImpl::disposing (e);
117         mxButton.clear ();
118     }
119 
120     virtual void SAL_CALL actionPerformed( const awt::ActionEvent& )
121         throw (uno::RuntimeException)
122     {
123         if ( !maClickHdl )
124             Click();
125         else
126             maClickHdl.Call( static_cast<Window *>( mpWindow ) );
127     }
128 
129     bool SetModeImage( uno::Reference< graphic::XGraphic > xGraph )
130     {
131         setProperty( "Graphic", uno::Any( xGraph ) );
132         return true;
133     }
134 };
135 
136 Button::~Button ()
137 {
138 }
139 
140 String Button::GetStandardText (sal_uInt16 button_type)
141 {
142     return ::Button::GetStandardText (button_type);
143 }
144 
145 void Button::SetText( OUString const& rStr )
146 {
147     if ( !getImpl().mxButton.is() )
148         return;
149     getImpl().mxButton->setLabel( rStr );
150 }
151 
152 void Button::SetClickHdl( const Link& link )
153 {
154     if (&getImpl () && getImpl().mxButton.is ())
155         getImpl().SetClickHdl( link );
156 }
157 
158 Link& Button::GetClickHdl ()
159 {
160     return getImpl().GetClickHdl ();
161 }
162 
163 bool Button::SetModeImage (Image const& image)
164 {
165     return getImpl().SetModeImage (image.getImpl().mxGraphic);
166 }
167 
168 bool Button::SetModeImage (::Image const& image, BmpColorMode mode)
169 {
170     return GetButton ()->SetModeImage (image, mode);
171 }
172 
173 void Button::SetImageAlign( ImageAlign eAlign )
174 {
175     getImpl().setProperty( "ImageAlign", uno::Any( (sal_Int16) eAlign ) );
176 }
177 
178 void Button::Click()
179 {
180 }
181 
182 IMPL_GET_IMPL( Button );
183 IMPL_CONSTRUCTORS( Button, Control, "button" );
184 IMPL_GET_WINDOW (Button);
185 
186 class PushButtonImpl : public ButtonImpl
187                  , public ::cppu::WeakImplHelper1< awt::XItemListener >
188 {
189     Link maToggleHdl;
190 public:
191     PushButtonImpl( Context *context, const PeerHandle &peer, Window *window )
192         : ButtonImpl( context, peer, window )
193     {
194     }
195 
196     void SetToggleHdl( const Link& link )
197     {
198         // XButton doesn't have an explicit event for Toggle. Anyway, it is a
199         // superset of the clicks: all clicks, and explicit toggles
200         if (!link && !!maToggleHdl)
201             mxButton->removeActionListener( this );
202         else if (!!link && !maToggleHdl)
203             mxButton->addActionListener( this );
204         maToggleHdl = link;
205     }
206     void SAL_CALL disposing( lang::EventObject const& e )
207         throw (uno::RuntimeException)
208     {
209         ButtonImpl::disposing (e);
210     }
211     virtual void SAL_CALL actionPerformed( awt::ActionEvent const& e )
212         throw (uno::RuntimeException)
213     {
214         ButtonImpl::actionPerformed( e );
215         fireToggle();
216     }
217     virtual void SAL_CALL itemStateChanged( const awt::ItemEvent& )
218         throw (uno::RuntimeException)
219     {
220         maToggleHdl.Call( static_cast<Window *>( mpWindow ) );
221     }
222     void fireToggle()
223     {
224         maToggleHdl.Call(  static_cast<Window *>( mpWindow ) );
225     }
226 
227 };
228 
229 PushButton::~PushButton ()
230 {
231     SetToggleHdl (Link ());
232 }
233 
234 void PushButton::Check( bool bCheck )
235 {
236     getImpl().setProperty( "State", uno::Any( (sal_Int16) !!bCheck ) );
237     // XButton doesn't have explicit toggle event
238     getImpl().fireToggle();
239 }
240 
241 bool PushButton::IsChecked() const
242 {
243     return !!( getImpl().getProperty( "State" ).get< sal_Int16 >() );
244 }
245 
246 void PushButton::Toggle()
247 {
248     Check( true );
249 }
250 
251 void PushButton::SetToggleHdl( const Link& link )
252 {
253     if (&getImpl () && getImpl().mxButton.is ())
254         getImpl().SetToggleHdl( link );
255 }
256 
257 IMPL_GET_IMPL( PushButton );
258 IMPL_CONSTRUCTORS( PushButton, Button, "pushbutton" );
259 IMPL_GET_WINDOW (PushButton);
260 
261 class RadioButtonImpl : public ButtonImpl
262                       , public ::cppu::WeakImplHelper1< awt::XItemListener >
263 {
264     Link maToggleHdl;
265 public:
266     uno::Reference< awt::XRadioButton > mxRadioButton;
267     RadioButtonImpl( Context *context, const PeerHandle &peer, Window *window )
268         : ButtonImpl( context, peer, window )
269         , mxRadioButton( peer, uno::UNO_QUERY )
270     {
271     }
272 
273     void Check( bool bCheck )
274     {
275         if ( !mxRadioButton.is() )
276             return;
277 
278 #if 1
279         // Have setState fire item event for
280         // RadioGroups::RadioGroup::itemStateChanged ()
281         ::RadioButton *r = static_cast<RadioButton*>(mpWindow)->GetRadioButton ();
282         bool state = r->IsRadioCheckEnabled ();
283         r->EnableRadioCheck();
284         mxRadioButton->setState( !!bCheck );
285         r->EnableRadioCheck (state);
286 #else
287         mxRadioButton->setState( !!bCheck );
288 #endif
289         fireToggle();
290     }
291 
292     bool IsChecked()
293     {
294         if ( !mxRadioButton.is() )
295             return false;
296         return mxRadioButton->getState();
297     }
298 
299     void SetToggleHdl( const Link& link )
300     {
301         if (!link && !!maToggleHdl)
302             mxRadioButton->removeItemListener( this );
303         else if (!!link && !maToggleHdl)
304             mxRadioButton->addItemListener( this );
305         maToggleHdl = link;
306     }
307 
308     inline void fireToggle()
309     {
310         maToggleHdl.Call(  static_cast<Window *>( mpWindow ) );
311     }
312 
313     virtual void SetClickHdl( const Link& link )
314     {
315         // Keep RadioGroups::RadioGroup's actionListener at HEAD
316         // of list.  This way, it can handle RadioGroup's button
317         // states before all other callbacks and make sure the
318         // client code has the right state.
319 
320         // IWBN to add an XRadioButton2 and layout::VCLXRadioButton
321         // with {get,set}RadioGroup() (and a "radiogroup" property
322         // even) and handle the grouping here in RadioButtonImpl.
323         uno::Reference< uno::XInterface > x = static_cast<VCLXRadioButton*> (mpWindow->GetVCLXWindow ())->getFirstActionListener ();
324         uno::Reference< awt::XActionListener > a = uno::Reference< awt::XActionListener> (x ,uno::UNO_QUERY );
325         mxButton->removeActionListener (a);
326         ButtonImpl::SetClickHdl (link);
327         mxButton->addActionListener (a);
328     }
329 
330     void SAL_CALL disposing( lang::EventObject const& e )
331         throw (uno::RuntimeException)
332     {
333         ButtonImpl::disposing (e);
334     }
335 
336     virtual void SAL_CALL itemStateChanged( const awt::ItemEvent& )
337         throw (uno::RuntimeException)
338     {
339         maToggleHdl.Call( static_cast<Window *>( mpWindow ) );
340     }
341 };
342 
343 RadioButton::~RadioButton ()
344 {
345     SetToggleHdl (Link ());
346 }
347 
348 void RadioButton::Check( bool bCheck )
349 {
350     getImpl().Check( bCheck );
351 }
352 
353 bool RadioButton::IsChecked() const
354 {
355     return getImpl().IsChecked();
356 }
357 
358 void RadioButton::SetToggleHdl( const Link& link )
359 {
360     if (&getImpl () && getImpl().mxRadioButton.is ())
361         getImpl().SetToggleHdl( link );
362 }
363 
364 IMPL_GET_IMPL( RadioButton );
365 IMPL_GET_WINDOW( RadioButton );
366 IMPL_GET_VCLXWINDOW( RadioButton );
367 IMPL_CONSTRUCTORS( RadioButton, Button, "radiobutton" );
368 
369 class CheckBoxImpl : public ButtonImpl
370                  , public ::cppu::WeakImplHelper1< awt::XItemListener >
371 {
372     Link maToggleHdl;
373   public:
374     uno::Reference< awt::XCheckBox > mxCheckBox;
375     CheckBoxImpl( Context *context, const PeerHandle &peer, Window *window )
376         : ButtonImpl( context, peer, window )
377         , mxCheckBox( peer, uno::UNO_QUERY )
378     {
379     }
380 
381     void SetToggleHdl( const Link& link )
382     {
383         if (!link && !!maToggleHdl)
384             mxCheckBox->removeItemListener( this );
385         else if (!!link && !maToggleHdl)
386             mxCheckBox->addItemListener( this );
387         maToggleHdl = link;
388     }
389     void SAL_CALL disposing( lang::EventObject const& e )
390         throw (uno::RuntimeException)
391     {
392         ButtonImpl::disposing (e);
393     }
394     virtual void SAL_CALL itemStateChanged( const awt::ItemEvent& )
395         throw (uno::RuntimeException)
396     {
397         maToggleHdl.Call( static_cast<Window *>( mpWindow ) );
398     }
399 };
400 
401 CheckBox::~CheckBox ()
402 {
403     SetToggleHdl (Link ());
404 }
405 
406 void CheckBox::Check( bool bCheck )
407 {
408     if ( !getImpl().mxCheckBox.is() )
409         return;
410     getImpl().mxCheckBox->setState( !!bCheck );
411 }
412 
413 bool CheckBox::IsChecked() const
414 {
415     if ( !getImpl().mxCheckBox.is() )
416         return false;
417     return getImpl().mxCheckBox->getState() != 0;
418 }
419 
420 void CheckBox::SetToggleHdl( const Link& link )
421 {
422     if (&getImpl () && getImpl().mxCheckBox.is ())
423         getImpl().SetToggleHdl( link );
424 }
425 
426 IMPL_GET_IMPL( CheckBox );
427 IMPL_CONSTRUCTORS( CheckBox, Button, "checkbox" );
428 
429 #define BUTTON_IMPL(t, parent, response) \
430     class t##Impl : public parent##Impl \
431     { \
432     public: \
433         t##Impl( Context *context, PeerHandle const& peer, Window *window ) \
434             : parent##Impl( context, peer, window ) \
435         { \
436         } \
437         void Click() \
438         { \
439             if (Dialog *d = static_cast<Dialog *> (mpCtx)) \
440                 d->EndDialog( response ); \
441         } \
442     }
443 
444 /* Common button types currently unavailable in OOo: */
445 /* mpReset */
446 /* mpApply */
447 /* mpAction */
448 #define RET_RESET 6
449 #define RET_APPLY 7
450 #define BUTTONID_RESET RET_RESET
451 #define BUTTONID_APPLY RET_APPLY
452 
453 BUTTON_IMPL( OKButton, PushButton, BUTTONID_OK );
454 BUTTON_IMPL( CancelButton, PushButton, BUTTONID_CANCEL );
455 BUTTON_IMPL( YesButton, PushButton, BUTTONID_YES );
456 BUTTON_IMPL( NoButton, PushButton, BUTTONID_NO );
457 BUTTON_IMPL( RetryButton, PushButton, BUTTONID_RETRY );
458 BUTTON_IMPL( IgnoreButton, PushButton, BUTTONID_IGNORE );
459 BUTTON_IMPL( ResetButton, PushButton, BUTTONID_RESET );
460 BUTTON_IMPL( ApplyButton, PushButton, BUTTONID_APPLY ); /* Deprecated? */
461 BUTTON_IMPL( HelpButton, PushButton, BUTTONID_HELP );
462 
463 IMPL_CONSTRUCTORS( OKButton, PushButton, "okbutton" );
464 IMPL_CONSTRUCTORS( CancelButton, PushButton, "cancelbutton" );
465 IMPL_CONSTRUCTORS( YesButton, PushButton, "yesbutton" );
466 IMPL_CONSTRUCTORS( NoButton, PushButton, "nobutton" );
467 IMPL_CONSTRUCTORS( RetryButton, PushButton, "retrybutton" );
468 IMPL_CONSTRUCTORS( IgnoreButton, PushButton, "ignorebutton" );
469 IMPL_CONSTRUCTORS( ResetButton, PushButton, "resetbutton" );
470 IMPL_CONSTRUCTORS( ApplyButton, PushButton, "applybutton" );  /* Deprecated? */
471 IMPL_CONSTRUCTORS( HelpButton, PushButton, "helpbutton" );
472 
473 IMPL_IMPL (ImageButton, PushButton)
474 
475 
476 IMPL_CONSTRUCTORS( ImageButton, PushButton, "imagebutton" );
477 
478 class AdvancedButtonImpl : public PushButtonImpl
479 {
480 protected:
481     bool bAdvancedMode;
482     std::list< Window*> maAdvanced;
483     std::list< Window*> maSimple;
484 
485 public:
486     rtl::OUString mAdvancedLabel;
487     rtl::OUString mSimpleLabel;
488 
489 protected:
490     Window* Remove( std::list< Window*> lst, Window* w )
491     {
492         for ( std::list< Window*>::iterator it = maAdvanced.begin();
493               it != maAdvanced.end(); it++ )
494             if ( *it == w )
495             {
496                 lst.erase( it );
497                 return *it;
498             }
499         return 0;
500     }
501 
502 public:
503     AdvancedButtonImpl( Context *context, PeerHandle const& peer, Window *window )
504         : PushButtonImpl( context, peer, window )
505         , bAdvancedMode( false )
506           // TODO: i18n
507           // Button::GetStandardText( BUTTON_ADVANCED );
508           // Button::GetStandardText( BUTTON_SIMPLE );
509         , mAdvancedLabel( rtl::OUString::createFromAscii( "Advanced..." ) )
510         , mSimpleLabel( rtl::OUString::createFromAscii( "Simple..." ) )
511     {
512     }
513     void Click()
514     {
515         bAdvancedMode = !bAdvancedMode;
516         if ( bAdvancedMode )
517             advancedMode();
518         else
519             simpleMode();
520     }
521     void setAlign ()
522     {
523         ::PushButton *b = static_cast<PushButton*> (mpWindow)->GetPushButton ();
524         b->SetSymbolAlign (SYMBOLALIGN_RIGHT);
525         b->SetSmallSymbol ();
526         //mpWindow->SetStyle (mpWindow->GetStyle() | WB_CENTER);
527     }
528     void advancedMode()
529     {
530         ::PushButton *b = static_cast<PushButton*> (mpWindow)->GetPushButton ();
531         b->SetSymbol (SYMBOL_PAGEUP);
532         setAlign ();
533         if (mSimpleLabel.getLength ())
534             b->SetText (mSimpleLabel);
535         for ( std::list< Window*>::iterator it = maAdvanced.begin();
536               it != maAdvanced.end(); it++ )
537             ( *it )->Show();
538         for ( std::list< Window*>::iterator it = maSimple.begin();
539               it != maSimple.end(); it++ )
540             ( *it )->Hide();
541 
542         redraw ();
543     }
544     void simpleMode()
545     {
546         //mxButton->setLabel( mSimpleLabel );
547         ::PushButton *b = static_cast<PushButton*> (mpWindow)->GetPushButton ();
548         b->SetSymbol (SYMBOL_PAGEDOWN);
549         if (mAdvancedLabel.getLength ())
550             b->SetText (mAdvancedLabel);
551         setAlign ();
552         for ( std::list< Window*>::iterator it = maAdvanced.begin();
553               it != maAdvanced.end(); it++ )
554             ( *it )->Hide();
555         for ( std::list< Window*>::iterator it = maSimple.begin();
556               it != maSimple.end(); it++ )
557             ( *it )->Show();
558 
559         redraw (true);
560     }
561     void AddAdvanced( Window* w )
562     {
563         maAdvanced.push_back( w );
564         if ( !bAdvancedMode )
565             w->Hide();
566     }
567     void AddSimple( Window* w )
568     {
569         maSimple.push_back( w );
570         if ( bAdvancedMode )
571             w->Hide();
572     }
573     void RemoveAdvanced( Window* w )
574     {
575         Remove( maAdvanced, w );
576     }
577     void RemoveSimple( Window* w )
578     {
579         Remove( maSimple, w );
580     }
581 };
582 
583 void AdvancedButton::AddAdvanced( Window* w )
584 {
585     getImpl().AddAdvanced( w );
586 }
587 
588 void AdvancedButton::AddSimple( Window* w )
589 {
590     getImpl().AddSimple( w );
591 }
592 
593 void AdvancedButton::RemoveAdvanced( Window* w )
594 {
595     getImpl().RemoveAdvanced( w );
596 }
597 
598 void AdvancedButton::RemoveSimple( Window* w )
599 {
600     getImpl().RemoveSimple( w );
601 }
602 
603 void AdvancedButton::SetAdvancedText (rtl::OUString const& text)
604 {
605     if (text.getLength ())
606         getImpl ().mAdvancedLabel = text;
607 }
608 
609 void AdvancedButton::SetSimpleText (rtl::OUString const& text)
610 {
611     if (text.getLength ())
612         getImpl ().mSimpleLabel = text;
613 }
614 
615 rtl::OUString AdvancedButton::GetAdvancedText () const
616 {
617     return getImpl ().mAdvancedLabel;
618 }
619 
620 rtl::OUString AdvancedButton::GetSimpleText () const
621 {
622     return getImpl ().mSimpleLabel;
623 }
624 
625 void AdvancedButton::SetDelta (int)
626 {
627 }
628 
629 IMPL_CONSTRUCTORS_BODY( AdvancedButton, PushButton, "advancedbutton", getImpl().simpleMode () );
630 IMPL_GET_IMPL( AdvancedButton );
631 
632 
633 class MoreButtonImpl : public AdvancedButtonImpl
634 {
635 public:
636     MoreButtonImpl( Context *context, PeerHandle const& peer, Window *window )
637         : AdvancedButtonImpl( context, peer, window)
638     {
639         mSimpleLabel = Button::GetStandardText( BUTTON_MORE );
640         mAdvancedLabel = Button::GetStandardText( BUTTON_LESS );
641     }
642     void AddWindow( Window* w ) { AddAdvanced( w ); }
643     void RemoveWindow( Window* w ) { RemoveAdvanced( w ); }
644 };
645 
646 // TODO
647 //BUTTON_IMPL( MoreButton, PushButton, 0 );
648 IMPL_CONSTRUCTORS_BODY( MoreButton, AdvancedButton, "morebutton", getImpl().simpleMode () );
649 IMPL_GET_IMPL( MoreButton );
650 
651 void MoreButton::AddWindow( Window* w )
652 {
653     getImpl().AddWindow( w );
654 }
655 
656 void MoreButton::RemoveWindow( Window* w )
657 {
658     getImpl().RemoveWindow( w );
659 }
660 
661 void MoreButton::SetMoreText (rtl::OUString const& text)
662 {
663     SetAdvancedText (text);
664 }
665 
666 void MoreButton::SetLessText (rtl::OUString const& text)
667 {
668     SetSimpleText (text);
669 }
670 
671 rtl::OUString MoreButton::GetMoreText () const
672 {
673     return GetAdvancedText ();
674 }
675 
676 rtl::OUString MoreButton::GetLessText () const
677 {
678     return GetSimpleText ();
679 }
680 
681 } // namespace layout
682