Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/chart2/source/controller/dialogs/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 41 kB image not shown  

Quelle  DataBrowser.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


#include <svl/zforlist.hxx>

#include "DataBrowser.hxx"
#include <DataBrowserModel.hxx>
#include <strings.hrc>
#include <DataSeries.hxx>
#include <DataSeriesHelper.hxx>
#include <DiagramHelper.hxx>
#include <CommonConverters.hxx>
#include <NumberFormatterWrapper.hxx>
#include <servicenames_charttypes.hxx>
#include <ResId.hxx>
#include <bitmaps.hlst>
#include <helpids.h>
#include <ChartModel.hxx>
#include <ChartType.hxx>

#include <vcl/weld.hxx>
#include <vcl/settings.hxx>
#include <vcl/svapp.hxx>
#include <vcl/virdev.hxx>
#include <o3tl/safeint.hxx>
#include <osl/diagnose.h>
#include <svl/numformat.hxx>
#include <toolkit/helper/vclunohelper.hxx>

#include <com/sun/star/container/XIndexReplace.hpp>

#include <algorithm>
#include <limits>


using namespace ::com::sun::star;
using ::com::sun::star::uno::Reference;

using namespace ::svt;

namespace
{
/*  BrowserMode::COLUMNSELECTION : single cells may be selected rather than only
                                   entire rows
    BrowserMode::(H|V)LINES : show horizontal or vertical grid-lines
    BrowserMode::AUTO_(H|V)SCROLL : scroll automated horizontally or vertically when
                                    cursor is moved beyond the edge of the dialog
    BrowserMode::HIDESELECT : Do not mark the current row with selection color
                              (usually blue)
  ! BrowserMode::HIDECURSOR would prevent flickering in edit fields, but navigating
        with shift up/down, and entering non-editable cells would be problematic,
        e.g.  the first cell, or when being in read-only mode
*/

const BrowserMode BrowserStdFlags = BrowserMode::COLUMNSELECTION |
                                    BrowserMode::HLINES | BrowserMode::VLINES |
                                    BrowserMode::AUTO_HSCROLL | BrowserMode::AUTO_VSCROLL |
                                    BrowserMode::HIDESELECT;

sal_Int32 lcl_getColumnInData( sal_uInt16 nCol )
{
    return static_cast< sal_Int32 >( nCol ) - 1;
}

// anonymous namespace

namespace chart
{

namespace impl
{

class SeriesHeaderEdit
{
public:
    explicit SeriesHeaderEdit(std::unique_ptr<weld::Entry> xControl);

    void setStartColumn( sal_Int32 nStartColumn );
    sal_Int32 getStartColumn() const { return m_nStartColumn;}
    void SetShowWarningBox( bool bShowWarning );

    OUString GetText() const { return m_xControl->get_text(); }
    void SetText(const OUString& rText) { m_xControl->set_text(rText); }

    bool HasFocus() const { return m_xControl->has_focus(); }

    void set_size_request(int nWidth, int nHeight) { m_xControl->set_size_request(nWidth, nHeight); }
    void set_margin_start(int nLeft) { m_xControl->set_margin_start(nLeft); }

    void SetModifyHdl(const Link<SeriesHeaderEdit&,void>& rLink) { m_aModifyHdl = rLink; }
    void SetGetFocusHdl(const Link<SeriesHeaderEdit&,void>& rLink) { m_aFocusInHdl = rLink; }

private:
    DECL_LINK(NameEdited, weld::Entry&, void);
    DECL_LINK(NameFocusIn, weld::Widget&, void);
    DECL_LINK(MousePressHdl, const MouseEvent&, bool);

    std::unique_ptr<weld::Entry> m_xControl;
    Link<SeriesHeaderEdit&,void> m_aModifyHdl;
    Link<SeriesHeaderEdit&,void> m_aFocusInHdl;
    sal_Int32 m_nStartColumn;
    bool m_bShowWarningBox;
};

SeriesHeaderEdit::SeriesHeaderEdit(std::unique_ptr<weld::Entry> xControl)
    : m_xControl(std::move(xControl))
    , m_nStartColumn(0)
    , m_bShowWarningBox(false)
{
    m_xControl->set_help_id(HID_SCH_DATA_SERIES_LABEL);
    m_xControl->connect_changed(LINK(this, SeriesHeaderEdit, NameEdited));
    m_xControl->connect_focus_in(LINK(this, SeriesHeaderEdit, NameFocusIn));
    m_xControl->connect_mouse_press(LINK(this, SeriesHeaderEdit, MousePressHdl));
}

IMPL_LINK_NOARG(SeriesHeaderEdit, NameEdited, weld::Entry&, void)
{
    m_aModifyHdl.Call(*this);
}

IMPL_LINK_NOARG(SeriesHeaderEdit, NameFocusIn, weld::Widget&, void)
{
    m_aFocusInHdl.Call(*this);
}

void SeriesHeaderEdit::setStartColumn( sal_Int32 nStartColumn )
{
    m_nStartColumn = nStartColumn;
}

void SeriesHeaderEdit::SetShowWarningBox( bool bShowWarning )
{
    m_bShowWarningBox = bShowWarning;
}

IMPL_LINK_NOARG(SeriesHeaderEdit, MousePressHdl, const MouseEvent&, bool)
{
    if (m_bShowWarningBox)
    {
        std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(m_xControl.get(),
                                                   VclMessageType::Warning, VclButtonsType::Ok,
                                                   SchResId(STR_INVALID_NUMBER)));
        xWarn->run();
    }

    return false;
}

class SeriesHeader
{
public:
    explicit SeriesHeader(weld::Container* pParent, weld::Container* pColorParent);
            ~SeriesHeader();

    void SetColor( const Color & rCol );
    void SetPos();
    void SetWidth( sal_Int32 nWidth );
    void SetChartType( const rtl::Reference< ::chart::ChartType > & xChartType,
                       bool bSwapXAndYAxis );
    void SetSeriesName( const OUString & rName );
    void SetRange( sal_Int32 nStartCol, sal_Int32 nEndCol );

