Resolves: tdf#114555 check .xlsx col/row/tab overflow and display warning

Change-Id: I3091a890b6d4a3f27d9284fc5c0e2df3bc8ce527
Reviewed-on: https://gerrit.libreoffice.org/50541
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Eike Rathke <erack@redhat.com>
diff --git a/sc/source/filter/inc/addressconverter.hxx b/sc/source/filter/inc/addressconverter.hxx
index 57f1f33..d1d5353 100644
--- a/sc/source/filter/inc/addressconverter.hxx
+++ b/sc/source/filter/inc/addressconverter.hxx
@@ -479,6 +479,10 @@ public:
    static css::uno::Sequence<css::table::CellRangeAddress>
                        toApiSequence(const ScRangeList& orRanges);

    bool                isColOverflow() const { return mbColOverflow; }
    bool                isRowOverflow() const { return mbRowOverflow; }
    bool                isTabOverflow() const { return mbTabOverflow; }

private:
    void                initializeMaxPos(
                            sal_Int16 nMaxXlsTab, sal_Int32 nMaxXlsCol, sal_Int32 nMaxXlsRow );
diff --git a/sc/source/filter/oox/excelfilter.cxx b/sc/source/filter/oox/excelfilter.cxx
index 989befcb..006c481 100644
--- a/sc/source/filter/oox/excelfilter.cxx
+++ b/sc/source/filter/oox/excelfilter.cxx
@@ -30,6 +30,15 @@
#include <workbookfragment.hxx>
#include <xestream.hxx>

#include <addressconverter.hxx>
#include <document.hxx>
#include <docsh.hxx>
#include <scerrors.hxx>
#include <vcl/svapp.hxx>
#include <vcl/weld.hxx>
#include <svtools/sfxecode.hxx>
#include <tools/urlobj.hxx>

namespace oox {
namespace xls {

@@ -97,9 +106,67 @@ bool ExcelFilter::importDocument()
            the class WorkbookHelper, and execute the import filter by constructing
            an instance of WorkbookFragment and loading the file. */
        WorkbookGlobalsRef xBookGlob(WorkbookHelper::constructGlobals(*this));
        if (xBookGlob.get() && importFragment(new WorkbookFragment(*xBookGlob, aWorkbookPath)))
        if (xBookGlob.get())
        {
            return true;
            rtl::Reference<FragmentHandler> xWorkbookFragment( new WorkbookFragment(*xBookGlob, aWorkbookPath));
            bool bRet = importFragment( xWorkbookFragment);
            if (bRet)
            {
                const WorkbookFragment* pWF = static_cast<const WorkbookFragment*>(xWorkbookFragment.get());
                const AddressConverter& rAC = pWF->getAddressConverter();
                if (rAC.isTabOverflow() || rAC.isColOverflow() || rAC.isRowOverflow())
                {
                    const ScDocument& rDoc = pWF->getScDocument();
                    if (rDoc.IsUserInteractionEnabled())
                    {
                        // Show data loss warning.

                        INetURLObject aURL( getFileUrl());
                        SfxErrorContext aContext( ERRCTX_SFX_OPENDOC,
                                aURL.getName( INetURLObject::LAST_SEGMENT, true,
                                    INetURLObject::DecodeMechanism::WithCharset),
                                nullptr, RID_ERRCTX);

                        OUString aWarning;
                        aContext.GetString( ERRCODE_NONE.MakeWarning(), aWarning);
                        aWarning += ":\n";

                        OUString aMsg;
                        if (rAC.isTabOverflow())
                        {
                            if (ErrorHandler::GetErrorString( SCWARN_IMPORT_SHEET_OVERFLOW, aMsg))
                                aWarning += aMsg;
                        }
                        if (rAC.isColOverflow())
                        {
                            if (!aMsg.isEmpty())
                                aWarning += "\n";
                            if (ErrorHandler::GetErrorString( SCWARN_IMPORT_COLUMN_OVERFLOW, aMsg))
                                aWarning += aMsg;
                        }
                        if (rAC.isRowOverflow())
                        {
                            if (!aMsg.isEmpty())
                                aWarning += "\n";
                            if (ErrorHandler::GetErrorString( SCWARN_IMPORT_ROW_OVERFLOW, aMsg))
                                aWarning += aMsg;
                        }

                        /* XXX displaying a dialog here is ugly and should
                         * rather happen at UI level instead of at the filter
                         * level, but it seems there's no way to transport
                         * detailed information other than returning true or
                         * false at this point? */

                        vcl::Window* pWin = ScDocShell::GetActiveDialogParent();
                        std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(pWin ? pWin->GetFrameWeld() : nullptr,
                                                                   VclMessageType::Warning, VclButtonsType::Ok,
                                                                   aWarning));
                        xWarn->run();
                    }
                }
            }
            return bRet;
        }
    }
    catch (...)
