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