    void SetPixelWidth( sal_Int32 nWidth );

    sal_Int32 GetStartColumn() const { return m_nStartCol;}
    sal_Int32 GetEndColumn() const { return m_nEndCol;}

    static const sal_Int32 nSymbolHeight = 10;
    static const sal_Int32 nSymbolDistance = 2;

    static sal_Int32 GetRelativeAppFontXPosForNameField() { return nSymbolHeight + nSymbolDistance; }

    void Show();
    void Hide();

    /** call this before destroying the class.  This notifies the listeners to
        changes of the edit field for the series name.
     */

    void applyChanges();

    void SetGetFocusHdl(const Link<SeriesHeaderEdit&,void>& rLink);

    void SetEditChangedHdl( const Link<SeriesHeaderEdit&,void> & rLink );

    bool HasFocus() const;

private:
    Timer m_aUpdateDataTimer;

    std::unique_ptr<weld::Builder> m_xBuilder1;
    std::unique_ptr<weld::Builder> m_xBuilder2;

    weld::Container* m_pParent;
    weld::Container* m_pColorParent;

    std::unique_ptr<weld::Container> m_xContainer1;
    std::unique_ptr<weld::Container> m_xContainer2;
    std::unique_ptr<weld::Image> m_spSymbol;
    std::unique_ptr<SeriesHeaderEdit> m_spSeriesName;
    std::unique_ptr<weld::Image> m_spColorBar;
    VclPtr< OutputDevice> m_xDevice;
    Link<SeriesHeaderEdit&,void> m_aChangeLink;
    Color m_aColor;

    void notifyChanges();
    DECL_LINK( ImplUpdateDataHdl, Timer*, void );
    DECL_LINK( SeriesNameEdited, SeriesHeaderEdit&, void );

    static OUString GetChartTypeImage(
        const rtl::Reference< ::chart::ChartType > & xChartType,
        bool bSwapXAndYAxis
        );

    sal_Int32 m_nStartCol, m_nEndCol;
    sal_Int32 m_nWidth;
    bool      m_bSeriesNameChangePending;
};

SeriesHeader::SeriesHeader(weld::Container* pParent, weld::Container* pColorParent)
    : m_aUpdateDataTimer( "SeriesHeader UpdateDataTimer" )
    , m_xBuilder1(Application::CreateBuilder(pParent, u"modules/schart/ui/columnfragment.ui"_ustr))
    , m_xBuilder2(Application::CreateBuilder(pColorParent, u"modules/schart/ui/imagefragment.ui"_ustr))
    , m_pParent(pParent)
    , m_pColorParent(pColorParent)
    , m_xContainer1(m_xBuilder1->weld_container(u"container"_ustr))
    , m_xContainer2(m_xBuilder2->weld_container(u"container"_ustr))
    , m_spSymbol(m_xBuilder1->weld_image(u"image"_ustr))
    , m_spSeriesName(new SeriesHeaderEdit(m_xBuilder1->weld_entry(u"entry"_ustr)))
    , m_spColorBar(m_xBuilder2->weld_image(u"image"_ustr))
    , m_xDevice(Application::GetDefaultDevice())
    , m_nStartCol( 0 )
    , m_nEndCol( 0 )
    , m_nWidth( 42 )
    , m_bSeriesNameChangePending( false )
{
    m_aUpdateDataTimer.SetInvokeHandler(LINK(this, SeriesHeader, ImplUpdateDataHdl));
    m_aUpdateDataTimer.SetTimeout(4 * EDIT_UPDATEDATA_TIMEOUT);

    m_spSeriesName->SetModifyHdl(LINK(this, SeriesHeader, SeriesNameEdited));
    Show();
}

SeriesHeader::~SeriesHeader()
{
    m_aUpdateDataTimer.Stop();
    m_pParent->move(m_xContainer1.get(), nullptr);
    m_pColorParent->move(m_xContainer2.get(), nullptr);
}

void SeriesHeader::notifyChanges()
{
    m_aChangeLink.Call(*m_spSeriesName);
    m_bSeriesNameChangePending = false;
}

void SeriesHeader::applyChanges()
{
    if( m_bSeriesNameChangePending )
    {
        notifyChanges();
    }
}

void SeriesHeader::SetColor( const Color & rCol )
{
    m_aColor = rCol;
}

void SeriesHeader::SetPos()
{
    // chart type symbol
    Size aSize( nSymbolHeight, nSymbolHeight );
    aSize = m_xDevice->LogicToPixel(aSize, MapMode(MapUnit::MapAppFont));
    m_spSymbol->set_size_request(aSize.Width(), aSize.Height());

    // series name edit field
    m_spSeriesName->set_margin_start(2);

    sal_Int32 nHeightPx = m_xDevice->LogicToPixel(Size(0, 12), MapMode(MapUnit::MapAppFont)).Height();
    m_spSeriesName->set_size_request(m_nWidth - aSize.Width() - 2, nHeightPx);

    // color bar
    nHeightPx = m_xDevice->LogicToPixel(Size(0, 3), MapMode(MapUnit::MapAppFont)).Height();
    m_spColorBar->set_size_request(m_nWidth, nHeightPx);

    ScopedVclPtr<VirtualDevice> xVirDev(m_spColorBar->create_virtual_device());
    xVirDev->SetOutputSizePixel(Size(m_nWidth, nHeightPx));
    xVirDev->SetFillColor(m_aColor);
    xVirDev->SetLineColor(m_aColor);
    xVirDev->DrawRect(tools::Rectangle(Point(0, 0), aSize));
    m_spColorBar->set_image(xVirDev.get());
}

void SeriesHeader::SetWidth( sal_Int32 nWidth )
{
    m_nWidth = nWidth;
    SetPos();
}

void SeriesHeader::SetPixelWidth( sal_Int32 nWidth )
{
    SetWidth(nWidth);
}

void SeriesHeader::SetChartType(
    const rtl::Reference< ChartType > & xChartType,
    bool bSwapXAndYAxis
)
{
    m_spSymbol->set_from_icon_name( GetChartTypeImage( xChartType, bSwapXAndYAxis ) );
}

void SeriesHeader::SetSeriesName( const OUString & rName )
{
    m_spSeriesName->SetText(rName);
}

void SeriesHeader::SetRange( sal_Int32 nStartCol, sal_Int32 nEndCol )
{
    m_nStartCol = nStartCol;
    m_nEndCol = std::max(nEndCol, nStartCol);
    m_spSeriesName->setStartColumn( nStartCol );
}

void SeriesHeader::Show()
{
    m_xContainer1->show();
    m_xContainer2->show();
}

void SeriesHeader::Hide()
{
    m_xContainer1->hide();
    m_xContainer2->hide();
}

void SeriesHeader::SetEditChangedHdl( const Link<SeriesHeaderEdit&,void> & rLink )
{
    m_aChangeLink = rLink;
}

IMPL_LINK_NOARG(SeriesHeader, ImplUpdateDataHdl, Timer*, void)
{
    notifyChanges();
}

IMPL_LINK_NOARG(SeriesHeader, SeriesNameEdited, SeriesHeaderEdit&, void)
{
    m_bSeriesNameChangePending = true;
    m_aUpdateDataTimer.Start();
}

void SeriesHeader::SetGetFocusHdl( const Link<SeriesHeaderEdit&,>void>& rLink )
{
    m_spSeriesName->SetGetFocusHdl( rLink );
}

bool SeriesHeader::HasFocus() const
{
    return m_spSeriesName->HasFocus();
}

OUString SeriesHeader::GetChartTypeImage(
    const rtl::Reference< ChartType > & xChartType,
    bool bSwapXAndYAxis
)
{
    OUString aResult;
    if( !xChartType.is())
        return aResult;
    OUString aChartTypeName( xChartType->getChartType());

    if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_AREA )
    {
        aResult = BMP_TYPE_AREA;
    }
    else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_COLUMN )
    {
        if( bSwapXAndYAxis )
            aResult = BMP_TYPE_BAR;
        else
            aResult = BMP_TYPE_COLUMN;
    }
    else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_LINE )
    {
        aResult = BMP_TYPE_LINE;
    }
    else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_SCATTER )
    {
        aResult = BMP_TYPE_XY;
    }
    else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_PIE )
    {
        aResult = BMP_TYPE_PIE;
    }
    else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_NET
          || aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET )
    {
        aResult = BMP_TYPE_NET;
    }
    else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK )
    {
        // @todo: correct image for candle-stick type
        aResult = BMP_TYPE_STOCK;
    }
    else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE )
    {
        aResult = BMP_TYPE_BUBBLE;
    }

    return aResult;
}