diff --git a/sc/source/filter/oox/sheetdatacontext.cxx b/sc/source/filter/oox/sheetdatacontext.cxx
index b221cb1..5f17d8c 100644
--- a/sc/source/filter/oox/sheetdatacontext.cxx
+++ b/sc/source/filter/oox/sheetdatacontext.cxx
@@ -273,6 +273,7 @@ void SheetDataContext::importRow( const AttributeList& rAttribs )
    }
    else
        aModel.mnRow = ++mnRow;
    mrAddressConv.checkRow( mnRow, true);
    mnCol = -1;

    aModel.mfHeight       = rAttribs.getDouble( XML_ht, -1.0 );
@@ -297,8 +298,14 @@ void SheetDataContext::importRow( const AttributeList& rAttribs )
        if( (0 < nSepPos) && (nSepPos + 1 < aColSpanToken.getLength()) )
        {
            // OOXML uses 1-based integer column indexes, row model expects 0-based colspans
            sal_Int32 nLastCol = ::std::min( aColSpanToken.copy( nSepPos + 1 ).toInt32() - 1, nMaxCol );
            aModel.insertColSpan( ValueRange( aColSpanToken.copy( 0, nSepPos ).toInt32() - 1, nLastCol ) );
            const sal_Int32 nCol1 = aColSpanToken.copy( 0, nSepPos ).toInt32() - 1;
            const bool bValid1 = mrAddressConv.checkCol( nCol1, true);
            if (bValid1)
            {
                const sal_Int32 nCol2 = aColSpanToken.copy( nSepPos + 1 ).toInt32() - 1;
                mrAddressConv.checkCol( nCol2, true);
                aModel.insertColSpan( ValueRange( nCol1, ::std::min( nCol2, nMaxCol )));
            }
        }
    }

@@ -314,7 +321,9 @@ bool SheetDataContext::importCell( const AttributeList& rAttribs )
    if (!p)
    {
        ++mnCol;
        maCellData.maCellAddr = ScAddress( mnCol, mnRow, mnSheet );
        ScAddress aAddress( mnCol, mnRow, mnSheet );
        bValid = mrAddressConv.checkCellAddress( aAddress, true );
        maCellData.maCellAddr = aAddress;
    }
    else
    {
@@ -374,6 +383,7 @@ void SheetDataContext::importRow( SequenceInputStream& rStrm )
    nSpanCount = rStrm.readInt32();
    maCurrPos.mnCol = 0;

    mrAddressConv.checkRow( maCurrPos.mnRow, true);
    // row index is 0-based in BIFF12, but RowModel expects 1-based
    aModel.mnRow          = maCurrPos.mnRow + 1;
    // row height is in twips in BIFF12, convert to points
@@ -393,8 +403,11 @@ void SheetDataContext::importRow( SequenceInputStream& rStrm )
    {
        sal_Int32 nFirstCol, nLastCol;
        nFirstCol = rStrm.readInt32();
        const bool bValid1 = mrAddressConv.checkCol( nFirstCol, true);
        nLastCol = rStrm.readInt32();
        aModel.insertColSpan( ValueRange( nFirstCol, ::std::min( nLastCol, nMaxCol ) ) );
        mrAddressConv.checkCol( nLastCol, true);
        if (bValid1)
            aModel.insertColSpan( ValueRange( nFirstCol, ::std::min( nLastCol, nMaxCol ) ) );
    }

    // set row properties in the current sheet