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