// namespace impl

namespace
{

/** returns false, if no header as the focus.

    If a header has the focus, true is returned and the index of the header
    with focus is set at pIndex if pOutIndex is not 0.
*/

bool lcl_SeriesHeaderHasFocus(
    const std::vector< std::shared_ptr< ::chart::impl::SeriesHeader > > & rSeriesHeader,
    sal_Int32 * pOutIndex = nullptr )
{
    sal_Int32 nIndex = 0;
    for (auto const& elem : rSeriesHeader)
    {
        if(elem->HasFocus())
        {
            if( pOutIndex )
                *pOutIndex = nIndex;
            return true;
        }
        ++nIndex;
    }
    return false;
}

sal_Int32 lcl_getColumnInDataOrHeader(
    sal_uInt16 nCol, const std::vector< std::shared_ptr< ::chart::impl::SeriesHeader > > & rSeriesHeader )
{
    sal_Int32 nColIdx = 0;
    bool bHeaderHasFocus( lcl_SeriesHeaderHasFocus( rSeriesHeader, &nColIdx ));

    if( bHeaderHasFocus )
        nColIdx = lcl_getColumnInData( static_cast< sal_uInt16 >( rSeriesHeader[nColIdx]->GetStartColumn()));
    else
        nColIdx = lcl_getColumnInData( nCol );

    return nColIdx;
}

// anonymous namespace

DataBrowser::DataBrowser(const css::uno::Reference<css::awt::XWindow> &rParent,
                         weld::Container* pColumns, weld::Container* pColors) :
    ::svt::EditBrowseBox(VCLUnoHelper::GetWindow(rParent),
            EditBrowseBoxFlags::SMART_TAB_TRAVEL | EditBrowseBoxFlags::HANDLE_COLUMN_TEXT,
            WB_BORDER | WB_TABSTOP, BrowserStdFlags ),
    m_nSeekRow( 0 ),
    m_bIsReadOnly( false ),
    m_bDataValid( true ),
    m_aNumberEditField(VclPtr<FormattedControl>::Create(&EditBrowseBox::GetDataWindow(), false)),
    m_aTextEditField(VclPtr<EditControl>::Create(&EditBrowseBox::GetDataWindow())),
    m_pColumnsWin(pColumns),
    m_pColorsWin(pColors),
    m_rNumberEditController( new ::svt::FormattedFieldCellController( m_aNumberEditField.get() )),
    m_rTextEditController( new ::svt::EditCellController( m_aTextEditField.get() ))
{
    Formatter& rFormatter = m_aNumberEditField->get_formatter();
    rFormatter.SetDefaultValue( std::numeric_limits<double>::quiet_NaN() );
    rFormatter.TreatAsNumber( true );
    RenewTable();
}

DataBrowser::~DataBrowser()
{
    disposeOnce();
}

void DataBrowser::dispose()
{
    m_aSeriesHeaders.clear();
    m_aNumberEditField.disposeAndClear();
    m_aTextEditField.disposeAndClear();
    ::svt::EditBrowseBox::dispose();
}

bool DataBrowser::MayInsertRow() const
{
    return ! IsReadOnly()
        && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders ));
}

bool DataBrowser::MayInsertColumn() const
{
    return ! IsReadOnly();
}

