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