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 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_chart2.hxx" 30 31 #include "tp_DataSource.hxx" 32 #include "tp_DataSource.hrc" 33 #include "Strings.hrc" 34 #include "ResId.hxx" 35 #include "chartview/ChartSfxItemIds.hxx" 36 #include "macros.hxx" 37 #include "ChartTypeTemplateProvider.hxx" 38 #include "RangeSelectionHelper.hxx" 39 #include "DataSeriesHelper.hxx" 40 #include "tp_DataSourceControls.hxx" 41 #include "ControllerLockGuard.hxx" 42 #include "DataSourceHelper.hxx" 43 #include <com/sun/star/sheet/XRangeSelection.hpp> 44 #include <com/sun/star/table/XCellRange.hpp> 45 #include <com/sun/star/chart2/XChartType.hpp> 46 #include <com/sun/star/chart2/XChartTypeTemplate.hpp> 47 #include <com/sun/star/util/XModifiable.hpp> 48 #include <com/sun/star/chart2/data/XDataSink.hpp> 49 50 // for RET_OK 51 #include <vcl/msgbox.hxx> 52 #include <rtl/ustrbuf.hxx> 53 54 #include <functional> 55 #include <algorithm> 56 #include <map> 57 58 using namespace ::com::sun::star; 59 using namespace ::com::sun::star::chart2; 60 61 using ::com::sun::star::uno::Reference; 62 using ::com::sun::star::uno::Sequence; 63 using ::rtl::OUString; 64 using ::rtl::OUStringBuffer; 65 66 // -------------------------------------------------------------------------------- 67 68 namespace 69 { 70 71 const OUString lcl_aLabelRole( RTL_CONSTASCII_USTRINGPARAM( "label" )); 72 73 String lcl_GetRoleLBEntry( 74 const OUString & rRole, const OUString & rRange ) 75 { 76 String aEntry( rRole ); 77 aEntry += '\t'; 78 aEntry += String( 79 ::chart::DialogModel::ConvertRoleFromInternalToUI( rRole )); 80 aEntry += '\t'; 81 aEntry += String( rRange ); 82 83 return aEntry; 84 } 85 86 void lcl_UpdateCurrentRange( 87 SvTabListBox & rOutListBox, 88 const OUString & rRole, const OUString & rRange ) 89 { 90 SvLBoxEntry * pEntry = rOutListBox.FirstSelected(); 91 if( pEntry ) 92 rOutListBox.SetEntryText( lcl_GetRoleLBEntry( rRole, rRange ), pEntry ); 93 } 94 95 bool lcl_UpdateCurrentSeriesName( 96 SvTreeListBox & rOutListBox ) 97 { 98 bool bResult = false; 99 ::chart::SeriesEntry * pEntry = dynamic_cast< ::chart::SeriesEntry * >( rOutListBox.FirstSelected()); 100 if( pEntry && 101 pEntry->m_xDataSeries.is() && 102 pEntry->m_xChartType.is()) 103 { 104 String aLabel( ::chart::DataSeriesHelper::getDataSeriesLabel( 105 pEntry->m_xDataSeries, 106 pEntry->m_xChartType->getRoleOfSequenceForSeriesLabel())); 107 if( aLabel.Len()) 108 { 109 rOutListBox.SetEntryText( pEntry, aLabel ); 110 bResult = true; 111 } 112 } 113 return bResult; 114 } 115 116 OUString lcl_GetSelectedRole( const SvTabListBox & rRoleListBox, bool bUITranslated = false ) 117 { 118 OUString aResult; 119 SvLBoxEntry * pEntry = rRoleListBox.FirstSelected(); 120 if( pEntry ) 121 aResult = OUString( rRoleListBox.GetEntryText( pEntry, 122 bUITranslated ? 1 : 0 )); 123 return aResult; 124 } 125 126 OUString lcl_GetSelectedRolesRange( const SvTabListBox & rRoleListBox ) 127 { 128 OUString aResult; 129 SvLBoxEntry * pEntry = rRoleListBox.FirstSelected(); 130 if( pEntry ) 131 aResult = OUString( rRoleListBox.GetEntryText( pEntry, 2 )); 132 return aResult; 133 } 134 135 OUString lcl_GetSequenceNameForLabel( ::chart::SeriesEntry * pEntry ) 136 { 137 OUString aResult( RTL_CONSTASCII_USTRINGPARAM("values-y")); 138 if( pEntry && 139 pEntry->m_xChartType.is()) 140 { 141 aResult = pEntry->m_xChartType->getRoleOfSequenceForSeriesLabel(); 142 } 143 return aResult; 144 } 145 146 static long lcl_pRoleListBoxTabs[] = 147 { 3, // Number of Tabs 148 0, 0, 75 149 }; 150 151 void lcl_ShowChooserButton( 152 ::chart::RangeSelectionButton & rChooserButton, 153 Edit & rEditField, 154 sal_Bool bShow ) 155 { 156 if( rChooserButton.IsVisible() != bShow ) 157 { 158 rChooserButton.Show( bShow ); 159 sal_Int32 nWidhtDiff = 12 + 4; 160 if( bShow ) 161 nWidhtDiff = -nWidhtDiff; 162 Size aSize = rChooserButton.PixelToLogic( rEditField.GetSizePixel(), MAP_APPFONT ); 163 aSize.setWidth( aSize.getWidth() + nWidhtDiff ); 164 rEditField.SetSizePixel( rChooserButton.LogicToPixel( aSize, MAP_APPFONT )); 165 } 166 } 167 168 void lcl_enableRangeChoosing( bool bEnable, Dialog * pDialog ) 169 { 170 if( pDialog ) 171 { 172 pDialog->Show( bEnable ? sal_False : sal_True ); 173 pDialog->SetModalInputMode( bEnable ? sal_False : sal_True ); 174 } 175 } 176 177 void lcl_addLSequenceToDataSource( 178 const Reference< chart2::data::XLabeledDataSequence > & xLSequence, 179 const Reference< chart2::data::XDataSource > & xSource ) 180 { 181 Reference< data::XDataSink > xSink( xSource, uno::UNO_QUERY ); 182 if( xSink.is()) 183 { 184 Sequence< Reference< chart2::data::XLabeledDataSequence > > aData( xSource->getDataSequences()); 185 aData.realloc( aData.getLength() + 1 ); 186 aData[ aData.getLength() - 1 ] = xLSequence; 187 xSink->setData( aData ); 188 } 189 } 190 191 Reference< chart2::data::XLabeledDataSequence > lcl_findLSequenceWithOnlyLabel( 192 const Reference< chart2::data::XDataSource > & xDataSource ) 193 { 194 Reference< chart2::data::XLabeledDataSequence > xResult; 195 Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences( xDataSource->getDataSequences()); 196 197 for( sal_Int32 i=0; i<aSequences.getLength(); ++i ) 198 { 199 // no values are set but a label exists 200 if( ! aSequences[i]->getValues().is() && 201 aSequences[i]->getLabel().is()) 202 { 203 xResult.set( aSequences[i] ); 204 break; 205 } 206 } 207 208 return xResult; 209 } 210 211 void lcl_shiftControlY( Control & rControl, long nYOffset ) 212 { 213 Point aPos( rControl.GetPosPixel()); 214 aPos.setY( aPos.getY() + nYOffset ); 215 rControl.SetPosPixel( aPos ); 216 } 217 218 void lcl_increaseHeightOfControl( Control & rControl, long nYOffset ) 219 { 220 Size aSize( rControl.GetSizePixel()); 221 aSize.setHeight( aSize.getHeight () + nYOffset ); 222 rControl.SetSizePixel( aSize ); 223 } 224 225 } // anonymous namespace 226 227 // -------------------------------------------------------------------------------- 228 229 namespace chart 230 { 231 232 DataSourceTabPage::DataSourceTabPage( 233 Window * pParent, 234 DialogModel & rDialogModel, 235 ChartTypeTemplateProvider* pTemplateProvider, 236 Dialog * pParentDialog, 237 bool bHideDescription /* = false */ ) : 238 ::svt::OWizardPage( pParent, SchResId( TP_DATA_SOURCE )), 239 240 m_aFT_CAPTION ( this, SchResId( FT_CAPTION_FOR_WIZARD )), 241 m_aFT_SERIES ( this, SchResId( FT_SERIES )), 242 m_apLB_SERIES( new SeriesListBox( this, SchResId( LB_SERIES ))), 243 m_aBTN_ADD ( this, SchResId( BTN_ADD )), 244 m_aBTN_REMOVE ( this, SchResId( BTN_REMOVE )), 245 m_aBTN_UP ( this, SchResId( BTN_UP )), 246 m_aBTN_DOWN ( this, SchResId( BTN_DOWN )), 247 m_aFT_ROLE ( this, SchResId( FT_ROLE )), 248 m_aLB_ROLE ( this, SchResId( LB_ROLE )), 249 m_aFT_RANGE ( this, SchResId( FT_RANGE )), 250 m_aEDT_RANGE ( this, SchResId( EDT_RANGE )), 251 m_aIMB_RANGE_MAIN ( this, SchResId( IMB_RANGE_MAIN )), 252 m_aFT_CATEGORIES ( this, SchResId( FT_CATEGORIES )), 253 m_aFT_DATALABELS ( this, SchResId( FT_DATALABELS )), 254 m_aEDT_CATEGORIES ( this, SchResId( EDT_CATEGORIES )), 255 m_aIMB_RANGE_CAT ( this, SchResId( IMB_RANGE_CAT )), 256 257 m_pTemplateProvider( pTemplateProvider ), 258 m_rDialogModel( rDialogModel ), 259 260 m_pCurrentRangeChoosingField( 0 ), 261 m_bIsDirty( false ), 262 m_pParentDialog( pParentDialog ), 263 m_pTabPageNotifiable( dynamic_cast< TabPageNotifiable * >( pParentDialog )) 264 { 265 FreeResource(); 266 267 if( bHideDescription ) 268 { 269 // note: the offset should be a negative value for shifting upwards, the 270 // 4 is for the offset difference between a wizard page and a tab-page 271 long nYOffset = - ( m_aFT_SERIES.GetPosPixel().getY() - m_aFT_CAPTION.GetPosPixel().getY() + 4 ); 272 long nUpShift = - 2; 273 long nYResize = - (nYOffset - nUpShift); 274 m_aFT_CAPTION.Hide(); 275 276 // shift list boxes and enlarge them by the space saved by hiding the caption 277 lcl_shiftControlY( m_aFT_SERIES, nYOffset ); 278 lcl_shiftControlY( *(m_apLB_SERIES.get()), nYOffset ); 279 lcl_increaseHeightOfControl( *(m_apLB_SERIES.get()), nYResize ); 280 281 lcl_shiftControlY( m_aFT_ROLE, nYOffset ); 282 lcl_shiftControlY( m_aLB_ROLE, nYOffset ); 283 lcl_increaseHeightOfControl( m_aLB_ROLE, nYResize ); 284 285 lcl_shiftControlY( m_aBTN_ADD, nUpShift ); 286 lcl_shiftControlY( m_aBTN_REMOVE, nUpShift ); 287 lcl_shiftControlY( m_aBTN_UP, nUpShift ); 288 lcl_shiftControlY( m_aBTN_DOWN, nUpShift ); 289 lcl_shiftControlY( m_aFT_RANGE, nUpShift ); 290 lcl_shiftControlY( m_aEDT_RANGE, nUpShift ); 291 lcl_shiftControlY( m_aIMB_RANGE_MAIN, nUpShift ); 292 lcl_shiftControlY( m_aFT_CATEGORIES, nUpShift ); 293 lcl_shiftControlY( m_aFT_DATALABELS, nUpShift ); 294 lcl_shiftControlY( m_aEDT_CATEGORIES, nUpShift ); 295 lcl_shiftControlY( m_aIMB_RANGE_CAT, nUpShift ); 296 } 297 else 298 { 299 // make font of caption bold 300 Font aFont( m_aFT_CAPTION.GetControlFont() ); 301 aFont.SetWeight( WEIGHT_BOLD ); 302 m_aFT_CAPTION.SetControlFont( aFont ); 303 304 // no mnemonic 305 m_aFT_CAPTION.SetStyle( m_aFT_CAPTION.GetStyle() | WB_NOLABEL ); 306 } 307 308 m_aFixedTextRange = OUString( m_aFT_RANGE.GetText() ); 309 this->SetText( String( SchResId( STR_OBJECT_DATASERIES_PLURAL ) ) ); 310 311 // set handlers 312 m_apLB_SERIES->SetSelectHdl( LINK( this, DataSourceTabPage, SeriesSelectionChangedHdl )); 313 314 m_aLB_ROLE.SetStyle( m_aLB_ROLE.GetStyle() | WB_HSCROLL | WB_CLIPCHILDREN ); 315 m_aLB_ROLE.SetSelectionMode( SINGLE_SELECTION ); 316 m_aLB_ROLE.SetSelectHdl( LINK( this, DataSourceTabPage, RoleSelectionChangedHdl )); 317 318 m_aEDT_RANGE.SetKeyInputHdl( LINK( this, DataSourceTabPage, MainRangeButtonClickedHdl )); 319 m_aEDT_CATEGORIES.SetKeyInputHdl( LINK( this, DataSourceTabPage, CategoriesRangeButtonClickedHdl )); 320 321 m_aIMB_RANGE_MAIN.SetClickHdl( LINK( this, DataSourceTabPage, MainRangeButtonClickedHdl )); 322 m_aIMB_RANGE_CAT.SetClickHdl( LINK( this, DataSourceTabPage, CategoriesRangeButtonClickedHdl )); 323 324 m_aBTN_ADD.SetClickHdl( LINK( this, DataSourceTabPage, AddButtonClickedHdl )); 325 m_aBTN_REMOVE.SetClickHdl( LINK( this, DataSourceTabPage, RemoveButtonClickedHdl )); 326 327 m_aBTN_UP.SetClickHdl( LINK( this, DataSourceTabPage, UpButtonClickedHdl )); 328 m_aBTN_DOWN.SetClickHdl( LINK( this, DataSourceTabPage, DownButtonClickedHdl )); 329 330 m_aEDT_RANGE.SetModifyHdl( LINK( this, DataSourceTabPage, RangeModifiedHdl )); 331 m_aEDT_CATEGORIES.SetModifyHdl( LINK( this, DataSourceTabPage, RangeModifiedHdl )); 332 m_aEDT_RANGE.SetUpdateDataHdl( LINK( this, DataSourceTabPage, RangeUpdateDataHdl )); 333 m_aEDT_CATEGORIES.SetUpdateDataHdl( LINK( this, DataSourceTabPage, RangeUpdateDataHdl )); 334 335 // #i75179# enable setting the background to a different color 336 m_aEDT_RANGE.SetStyle( m_aEDT_RANGE.GetStyle() | WB_FORCECTRLBACKGROUND ); 337 m_aEDT_CATEGORIES.SetStyle( m_aEDT_CATEGORIES.GetStyle() | WB_FORCECTRLBACKGROUND ); 338 339 // set symbol font for arrows 340 // note: StarSymbol is substituted to OpenSymbol for OOo 341 Font aSymbolFont( m_aBTN_UP.GetFont()); 342 aSymbolFont.SetName( String( RTL_CONSTASCII_USTRINGPARAM( "StarSymbol" ))); 343 m_aBTN_UP.SetControlFont( aSymbolFont ); 344 m_aBTN_DOWN.SetControlFont( aSymbolFont ); 345 346 // set button text 347 sal_Unicode cBlackUpPointingTriangle( 0x25b2 ); 348 sal_Unicode cBlackDownPointingTriangle( 0x25bc ); 349 m_aBTN_UP.SetText( String( cBlackUpPointingTriangle )); 350 m_aBTN_DOWN.SetText( String( cBlackDownPointingTriangle )); 351 352 // init controls 353 m_aLB_ROLE.SetTabs( lcl_pRoleListBoxTabs, MAP_APPFONT ); 354 m_aLB_ROLE.Show(); 355 356 updateControlsFromDialogModel(); 357 358 // select first series 359 if( m_apLB_SERIES->First()) 360 m_apLB_SERIES->Select( m_apLB_SERIES->First()); 361 m_apLB_SERIES->GrabFocus(); 362 m_aBTN_UP.SetAccessibleName(String(SchResId(STR_BUTTON_UP))); 363 m_aBTN_DOWN.SetAccessibleName(String(SchResId(STR_BUTTON_DOWN))); 364 } 365 366 DataSourceTabPage::~DataSourceTabPage() 367 {} 368 369 void DataSourceTabPage::ActivatePage() 370 { 371 OWizardPage::ActivatePage(); 372 updateControlsFromDialogModel(); 373 } 374 375 void DataSourceTabPage::initializePage() 376 { 377 } 378 379 void DataSourceTabPage::DeactivatePage() 380 { 381 commitPage(); 382 svt::OWizardPage::DeactivatePage(); 383 } 384 385 void DataSourceTabPage::commitPage() 386 { 387 commitPage(::svt::WizardTypes::eFinish); 388 } 389 390 sal_Bool DataSourceTabPage::commitPage( ::svt::WizardTypes::CommitPageReason /*eReason*/ ) 391 { 392 //ranges may have been edited in the meanwhile (dirty is true in that case here) 393 if( isValid() ) 394 { 395 updateModelFromControl( 0 /*update all*/ ); 396 return sal_True;//return false if this page should not be left 397 } 398 else 399 return sal_False; 400 } 401 402 bool DataSourceTabPage::isRangeFieldContentValid( Edit & rEdit ) 403 { 404 OUString aRange( rEdit.GetText()); 405 bool bIsValid = ( aRange.getLength() == 0 ) || 406 m_rDialogModel.getRangeSelectionHelper()->verifyCellRange( aRange ); 407 408 if( bIsValid ) 409 { 410 rEdit.SetControlForeground(); 411 rEdit.SetControlBackground(); 412 } 413 else 414 { 415 rEdit.SetControlBackground( RANGE_SELECTION_INVALID_RANGE_BACKGROUND_COLOR ); 416 rEdit.SetControlForeground( RANGE_SELECTION_INVALID_RANGE_FOREGROUND_COLOR ); 417 } 418 419 return bIsValid; 420 } 421 422 bool DataSourceTabPage::isValid() 423 { 424 bool bRoleRangeValid = true; 425 bool bCategoriesRangeValid = true; 426 bool bHasSelectedEntry = (m_apLB_SERIES->FirstSelected() != 0); 427 428 if( bHasSelectedEntry ) 429 bRoleRangeValid = isRangeFieldContentValid( m_aEDT_RANGE ); 430 if( m_aEDT_CATEGORIES.IsEnabled() ) 431 bCategoriesRangeValid = isRangeFieldContentValid( m_aEDT_CATEGORIES ); 432 bool bValid = ( bRoleRangeValid && bCategoriesRangeValid ); 433 434 if( m_pTabPageNotifiable ) 435 { 436 if( bValid ) 437 m_pTabPageNotifiable->setValidPage( this ); 438 else 439 m_pTabPageNotifiable->setInvalidPage( this ); 440 } 441 442 return bValid; 443 } 444 445 void DataSourceTabPage::setDirty() 446 { 447 m_bIsDirty = true; 448 } 449 450 void DataSourceTabPage::updateControlsFromDialogModel() 451 { 452 // series 453 fillSeriesListBox(); 454 SeriesSelectionChangedHdl( 0 ); 455 456 // categories 457 m_aEDT_CATEGORIES.SetText( String( m_rDialogModel.getCategoriesRange() )); 458 459 updateControlState(); 460 } 461 462 void DataSourceTabPage::fillSeriesListBox() 463 { 464 m_apLB_SERIES->SetUpdateMode( sal_False ); 465 466 Reference< XDataSeries > xSelected; 467 SeriesEntry * pEntry = dynamic_cast< SeriesEntry * >( m_apLB_SERIES->FirstSelected()); 468 if( pEntry ) 469 xSelected.set( pEntry->m_xDataSeries ); 470 471 bool bHasSelectedEntry = (pEntry != 0); 472 SvLBoxEntry * pSelectedEntry = 0; 473 m_apLB_SERIES->Clear(); 474 475 ::std::vector< DialogModel::tSeriesWithChartTypeByName > aSeries( 476 m_rDialogModel.getAllDataSeriesWithLabel() ); 477 478 sal_Int32 nUnnamedSeriesIndex = 1; 479 for( ::std::vector< DialogModel::tSeriesWithChartTypeByName >::const_iterator aIt = aSeries.begin(); 480 aIt != aSeries.end(); ++aIt ) 481 { 482 String aLabel( (*aIt).first ); 483 if( !aLabel.Len()) 484 { 485 if( nUnnamedSeriesIndex > 1 ) 486 { 487 OUString aResString( String( ::chart::SchResId( STR_DATA_UNNAMED_SERIES_WITH_INDEX ))); 488 489 // replace index of unnamed series 490 const OUString aReplacementStr( RTL_CONSTASCII_USTRINGPARAM( "%NUMBER" )); 491 sal_Int32 nIndex = aResString.indexOf( aReplacementStr ); 492 if( nIndex != -1 ) 493 aLabel = String( aResString.replaceAt( 494 nIndex, aReplacementStr.getLength(), 495 String::CreateFromInt32( nUnnamedSeriesIndex ))); 496 } 497 if( aLabel.Len() == 0 ) 498 aLabel = String( ::chart::SchResId( STR_DATA_UNNAMED_SERIES )); 499 500 ++nUnnamedSeriesIndex; 501 } 502 pEntry = dynamic_cast< SeriesEntry * >( 503 m_apLB_SERIES->InsertEntry( aLabel )); 504 if( pEntry ) 505 { 506 pEntry->m_xDataSeries.set( (*aIt).second.first ); 507 pEntry->m_xChartType.set( (*aIt).second.second ); 508 if( bHasSelectedEntry && ((*aIt).second.first == xSelected)) 509 pSelectedEntry = pEntry; 510 } 511 } 512 513 if( bHasSelectedEntry && pSelectedEntry ) 514 m_apLB_SERIES->Select( pSelectedEntry ); 515 516 m_apLB_SERIES->SetUpdateMode( sal_True ); 517 } 518 519 void DataSourceTabPage::fillRoleListBox() 520 { 521 SeriesEntry * pSeriesEntry = dynamic_cast< SeriesEntry * >( m_apLB_SERIES->FirstSelected()); 522 bool bHasSelectedEntry = (pSeriesEntry != 0); 523 524 SvLBoxEntry * pRoleEntry = m_aLB_ROLE.FirstSelected(); 525 sal_uLong nRoleIndex = SAL_MAX_UINT32; 526 if( pRoleEntry ) 527 nRoleIndex = m_aLB_ROLE.GetModel()->GetAbsPos( pRoleEntry ); 528 529 if( bHasSelectedEntry ) 530 { 531 DialogModel::tRolesWithRanges aRoles( 532 m_rDialogModel.getRolesWithRanges( 533 pSeriesEntry->m_xDataSeries, 534 lcl_GetSequenceNameForLabel( pSeriesEntry ), 535 pSeriesEntry->m_xChartType )); 536 537 // fill role list 538 m_aLB_ROLE.SetUpdateMode( sal_False ); 539 m_aLB_ROLE.Clear(); 540 m_aLB_ROLE.RemoveSelection(); 541 542 for( DialogModel::tRolesWithRanges::const_iterator aIt( aRoles.begin()); 543 aIt != aRoles.end(); ++ aIt ) 544 { 545 m_aLB_ROLE.InsertEntry( lcl_GetRoleLBEntry( aIt->first, aIt->second )); 546 } 547 548 // series may contain no roles, check listbox size before selecting entries 549 if( m_aLB_ROLE.GetEntryCount() > 0 ) 550 { 551 if( nRoleIndex >= m_aLB_ROLE.GetEntryCount()) 552 nRoleIndex = 0; 553 m_aLB_ROLE.Select( m_aLB_ROLE.GetEntry( nRoleIndex )); 554 } 555 556 m_aLB_ROLE.SetUpdateMode( sal_True ); 557 } 558 } 559 560 void DataSourceTabPage::updateControlState() 561 { 562 SvLBoxEntry * pSeriesEntry = m_apLB_SERIES->FirstSelected(); 563 bool bHasSelectedSeries = (pSeriesEntry != 0); 564 bool bHasValidRole = false; 565 bool bHasRangeChooser = m_rDialogModel.getRangeSelectionHelper()->hasRangeSelection(); 566 567 if( bHasSelectedSeries ) 568 { 569 SvLBoxEntry * pRoleEntry = m_aLB_ROLE.FirstSelected(); 570 bHasValidRole = (pRoleEntry != 0); 571 } 572 573 m_aBTN_ADD.Enable( true ); 574 m_aBTN_REMOVE.Enable( bHasSelectedSeries ); 575 576 m_aBTN_UP.Enable( bHasSelectedSeries && (pSeriesEntry != m_apLB_SERIES->First())); 577 m_aBTN_DOWN.Enable( bHasSelectedSeries && (pSeriesEntry != m_apLB_SERIES->Last())); 578 579 bool bHasCategories = m_rDialogModel.isCategoryDiagram(); 580 581 m_aFT_DATALABELS.Show(!bHasCategories); 582 m_aFT_CATEGORIES.Show( bHasCategories); 583 sal_Bool bShowIB = bHasRangeChooser; 584 lcl_ShowChooserButton( m_aIMB_RANGE_CAT, m_aEDT_CATEGORIES, bShowIB ); 585 586 m_aFT_SERIES.Enable(); 587 m_apLB_SERIES->Enable(); 588 589 m_aFT_ROLE.Enable( bHasSelectedSeries ); 590 m_aLB_ROLE.Enable( bHasSelectedSeries ); 591 592 m_aFT_RANGE.Enable( bHasValidRole ); 593 m_aEDT_RANGE.Enable( bHasValidRole ); 594 lcl_ShowChooserButton( m_aIMB_RANGE_MAIN, m_aEDT_RANGE, bShowIB ); 595 isValid(); 596 } 597 598 IMPL_LINK( DataSourceTabPage, SeriesSelectionChangedHdl, void *, EMPTYARG ) 599 { 600 m_rDialogModel.startControllerLockTimer(); 601 if( m_apLB_SERIES->FirstSelected()) 602 { 603 fillRoleListBox(); 604 RoleSelectionChangedHdl( 0 ); 605 } 606 updateControlState(); 607 608 return 0; 609 } 610 611 IMPL_LINK( DataSourceTabPage, RoleSelectionChangedHdl, void *, EMPTYARG ) 612 { 613 m_rDialogModel.startControllerLockTimer(); 614 SvLBoxEntry * pEntry = m_aLB_ROLE.FirstSelected(); 615 if( pEntry ) 616 { 617 OUString aRange( m_aEDT_RANGE.GetText()); 618 OUString aSelectedRoleUI = lcl_GetSelectedRole( m_aLB_ROLE, true ); 619 OUString aSelectedRange = lcl_GetSelectedRolesRange( m_aLB_ROLE ); 620 621 // replace role in fixed text label 622 const OUString aReplacementStr( RTL_CONSTASCII_USTRINGPARAM( "%VALUETYPE" )); 623 sal_Int32 nIndex = m_aFixedTextRange.indexOf( aReplacementStr ); 624 if( nIndex != -1 ) 625 { 626 m_aFT_RANGE.SetText( 627 String( m_aFixedTextRange.replaceAt( 628 nIndex, aReplacementStr.getLength(), aSelectedRoleUI ))); 629 } 630 631 m_aEDT_RANGE.SetText( String( aSelectedRange )); 632 isValid(); 633 } 634 635 return 0; 636 } 637 638 IMPL_LINK( DataSourceTabPage, MainRangeButtonClickedHdl, void *, EMPTYARG ) 639 { 640 OSL_ASSERT( m_pCurrentRangeChoosingField == 0 ); 641 m_pCurrentRangeChoosingField = & m_aEDT_RANGE; 642 if( m_aEDT_RANGE.GetText().Len() > 0 && 643 ! updateModelFromControl( m_pCurrentRangeChoosingField )) 644 return 0; 645 646 SeriesEntry * pEntry = dynamic_cast< SeriesEntry * >( m_apLB_SERIES->FirstSelected()); 647 bool bHasSelectedEntry = (pEntry != 0); 648 649 OUString aSelectedRolesRange = lcl_GetSelectedRolesRange( m_aLB_ROLE ); 650 651 if( bHasSelectedEntry && (m_aLB_ROLE.FirstSelected() != 0)) 652 { 653 String aStr( SchResId( STR_DATA_SELECT_RANGE_FOR_SERIES )); 654 OUString aUIStr( aStr ); 655 656 // replace role 657 OUString aReplacement( RTL_CONSTASCII_USTRINGPARAM( "%VALUETYPE" )); 658 sal_Int32 nIndex = aUIStr.indexOf( aReplacement ); 659 if( nIndex != -1 ) 660 { 661 aUIStr = aUIStr.replaceAt( nIndex, aReplacement.getLength(), 662 lcl_GetSelectedRole( m_aLB_ROLE, true )); 663 } 664 // replace series name 665 aReplacement = C2U( "%SERIESNAME" ); 666 nIndex = aUIStr.indexOf( aReplacement ); 667 if( nIndex != -1 ) 668 { 669 aUIStr = aUIStr.replaceAt( nIndex, aReplacement.getLength(), 670 OUString( m_apLB_SERIES->GetEntryText( pEntry ))); 671 } 672 673 lcl_enableRangeChoosing( true, m_pParentDialog ); 674 m_rDialogModel.getRangeSelectionHelper()->chooseRange( aSelectedRolesRange, aUIStr, *this ); 675 } 676 else 677 m_pCurrentRangeChoosingField = 0; 678 679 return 0; 680 } 681 682 IMPL_LINK( DataSourceTabPage, CategoriesRangeButtonClickedHdl, void *, EMPTYARG ) 683 { 684 OSL_ASSERT( m_pCurrentRangeChoosingField == 0 ); 685 m_pCurrentRangeChoosingField = & m_aEDT_CATEGORIES; 686 if( m_aEDT_CATEGORIES.GetText().Len() > 0 && 687 ! updateModelFromControl( m_pCurrentRangeChoosingField )) 688 return 0; 689 690 String aStr( SchResId( m_aFT_CATEGORIES.IsVisible() ? STR_DATA_SELECT_RANGE_FOR_CATEGORIES : STR_DATA_SELECT_RANGE_FOR_DATALABELS )); 691 lcl_enableRangeChoosing( true, m_pParentDialog ); 692 m_rDialogModel.getRangeSelectionHelper()->chooseRange( 693 m_rDialogModel.getCategoriesRange(), OUString( aStr ), *this ); 694 return 0; 695 } 696 697 IMPL_LINK( DataSourceTabPage, AddButtonClickedHdl, void *, EMPTYARG ) 698 { 699 m_rDialogModel.startControllerLockTimer(); 700 SeriesEntry * pEntry = dynamic_cast< SeriesEntry * >( m_apLB_SERIES->FirstSelected()); 701 Reference< XDataSeries > xSeriesToInsertAfter; 702 Reference< XChartType > xChartTypeForNewSeries; 703 if( m_pTemplateProvider ) 704 m_rDialogModel.setTemplate( m_pTemplateProvider->getCurrentTemplate()); 705 706 if( pEntry ) 707 { 708 xSeriesToInsertAfter.set( pEntry->m_xDataSeries ); 709 xChartTypeForNewSeries.set( pEntry->m_xChartType ); 710 } 711 else 712 { 713 ::std::vector< Reference< XDataSeriesContainer > > aCntVec( 714 m_rDialogModel.getAllDataSeriesContainers()); 715 if( ! aCntVec.empty()) 716 xChartTypeForNewSeries.set( aCntVec.front(), uno::UNO_QUERY ); 717 } 718 OSL_ENSURE( xChartTypeForNewSeries.is(), "Cannot insert new series" ); 719 720 m_rDialogModel.insertSeriesAfter( xSeriesToInsertAfter, xChartTypeForNewSeries ); 721 setDirty(); 722 723 fillSeriesListBox(); 724 // note the box was cleared and refilled, so pEntry is invalid now 725 SvLBoxEntry * pSelEntry = m_apLB_SERIES->FirstSelected(); 726 if( pSelEntry ) 727 { 728 SvLBoxEntry * pNextEntry = m_apLB_SERIES->Next( pSelEntry ); 729 if( pNextEntry ) 730 m_apLB_SERIES->Select( pNextEntry ); 731 } 732 SeriesSelectionChangedHdl( 0 ); 733 734 return 0; 735 } 736 737 IMPL_LINK( DataSourceTabPage, RemoveButtonClickedHdl, void *, EMPTYARG ) 738 { 739 m_rDialogModel.startControllerLockTimer(); 740 SeriesEntry * pEntry = dynamic_cast< SeriesEntry * >( m_apLB_SERIES->FirstSelected()); 741 if( pEntry ) 742 { 743 Reference< XDataSeries > xNewSelSeries; 744 SeriesEntry * pNewSelEntry = dynamic_cast< SeriesEntry * >( 745 m_apLB_SERIES->Next( pEntry )); 746 if( pNewSelEntry ) 747 xNewSelSeries.set( pNewSelEntry->m_xDataSeries ); 748 else 749 { 750 pNewSelEntry = dynamic_cast< SeriesEntry * >( m_apLB_SERIES->Prev( pEntry )); 751 if( pNewSelEntry ) 752 xNewSelSeries.set( pNewSelEntry->m_xDataSeries ); 753 } 754 755 m_rDialogModel.deleteSeries( pEntry->m_xDataSeries, pEntry->m_xChartType ); 756 setDirty(); 757 758 m_apLB_SERIES->RemoveSelection(); 759 fillSeriesListBox(); 760 761 // select previous or next series 762 //@improve: see methods GetModel()->GetAbsPos()/GetEntry() for absoulte list positions 763 if( xNewSelSeries.is()) 764 { 765 pEntry = dynamic_cast< SeriesEntry * >( m_apLB_SERIES->First()); 766 while( pEntry ) 767 { 768 if( pEntry->m_xDataSeries == xNewSelSeries ) 769 { 770 m_apLB_SERIES->Select( pEntry ); 771 break; 772 } 773 pEntry = dynamic_cast< SeriesEntry * >( m_apLB_SERIES->Next( pEntry )); 774 } 775 } 776 SeriesSelectionChangedHdl( 0 ); 777 } 778 779 return 0; 780 } 781 782 IMPL_LINK( DataSourceTabPage, UpButtonClickedHdl, void *, EMPTYARG ) 783 { 784 m_rDialogModel.startControllerLockTimer(); 785 SeriesEntry * pEntry = dynamic_cast< SeriesEntry * >( m_apLB_SERIES->FirstSelected()); 786 bool bHasSelectedEntry = (pEntry != 0); 787 788 if( bHasSelectedEntry ) 789 { 790 m_rDialogModel.moveSeries( pEntry->m_xDataSeries, DialogModel::MOVE_UP ); 791 setDirty(); 792 fillSeriesListBox(); 793 SeriesSelectionChangedHdl(0); 794 } 795 796 return 0; 797 } 798 799 IMPL_LINK( DataSourceTabPage, DownButtonClickedHdl, void *, EMPTYARG ) 800 { 801 m_rDialogModel.startControllerLockTimer(); 802 SeriesEntry * pEntry = dynamic_cast< SeriesEntry * >( m_apLB_SERIES->FirstSelected()); 803 bool bHasSelectedEntry = (pEntry != 0); 804 805 if( bHasSelectedEntry ) 806 { 807 m_rDialogModel.moveSeries( pEntry->m_xDataSeries, DialogModel::MOVE_DOWN ); 808 setDirty(); 809 fillSeriesListBox(); 810 SeriesSelectionChangedHdl(0); 811 } 812 813 return 0; 814 } 815 816 IMPL_LINK( DataSourceTabPage, RangeModifiedHdl, Edit*, pEdit ) 817 { 818 if( isRangeFieldContentValid( *pEdit )) 819 setDirty(); 820 821 // enable/disable OK button 822 isValid(); 823 824 return 0; 825 } 826 827 IMPL_LINK( DataSourceTabPage, RangeUpdateDataHdl, Edit*, pEdit ) 828 { 829 // note: isValid sets the color of the edit field 830 if( isRangeFieldContentValid( *pEdit )) 831 { 832 setDirty(); 833 updateModelFromControl( pEdit ); 834 if( pEdit== &m_aEDT_RANGE ) 835 { 836 if( ! lcl_UpdateCurrentSeriesName( *m_apLB_SERIES )) 837 fillSeriesListBox(); 838 } 839 } 840 // enable/disable OK button 841 isValid(); 842 843 return 0; 844 } 845 846 void DataSourceTabPage::listeningFinished( 847 const ::rtl::OUString & rNewRange ) 848 { 849 // rNewRange becomes invalid after removing the listener 850 OUString aRange( rNewRange ); 851 852 m_rDialogModel.startControllerLockTimer(); 853 854 // stop listening 855 m_rDialogModel.getRangeSelectionHelper()->stopRangeListening(); 856 857 // change edit field 858 ToTop(); 859 GrabFocus(); 860 if( m_pCurrentRangeChoosingField ) 861 { 862 m_pCurrentRangeChoosingField->SetText( String( aRange )); 863 m_pCurrentRangeChoosingField->GrabFocus(); 864 } 865 866 if( m_pCurrentRangeChoosingField == & m_aEDT_RANGE ) 867 { 868 m_aEDT_RANGE.SetText( String( aRange )); 869 setDirty(); 870 } 871 else if( m_pCurrentRangeChoosingField == & m_aEDT_CATEGORIES ) 872 { 873 m_aEDT_CATEGORIES.SetText( String( aRange )); 874 setDirty(); 875 } 876 877 updateModelFromControl( m_pCurrentRangeChoosingField ); 878 if( ! lcl_UpdateCurrentSeriesName( *m_apLB_SERIES )) 879 fillSeriesListBox(); 880 881 m_pCurrentRangeChoosingField = 0; 882 883 updateControlState(); 884 lcl_enableRangeChoosing( false, m_pParentDialog ); 885 } 886 887 void DataSourceTabPage::disposingRangeSelection() 888 { 889 m_rDialogModel.getRangeSelectionHelper()->stopRangeListening( false ); 890 } 891 892 bool DataSourceTabPage::updateModelFromControl( Edit * pField ) 893 { 894 if( !m_bIsDirty ) 895 return true; 896 897 ControllerLockGuard aLockedControllers( m_rDialogModel.getChartModel() ); 898 899 // @todo: validity check of field content 900 bool bResult = true; 901 bool bAll = (pField == 0); 902 Reference< data::XDataProvider > xDataProvider( m_rDialogModel.getDataProvider()); 903 904 if( bAll || (pField == & m_aEDT_CATEGORIES) ) 905 { 906 Reference< data::XLabeledDataSequence > xLabeledSeq( m_rDialogModel.getCategories() ); 907 if( xDataProvider.is()) 908 { 909 OUString aRange( m_aEDT_CATEGORIES.GetText()); 910 if( aRange.getLength()) 911 { 912 // create or change categories 913 if( !xLabeledSeq.is()) 914 { 915 xLabeledSeq.set( DataSourceHelper::createLabeledDataSequence( Reference< uno::XComponentContext >(0))); 916 m_rDialogModel.setCategories( xLabeledSeq ); 917 } 918 try 919 { 920 xLabeledSeq->setValues( xDataProvider->createDataSequenceByRangeRepresentation( aRange )); 921 } 922 catch( const uno::Exception & ex ) 923 { 924 // should work as validation should have happened before 925 ASSERT_EXCEPTION( ex ); 926 } 927 } 928 else if( xLabeledSeq.is()) 929 { 930 // clear existing categories 931 xLabeledSeq.set(0); 932 m_rDialogModel.setCategories( xLabeledSeq ); 933 } 934 } 935 } 936 937 SeriesEntry * pSeriesEntry = dynamic_cast< SeriesEntry * >( m_apLB_SERIES->FirstSelected()); 938 bool bHasSelectedEntry = (pSeriesEntry != 0); 939 940 if( bHasSelectedEntry ) 941 { 942 if( bAll || (pField == & m_aEDT_RANGE) ) 943 { 944 try 945 { 946 OUString aSelectedRole = lcl_GetSelectedRole( m_aLB_ROLE ); 947 OUString aRange( m_aEDT_RANGE.GetText()); 948 OUString aSequenceRole( aSelectedRole ); 949 bool bIsLabel = aSequenceRole.equals( lcl_aLabelRole ); 950 OUString aSequenceNameForLabel( lcl_GetSequenceNameForLabel( pSeriesEntry )); 951 952 if( bIsLabel ) 953 aSequenceRole = aSequenceNameForLabel; 954 955 Reference< data::XDataSource > xSource( pSeriesEntry->m_xDataSeries, uno::UNO_QUERY_THROW ); 956 Reference< data::XLabeledDataSequence > xLabeledSeq( 957 DataSeriesHelper::getDataSequenceByRole( xSource, aSequenceRole )); 958 959 if( xDataProvider.is()) 960 { 961 if( bIsLabel ) 962 { 963 if( ! xLabeledSeq.is()) 964 { 965 // check if there is already an "orphan" label sequence 966 xLabeledSeq.set( lcl_findLSequenceWithOnlyLabel( xSource )); 967 if( ! xLabeledSeq.is()) 968 { 969 // no corresponding labeled data sequence for label found 970 xLabeledSeq.set( DataSourceHelper::createLabeledDataSequence( Reference< uno::XComponentContext >(0))); 971 lcl_addLSequenceToDataSource( xLabeledSeq, xSource ); 972 } 973 } 974 if( xLabeledSeq.is()) 975 { 976 if( aRange.getLength()) 977 { 978 Reference< data::XDataSequence > xNewSeq; 979 try 980 { 981 xNewSeq.set( xDataProvider->createDataSequenceByRangeRepresentation( aRange )); 982 } 983 catch( const uno::Exception & ex ) 984 { 985 // should work as validation should have happened before 986 ASSERT_EXCEPTION( ex ); 987 } 988 if( xNewSeq.is()) 989 { 990 // update range name by the full string provided 991 // by the data provider. E.g. "a1" might become 992 // "$Sheet1.$A$1" 993 aRange = xNewSeq->getSourceRangeRepresentation(); 994 Reference< beans::XPropertySet > xProp( xNewSeq, uno::UNO_QUERY_THROW ); 995 xProp->setPropertyValue( C2U("Role"), uno::makeAny( lcl_aLabelRole )); 996 xLabeledSeq->setLabel( xNewSeq ); 997 } 998 } 999 else 1000 { 1001 xLabeledSeq->setLabel( Reference< data::XDataSequence >()); 1002 } 1003 } 1004 } 1005 else 1006 { 1007 if( aRange.getLength()) 1008 { 1009 Reference< data::XDataSequence > xNewSeq; 1010 try 1011 { 1012 xNewSeq.set( xDataProvider->createDataSequenceByRangeRepresentation( aRange )); 1013 } 1014 catch( const uno::Exception & ex ) 1015 { 1016 // should work as validation should have happened before 1017 ASSERT_EXCEPTION( ex ); 1018 } 1019 if( xNewSeq.is()) 1020 { 1021 // update range name by the full string provided 1022 // by the data provider. E.g. "a1:e1" might become 1023 // "$Sheet1.$A$1:$E$1" 1024 aRange = xNewSeq->getSourceRangeRepresentation(); 1025 1026 Reference< beans::XPropertySet > xProp( xNewSeq, uno::UNO_QUERY_THROW ); 1027 xProp->setPropertyValue( C2U("Role"), uno::makeAny( aSelectedRole )); 1028 if( !xLabeledSeq.is()) 1029 { 1030 if( aSelectedRole.equals( aSequenceNameForLabel )) 1031 xLabeledSeq.set( lcl_findLSequenceWithOnlyLabel( xSource )); 1032 if( ! xLabeledSeq.is()) 1033 { 1034 xLabeledSeq.set( DataSourceHelper::createLabeledDataSequence( Reference< uno::XComponentContext >(0))); 1035 lcl_addLSequenceToDataSource( xLabeledSeq, xSource ); 1036 } 1037 } 1038 xLabeledSeq->setValues( xNewSeq ); 1039 } 1040 } 1041 else if( xLabeledSeq.is()) 1042 { 1043 // values cannot be deleted. This would also delete the Role (for labels) 1044 // xLabeledSeq->setValues( Reference< data::XDataSequence >()); 1045 } 1046 } 1047 } 1048 1049 lcl_UpdateCurrentRange( m_aLB_ROLE, aSelectedRole, aRange ); 1050 } 1051 catch( uno::Exception & ex ) 1052 { 1053 bResult = false; 1054 ASSERT_EXCEPTION( ex ); 1055 } 1056 } 1057 } 1058 1059 // update View 1060 // @todo remove this when automatic view updates from calc, writer and own data sequences are available 1061 if( bResult ) 1062 { 1063 try 1064 { 1065 Reference< util::XModifiable > xModifiable( m_rDialogModel.getChartModel(), uno::UNO_QUERY ); 1066 if( xModifiable.is() ) 1067 xModifiable->setModified( sal_True ); 1068 } 1069 catch( uno::Exception & ex ) 1070 { 1071 ASSERT_EXCEPTION( ex ); 1072 } 1073 } 1074 1075 return bResult; 1076 } 1077 1078 } // namespace chart 1079