bool DataBrowser::MayDeleteRow() const
{
    return ! IsReadOnly()
        && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders ))
        && ( GetCurRow() >= 0 )
        && ( GetRowCount() > 1 );
}

bool DataBrowser::MayDeleteColumn() const
{
    // if a series header has the focus
    if( lcl_SeriesHeaderHasFocus( m_aSeriesHeaders ))
        return true;

    return ! IsReadOnly()
        && ( GetCurColumnId() > 1 )
        && ( ColCount() > 2 );
}

bool DataBrowser::MayMoveUpRows() const
{
    return ! IsReadOnly()
        && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders ))
        && ( GetCurRow() > 0 )
        && ( GetCurRow() <= GetRowCount() - 1 );
}

bool DataBrowser::MayMoveDownRows() const
{
    return ! IsReadOnly()
        && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders ))
        && ( GetCurRow() >= 0 )
        && ( GetCurRow() < GetRowCount() - 1 );
}

bool DataBrowser::MayMoveLeftColumns() const
{
    // if a series header (except the last one) has the focus
    {
        sal_Int32 nColIndex(0);
        if( lcl_SeriesHeaderHasFocus( m_aSeriesHeaders, &nColIndex ))
            return (o3tl::make_unsigned( nColIndex ) <= (m_aSeriesHeaders.size() - 1)) && (static_cast< sal_uInt32 >( nColIndex ) != 0);
    }

    sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders );
    return ! IsReadOnly()
        && ( nColIdx > 1 )
        && ( nColIdx <= ColCount() - 2 )
        && m_apDataBrowserModel
        && !m_apDataBrowserModel->isCategoriesColumn( nColIdx );
}

bool DataBrowser::MayMoveRightColumns() const
{
    // if a series header (except the last one) has the focus
    {
        sal_Int32 nColIndex(0);
        if( lcl_SeriesHeaderHasFocus( m_aSeriesHeaders, &nColIndex ))
            return (o3tl::make_unsigned( nColIndex ) < (m_aSeriesHeaders.size() - 1));
    }

    sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders );
    return ! IsReadOnly()
        && ( nColIdx > 0 )
        && ( nColIdx < ColCount()-2 )
        && m_apDataBrowserModel
        && !m_apDataBrowserModel->isCategoriesColumn( nColIdx );
}

void DataBrowser::clearHeaders()
{
    forconst auto& spHeader : m_aSeriesHeaders )
        spHeader->applyChanges();
    m_aSeriesHeaders.clear();
}

void DataBrowser::RenewTable()
{
    if (!m_apDataBrowserModel)
        return;

    sal_Int32  nOldRow     = GetCurRow();
    sal_uInt16 nOldColId   = GetCurColumnId();

    bool bLastUpdateMode = GetUpdateMode();
    SetUpdateMode( false );

    if( IsModified() )
        SaveModified();

    DeactivateCell();

    RemoveColumns();
    RowRemoved( 1, GetRowCount() );

    // for row numbers
    InsertHandleColumn( static_cast< sal_uInt16 >(
                            GetDataWindow().LogicToPixel( Size( 42, 0 )).getWidth() ));

    OUString aDefaultSeriesName(SchResId(STR_COLUMN_LABEL));
    replaceParamterInString( aDefaultSeriesName, u"%COLUMNNUMBER", OUString::number( 24 ) );
    sal_Int32 nColumnWidth = GetDataWindow().GetTextWidth( aDefaultSeriesName )
        + GetDataWindow().LogicToPixel(Point(8 + impl::SeriesHeader::GetRelativeAppFontXPosForNameField(), 0), MapMode(MapUnit::MapAppFont)).X();
    sal_Int32 nColumnCount = m_apDataBrowserModel->getColumnCount();
    // nRowCount is a member of a base class
    sal_Int32 nRowCountLocal = m_apDataBrowserModel->getMaxRowCount();
    for( sal_Int32 nColIdx=1; nColIdx<=nColumnCount; ++nColIdx )
    {
        InsertDataColumn( static_cast< sal_uInt16 >( nColIdx ), GetColString( nColIdx ), nColumnWidth );
    }

    RowInserted( 1, nRowCountLocal );
    GoToRow( std::min( nOldRow, GetRowCount() - 1 ));
    GoToColumnId( std::min( nOldColId, static_cast< sal_uInt16 >( ColCount() - 1 )));

    // fill series headers
    clearHeaders();
    const DataBrowserModel::tDataHeaderVector& aHeaders( m_apDataBrowserModel->getDataHeaders());
    Link<impl::SeriesHeaderEdit&,void> aFocusLink( LINK( this, DataBrowser, SeriesHeaderGotFocus ));
    Link<impl::SeriesHeaderEdit&,void> aSeriesHeaderChangedLink( LINK( this, DataBrowser, SeriesHeaderChanged ));

    for (auto const& elemHeader : aHeaders)
    {
        auto spHeader = std::make_shared<impl::SeriesHeader>( m_pColumnsWin, m_pColorsWin );
        Color nColor;
        // @todo: Set "DraftColor", i.e. interpolated colors for gradients, bitmaps, etc.
        if( elemHeader.m_xDataSeries.is() &&
            ( elemHeader.m_xDataSeries->getPropertyValue( u"Color"_ustr ) >>= nColor ))
            spHeader->SetColor( nColor );
        spHeader->SetChartType( elemHeader.m_xChartType, elemHeader.m_bSwapXAndYAxis );
        spHeader->SetSeriesName(
            elemHeader.m_xDataSeries->getLabelForRole(
                        elemHeader.m_xChartType.is() ?
                         elemHeader.m_xChartType->getRoleOfSequenceForSeriesLabel() :
                         u"values-y"_ustr));
        // index is 1-based, as 0 is for the column that contains the row-numbers
        spHeader->SetRange( elemHeader.m_nStartColumn + 1, elemHeader.m_nEndColumn + 1 );
        spHeader->SetGetFocusHdl( aFocusLink );
        spHeader->SetEditChangedHdl( aSeriesHeaderChangedLink );
        m_aSeriesHeaders.push_back( spHeader );
    }

    ImplAdjustHeaderControls();
    SetUpdateMode( bLastUpdateMode );
    ActivateCell();
    Invalidate();
}

