Avoid potential negative array index access to cached text.
[LibreOffice.git] / chart2 / source / controller / dialogs / tp_DataSource.cxx
blobc30ce8afaedda0c492a8bbfe0eac6a794e7f4df6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "tp_DataSource.hxx"
21 #include <strings.hrc>
22 #include <ResId.hxx>
23 #include <ChartType.hxx>
24 #include <ChartTypeTemplateProvider.hxx>
25 #include <ChartTypeTemplate.hxx>
26 #include <ChartModel.hxx>
27 #include <RangeSelectionHelper.hxx>
28 #include <DataSeries.hxx>
29 #include <DataSeriesHelper.hxx>
30 #include <ControllerLockGuard.hxx>
31 #include <DataSourceHelper.hxx>
32 #include <LabeledDataSequence.hxx>
33 #include "DialogModel.hxx"
34 #include <o3tl/safeint.hxx>
35 #include <TabPageNotifiable.hxx>
36 #include <com/sun/star/chart2/XDataSeries.hpp>
37 #include <com/sun/star/chart2/data/XDataProvider.hpp>
39 #include <comphelper/diagnose_ex.hxx>
41 using namespace ::com::sun::star;
42 using namespace ::com::sun::star::chart2;
44 using ::com::sun::star::uno::Reference;
46 namespace
49 constexpr OUString lcl_aLabelRole( u"label"_ustr );
51 void lcl_UpdateCurrentRange(weld::TreeView& rOutListBox, const OUString & rRole,
52 const OUString& rRange)
54 int nEntry = rOutListBox.get_selected_index();
55 if (nEntry != -1)
57 rOutListBox.set_text(nEntry, ::chart::DialogModel::ConvertRoleFromInternalToUI(rRole), 0);
58 rOutListBox.set_text(nEntry, rRange, 1);
59 ::chart::SeriesEntry* pEntry = weld::fromId<::chart::SeriesEntry*>(rOutListBox.get_id(nEntry));
60 pEntry->m_sRole = rRole;
64 bool lcl_UpdateCurrentSeriesName(weld::TreeView& rOutListBox)
66 int nEntry = rOutListBox.get_selected_index();
67 if (nEntry == -1)
68 return false;
70 bool bResult = false;
71 ::chart::SeriesEntry * pEntry = weld::fromId<::chart::SeriesEntry*>(rOutListBox.get_id(nEntry));
72 if (pEntry->m_xDataSeries.is() && pEntry->m_xChartType.is())
74 OUString aLabel(pEntry->m_xDataSeries->getLabelForRole(
75 pEntry->m_xChartType->getRoleOfSequenceForSeriesLabel()));
76 if (!aLabel.isEmpty())
78 rOutListBox.set_text(nEntry, aLabel);
79 bResult = true;
82 return bResult;
85 OUString lcl_GetSelectedRole(const weld::TreeView& rRoleListBox, bool bUITranslated = false)
87 int nEntry = rRoleListBox.get_selected_index();
88 if (nEntry != -1)
90 if (bUITranslated)
91 return rRoleListBox.get_text(nEntry);
92 ::chart::SeriesEntry* pEntry = weld::fromId<::chart::SeriesEntry*>(rRoleListBox.get_id(nEntry));
93 return pEntry->m_sRole;
95 return OUString();
98 OUString lcl_GetSelectedRolesRange( const weld::TreeView& rRoleListBox )
100 OUString aResult;
101 int nEntry = rRoleListBox.get_selected_index();
102 if (nEntry != -1)
103 aResult = rRoleListBox.get_text(nEntry, 1);
104 return aResult;
107 OUString lcl_GetSequenceNameForLabel(const ::chart::SeriesEntry* pEntry)
109 OUString aResult("values-y");
110 if (pEntry && pEntry->m_xChartType.is())
111 aResult = pEntry->m_xChartType->getRoleOfSequenceForSeriesLabel();
112 return aResult;
115 void lcl_enableRangeChoosing(bool bEnable, weld::DialogController* pDialog)
117 if (!pDialog)
118 return;
119 weld::Dialog* pDlg = pDialog->getDialog();
120 pDlg->set_modal(!bEnable);
121 pDlg->set_visible(!bEnable);
124 void lcl_addLSequenceToDataSource(
125 const uno::Reference< chart2::data::XLabeledDataSequence > & xLSequence,
126 const Reference< ::chart::DataSeries > & xSource )
128 if( xSource.is())
130 std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aData = xSource->getDataSequences2();
131 aData.push_back( xLSequence );
132 xSource->setData( aData );
136 uno::Reference< chart2::data::XLabeledDataSequence > lcl_findLSequenceWithOnlyLabel(
137 const rtl::Reference< ::chart::DataSeries > & xDataSource )
139 uno::Reference< chart2::data::XLabeledDataSequence > xResult;
141 for( uno::Reference< chart2::data::XLabeledDataSequence > const & labeledDataSeq : xDataSource->getDataSequences2() )
143 // no values are set but a label exists
144 if( ! labeledDataSeq->getValues().is() &&
145 labeledDataSeq->getLabel().is())
147 xResult = labeledDataSeq;
148 break;
152 return xResult;
155 } // anonymous namespace
157 namespace chart
160 DataSourceTabPage::DataSourceTabPage(weld::Container* pPage, weld::DialogController* pController,
161 DialogModel & rDialogModel,
162 ChartTypeTemplateProvider* pTemplateProvider,
163 bool bHideDescription /* = false */)
164 : ::vcl::OWizardPage(pPage, pController, "modules/schart/ui/tp_DataSource.ui", "tp_DataSource")
165 , m_pTemplateProvider(pTemplateProvider)
166 , m_rDialogModel(rDialogModel)
167 , m_pCurrentRangeChoosingField( nullptr )
168 , m_bIsDirty( false )
169 , m_pTabPageNotifiable(dynamic_cast<TabPageNotifiable*>(pController))
170 , m_xFT_CAPTION(m_xBuilder->weld_label("FT_CAPTION_FOR_WIZARD"))
171 , m_xFT_SERIES(m_xBuilder->weld_label("FT_SERIES"))
172 , m_xLB_SERIES(m_xBuilder->weld_tree_view("LB_SERIES"))
173 , m_xBTN_ADD(m_xBuilder->weld_button("BTN_ADD"))
174 , m_xBTN_REMOVE(m_xBuilder->weld_button("BTN_REMOVE"))
175 , m_xBTN_UP(m_xBuilder->weld_button("BTN_UP"))
176 , m_xBTN_DOWN(m_xBuilder->weld_button("BTN_DOWN"))
177 , m_xFT_ROLE(m_xBuilder->weld_label("FT_ROLE"))
178 , m_xLB_ROLE(m_xBuilder->weld_tree_view("LB_ROLE"))
179 , m_xFT_RANGE(m_xBuilder->weld_label("FT_RANGE"))
180 , m_xEDT_RANGE(m_xBuilder->weld_entry("EDT_RANGE"))
181 , m_xIMB_RANGE_MAIN(m_xBuilder->weld_button("IMB_RANGE_MAIN"))
182 , m_xFT_CATEGORIES(m_xBuilder->weld_label("FT_CATEGORIES"))
183 , m_xFT_DATALABELS(m_xBuilder->weld_label("FT_DATALABELS"))
184 , m_xEDT_CATEGORIES(m_xBuilder->weld_entry("EDT_CATEGORIES"))
185 , m_xIMB_RANGE_CAT(m_xBuilder->weld_button("IMB_RANGE_CAT"))
187 m_xLB_SERIES->set_size_request(m_xLB_SERIES->get_approximate_digit_width() * 25,
188 m_xLB_SERIES->get_height_rows(10));
189 m_xLB_ROLE->set_size_request(m_xLB_ROLE->get_approximate_digit_width() * 60,
190 m_xLB_ROLE->get_height_rows(5));
191 m_xFT_CAPTION->set_visible(!bHideDescription);
193 m_aFixedTextRange = m_xFT_RANGE->get_label();
194 SetPageTitle(SchResId(STR_OBJECT_DATASERIES_PLURAL));
196 // set handlers
197 m_xLB_SERIES->connect_changed(LINK(this, DataSourceTabPage, SeriesSelectionChangedHdl));
198 m_xLB_ROLE->connect_changed(LINK(this, DataSourceTabPage, RoleSelectionChangedHdl));
200 m_xIMB_RANGE_MAIN->connect_clicked(LINK(this, DataSourceTabPage, MainRangeButtonClickedHdl));
201 m_xIMB_RANGE_CAT->connect_clicked(LINK(this, DataSourceTabPage, CategoriesRangeButtonClickedHdl));
203 m_xBTN_ADD->connect_clicked(LINK(this, DataSourceTabPage, AddButtonClickedHdl));
204 m_xBTN_REMOVE->connect_clicked(LINK(this, DataSourceTabPage, RemoveButtonClickedHdl));
206 m_xBTN_UP->connect_clicked(LINK(this, DataSourceTabPage, UpButtonClickedHdl));
207 m_xBTN_DOWN->connect_clicked(LINK(this, DataSourceTabPage, DownButtonClickedHdl));
209 m_xEDT_RANGE->connect_changed(LINK(this, DataSourceTabPage, RangeModifiedHdl));
210 m_xEDT_CATEGORIES->connect_changed(LINK( this, DataSourceTabPage, RangeModifiedHdl));
212 // init controls
213 std::vector<int> aWidths { o3tl::narrowing<int>(m_xLB_ROLE->get_approximate_digit_width() * 20) };
214 m_xLB_ROLE->set_column_fixed_widths(aWidths);
215 m_xLB_ROLE->show();
217 updateControlsFromDialogModel();
219 // select first series
220 if (m_xLB_SERIES->n_children())
221 m_xLB_SERIES->select(0);
224 void DataSourceTabPage::InsertRoleLBEntry(const OUString& rRole, const OUString& rRange)
226 m_aEntries.emplace_back(new SeriesEntry);
227 SeriesEntry* pEntry = m_aEntries.back().get();
228 pEntry->m_sRole = rRole;
229 m_xLB_ROLE->append(weld::toId(pEntry),
230 ::chart::DialogModel::ConvertRoleFromInternalToUI(rRole));
231 m_xLB_ROLE->set_text(m_xLB_ROLE->n_children() - 1, rRange, 1);
234 DataSourceTabPage::~DataSourceTabPage()
238 void DataSourceTabPage::Activate()
240 OWizardPage::Activate();
241 updateControlsFromDialogModel();
242 m_xLB_SERIES->grab_focus();
245 void DataSourceTabPage::initializePage()
249 void DataSourceTabPage::Deactivate()
251 commitPage();
252 vcl::OWizardPage::Deactivate();
255 void DataSourceTabPage::commitPage()
257 commitPage(::vcl::WizardTypes::eFinish);
260 bool DataSourceTabPage::commitPage( ::vcl::WizardTypes::CommitPageReason /*eReason*/ )
262 //ranges may have been edited in the meanwhile (dirty is true in that case here)
263 if( isValid() )
265 updateModelFromControl();
266 return true; //return false if this page should not be left
268 else
269 return false;
272 bool DataSourceTabPage::isRangeFieldContentValid(weld::Entry& rEdit )
274 OUString aRange(rEdit.get_text());
275 bool bIsValid = aRange.isEmpty() ||
276 m_rDialogModel.getRangeSelectionHelper()->verifyCellRange(aRange);
277 rEdit.set_message_type(bIsValid ? weld::EntryMessageType::Normal : weld::EntryMessageType::Error);
278 return bIsValid;
281 bool DataSourceTabPage::isValid()
283 bool bRoleRangeValid = true;
284 bool bCategoriesRangeValid = true;
285 bool bHasSelectedEntry = (m_xLB_SERIES->get_selected_index() != -1);
287 if (bHasSelectedEntry)
288 bRoleRangeValid = isRangeFieldContentValid(*m_xEDT_RANGE);
289 if (m_xEDT_CATEGORIES->get_sensitive())
290 bCategoriesRangeValid = isRangeFieldContentValid( *m_xEDT_CATEGORIES );
291 bool bValid = ( bRoleRangeValid && bCategoriesRangeValid );
293 if( m_pTabPageNotifiable )
295 if( bValid )
296 m_pTabPageNotifiable->setValidPage( this );
297 else
298 m_pTabPageNotifiable->setInvalidPage( this );
301 return bValid;
304 void DataSourceTabPage::setDirty()
306 m_bIsDirty = true;
309 void DataSourceTabPage::updateControlsFromDialogModel()
311 // series
312 fillSeriesListBox();
313 SeriesSelectionChangedHdl(*m_xLB_SERIES);
315 // categories
316 m_xEDT_CATEGORIES->set_text(m_rDialogModel.getCategoriesRange());
318 updateControlState();
321 void DataSourceTabPage::fillSeriesListBox()
323 rtl::Reference< DataSeries > xSelected;
324 SeriesEntry* pEntry = nullptr;
325 int nEntry = m_xLB_SERIES->get_selected_index();
326 if (nEntry != -1)
328 pEntry = weld::fromId<SeriesEntry*>(m_xLB_SERIES->get_id(nEntry));
329 xSelected = pEntry->m_xDataSeries;
332 bool bHasSelectedEntry = (pEntry != nullptr);
333 int nSelectedEntry = -1;
335 m_xLB_SERIES->freeze();
336 m_xLB_SERIES->clear();
338 std::vector< DialogModel::tSeriesWithChartTypeByName > aSeries(
339 m_rDialogModel.getAllDataSeriesWithLabel() );
341 sal_Int32 nUnnamedSeriesIndex = 1;
342 nEntry = 0;
343 for (auto const& series : aSeries)
345 OUString aLabel(series.first);
346 if (aLabel.isEmpty())
348 if( nUnnamedSeriesIndex > 1 )
350 OUString aResString(::chart::SchResId( STR_DATA_UNNAMED_SERIES_WITH_INDEX ));
352 // replace index of unnamed series
353 static constexpr OUString aReplacementStr( u"%NUMBER"_ustr );
354 sal_Int32 nIndex = aResString.indexOf( aReplacementStr );
355 if( nIndex != -1 )
356 aLabel = aResString.replaceAt(
357 nIndex, aReplacementStr.getLength(),
358 OUString::number(nUnnamedSeriesIndex));
360 if( aLabel.isEmpty() )
361 aLabel = ::chart::SchResId( STR_DATA_UNNAMED_SERIES );
363 ++nUnnamedSeriesIndex;
366 m_aEntries.emplace_back(new SeriesEntry);
367 pEntry = m_aEntries.back().get();
368 pEntry->m_xDataSeries = series.second.first;
369 pEntry->m_xChartType = series.second.second;
370 m_xLB_SERIES->append(weld::toId(pEntry), aLabel);
371 if (bHasSelectedEntry && series.second.first == xSelected)
372 nSelectedEntry = nEntry;
373 ++nEntry;
376 m_xLB_SERIES->thaw();
378 if (bHasSelectedEntry && nSelectedEntry != -1)
379 m_xLB_SERIES->select(nSelectedEntry);
382 void DataSourceTabPage::fillRoleListBox()
384 int nSeriesEntry = m_xLB_SERIES->get_selected_index();
385 SeriesEntry* pSeriesEntry = nullptr;
386 if (nSeriesEntry != -1)
387 pSeriesEntry = weld::fromId<SeriesEntry*>(m_xLB_SERIES->get_id(nSeriesEntry));
388 bool bHasSelectedEntry = (pSeriesEntry != nullptr);
390 int nRoleIndex = m_xLB_ROLE->get_selected_index();
391 if (!bHasSelectedEntry)
392 return;
394 DialogModel::tRolesWithRanges aRoles(
395 DialogModel::getRolesWithRanges(
396 pSeriesEntry->m_xDataSeries,
397 lcl_GetSequenceNameForLabel( pSeriesEntry ),
398 pSeriesEntry->m_xChartType ));
400 // fill role list
401 m_xLB_ROLE->freeze();
402 m_xLB_ROLE->clear();
404 for (auto const& elemRole : aRoles)
406 InsertRoleLBEntry(elemRole.first, elemRole.second);
409 m_xLB_ROLE->thaw();
411 // series may contain no roles, check listbox size before selecting entries
412 if (m_xLB_ROLE->n_children() > 0)
414 if (nRoleIndex == -1 || nRoleIndex >= m_xLB_ROLE->n_children())
415 nRoleIndex = 0;
416 m_xLB_ROLE->select(nRoleIndex);
420 void DataSourceTabPage::updateControlState()
422 int nSeriesEntry = m_xLB_SERIES->get_selected_index();
423 bool bHasSelectedSeries = nSeriesEntry != -1;
424 bool bHasValidRole = false;
425 bool bHasRangeChooser = m_rDialogModel.getRangeSelectionHelper()->hasRangeSelection();
427 if( bHasSelectedSeries )
429 int nRoleEntry = m_xLB_ROLE->get_selected_index();
430 bHasValidRole = nRoleEntry != -1;
433 m_xBTN_ADD->set_sensitive(true);
434 m_xBTN_REMOVE->set_sensitive(bHasSelectedSeries);
436 m_xBTN_UP->set_sensitive(bHasSelectedSeries && (nSeriesEntry != 0));
437 m_xBTN_DOWN->set_sensitive(bHasSelectedSeries && (nSeriesEntry != m_xLB_SERIES->n_children() - 1));
439 bool bHasCategories = m_rDialogModel.isCategoryDiagram();
441 m_xFT_DATALABELS->set_visible(!bHasCategories);
442 m_xFT_CATEGORIES->set_visible( bHasCategories);
443 bool bShowIB = bHasRangeChooser;
445 m_xIMB_RANGE_CAT->set_visible(bShowIB);
447 m_xFT_ROLE->set_sensitive(bHasSelectedSeries);
448 m_xLB_ROLE->set_sensitive(bHasSelectedSeries);
450 m_xFT_RANGE->set_sensitive(bHasValidRole);
451 m_xEDT_RANGE->set_sensitive(bHasValidRole);
453 m_xFT_SERIES->set_sensitive(true);
454 m_xLB_SERIES->set_sensitive(true);
456 m_xIMB_RANGE_MAIN->set_visible(bShowIB);
458 isValid();
461 IMPL_LINK_NOARG(DataSourceTabPage, SeriesSelectionChangedHdl, weld::TreeView&, void)
463 m_rDialogModel.startControllerLockTimer();
464 if (m_xLB_SERIES->get_selected_index() != -1)
466 fillRoleListBox();
467 RoleSelectionChangedHdl(*m_xLB_ROLE);
469 updateControlState();
472 IMPL_LINK_NOARG(DataSourceTabPage, RoleSelectionChangedHdl, weld::TreeView&, void)
474 m_rDialogModel.startControllerLockTimer();
475 int nEntry = m_xLB_ROLE->get_selected_index();
476 if (nEntry == -1)
477 return;
479 OUString aSelectedRoleUI = lcl_GetSelectedRole( *m_xLB_ROLE, true );
480 OUString aSelectedRange = lcl_GetSelectedRolesRange( *m_xLB_ROLE );
482 // replace role in fixed text label
483 static constexpr OUString aReplacementStr( u"%VALUETYPE"_ustr );
484 sal_Int32 nIndex = m_aFixedTextRange.indexOf( aReplacementStr );
485 if( nIndex != -1 )
487 m_xFT_RANGE->set_label(
488 m_aFixedTextRange.replaceAt(
489 nIndex, aReplacementStr.getLength(), aSelectedRoleUI ));
492 m_xEDT_RANGE->set_text(aSelectedRange);
493 isValid();
496 IMPL_LINK_NOARG(DataSourceTabPage, MainRangeButtonClickedHdl, weld::Button&, void)
498 OSL_ASSERT( m_pCurrentRangeChoosingField == nullptr );
499 m_pCurrentRangeChoosingField = m_xEDT_RANGE.get();
500 if (!m_xEDT_RANGE->get_text().isEmpty() &&
501 !updateModelFromControl( m_pCurrentRangeChoosingField))
502 return;
504 int nEntry = m_xLB_SERIES->get_selected_index();
505 bool bHasSelectedEntry = (nEntry != -1);
507 OUString aSelectedRolesRange = lcl_GetSelectedRolesRange(*m_xLB_ROLE);
509 if (bHasSelectedEntry && (m_xLB_ROLE->get_selected_index() != -1))
511 OUString aUIStr(SchResId(STR_DATA_SELECT_RANGE_FOR_SERIES));
513 // replace role
514 OUString aReplacement( "%VALUETYPE" );
515 sal_Int32 nIndex = aUIStr.indexOf( aReplacement );
516 if( nIndex != -1 )
518 aUIStr = aUIStr.replaceAt( nIndex, aReplacement.getLength(),
519 lcl_GetSelectedRole( *m_xLB_ROLE, true ));
521 // replace series name
522 aReplacement = "%SERIESNAME";
523 nIndex = aUIStr.indexOf( aReplacement );
524 if( nIndex != -1 )
526 aUIStr = aUIStr.replaceAt(nIndex, aReplacement.getLength(),
527 m_xLB_SERIES->get_text(nEntry));
530 lcl_enableRangeChoosing(true, m_pDialogController);
531 m_rDialogModel.getRangeSelectionHelper()->chooseRange( aSelectedRolesRange, aUIStr, *this );
533 else
534 m_pCurrentRangeChoosingField = nullptr;
537 IMPL_LINK_NOARG(DataSourceTabPage, CategoriesRangeButtonClickedHdl, weld::Button&, void)
539 OSL_ASSERT( m_pCurrentRangeChoosingField == nullptr );
540 m_pCurrentRangeChoosingField = m_xEDT_CATEGORIES.get();
541 if( !m_xEDT_CATEGORIES->get_text().isEmpty() &&
542 ! updateModelFromControl( m_pCurrentRangeChoosingField ))
543 return;
545 OUString aStr(SchResId(m_xFT_CATEGORIES->get_visible() ? STR_DATA_SELECT_RANGE_FOR_CATEGORIES : STR_DATA_SELECT_RANGE_FOR_DATALABELS));
546 lcl_enableRangeChoosing(true, m_pDialogController);
547 m_rDialogModel.getRangeSelectionHelper()->chooseRange(
548 m_rDialogModel.getCategoriesRange(), aStr, *this );
551 IMPL_LINK_NOARG(DataSourceTabPage, AddButtonClickedHdl, weld::Button&, void)
553 m_rDialogModel.startControllerLockTimer();
554 int nEntry = m_xLB_SERIES->get_selected_index();
555 rtl::Reference< DataSeries > xSeriesToInsertAfter;
556 rtl::Reference< ChartType > xChartTypeForNewSeries;
557 if( m_pTemplateProvider )
558 m_rDialogModel.setTemplate( m_pTemplateProvider->getCurrentTemplate());
560 if (nEntry != -1)
562 ::chart::SeriesEntry* pEntry = weld::fromId<::chart::SeriesEntry*>(m_xLB_SERIES->get_id(nEntry));
563 xSeriesToInsertAfter = pEntry->m_xDataSeries;
564 xChartTypeForNewSeries = pEntry->m_xChartType;
566 else
568 std::vector< rtl::Reference< ChartType > > aCntVec(
569 m_rDialogModel.getAllDataSeriesContainers());
570 if( ! aCntVec.empty())
571 xChartTypeForNewSeries = aCntVec.front();
573 OSL_ENSURE( xChartTypeForNewSeries.is(), "Cannot insert new series" );
575 m_rDialogModel.insertSeriesAfter( xSeriesToInsertAfter, xChartTypeForNewSeries );
576 setDirty();
578 fillSeriesListBox();
579 // note the box was cleared and refilled, so nEntry is invalid now
581 int nSelEntry = m_xLB_SERIES->get_selected_index();
582 if (nSelEntry != -1)
584 ++nSelEntry;
585 if (nSelEntry < m_xLB_SERIES->n_children())
586 m_xLB_SERIES->select(nSelEntry);
588 SeriesSelectionChangedHdl(*m_xLB_SERIES);
591 IMPL_LINK_NOARG(DataSourceTabPage, RemoveButtonClickedHdl, weld::Button&, void)
593 m_rDialogModel.startControllerLockTimer();
594 int nEntry = m_xLB_SERIES->get_selected_index();
595 if (nEntry == -1)
596 return;
598 SeriesEntry* pEntry = weld::fromId<::chart::SeriesEntry*>(m_xLB_SERIES->get_id(nEntry));
599 rtl::Reference< DataSeries > xNewSelSeries;
600 SeriesEntry * pNewSelEntry = nullptr;
601 if (nEntry + 1 < m_xLB_SERIES->n_children())
602 pNewSelEntry = weld::fromId<::chart::SeriesEntry*>(m_xLB_SERIES->get_id(nEntry + 1));
603 else if (nEntry > 0)
604 pNewSelEntry = weld::fromId<::chart::SeriesEntry*>(m_xLB_SERIES->get_id(nEntry - 1));
605 if (pNewSelEntry)
606 xNewSelSeries = pNewSelEntry->m_xDataSeries;
608 m_rDialogModel.deleteSeries( pEntry->m_xDataSeries, pEntry->m_xChartType );
609 setDirty();
611 m_xLB_SERIES->remove(nEntry);
612 fillSeriesListBox();
614 // select previous or next series
615 if (xNewSelSeries.is())
617 for (int i = 0; i < m_xLB_SERIES->n_children(); ++i)
619 pEntry = weld::fromId<::chart::SeriesEntry*>(m_xLB_SERIES->get_id(i));
620 if (pEntry->m_xDataSeries == xNewSelSeries)
622 m_xLB_SERIES->select(i);
623 break;
627 SeriesSelectionChangedHdl(*m_xLB_SERIES);
630 IMPL_LINK_NOARG(DataSourceTabPage, UpButtonClickedHdl, weld::Button&, void)
632 m_rDialogModel.startControllerLockTimer();
634 int nEntry = m_xLB_SERIES->get_selected_index();
635 SeriesEntry* pEntry = nullptr;
636 if (nEntry != -1)
637 pEntry = weld::fromId<SeriesEntry*>(m_xLB_SERIES->get_id(nEntry));
639 bool bHasSelectedEntry = (pEntry != nullptr);
641 if (bHasSelectedEntry)
643 m_rDialogModel.moveSeries( pEntry->m_xDataSeries, DialogModel::MoveDirection::Up );
644 setDirty();
645 fillSeriesListBox();
646 SeriesSelectionChangedHdl(*m_xLB_SERIES);
650 IMPL_LINK_NOARG(DataSourceTabPage, DownButtonClickedHdl, weld::Button&, void)
652 m_rDialogModel.startControllerLockTimer();
654 int nEntry = m_xLB_SERIES->get_selected_index();
655 SeriesEntry* pEntry = nullptr;
656 if (nEntry != -1)
657 pEntry = weld::fromId<SeriesEntry*>(m_xLB_SERIES->get_id(nEntry));
659 bool bHasSelectedEntry = (pEntry != nullptr);
661 if (bHasSelectedEntry)
663 m_rDialogModel.moveSeries( pEntry->m_xDataSeries, DialogModel::MoveDirection::Down );
664 setDirty();
665 fillSeriesListBox();
666 SeriesSelectionChangedHdl(*m_xLB_SERIES);
670 IMPL_LINK(DataSourceTabPage, RangeModifiedHdl, weld::Entry&, rEdit, void)
672 // note: isValid sets the color of the edit field
673 if( isRangeFieldContentValid( rEdit ))
675 setDirty();
676 updateModelFromControl( &rEdit );
677 if (&rEdit == m_xEDT_RANGE.get())
679 if( ! lcl_UpdateCurrentSeriesName( *m_xLB_SERIES ))
680 fillSeriesListBox();
684 // enable/disable OK button
685 isValid();
688 void DataSourceTabPage::listeningFinished(
689 const OUString & rNewRange )
691 // rNewRange becomes invalid after removing the listener
692 OUString aRange( rNewRange );
694 m_rDialogModel.startControllerLockTimer();
696 // stop listening
697 m_rDialogModel.getRangeSelectionHelper()->stopRangeListening();
699 // change edit field
700 if( m_pCurrentRangeChoosingField )
702 m_pCurrentRangeChoosingField->set_text(aRange);
703 m_pCurrentRangeChoosingField->grab_focus();
706 if (m_pCurrentRangeChoosingField == m_xEDT_RANGE.get())
708 m_xEDT_RANGE->set_text(aRange);
709 setDirty();
711 else if (m_pCurrentRangeChoosingField == m_xEDT_CATEGORIES.get())
713 m_xEDT_CATEGORIES->set_text(aRange);
714 setDirty();
717 updateModelFromControl(m_pCurrentRangeChoosingField);
718 if (!lcl_UpdateCurrentSeriesName(*m_xLB_SERIES))
719 fillSeriesListBox();
721 m_pCurrentRangeChoosingField = nullptr;
723 updateControlState();
724 lcl_enableRangeChoosing(false, m_pDialogController);
727 void DataSourceTabPage::disposingRangeSelection()
729 m_rDialogModel.getRangeSelectionHelper()->stopRangeListening( false );
732 bool DataSourceTabPage::updateModelFromControl(const weld::Entry* pField)
734 if (!m_bIsDirty)
735 return true;
737 ControllerLockGuardUNO aLockedControllers( m_rDialogModel.getChartModel() );
739 // @todo: validity check of field content
740 bool bResult = true;
741 bool bAll = (pField == nullptr);
742 Reference< data::XDataProvider > xDataProvider( m_rDialogModel.getDataProvider());
744 if (bAll || (pField == m_xEDT_CATEGORIES.get()))
746 uno::Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( m_rDialogModel.getCategories() );
747 if( xDataProvider.is())
749 OUString aRange(m_xEDT_CATEGORIES->get_text());
750 if (!aRange.isEmpty())
752 // create or change categories
753 if( !xLabeledSeq.is())
755 xLabeledSeq = DataSourceHelper::createLabeledDataSequence();
756 m_rDialogModel.setCategories( xLabeledSeq );
760 xLabeledSeq->setValues( xDataProvider->createDataSequenceByRangeRepresentation( aRange ));
762 catch( const uno::Exception & )
764 // should work as validation should have happened before
765 DBG_UNHANDLED_EXCEPTION("chart2");
768 else if( xLabeledSeq.is())
770 // clear existing categories
771 xLabeledSeq.clear();
772 m_rDialogModel.setCategories( xLabeledSeq );
777 int nSeriesEntry = m_xLB_SERIES->get_selected_index();
778 SeriesEntry* pSeriesEntry = nullptr;
779 if (nSeriesEntry != -1)
780 pSeriesEntry = weld::fromId<SeriesEntry*>(m_xLB_SERIES->get_id(nSeriesEntry));
781 bool bHasSelectedEntry = (pSeriesEntry != nullptr);
783 if( bHasSelectedEntry )
785 if( bAll || (pField == m_xEDT_RANGE.get()) )
789 OUString aSelectedRole = lcl_GetSelectedRole( *m_xLB_ROLE );
790 OUString aRange(m_xEDT_RANGE->get_text());
791 OUString aSequenceRole( aSelectedRole );
792 bool bIsLabel = (aSequenceRole == lcl_aLabelRole );
793 OUString aSequenceNameForLabel( lcl_GetSequenceNameForLabel( pSeriesEntry ));
795 if( bIsLabel )
796 aSequenceRole = aSequenceNameForLabel;
798 uno::Reference< chart2::data::XLabeledDataSequence > xLabeledSeq =
799 DataSeriesHelper::getDataSequenceByRole( pSeriesEntry->m_xDataSeries, aSequenceRole );
801 if( xDataProvider.is())
803 if( bIsLabel )
805 if( ! xLabeledSeq.is())
807 // check if there is already an "orphan" label sequence
808 xLabeledSeq = lcl_findLSequenceWithOnlyLabel( pSeriesEntry->m_xDataSeries );
809 if( ! xLabeledSeq.is())
811 // no corresponding labeled data sequence for label found
812 xLabeledSeq = DataSourceHelper::createLabeledDataSequence();
813 lcl_addLSequenceToDataSource( xLabeledSeq, pSeriesEntry->m_xDataSeries );
816 if( xLabeledSeq.is())
818 if( !aRange.isEmpty())
820 Reference< data::XDataSequence > xNewSeq;
823 xNewSeq.set( xDataProvider->createDataSequenceByRangeRepresentation( aRange ));
825 catch( const uno::Exception & )
827 // should work as validation should have happened before
828 DBG_UNHANDLED_EXCEPTION("chart2");
830 if( xNewSeq.is())
832 // update range name by the full string provided
833 // by the data provider. E.g. "a1" might become
834 // "$Sheet1.$A$1"
835 aRange = xNewSeq->getSourceRangeRepresentation();
836 Reference< beans::XPropertySet > xProp( xNewSeq, uno::UNO_QUERY_THROW );
837 xProp->setPropertyValue( "Role" , uno::Any( lcl_aLabelRole ));
839 //Labels should always include hidden cells, regardless of the setting chosen
840 xProp->setPropertyValue( "IncludeHiddenCells", uno::Any(true));
841 xLabeledSeq->setLabel( xNewSeq );
844 else
846 xLabeledSeq->setLabel( Reference< data::XDataSequence >());
850 else
852 if( !aRange.isEmpty())
854 Reference< data::XDataSequence > xNewSeq;
857 xNewSeq.set( xDataProvider->createDataSequenceByRangeRepresentation( aRange ));
859 catch( const uno::Exception & )
861 // should work as validation should have happened before
862 DBG_UNHANDLED_EXCEPTION("chart2");
864 if( xNewSeq.is())
866 // update range name by the full string provided
867 // by the data provider. E.g. "a1:e1" might become
868 // "$Sheet1.$A$1:$E$1"
869 aRange = xNewSeq->getSourceRangeRepresentation();
871 Reference< beans::XPropertySet > xProp( xNewSeq, uno::UNO_QUERY_THROW );
872 xProp->setPropertyValue( "Role" , uno::Any( aSelectedRole ));
873 if( !xLabeledSeq.is())
875 if( aSelectedRole == aSequenceNameForLabel )
876 xLabeledSeq = lcl_findLSequenceWithOnlyLabel( pSeriesEntry->m_xDataSeries );
877 if( ! xLabeledSeq.is())
879 xLabeledSeq = DataSourceHelper::createLabeledDataSequence();
880 lcl_addLSequenceToDataSource( xLabeledSeq, pSeriesEntry->m_xDataSeries );
883 xLabeledSeq->setValues( xNewSeq );
889 lcl_UpdateCurrentRange( *m_xLB_ROLE, aSelectedRole, aRange );
891 catch( const uno::Exception & )
893 DBG_UNHANDLED_EXCEPTION("chart2");
894 bResult = false;
899 // update View
900 // @todo remove this when automatic view updates from calc, writer and own data sequences are available
901 if( bResult )
905 if( m_rDialogModel.getChartModel() )
906 m_rDialogModel.getChartModel()->setModified( true );
907 const DialogModelTimeBasedInfo& rInfo = m_rDialogModel.getTimeBasedInfo();
908 if(rInfo.bTimeBased)
910 m_rDialogModel.setTimeBasedRange(rInfo.bTimeBased, rInfo.nStart, rInfo.nEnd);
913 catch( const uno::Exception & )
915 DBG_UNHANDLED_EXCEPTION("chart2");
919 return bResult;
922 } // namespace chart
924 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */