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