const OUString & DataBrowser::GetColString( sal_Int32 nColumnId ) const
{
    OSL_ASSERT(m_apDataBrowserModel);
    if( nColumnId > 0 )
        return m_apDataBrowserModel->getRoleOfColumn( nColumnId - 1 );
    return EMPTY_OUSTRING;
}

OUString DataBrowser::GetCellText( sal_Int32 nRow, sal_uInt16 nColumnId ) const
{
    OUString aResult;

    if( nColumnId == 0 )
    {
        aResult = OUString::number(nRow + 1);
    }
    else if( nRow >= 0 && m_apDataBrowserModel)
    {
        sal_Int32 nColIndex = static_cast< sal_Int32 >( nColumnId ) - 1;

        if( m_apDataBrowserModel->getCellType( nColIndex ) == DataBrowserModel::NUMBER )
        {
            double fData( m_apDataBrowserModel->getCellNumber( nColIndex, nRow ));

            if( ! std::isnan( fData ) &&
                m_spNumberFormatterWrapper )
            {
                bool bColorChanged = false;
                Color nLabelColor;
                aResult = m_spNumberFormatterWrapper->getFormattedString(
                                      GetNumberFormatKey( nColumnId ),
                                      fData, nLabelColor, bColorChanged );
            }
        }
        else if( m_apDataBrowserModel->getCellType( nColIndex ) == DataBrowserModel::TEXTORDATE )
        {
            uno::Any aAny = m_apDataBrowserModel->getCellAny( nColIndex, nRow );
            OUString aText;
            double fDouble=0.0;
            if( aAny>>=aText )
                aResult = aText;
            else if( aAny>>=fDouble )
            {
                if( ! std::isnan( fDouble ) && m_spNumberFormatterWrapper )
                {
                    // If a numberformat was available here we could directly
                    // obtain the corresponding edit format in
                    // getDateTimeInputNumberFormat() instead of doing the
                    // guess work.
                    sal_Int32 nNumberFormat = DiagramHelper::getDateTimeInputNumberFormat(
                            m_xChartDoc, fDouble );
                    Color nLabelColor;
                    bool bColorChanged = false;
                    aResult = m_spNumberFormatterWrapper->getFormattedString(
                        nNumberFormat, fDouble, nLabelColor, bColorChanged );
                }
            }
        }
        else
        {
            OSL_ASSERT( m_apDataBrowserModel->getCellType( nColIndex ) == DataBrowserModel::TEXT );
            aResult = m_apDataBrowserModel->getCellText( nColIndex, nRow );
        }
    }

    return aResult;
}

double DataBrowser::GetCellNumber( sal_Int32 nRow, sal_uInt16 nColumnId ) const
{
    if(( nColumnId >= 1 ) && ( nRow >= 0 ) && m_apDataBrowserModel)
    {
        return m_apDataBrowserModel->getCellNumber(
            static_cast< sal_Int32 >( nColumnId ) - 1, nRow );
    }

    return std::numeric_limits<double>::quiet_NaN();
}

void DataBrowser::Resize()
{
    bool bLastUpdateMode = GetUpdateMode();
    SetUpdateMode( false );

    ::svt::EditBrowseBox::Resize();
    ImplAdjustHeaderControls();
    SetUpdateMode( bLastUpdateMode );
}

void DataBrowser::SetReadOnly( bool bNewState )
{
    if( m_bIsReadOnly != bNewState )
    {
        m_bIsReadOnly = bNewState;
        Invalidate();
        DeactivateCell();
    }
}

void DataBrowser::CursorMoved()
{
    EditBrowseBox::CursorMoved();

    if( GetUpdateMode() )
        m_aCursorMovedHdlLink.Call( this );
}

void DataBrowser::MouseButtonDown( const BrowserMouseEvent& rEvt )
{
    if( !m_bDataValid )
        ShowWarningBox();
    else
        EditBrowseBox::MouseButtonDown( rEvt );
}

void DataBrowser::ShowWarningBox()
{
    std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetFrameWeld(),
                                               VclMessageType::Warning, VclButtonsType::Ok,
                                               SchResId(STR_INVALID_NUMBER)));
    xWarn->run();
}

bool DataBrowser::ShowQueryBox()
{
    std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetFrameWeld(),
                                                   VclMessageType::Question, VclButtonsType::YesNo,
                                                   SchResId(STR_DATA_EDITOR_INCORRECT_INPUT)));
    return xQueryBox->run() == RET_YES;
}

bool DataBrowser::IsDataValid() const
{
    bool bValid = true;
    const sal_Int32 nCol = lcl_getColumnInData( GetCurColumnId());

    if( m_apDataBrowserModel->getCellType( nCol ) == DataBrowserModel::NUMBER )
    {
        sal_uInt32 nDummy = 0;
        double fDummy = 0.0;
        OUString aText(m_aNumberEditField->get_widget().get_text());

        if( !aText.isEmpty() &&
            m_spNumberFormatterWrapper &&
            m_spNumberFormatterWrapper->getSvNumberFormatter() &&
            ! m_spNumberFormatterWrapper->getSvNumberFormatter()->IsNumberFormat(
              aText, nDummy, fDummy ))
        {
            bValid = false;
        }
    }

    return bValid;
}

void DataBrowser::CellModified()
{
    m_bDataValid = IsDataValid();
    m_aCursorMovedHdlLink.Call( this );
}

