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
lcl_GetRoleLBEntry(const OUString & rRole,const OUString & rRange)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
lcl_UpdateCurrentRange(SvTabListBox & rOutListBox,const OUString & rRole,const OUString & rRange)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
lcl_UpdateCurrentSeriesName(SvTreeListBox & rOutListBox)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
lcl_GetSelectedRole(const SvTabListBox & rRoleListBox,bool bUITranslated=false)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
lcl_GetSelectedRolesRange(const SvTabListBox & rRoleListBox)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
lcl_GetSequenceNameForLabel(::chart::SeriesEntry * pEntry)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
lcl_ShowChooserButton(::chart::RangeSelectionButton & rChooserButton,Edit & rEditField,sal_Bool bShow)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
lcl_enableRangeChoosing(bool bEnable,Dialog * pDialog)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
lcl_addLSequenceToDataSource(const Reference<chart2::data::XLabeledDataSequence> & xLSequence,const Reference<chart2::data::XDataSource> & xSource)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
lcl_findLSequenceWithOnlyLabel(const Reference<chart2::data::XDataSource> & xDataSource)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
lcl_shiftControlY(Control & rControl,long nYOffset)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
lcl_increaseHeightOfControl(Control & rControl,long nYOffset)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
DataSourceTabPage(Window * pParent,DialogModel & rDialogModel,ChartTypeTemplateProvider * pTemplateProvider,Dialog * pParentDialog,bool bHideDescription)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
~DataSourceTabPage()362 DataSourceTabPage::~DataSourceTabPage()
363 {}
364
ActivatePage()365 void DataSourceTabPage::ActivatePage()
366 {
367 OWizardPage::ActivatePage();
368 updateControlsFromDialogModel();
369 }
370
initializePage()371 void DataSourceTabPage::initializePage()
372 {
373 }
374
DeactivatePage()375 void DataSourceTabPage::DeactivatePage()
376 {
377 commitPage();
378 svt::OWizardPage::DeactivatePage();
379 }
380
commitPage()381 void DataSourceTabPage::commitPage()
382 {
383 commitPage(::svt::WizardTypes::eFinish);
384 }
385
commitPage(::svt::WizardTypes::CommitPageReason)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
isRangeFieldContentValid(Edit & rEdit)398 bool DataSourceTabPage::isRangeFieldContentValid( Edit & rEdit )
399 {
400 OUString aRange( rEdit.GetText());
401 bool bIsValid = aRange.isEmpty() ||
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
isValid()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
setDirty()441 void DataSourceTabPage::setDirty()
442 {
443 m_bIsDirty = true;
444 }
445
updateControlsFromDialogModel()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
fillSeriesListBox()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
fillRoleListBox()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
updateControlState()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
IMPL_LINK(DataSourceTabPage,SeriesSelectionChangedHdl,void *,EMPTYARG)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
IMPL_LINK(DataSourceTabPage,RoleSelectionChangedHdl,void *,EMPTYARG)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
IMPL_LINK(DataSourceTabPage,MainRangeButtonClickedHdl,void *,EMPTYARG)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
IMPL_LINK(DataSourceTabPage,CategoriesRangeButtonClickedHdl,void *,EMPTYARG)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
IMPL_LINK(DataSourceTabPage,AddButtonClickedHdl,void *,EMPTYARG)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
IMPL_LINK(DataSourceTabPage,RemoveButtonClickedHdl,void *,EMPTYARG)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
IMPL_LINK(DataSourceTabPage,UpButtonClickedHdl,void *,EMPTYARG)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
IMPL_LINK(DataSourceTabPage,DownButtonClickedHdl,void *,EMPTYARG)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
IMPL_LINK(DataSourceTabPage,RangeModifiedHdl,Edit *,pEdit)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
IMPL_LINK(DataSourceTabPage,RangeUpdateDataHdl,Edit *,pEdit)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
listeningFinished(const::rtl::OUString & rNewRange)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
disposingRangeSelection()883 void DataSourceTabPage::disposingRangeSelection()
884 {
885 m_rDialogModel.getRangeSelectionHelper()->stopRangeListening( false );
886 }
887
updateModelFromControl(Edit * pField)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.isEmpty() )
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.isEmpty() )
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.isEmpty() )
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