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