void DataBrowser::SetDataFromModel(
    const rtl::Reference<::chart::ChartModel> & xChartDoc )
{
    m_xChartDoc = xChartDoc;

    m_apDataBrowserModel.reset( new DataBrowserModel( m_xChartDoc ));
    m_spNumberFormatterWrapper =
        std::make_shared<NumberFormatterWrapper>(m_xChartDoc);

    Formatter& rFormatter = m_aNumberEditField->get_formatter();
    rFormatter.SetFormatter( m_spNumberFormatterWrapper->getSvNumberFormatter() );

    RenewTable();

    const sal_Int32 nColCnt  = m_apDataBrowserModel->getColumnCount();
    const sal_Int32 nRowCnt =  m_apDataBrowserModel->getMaxRowCount();
    if( nRowCnt && nColCnt )
    {
        GoToRow( 0 );
        GoToColumnId( 1 );
    }
}

void DataBrowser::InsertColumn()
{
    sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders );

    if( nColIdx >= 0 && m_apDataBrowserModel)
    {
        // save changes made to edit-field
        if( IsModified() )
            SaveModified();

        m_apDataBrowserModel->insertDataSeries( nColIdx );
        RenewTable();
    }
}

void DataBrowser::InsertTextColumn()
{
    sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders );

    if( nColIdx >= 0 && m_apDataBrowserModel)
    {
        // save changes made to edit-field
        if( IsModified() )
            SaveModified();

        m_apDataBrowserModel->insertComplexCategoryLevel( nColIdx );
        RenewTable();
    }
}

void DataBrowser::RemoveColumn()
{
    sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders );

    if( nColIdx >= 0 && m_apDataBrowserModel)
    {
        // save changes made to edit-field
        if( IsModified() )
            SaveModified();

        m_bDataValid = true;
        m_apDataBrowserModel->removeDataSeriesOrComplexCategoryLevel( nColIdx );
        RenewTable();
    }
}

void DataBrowser::InsertRow()
{
    sal_Int32 nRowIdx = GetCurRow();

    if( nRowIdx >= 0 && m_apDataBrowserModel)
    {
        // save changes made to edit-field
        if( IsModified() )
            SaveModified();

        m_apDataBrowserModel->insertDataPointForAllSeries( nRowIdx );
        RenewTable();
    }
}

void DataBrowser::RemoveRow()
{
    sal_Int32 nRowIdx = GetCurRow();

    if( nRowIdx >= 0 && m_apDataBrowserModel)
    {
        // save changes made to edit-field
        if( IsModified() )
            SaveModified();

        m_bDataValid = true;
        m_apDataBrowserModel->removeDataPointForAllSeries( nRowIdx );
        RenewTable();
    }
}

void DataBrowser::MoveLeftColumn()
{
    sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders );

    if( !(nColIdx > 0 && m_apDataBrowserModel))
        return;

    // save changes made to edit-field
    if( IsModified() )
        SaveModified();

    m_apDataBrowserModel->swapDataSeries( nColIdx - 1 );

    // keep cursor in swapped column
    if(( 0 < GetCurColumnId() ) && ( GetCurColumnId() <= ColCount() - 1 ))
    {
        Dispatch(BrowserDispatchId::CURSORLEFT);
    }
    RenewTable();
}

void DataBrowser::MoveRightColumn()
{
    sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders );

    if( !(nColIdx >= 0 && m_apDataBrowserModel))
        return;

    // save changes made to edit-field
    if( IsModified() )
        SaveModified();

    m_apDataBrowserModel->swapDataSeries( nColIdx );

    // keep cursor in swapped column
    if( GetCurColumnId() < ColCount() - 1 )
    {
        Dispatch(BrowserDispatchId::CURSORRIGHT);
    }
    RenewTable();
}

void DataBrowser::MoveUpRow()
{
    sal_Int32 nRowIdx = GetCurRow();

    if( !(nRowIdx > 0 && m_apDataBrowserModel))
        return;

    // save changes made to edit-field
    if( IsModified() )
        SaveModified();

    m_apDataBrowserModel->swapDataPointForAllSeries( nRowIdx - 1 );

    // keep cursor in swapped row
    if(( 0 < GetCurRow() ) && ( GetCurRow() <= GetRowCount() - 1 ))
    {
        Dispatch(BrowserDispatchId::CURSORUP);
    }
    RenewTable();
}

void DataBrowser::MoveDownRow()
{
    sal_Int32 nRowIdx = GetCurRow();

    if( !(nRowIdx >= 0 && m_apDataBrowserModel))
        return;

    // save changes made to edit-field
    if( IsModified() )
        SaveModified();

    m_apDataBrowserModel->swapDataPointForAllSeries( nRowIdx );

    // keep cursor in swapped row
    if( GetCurRow() < GetRowCount() - 1 )
    {
        Dispatch(BrowserDispatchId::CURSORDOWN);
    }
    RenewTable();
}

void DataBrowser::SetCursorMovedHdl( const Link<DataBrowser*,void>& rLink )
{
    m_aCursorMovedHdlLink = rLink;
}

// implementations for ::svt::EditBrowseBox (pure virtual methods)
void DataBrowser::PaintCell(
    OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColumnId ) const
{
    Point aPos( rRect.TopLeft());
    aPos.AdjustX(1 );

    OUString aText = GetCellText( m_nSeekRow, nColumnId );
    Size TxtSize( GetDataWindow().GetTextWidth( aText ), GetDataWindow().GetTextHeight());

    // clipping
    if( aPos.X() < rRect.Right() || aPos.X() + TxtSize.Width() > rRect.Right() ||
        aPos.Y() < rRect.Top() || aPos.Y() + TxtSize.Height() > rRect.Bottom())
        rDev.SetClipRegion(vcl::Region(rRect));

    // allow for a disabled control ...
    bool bEnabled = IsEnabled();
    Color aOriginalColor = rDev.GetTextColor();
    if( ! bEnabled )
        rDev.SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() );

    // draw the text
    rDev.DrawText( aPos, aText );

    // reset the color (if necessary)
    if( ! bEnabled )
        rDev.SetTextColor( aOriginalColor );

    if( rDev.IsClipRegion())
        rDev.SetClipRegion();
}

bool DataBrowser::SeekRow( sal_Int32 nRow )
{
    if( ! EditBrowseBox::SeekRow( nRow ))
        return false;

    if( nRow < 0 )
        m_nSeekRow = - 1;
    else
        m_nSeekRow = nRow;

    return true;
}

