Coverage Report

Created: 2026-04-09 11:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/chart2/source/controller/dialogs/tp_DataSource.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
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/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
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 .
18
 */
19
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/data/XDataProvider.hpp>
37
#include <vcl/weld/Builder.hxx>
38
#include <vcl/weld/TreeView.hxx>
39
40
#include <comphelper/diagnose_ex.hxx>
41
42
using namespace ::com::sun::star;
43
using namespace ::com::sun::star::chart2;
44
45
using ::com::sun::star::uno::Reference;
46
47
namespace
48
{
49
50
constexpr OUString lcl_aLabelRole( u"label"_ustr );
51
52
void lcl_UpdateCurrentRange(weld::TreeView& rOutListBox, const OUString & rRole,
53
                            const OUString& rRange)
54
0
{
55
0
    int nEntry = rOutListBox.get_selected_index();
56
0
    if (nEntry != -1)
57
0
    {
58
0
        rOutListBox.set_text(nEntry, ::chart::DialogModel::ConvertRoleFromInternalToUI(rRole), 0);
59
0
        rOutListBox.set_text(nEntry, rRange, 1);
60
0
        ::chart::SeriesEntry* pEntry = weld::fromId<::chart::SeriesEntry*>(rOutListBox.get_id(nEntry));
61
0
        pEntry->m_sRole = rRole;
62
0
    }
63
0
}
64
65
bool lcl_UpdateCurrentSeriesName(weld::TreeView& rOutListBox)
66
0
{
67
0
    int nEntry = rOutListBox.get_selected_index();
68
0
    if (nEntry == -1)
69
0
        return false;
70
71
0
    bool bResult = false;
72
0
    ::chart::SeriesEntry * pEntry = weld::fromId<::chart::SeriesEntry*>(rOutListBox.get_id(nEntry));
73
0
    if (pEntry->m_xDataSeries.is() && pEntry->m_xChartType.is())
74
0
    {
75
0
        OUString aLabel(pEntry->m_xDataSeries->getLabelForRole(
76
0
                        pEntry->m_xChartType->getRoleOfSequenceForSeriesLabel()));
77
0
        if (!aLabel.isEmpty())
78
0
        {
79
0
            rOutListBox.set_text(nEntry, aLabel);
80
0
            bResult = true;
81
0
        }
82
0
    }
83
0
    return bResult;
84
0
}
85
86
OUString lcl_GetSelectedRole(const weld::TreeView& rRoleListBox, bool bUITranslated = false)
87
0
{
88
0
    int nEntry = rRoleListBox.get_selected_index();
89
0
    if (nEntry != -1)
90
0
    {
91
0
        if (bUITranslated)
92
0
            return rRoleListBox.get_text(nEntry);
93
0
        ::chart::SeriesEntry* pEntry = weld::fromId<::chart::SeriesEntry*>(rRoleListBox.get_id(nEntry));
94
0
        return pEntry->m_sRole;
95
0
    }
96
0
    return OUString();
97
0
}
98
99
OUString lcl_GetSelectedRolesRange( const weld::TreeView& rRoleListBox )
100
0
{
101
0
    OUString aResult;
102
0
    int nEntry = rRoleListBox.get_selected_index();
103
0
    if (nEntry != -1)
104
0
        aResult = rRoleListBox.get_text(nEntry, 1);
105
0
    return aResult;
106
0
}
107
108
OUString lcl_GetSequenceNameForLabel(const ::chart::SeriesEntry* pEntry)
109
0
{
110
0
    OUString aResult(u"values-y"_ustr);
111
0
    if (pEntry && pEntry->m_xChartType.is())
112
0
        aResult = pEntry->m_xChartType->getRoleOfSequenceForSeriesLabel();
113
0
    return aResult;
114
0
}
115
116
void lcl_addLSequenceToDataSource(
117
    const uno::Reference< chart2::data::XLabeledDataSequence > & xLSequence,
118
    const Reference< ::chart::DataSeries > & xSource )
119
0
{
120
0
    if( xSource.is())
121
0
    {
122
0
        std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aData = xSource->getDataSequences2();
123
0
        aData.push_back( xLSequence );
124
0
        xSource->setData( aData );
125
0
    }
126
0
}
127
128
uno::Reference< chart2::data::XLabeledDataSequence > lcl_findLSequenceWithOnlyLabel(
129
    const rtl::Reference< ::chart::DataSeries > & xDataSource )
130
0
{
131
0
    uno::Reference< chart2::data::XLabeledDataSequence > xResult;
132
133
0
    for( uno::Reference< chart2::data::XLabeledDataSequence > const & labeledDataSeq : xDataSource->getDataSequences2() )
134
0
    {
135
        // no values are set but a label exists
136
0
        if( ! labeledDataSeq->getValues().is() &&
137
0
            labeledDataSeq->getLabel().is())
138
0
        {
139
0
            xResult = labeledDataSeq;
140
0
            break;
141
0
        }
142
0
    }
143
144
0
    return xResult;
145
0
}
146
147
} //  anonymous namespace
148
149
namespace chart
150
{
151
152
DataSourceTabPage::DataSourceTabPage(weld::Container* pPage, weld::DialogController* pController,
153
                                     DialogModel & rDialogModel,
154
                                     ChartTypeTemplateProvider* pTemplateProvider,
155
                                     bool bHideDescription /* = false */)
156
0
    : ::vcl::OWizardPage(pPage, pController, u"modules/schart/ui/tp_DataSource.ui"_ustr, u"tp_DataSource"_ustr)
157
0
    , m_pTemplateProvider(pTemplateProvider)
158
0
    , m_rDialogModel(rDialogModel)
159
0
    , m_pCurrentRangeChoosingField( nullptr )
160
0
    , m_bIsDirty( false )
161
0
    , m_pTabPageNotifiable(dynamic_cast<TabPageNotifiable*>(pController))
162
0
    , m_xFT_CAPTION(m_xBuilder->weld_label(u"FT_CAPTION_FOR_WIZARD"_ustr))
163
0
    , m_xFT_SERIES(m_xBuilder->weld_label(u"FT_SERIES"_ustr))
164
0
    , m_xLB_SERIES(m_xBuilder->weld_tree_view(u"LB_SERIES"_ustr))
165
0
    , m_xBTN_ADD(m_xBuilder->weld_button(u"BTN_ADD"_ustr))
166
0
    , m_xBTN_REMOVE(m_xBuilder->weld_button(u"BTN_REMOVE"_ustr))
167
0
    , m_xBTN_UP(m_xBuilder->weld_button(u"BTN_UP"_ustr))
168
0
    , m_xBTN_DOWN(m_xBuilder->weld_button(u"BTN_DOWN"_ustr))
169
0
    , m_xFT_ROLE(m_xBuilder->weld_label(u"FT_ROLE"_ustr))
170
0
    , m_xLB_ROLE(m_xBuilder->weld_tree_view(u"LB_ROLE"_ustr))
171
0
    , m_xFT_RANGE(m_xBuilder->weld_label(u"FT_RANGE"_ustr))
172
0
    , m_xEDT_RANGE(m_xBuilder->weld_entry(u"EDT_RANGE"_ustr))
173
0
    , m_xIMB_RANGE_MAIN(m_xBuilder->weld_button(u"IMB_RANGE_MAIN"_ustr))
174
0
    , m_xFT_CATEGORIES(m_xBuilder->weld_label(u"FT_CATEGORIES"_ustr))
175
0
    , m_xFT_DATALABELS(m_xBuilder->weld_label(u"FT_DATALABELS"_ustr))
176
0
    , m_xEDT_CATEGORIES(m_xBuilder->weld_entry(u"EDT_CATEGORIES"_ustr))
177
0
    , m_xIMB_RANGE_CAT(m_xBuilder->weld_button(u"IMB_RANGE_CAT"_ustr))
178
0
{
179
0
    m_xLB_SERIES->set_size_request(m_xLB_SERIES->get_approximate_digit_width() * 25,
180
0
                                   m_xLB_SERIES->get_height_rows(10));
181
0
    m_xLB_ROLE->set_size_request(m_xLB_ROLE->get_approximate_digit_width() * 60,
182
0
                                 m_xLB_ROLE->get_height_rows(5));
183
0
    m_xFT_CAPTION->set_visible(!bHideDescription);
184
185
0
    m_aFixedTextRange = m_xFT_RANGE->get_label();
186
0
    SetPageTitle(SchResId(STR_OBJECT_DATASERIES_PLURAL));
187
188
    // set handlers
189
0
    m_xLB_SERIES->connect_selection_changed(
190
0
        LINK(this, DataSourceTabPage, SeriesSelectionChangedHdl));
191
0
    m_xLB_ROLE->connect_selection_changed(LINK(this, DataSourceTabPage, RoleSelectionChangedHdl));
192
193
0
    m_xIMB_RANGE_MAIN->connect_clicked(LINK(this, DataSourceTabPage, MainRangeButtonClickedHdl));
194
0
    m_xIMB_RANGE_CAT->connect_clicked(LINK(this, DataSourceTabPage, CategoriesRangeButtonClickedHdl));
195
196
0
    m_xBTN_ADD->connect_clicked(LINK(this, DataSourceTabPage, AddButtonClickedHdl));
197
0
    m_xBTN_REMOVE->connect_clicked(LINK(this, DataSourceTabPage, RemoveButtonClickedHdl));
198
199
0
    m_xBTN_UP->connect_clicked(LINK(this, DataSourceTabPage, UpButtonClickedHdl));
200
0
    m_xBTN_DOWN->connect_clicked(LINK(this, DataSourceTabPage, DownButtonClickedHdl));
201
202
0
    m_xEDT_RANGE->connect_changed(LINK(this, DataSourceTabPage, RangeModifiedHdl));
203
0
    m_xEDT_CATEGORIES->connect_changed(LINK( this, DataSourceTabPage, RangeModifiedHdl));
204
205
    // init controls
206
0
    std::vector<int> aWidths { o3tl::narrowing<int>(m_xLB_ROLE->get_approximate_digit_width() * 20) };
207
0
    m_xLB_ROLE->set_column_fixed_widths(aWidths);
208
0
    m_xLB_ROLE->show();
209
210
0
    updateControlsFromDialogModel();
211
212
    // select first series
213
0
    if (m_xLB_SERIES->n_children())
214
0
        m_xLB_SERIES->select(0);
215
0
}
216
217
void DataSourceTabPage::InsertRoleLBEntry(const OUString& rRole, const OUString& rRange)
218
0
{
219
0
    m_aEntries.emplace_back(new SeriesEntry);
220
0
    SeriesEntry* pEntry = m_aEntries.back().get();
221
0
    pEntry->m_sRole = rRole;
222
0
    m_xLB_ROLE->append(weld::toId(pEntry),
223
0
                       ::chart::DialogModel::ConvertRoleFromInternalToUI(rRole));
224
0
    m_xLB_ROLE->set_text(m_xLB_ROLE->n_children() - 1, rRange, 1);
225
0
}
226
227
DataSourceTabPage::~DataSourceTabPage()
228
0
{
229
0
}
230
231
void DataSourceTabPage::Activate()
232
0
{
233
0
    OWizardPage::Activate();
234
0
    updateControlsFromDialogModel();
235
0
    m_xLB_SERIES->grab_focus();
236
0
}
237
238
void DataSourceTabPage::initializePage()
239
0
{
240
0
}
241
242
void DataSourceTabPage::Deactivate()
243
0
{
244
0
    commitPage();
245
0
    vcl::OWizardPage::Deactivate();
246
0
}
247
248
void DataSourceTabPage::commitPage()
249
0
{
250
0
    commitPage(::vcl::WizardTypes::eFinish);
251
0
}
252
253
bool DataSourceTabPage::commitPage( ::vcl::WizardTypes::CommitPageReason /*eReason*/ )
254
0
{
255
    //ranges may have been edited in the meanwhile (dirty is true in that case here)
256
0
    if( isValid() )
257
0
    {
258
0
        updateModelFromControl();
259
0
        return true; //return false if this page should not be left
260
0
    }
261
0
    else
262
0
        return false;
263
0
}
264
265
bool DataSourceTabPage::isRangeFieldContentValid(weld::Entry& rEdit )
266
0
{
267
0
    OUString aRange(rEdit.get_text());
268
0
    bool bIsValid = aRange.isEmpty() ||
269
0
        m_rDialogModel.getRangeSelectionHelper()->verifyCellRange(aRange);
270
0
    rEdit.set_message_type(bIsValid ? weld::EntryMessageType::Normal : weld::EntryMessageType::Error);
271
0
    return bIsValid;
272
0
}
273
274
bool DataSourceTabPage::isValid()
275
0
{
276
0
    bool bRoleRangeValid = true;
277
0
    bool bCategoriesRangeValid = true;
278
0
    bool bHasSelectedEntry = (m_xLB_SERIES->get_selected_index() != -1);
279
280
0
    if (bHasSelectedEntry)
281
0
        bRoleRangeValid = isRangeFieldContentValid(*m_xEDT_RANGE);
282
0
    if (m_xEDT_CATEGORIES->get_sensitive())
283
0
        bCategoriesRangeValid = isRangeFieldContentValid( *m_xEDT_CATEGORIES );
284
0
    bool bValid = ( bRoleRangeValid && bCategoriesRangeValid );
285
286
0
    if( m_pTabPageNotifiable )
287
0
    {
288
0
        if( bValid )
289
0
            m_pTabPageNotifiable->setValidPage( this );
290
0
        else
291
0
            m_pTabPageNotifiable->setInvalidPage( this );
292
0
    }
293
294
0
    return bValid;
295
0
}
296
297
void DataSourceTabPage::setDirty()
298
0
{
299
0
    m_bIsDirty = true;
300
0
}
301
302
void DataSourceTabPage::updateControlsFromDialogModel()
303
0
{
304
    // series
305
0
    fillSeriesListBox();
306
0
    SeriesSelectionChangedHdl(*m_xLB_SERIES);
307
308
    // categories
309
0
    m_xEDT_CATEGORIES->set_text(m_rDialogModel.getCategoriesRange());
310
311
0
    updateControlState();
312
0
}
313
314
void DataSourceTabPage::fillSeriesListBox()
315
0
{
316
0
    rtl::Reference< DataSeries > xSelected;
317
0
    SeriesEntry* pEntry = nullptr;
318
0
    int nEntry = m_xLB_SERIES->get_selected_index();
319
0
    if (nEntry != -1)
320
0
    {
321
0
        pEntry = weld::fromId<SeriesEntry*>(m_xLB_SERIES->get_id(nEntry));
322
0
        xSelected = pEntry->m_xDataSeries;
323
0
    }
324
325
0
    bool bHasSelectedEntry = (pEntry != nullptr);
326
0
    int nSelectedEntry = -1;
327
328
0
    m_xLB_SERIES->freeze();
329
0
    m_xLB_SERIES->clear();
330
331
0
    std::vector< DialogModel::tSeriesWithChartTypeByName > aSeries(
332
0
        m_rDialogModel.getAllDataSeriesWithLabel() );
333
334
0
    sal_Int32 nUnnamedSeriesIndex = 1;
335
0
    nEntry = 0;
336
0
    for (auto const& series : aSeries)
337
0
    {
338
0
        OUString aLabel(series.first);
339
0
        if (aLabel.isEmpty())
340
0
        {
341
0
            if( nUnnamedSeriesIndex > 1 )
342
0
            {
343
0
                OUString aResString(::chart::SchResId( STR_DATA_UNNAMED_SERIES_WITH_INDEX ));
344
345
                // replace index of unnamed series
346
0
                static constexpr OUString aReplacementStr( u"%NUMBER"_ustr );
347
0
                sal_Int32 nIndex = aResString.indexOf( aReplacementStr );
348
0
                if( nIndex != -1 )
349
0
                    aLabel = aResString.replaceAt(
350
0
                                         nIndex, aReplacementStr.getLength(),
351
0
                                         OUString::number(nUnnamedSeriesIndex));
352
0
            }
353
0
            if( aLabel.isEmpty() )
354
0
                aLabel = ::chart::SchResId( STR_DATA_UNNAMED_SERIES );
355
356
0
            ++nUnnamedSeriesIndex;
357
0
        }
358
359
0
        m_aEntries.emplace_back(new SeriesEntry);
360
0
        pEntry = m_aEntries.back().get();
361
0
        pEntry->m_xDataSeries = series.second.first;
362
0
        pEntry->m_xChartType = series.second.second;
363
0
        m_xLB_SERIES->append(weld::toId(pEntry), aLabel);
364
0
        if (bHasSelectedEntry && series.second.first == xSelected)
365
0
            nSelectedEntry = nEntry;
366
0
        ++nEntry;
367
0
    }
368
369
0
    m_xLB_SERIES->thaw();
370
371
0
    if (bHasSelectedEntry && nSelectedEntry != -1)
372
0
        m_xLB_SERIES->select(nSelectedEntry);
373
0
}
374
375
void DataSourceTabPage::fillRoleListBox()
376
0
{
377
0
    int nSeriesEntry = m_xLB_SERIES->get_selected_index();
378
0
    SeriesEntry* pSeriesEntry = nullptr;
379
0
    if (nSeriesEntry != -1)
380
0
        pSeriesEntry = weld::fromId<SeriesEntry*>(m_xLB_SERIES->get_id(nSeriesEntry));
381
0
    bool bHasSelectedEntry = (pSeriesEntry != nullptr);
382
383
0
    int nRoleIndex = m_xLB_ROLE->get_selected_index();
384
0
    if (!bHasSelectedEntry)
385
0
        return;
386
387
0
    DialogModel::tRolesWithRanges aRoles(
388
0
        DialogModel::getRolesWithRanges(
389
0
            pSeriesEntry->m_xDataSeries,
390
0
            lcl_GetSequenceNameForLabel( pSeriesEntry ),
391
0
            pSeriesEntry->m_xChartType ));
392
393
    // fill role list
394
0
    m_xLB_ROLE->freeze();
395
0
    m_xLB_ROLE->clear();
396
397
0
    for (auto const& elemRole : aRoles)
398
0
    {
399
0
        InsertRoleLBEntry(elemRole.first, elemRole.second);
400
0
    }
401
402
0
    m_xLB_ROLE->thaw();
403
404
    // series may contain no roles, check listbox size before selecting entries
405
0
    if (m_xLB_ROLE->n_children() > 0)
406
0
    {
407
0
        if (nRoleIndex == -1 || nRoleIndex >= m_xLB_ROLE->n_children())
408
0
            nRoleIndex = 0;
409
0
        m_xLB_ROLE->select(nRoleIndex);
410
0
    }
411
0
}
412
413
void DataSourceTabPage::updateControlState()
414
0
{
415
0
    int nSeriesEntry = m_xLB_SERIES->get_selected_index();
416
0
    bool bHasSelectedSeries = nSeriesEntry != -1;
417
0
    bool bHasValidRole = false;
418
0
    bool bHasRangeChooser = m_rDialogModel.getRangeSelectionHelper()->hasRangeSelection();
419
420
0
    if( bHasSelectedSeries )
421
0
    {
422
0
        int nRoleEntry = m_xLB_ROLE->get_selected_index();
423
0
        bHasValidRole = nRoleEntry != -1;
424
0
    }
425
426
0
    m_xBTN_ADD->set_sensitive(true);
427
0
    m_xBTN_REMOVE->set_sensitive(bHasSelectedSeries);
428
429
0
    m_xBTN_UP->set_sensitive(bHasSelectedSeries && (nSeriesEntry != 0));
430
0
    m_xBTN_DOWN->set_sensitive(bHasSelectedSeries && (nSeriesEntry != m_xLB_SERIES->n_children() - 1));
431
432
0
    bool bHasCategories = m_rDialogModel.isCategoryDiagram();
433
434
0
    m_xFT_DATALABELS->set_visible(!bHasCategories);
435
0
    m_xFT_CATEGORIES->set_visible( bHasCategories);
436
0
    bool bShowIB = bHasRangeChooser;
437
438
0
    m_xIMB_RANGE_CAT->set_visible(bShowIB);
439
440
0
    m_xFT_ROLE->set_sensitive(bHasSelectedSeries);
441
0
    m_xLB_ROLE->set_sensitive(bHasSelectedSeries);
442
443
0
    m_xFT_RANGE->set_sensitive(bHasValidRole);
444
0
    m_xEDT_RANGE->set_sensitive(bHasValidRole);
445
446
0
    m_xFT_SERIES->set_sensitive(true);
447
0
    m_xLB_SERIES->set_sensitive(true);
448
449
0
    m_xIMB_RANGE_MAIN->set_visible(bShowIB);
450
451
0
    isValid();
452
0
}
453
454
IMPL_LINK_NOARG(DataSourceTabPage, SeriesSelectionChangedHdl, weld::TreeView&, void)
455
0
{
456
0
    m_rDialogModel.startControllerLockTimer();
457
0
    if (m_xLB_SERIES->get_selected_index() != -1)
458
0
    {
459
0
        fillRoleListBox();
460
0
        RoleSelectionChangedHdl(*m_xLB_ROLE);
461
0
    }
462
0
    updateControlState();
463
0
}
464
465
IMPL_LINK_NOARG(DataSourceTabPage, RoleSelectionChangedHdl, weld::TreeView&, void)
466
0
{
467
0
    m_rDialogModel.startControllerLockTimer();
468
0
    int nEntry = m_xLB_ROLE->get_selected_index();
469
0
    if (nEntry == -1)
470
0
        return;
471
472
0
    OUString aSelectedRoleUI = lcl_GetSelectedRole( *m_xLB_ROLE, true );
473
0
    OUString aSelectedRange = lcl_GetSelectedRolesRange( *m_xLB_ROLE );
474
475
    // replace role in fixed text label
476
0
    static constexpr OUString aReplacementStr( u"%VALUETYPE"_ustr );
477
0
    sal_Int32 nIndex = m_aFixedTextRange.indexOf( aReplacementStr );
478
0
    if( nIndex != -1 )
479
0
    {
480
0
        m_xFT_RANGE->set_label(
481
0
            m_aFixedTextRange.replaceAt(
482
0
                        nIndex, aReplacementStr.getLength(), aSelectedRoleUI ));
483
0
    }
484
485
0
    m_xEDT_RANGE->set_text(aSelectedRange);
486
0
    isValid();
487
0
}
488
489
IMPL_LINK_NOARG(DataSourceTabPage, MainRangeButtonClickedHdl, weld::Button&, void)
490
0
{
491
0
    OSL_ASSERT( m_pCurrentRangeChoosingField == nullptr );
492
0
    m_pCurrentRangeChoosingField = m_xEDT_RANGE.get();
493
0
    if (!m_xEDT_RANGE->get_text().isEmpty() &&
494
0
        !updateModelFromControl( m_pCurrentRangeChoosingField))
495
0
        return;
496
497
0
    int nEntry = m_xLB_SERIES->get_selected_index();
498
0
    bool bHasSelectedEntry = (nEntry != -1);
499
500
0
    OUString aSelectedRolesRange = lcl_GetSelectedRolesRange(*m_xLB_ROLE);
501
502
0
    if (bHasSelectedEntry && (m_xLB_ROLE->get_selected_index() != -1))
503
0
    {
504
0
        OUString aUIStr(SchResId(STR_DATA_SELECT_RANGE_FOR_SERIES));
505
506
        // replace role
507
0
        OUString aReplacement( u"%VALUETYPE"_ustr );
508
0
        sal_Int32 nIndex = aUIStr.indexOf( aReplacement );
509
0
        if( nIndex != -1 )
510
0
        {
511
0
            aUIStr = aUIStr.replaceAt( nIndex, aReplacement.getLength(),
512
0
                                       lcl_GetSelectedRole( *m_xLB_ROLE, true ));
513
0
        }
514
        // replace series name
515
0
        aReplacement = "%SERIESNAME";
516
0
        nIndex = aUIStr.indexOf( aReplacement );
517
0
        if( nIndex != -1 )
518
0
        {
519
0
            aUIStr = aUIStr.replaceAt(nIndex, aReplacement.getLength(),
520
0
                                      m_xLB_SERIES->get_text(nEntry));
521
0
        }
522
523
0
        enableRangeChoosing(true, m_pDialogController);
524
0
        m_rDialogModel.getRangeSelectionHelper()->chooseRange( aSelectedRolesRange, aUIStr, *this );
525
0
    }
526
0
    else
527
0
        m_pCurrentRangeChoosingField = nullptr;
528
0
}
529
530
IMPL_LINK_NOARG(DataSourceTabPage, CategoriesRangeButtonClickedHdl, weld::Button&, void)
531
0
{
532
0
    OSL_ASSERT( m_pCurrentRangeChoosingField == nullptr );
533
0
    m_pCurrentRangeChoosingField = m_xEDT_CATEGORIES.get();
534
0
    if( !m_xEDT_CATEGORIES->get_text().isEmpty() &&
535
0
        ! updateModelFromControl( m_pCurrentRangeChoosingField ))
536
0
        return;
537
538
0
    OUString aStr(SchResId(m_xFT_CATEGORIES->get_visible() ? STR_DATA_SELECT_RANGE_FOR_CATEGORIES : STR_DATA_SELECT_RANGE_FOR_DATALABELS));
539
0
    enableRangeChoosing(true, m_pDialogController);
540
0
    m_rDialogModel.getRangeSelectionHelper()->chooseRange(
541
0
        m_rDialogModel.getCategoriesRange(), aStr, *this );
542
0
}
543
544
IMPL_LINK_NOARG(DataSourceTabPage, AddButtonClickedHdl, weld::Button&, void)
545
0
{
546
0
    m_rDialogModel.startControllerLockTimer();
547
0
    int nEntry = m_xLB_SERIES->get_selected_index();
548
0
    rtl::Reference< DataSeries > xSeriesToInsertAfter;
549
0
    rtl::Reference< ChartType > xChartTypeForNewSeries;
550
0
    if( m_pTemplateProvider )
551
0
            m_rDialogModel.setTemplate( m_pTemplateProvider->getCurrentTemplate());
552
553
0
    if (nEntry != -1)
554
0
    {
555
0
        ::chart::SeriesEntry* pEntry = weld::fromId<::chart::SeriesEntry*>(m_xLB_SERIES->get_id(nEntry));
556
0
        xSeriesToInsertAfter = pEntry->m_xDataSeries;
557
0
        xChartTypeForNewSeries = pEntry->m_xChartType;
558
0
    }
559
0
    else
560
0
    {
561
0
        std::vector< rtl::Reference< ChartType > > aCntVec(
562
0
            m_rDialogModel.getAllDataSeriesContainers());
563
0
        if( ! aCntVec.empty())
564
0
            xChartTypeForNewSeries = aCntVec.front();
565
0
    }
566
0
    OSL_ENSURE( xChartTypeForNewSeries.is(), "Cannot insert new series" );
567
568
0
    m_rDialogModel.insertSeriesAfter( xSeriesToInsertAfter, xChartTypeForNewSeries );
569
0
    setDirty();
570
571
0
    fillSeriesListBox();
572
    // note the box was cleared and refilled, so nEntry is invalid now
573
574
0
    int nSelEntry = m_xLB_SERIES->get_selected_index();
575
0
    if (nSelEntry != -1)
576
0
    {
577
0
        ++nSelEntry;
578
0
        if (nSelEntry < m_xLB_SERIES->n_children())
579
0
            m_xLB_SERIES->select(nSelEntry);
580
0
    }
581
0
    SeriesSelectionChangedHdl(*m_xLB_SERIES);
582
0
}
583
584
IMPL_LINK_NOARG(DataSourceTabPage, RemoveButtonClickedHdl, weld::Button&, void)
585
0
{
586
0
    m_rDialogModel.startControllerLockTimer();
587
0
    int nEntry = m_xLB_SERIES->get_selected_index();
588
0
    if (nEntry == -1)
589
0
        return;
590
591
0
    SeriesEntry* pEntry = weld::fromId<::chart::SeriesEntry*>(m_xLB_SERIES->get_id(nEntry));
592
0
    rtl::Reference< DataSeries > xNewSelSeries;
593
0
    SeriesEntry * pNewSelEntry = nullptr;
594
0
    if (nEntry + 1 < m_xLB_SERIES->n_children())
595
0
        pNewSelEntry = weld::fromId<::chart::SeriesEntry*>(m_xLB_SERIES->get_id(nEntry + 1));
596
0
    else if (nEntry > 0)
597
0
        pNewSelEntry = weld::fromId<::chart::SeriesEntry*>(m_xLB_SERIES->get_id(nEntry - 1));
598
0
    if (pNewSelEntry)
599
0
        xNewSelSeries = pNewSelEntry->m_xDataSeries;
600
601
0
    m_rDialogModel.deleteSeries( pEntry->m_xDataSeries, pEntry->m_xChartType );
602
0
    setDirty();
603
604
0
    m_xLB_SERIES->remove(nEntry);
605
0
    fillSeriesListBox();
606
607
    // select previous or next series
608
0
    if (xNewSelSeries.is())
609
0
    {
610
0
        for (int i = 0; i < m_xLB_SERIES->n_children(); ++i)
611
0
        {
612
0
            pEntry = weld::fromId<::chart::SeriesEntry*>(m_xLB_SERIES->get_id(i));
613
0
            if (pEntry->m_xDataSeries == xNewSelSeries)
614
0
            {
615
0
                m_xLB_SERIES->select(i);
616
0
                break;
617
0
            }
618
0
        }
619
0
    }
620
0
    SeriesSelectionChangedHdl(*m_xLB_SERIES);
621
0
}
622
623
IMPL_LINK_NOARG(DataSourceTabPage, UpButtonClickedHdl, weld::Button&, void)
624
0
{
625
0
    m_rDialogModel.startControllerLockTimer();
626
627
0
    int nEntry = m_xLB_SERIES->get_selected_index();
628
0
    SeriesEntry* pEntry = nullptr;
629
0
    if (nEntry != -1)
630
0
        pEntry = weld::fromId<SeriesEntry*>(m_xLB_SERIES->get_id(nEntry));
631
632
0
    bool bHasSelectedEntry = (pEntry != nullptr);
633
634
0
    if (bHasSelectedEntry)
635
0
    {
636
0
        m_rDialogModel.moveSeries( pEntry->m_xDataSeries, DialogModel::MoveDirection::Up );
637
0
        setDirty();
638
0
        fillSeriesListBox();
639
0
        SeriesSelectionChangedHdl(*m_xLB_SERIES);
640
0
    }
641
0
}
642
643
IMPL_LINK_NOARG(DataSourceTabPage, DownButtonClickedHdl, weld::Button&, void)
644
0
{
645
0
    m_rDialogModel.startControllerLockTimer();
646
647
0
    int nEntry = m_xLB_SERIES->get_selected_index();
648
0
    SeriesEntry* pEntry = nullptr;
649
0
    if (nEntry != -1)
650
0
        pEntry = weld::fromId<SeriesEntry*>(m_xLB_SERIES->get_id(nEntry));
651
652
0
    bool bHasSelectedEntry = (pEntry != nullptr);
653
654
0
    if (bHasSelectedEntry)
655
0
    {
656
0
        m_rDialogModel.moveSeries( pEntry->m_xDataSeries, DialogModel::MoveDirection::Down );
657
0
        setDirty();
658
0
        fillSeriesListBox();
659
0
        SeriesSelectionChangedHdl(*m_xLB_SERIES);
660
0
    }
661
0
}
662
663
IMPL_LINK(DataSourceTabPage, RangeModifiedHdl, weld::Entry&, rEdit, void)
664
0
{
665
    // note: isValid sets the color of the edit field
666
0
    if( isRangeFieldContentValid( rEdit ))
667
0
    {
668
0
        setDirty();
669
0
        updateModelFromControl( &rEdit );
670
0
        if (&rEdit == m_xEDT_RANGE.get())
671
0
        {
672
0
            if( ! lcl_UpdateCurrentSeriesName( *m_xLB_SERIES ))
673
0
                fillSeriesListBox();
674
0
        }
675
0
    }
676
677
    // enable/disable OK button
678
0
    isValid();
679
0
}
680
681
void DataSourceTabPage::listeningFinished(
682
    const OUString & rNewRange )
683
0
{
684
    // rNewRange becomes invalid after removing the listener
685
0
    OUString aRange( rNewRange );
686
687
0
    m_rDialogModel.startControllerLockTimer();
688
689
    // stop listening
690
0
    m_rDialogModel.getRangeSelectionHelper()->stopRangeListening();
691
692
    // change edit field
693
0
    if( m_pCurrentRangeChoosingField )
694
0
    {
695
0
        m_pCurrentRangeChoosingField->set_text(aRange);
696
0
        m_pCurrentRangeChoosingField->grab_focus();
697
0
    }
698
699
0
    if (m_pCurrentRangeChoosingField == m_xEDT_RANGE.get())
700
0
    {
701
0
        m_xEDT_RANGE->set_text(aRange);
702
0
        setDirty();
703
0
    }
704
0
    else if (m_pCurrentRangeChoosingField == m_xEDT_CATEGORIES.get())
705
0
    {
706
0
        m_xEDT_CATEGORIES->set_text(aRange);
707
0
        setDirty();
708
0
    }
709
710
0
    updateModelFromControl(m_pCurrentRangeChoosingField);
711
0
    if (!lcl_UpdateCurrentSeriesName(*m_xLB_SERIES))
712
0
        fillSeriesListBox();
713
714
0
    m_pCurrentRangeChoosingField = nullptr;
715
716
0
    updateControlState();
717
0
    enableRangeChoosing(false, m_pDialogController);
718
0
}
719
720
void DataSourceTabPage::disposingRangeSelection()
721
0
{
722
0
    m_rDialogModel.getRangeSelectionHelper()->stopRangeListening( false );
723
0
}
724
725
bool DataSourceTabPage::updateModelFromControl(const weld::Entry* pField)
726
0
{
727
0
    if (!m_bIsDirty)
728
0
        return true;
729
730
0
    ControllerLockGuardUNO aLockedControllers( m_rDialogModel.getChartModel() );
731
732
    // @todo: validity check of field content
733
0
    bool bResult = true;
734
0
    bool bAll = (pField == nullptr);
735
0
    Reference< data::XDataProvider > xDataProvider( m_rDialogModel.getDataProvider());
736
737
0
    if (bAll || (pField == m_xEDT_CATEGORIES.get()))
738
0
    {
739
0
        uno::Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( m_rDialogModel.getCategories() );
740
0
        if( xDataProvider.is())
741
0
        {
742
0
            OUString aRange(m_xEDT_CATEGORIES->get_text());
743
0
            if (!aRange.isEmpty())
744
0
            {
745
                // create or change categories
746
0
                if( !xLabeledSeq.is())
747
0
                {
748
0
                    xLabeledSeq = DataSourceHelper::createLabeledDataSequence();
749
0
                    m_rDialogModel.setCategories( xLabeledSeq );
750
0
                }
751
0
                try
752
0
                {
753
0
                    xLabeledSeq->setValues( xDataProvider->createDataSequenceByRangeRepresentation( aRange ));
754
0
                }
755
0
                catch( const uno::Exception & )
756
0
                {
757
                    // should work as validation should have happened before
758
0
                    DBG_UNHANDLED_EXCEPTION("chart2");
759
0
                }
760
0
            }
761
0
            else if( xLabeledSeq.is())
762
0
            {
763
                // clear existing categories
764
0
                xLabeledSeq.clear();
765
0
                m_rDialogModel.setCategories( xLabeledSeq );
766
0
            }
767
0
        }
768
0
    }
769
770
0
    int nSeriesEntry = m_xLB_SERIES->get_selected_index();
771
0
    SeriesEntry* pSeriesEntry = nullptr;
772
0
    if (nSeriesEntry != -1)
773
0
        pSeriesEntry = weld::fromId<SeriesEntry*>(m_xLB_SERIES->get_id(nSeriesEntry));
774
0
    bool bHasSelectedEntry = (pSeriesEntry != nullptr);
775
776
0
    if( bHasSelectedEntry )
777
0
    {
778
0
        if( bAll || (pField == m_xEDT_RANGE.get()) )
779
0
        {
780
0
            try
781
0
            {
782
0
                OUString aSelectedRole = lcl_GetSelectedRole( *m_xLB_ROLE );
783
0
                OUString aRange(m_xEDT_RANGE->get_text());
784
0
                OUString aSequenceRole( aSelectedRole );
785
0
                bool bIsLabel = (aSequenceRole == lcl_aLabelRole );
786
0
                OUString aSequenceNameForLabel( lcl_GetSequenceNameForLabel( pSeriesEntry ));
787
788
0
                if( bIsLabel )
789
0
                    aSequenceRole = aSequenceNameForLabel;
790
791
0
                uno::Reference< chart2::data::XLabeledDataSequence > xLabeledSeq =
792
0
                    DataSeriesHelper::getDataSequenceByRole( pSeriesEntry->m_xDataSeries, aSequenceRole );
793
794
0
                if( xDataProvider.is())
795
0
                {
796
0
                    if( bIsLabel )
797
0
                    {
798
0
                        if( ! xLabeledSeq.is())
799
0
                        {
800
                            // check if there is already an "orphan" label sequence
801
0
                            xLabeledSeq = lcl_findLSequenceWithOnlyLabel( pSeriesEntry->m_xDataSeries );
802
0
                            if( ! xLabeledSeq.is())
803
0
                            {
804
                                // no corresponding labeled data sequence for label found
805
0
                                xLabeledSeq = DataSourceHelper::createLabeledDataSequence();
806
0
                                lcl_addLSequenceToDataSource( xLabeledSeq, pSeriesEntry->m_xDataSeries );
807
0
                            }
808
0
                        }
809
0
                        if( xLabeledSeq.is())
810
0
                        {
811
0
                            if( !aRange.isEmpty())
812
0
                            {
813
0
                                Reference< data::XDataSequence > xNewSeq;
814
0
                                try
815
0
                                {
816
0
                                    xNewSeq.set( xDataProvider->createDataSequenceByRangeRepresentation( aRange ));
817
0
                                }
818
0
                                catch( const uno::Exception & )
819
0
                                {
820
                                    // should work as validation should have happened before
821
0
                                    DBG_UNHANDLED_EXCEPTION("chart2");
822
0
                                }
823
0
                                if( xNewSeq.is())
824
0
                                {
825
                                    // update range name by the full string provided
826
                                    // by the data provider. E.g. "a1" might become
827
                                    // "$Sheet1.$A$1"
828
0
                                    aRange = xNewSeq->getSourceRangeRepresentation();
829
0
                                    Reference< beans::XPropertySet > xProp( xNewSeq, uno::UNO_QUERY_THROW );
830
0
                                    xProp->setPropertyValue( u"Role"_ustr , uno::Any( lcl_aLabelRole ));
831
832
                                    //Labels should always include hidden cells, regardless of the setting chosen
833
0
                                    xProp->setPropertyValue( u"IncludeHiddenCells"_ustr, uno::Any(true));
834
0
                                    xLabeledSeq->setLabel( xNewSeq );
835
0
                                }
836
0
                            }
837
0
                            else
838
0
                            {
839
0
                                xLabeledSeq->setLabel( Reference< data::XDataSequence >());
840
0
                            }
841
0
                        }
842
0
                    }
843
0
                    else
844
0
                    {
845
0
                        if( !aRange.isEmpty())
846
0
                        {
847
0
                            Reference< data::XDataSequence > xNewSeq;
848
0
                            try
849
0
                            {
850
0
                                xNewSeq.set( xDataProvider->createDataSequenceByRangeRepresentation( aRange ));
851
0
                            }
852
0
                            catch( const uno::Exception & )
853
0
                            {
854
                                // should work as validation should have happened before
855
0
                                DBG_UNHANDLED_EXCEPTION("chart2");
856
0
                            }
857
0
                            if( xNewSeq.is())
858
0
                            {
859
                                // update range name by the full string provided
860
                                // by the data provider. E.g. "a1:e1" might become
861
                                // "$Sheet1.$A$1:$E$1"
862
0
                                aRange = xNewSeq->getSourceRangeRepresentation();
863
864
0
                                Reference< beans::XPropertySet > xProp( xNewSeq, uno::UNO_QUERY_THROW );
865
0
                                xProp->setPropertyValue( u"Role"_ustr , uno::Any( aSelectedRole ));
866
0
                                if( !xLabeledSeq.is())
867
0
                                {
868
0
                                    if( aSelectedRole == aSequenceNameForLabel )
869
0
                                        xLabeledSeq = lcl_findLSequenceWithOnlyLabel( pSeriesEntry->m_xDataSeries );
870
0
                                    if( ! xLabeledSeq.is())
871
0
                                    {
872
0
                                        xLabeledSeq = DataSourceHelper::createLabeledDataSequence();
873
0
                                        lcl_addLSequenceToDataSource( xLabeledSeq, pSeriesEntry->m_xDataSeries );
874
0
                                    }
875
0
                                }
876
0
                                xLabeledSeq->setValues( xNewSeq );
877
0
                            }
878
0
                        }
879
0
                    }
880
0
                }
881
882
0
                lcl_UpdateCurrentRange( *m_xLB_ROLE, aSelectedRole, aRange );
883
0
            }
884
0
            catch( const uno::Exception & )
885
0
            {
886
0
                DBG_UNHANDLED_EXCEPTION("chart2");
887
0
                bResult = false;
888
0
            }
889
0
        }
890
0
    }
891
892
    // update View
893
    // @todo remove this when automatic view updates from calc, writer and own data sequences are available
894
0
    if( bResult )
895
0
    {
896
0
        try
897
0
        {
898
0
            if( m_rDialogModel.getChartModel() )
899
0
                m_rDialogModel.getChartModel()->setModified( true );
900
0
            const DialogModelTimeBasedInfo& rInfo = m_rDialogModel.getTimeBasedInfo();
901
0
            if(rInfo.bTimeBased)
902
0
            {
903
0
                m_rDialogModel.setTimeBasedRange(rInfo.bTimeBased, rInfo.nStart, rInfo.nEnd);
904
0
            }
905
0
        }
906
0
        catch( const uno::Exception & )
907
0
        {
908
0
            DBG_UNHANDLED_EXCEPTION("chart2");
909
0
        }
910
0
    }
911
912
0
    return bResult;
913
0
}
914
915
} //  namespace chart
916
917
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */