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