bool DataBrowser::IsTabAllowed( bool bForward ) const
{
    sal_Int32 nRow = GetCurRow();
    sal_Int32 nCol = GetCurColumnId();

    // column 0 is header-column
    sal_Int32 nBadCol = bForward
        ? GetColumnCount() - 1
        : 1;
    sal_Int32 nBadRow = bForward
        ? GetRowCount() - 1
        : 0;

    if( !m_bDataValid )
    {
        const_cast< DataBrowser* >( this )->ShowWarningBox();
        return false;
    }

    return ( nRow != nBadRow ||
             nCol != nBadCol );
}

::svt::CellController* DataBrowser::GetController( sal_Int32 /*nRow*/, sal_uInt16 nCol )
{
    if( m_bIsReadOnly )
        return nullptr;

    if( CellContainsNumbers( nCol ))
    {
        Formatter& rFormatter = m_aNumberEditField->get_formatter();
        rFormatter.UseInputStringForFormatting();
        rFormatter.SetFormatKey( GetNumberFormatKey( nCol ));
        return m_rNumberEditController.get();
    }

    return m_rTextEditController.get();
}

void DataBrowser::InitController(
    ::svt::CellControllerRef& rController, sal_Int32 nRow, sal_uInt16 nCol )
{
    if( rController == m_rTextEditController )
    {
        OUString aText( GetCellText( nRow, nCol ) );
        weld::Entry& rEntry = m_aTextEditField->get_widget();
        rEntry.set_text(aText);
        rEntry.select_region(0, -1);
    }
    else if( rController == m_rNumberEditController )
    {
        // treat invalid and empty text as Nan
        Formatter& rFormatter = m_aNumberEditField->get_formatter();
        rFormatter.EnableNotANumber( true );
        if( std::isnan( GetCellNumber( nRow, nCol )))
            rFormatter.SetTextValue( OUString());
        else
            rFormatter.SetValue( GetCellNumber( nRow, nCol ) );
        weld::Entry& rEntry = m_aNumberEditField->get_widget();
        rEntry.select_region(0, -1);
    }
    else
    {
        OSL_FAIL( "Invalid Controller" );
    }
}

bool DataBrowser::CellContainsNumbers( sal_uInt16 nCol ) const
{
    if (!m_apDataBrowserModel)
        return false;
    return m_apDataBrowserModel->getCellType( lcl_getColumnInData( nCol )) == DataBrowserModel::NUMBER;
}

sal_uInt32 DataBrowser::GetNumberFormatKey( sal_uInt16 nCol ) const
{
    if (!m_apDataBrowserModel)
        return 0;
    return m_apDataBrowserModel->getNumberFormatKey( lcl_getColumnInData( nCol ) );
}

bool DataBrowser::isDateTimeString( const OUString& aInputString, double& fOutDateTimeValue )
{
    sal_uInt32 nNumberFormat=0;
    SvNumberFormatter* pSvNumberFormatter = m_spNumberFormatterWrapper ? m_spNumberFormatterWrapper->getSvNumberFormatter() : nullptr;
    if( !aInputString.isEmpty() &&  pSvNumberFormatter && pSvNumberFormatter->IsNumberFormat( aInputString, nNumberFormat, fOutDateTimeValue ) )
    {
        SvNumFormatType nType = pSvNumberFormatter->GetType( nNumberFormat);
        return (nType & SvNumFormatType::DATE) || (nType & SvNumFormatType::TIME);
    }
    return false;
}

bool DataBrowser::SaveModified()
{
    if( ! IsModified() )
        return true;

    bool bChangeValid = true;

    const sal_Int32 nRow = GetCurRow();
    const sal_Int32 nCol = lcl_getColumnInData( GetCurColumnId());

    OSL_ENSURE( nRow >= 0 || nCol >= 0, "This cell should not be modified!" );

    SvNumberFormatter* pSvNumberFormatter = m_spNumberFormatterWrapper ? m_spNumberFormatterWrapper->getSvNumberFormatter() : nullptr;
    switch( m_apDataBrowserModel->getCellType( nCol ))
    {
        case DataBrowserModel::NUMBER:
        {
            sal_uInt32 nDummy = 0;
            double fDummy = 0.0;
            OUString aText(m_aNumberEditField->get_widget().get_text());
            // an empty string is valid, if no numberformatter exists, all
            // values are treated as valid
            if( !aText.isEmpty() && pSvNumberFormatter &&
                ! pSvNumberFormatter->IsNumberFormat( aText, nDummy, fDummy ) )
            {
                bChangeValid = false;
            }
            else
            {
                Formatter& rFormatter = m_aNumberEditField->get_formatter();
                double fData = rFormatter.GetValue();
                bChangeValid = m_apDataBrowserModel->setCellNumber( nCol, nRow, fData );
            }
        }
        break;
        case DataBrowserModel::TEXTORDATE:
        {
            weld::Entry& rEntry = m_aTextEditField->get_widget();
            OUString aText(rEntry.get_text());
            double fValue = 0.0;
            bChangeValid = false;
            if( isDateTimeString( aText, fValue ) )
                bChangeValid = m_apDataBrowserModel->setCellAny( nCol, nRow, uno::Any( fValue ) );
            if(!bChangeValid)
                bChangeValid = m_apDataBrowserModel->setCellAny( nCol, nRow, uno::Any( aText ) );
        }
        break;
        case DataBrowserModel::TEXT:
        {
            weld::Entry& rEntry = m_aTextEditField->get_widget();
            OUString aText(rEntry.get_text());
            bChangeValid = m_apDataBrowserModel->setCellText( nCol, nRow, aText );
        }
        break;
    }

    // the first valid change changes this to true
    if( bChangeValid )
    {
        RowModified( GetCurRow(), GetCurColumnId());
        ::svt::CellController* pCtrl = GetController( GetCurRow(), GetCurColumnId());
        if( pCtrl )
            pCtrl->SaveValue();
    }

    return bChangeValid;
}

bool DataBrowser::EndEditing()
{
    SaveModified();

    // apply changes made to series headers
    forconst auto& spHeader : m_aSeriesHeaders )
        spHeader->applyChanges();

    if( m_bDataValid )
        return true;
    else
        return ShowQueryBox();
}

void DataBrowser::ColumnResized( sal_uInt16 nColId )
{
    bool bLastUpdateMode = GetUpdateMode();
    SetUpdateMode( false );

    EditBrowseBox::ColumnResized( nColId );
    ImplAdjustHeaderControls();
    SetUpdateMode( bLastUpdateMode );
}

void DataBrowser::EndScroll()
{
    bool bLastUpdateMode = GetUpdateMode();
    SetUpdateMode( false );

    EditBrowseBox::EndScroll();
    RenewSeriesHeaders();

    SetUpdateMode( bLastUpdateMode );
}

void DataBrowser::RenewSeriesHeaders()
{
    clearHeaders();
    DataBrowserModel::tDataHeaderVector aHeaders( m_apDataBrowserModel->getDataHeaders());
    Link<impl::SeriesHeaderEdit&,void> aFocusLink( LINK( this, DataBrowser, SeriesHeaderGotFocus ));
    Link<impl::SeriesHeaderEdit&,void> aSeriesHeaderChangedLink( LINK( this, DataBrowser, SeriesHeaderChanged ));

    for (auto const& elemHeader : aHeaders)
    {
        auto spHeader = std::make_shared<impl::SeriesHeader>( m_pColumnsWin, m_pColorsWin );
        Color nColor;
        if( elemHeader.m_xDataSeries.is() &&
            ( elemHeader.m_xDataSeries->getPropertyValue( u"Color"_ustr ) >>= nColor ))
            spHeader->SetColor( nColor );
        spHeader->SetChartType( elemHeader.m_xChartType, elemHeader.m_bSwapXAndYAxis );
        spHeader->SetSeriesName(
            elemHeader.m_xDataSeries->getLabelForRole(
                        elemHeader.m_xChartType.is() ?
                         elemHeader.m_xChartType->getRoleOfSequenceForSeriesLabel() :
                         u"values-y"_ustr));
        spHeader->SetRange( elemHeader.m_nStartColumn + 1, elemHeader.m_nEndColumn + 1 );
        spHeader->SetGetFocusHdl( aFocusLink );
        spHeader->SetEditChangedHdl( aSeriesHeaderChangedLink );
        m_aSeriesHeaders.push_back( spHeader );
    }

    ImplAdjustHeaderControls();
}

void DataBrowser::ImplAdjustHeaderControls()
{
    sal_uInt16 nColCount = GetColumnCount();
    sal_uInt32 nCurrentPos = GetPosPixel().getX();
    sal_uInt32 nMaxPos = nCurrentPos + GetOutputSizePixel().getWidth();
    sal_uInt32 nStartPos = nCurrentPos;

    // width of header column
    nCurrentPos +=  GetColumnWidth( 0 );

    weld::Container* pWin = m_pColumnsWin;
    weld::Container* pColorWin = m_pColorsWin;
    pWin->set_margin_start(nCurrentPos);
    pColorWin->set_margin_start(nCurrentPos);

    tSeriesHeaderContainer::iterator aIt( m_aSeriesHeaders.begin());
    sal_uInt16 i = GetFirstVisibleColNumber();
    while( (aIt != m_aSeriesHeaders.end()) && ((*aIt)->GetStartColumn() < i) )
    {
        (*aIt)->Hide();
        ++aIt;
    }
    for( ; i < nColCount && aIt != m_aSeriesHeaders.end(); ++i )
    {
        if( (*aIt)->GetStartColumn() == i )
            nStartPos = nCurrentPos;

        nCurrentPos += (GetColumnWidth( i ));

        if( (*aIt)->GetEndColumn() == i )
        {
            if( nStartPos < nMaxPos )
            {
                (*aIt)->SetPixelWidth( nCurrentPos - nStartPos );
                (*aIt)->Show();

                if (pWin)
                {
                    pWin->set_margin_start(nStartPos);
                    pColorWin->set_margin_start(nStartPos);
                    pWin = pColorWin = nullptr;
                }

            }
            else
                (*aIt)->Hide();
            ++aIt;
        }
    }
}

IMPL_LINK( DataBrowser, SeriesHeaderGotFocus, impl::SeriesHeaderEdit&, rEdit, void )
{
    rEdit.SetShowWarningBox( !m_bDataValid );

    if( !m_bDataValid )
        GoToCell( 0, 0 );
    else
    {
        MakeFieldVisible( GetCurRow(), static_cast< sal_uInt16 >( rEdit.getStartColumn()) );
        ActivateCell();
        m_aCursorMovedHdlLink.Call( this );
    }
}

IMPL_LINK( DataBrowser, SeriesHeaderChanged, impl::SeriesHeaderEdit&, rEdit, void )
{
    rtl::Reference< DataSeries > xSeries =
        m_apDataBrowserModel->getDataSeriesByColumn( rEdit.getStartColumn() - 1 );
    if( !xSeries.is())
        return;

    rtl::Reference< ChartType > xChartType(
        m_apDataBrowserModel->getHeaderForSeries( xSeries ).m_xChartType );
    if( xChartType.is())
    {
        uno::Reference< chart2::data::XLabeledDataSequence > xLabeledSeq =
            DataSeriesHelper::getDataSequenceByRole( xSeries, xChartType->getRoleOfSequenceForSeriesLabel());
        if( xLabeledSeq.is())
        {
            Reference< container::XIndexReplace > xIndexReplace( xLabeledSeq->getLabel(), uno::UNO_QUERY );
            if( xIndexReplace.is())
                xIndexReplace->replaceByIndex(
                    0, uno::Any( rEdit.GetText()));
        }
    }
}

// namespace chart

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

96%


¤ Dauer der Verarbeitung: 0.12 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.