Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/LibreOffice/svx/source/table/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 15 kB image not shown  

Quelle  tablehtmlimporter.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 <memory>
#include <vector>

#include <com/sun/star/table/XTable.hpp>
#include <com/sun/star/table/XMergeableCellRange.hpp>

#include <tools/stream.hxx>
#include <tools/UnitConversion.hxx>

#include <svx/svdetc.hxx>
#include <editeng/outlobj.hxx>

#include <cell.hxx>
#include <svx/svdotable.hxx>
#include <svx/svdoutl.hxx>
#include <editeng/editeng.hxx>
#include <editeng/editdata.hxx>
#include <svx/svdmodel.hxx>
#include <editeng/editids.hrc>
#include <sal/log.hxx>
#include <tools/debug.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <svtools/htmltokn.h>
#include <svtools/parhtml.hxx>

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::table;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::beans;

namespace sdr::table
{
namespace
{
struct RowColSpan
{
    sal_Int32 mnRowSpan;
    sal_Int32 mnColSpan;
    explicit RowColSpan()
        : mnRowSpan(1)
        , mnColSpan(1)
    {
    }
};

struct HTMLCellDefault
{
    sal_Int32 mnRowSpan;
    sal_Int32 mnColSpan; // MergeCell if >1, merged cells if 0
    sal_Int32 mnCellX;

    explicit HTMLCellDefault()
        : mnRowSpan(1)
        , mnColSpan(1)
        , mnCellX(0)
    {
    }
};
}

typedef std::vector<std::shared_ptr<HTMLCellDefault>> HTMLCellDefaultVector;

namespace
{
struct HTMLCellInfo
{
    SfxItemSet maItemSet;
    sal_Int32 mnStartPara;
    sal_Int32 mnParaCount;
    sal_Int32 mnCellX;
    sal_Int32 mnRowSpan;
    std::shared_ptr<HTMLCellInfo> mxVMergeCell;

    explicit HTMLCellInfo(SfxItemPool& rPool)
        : maItemSet(rPool)
        , mnStartPara(0)
        , mnParaCount(0)
        , mnCellX(0)
        , mnRowSpan(1)
    {
    }
};
}

typedef std::shared_ptr<HTMLCellInfo> HTMLCellInfoPtr;
typedef std::vector<HTMLCellInfoPtr> HTMLColumnVector;

typedef std::shared_ptr<HTMLColumnVector> HTMLColumnVectorPtr;

class SdrTableHTMLParser
{
public:
    explicit SdrTableHTMLParser(SdrTableObj& rTableObj);

    void Read(SvStream& rStream);

    void ProcToken(HtmlImportInfo* pInfo);

    void NextRow();
    void NextColumn();
    void NewCellRow();

    void InsertCell(sal_Int32 nStartPara, sal_Int32 nEndPara);
    void InsertColumnEdge(sal_Int32 nEdge);

    void FillTable();

    DECL_LINK(HTMLImportHdl, HtmlImportInfo&, void);

private:
    SdrTableObj& mrTableObj;
    std::unique_ptr<SdrOutliner> mpOutliner;
    SfxItemPool& mrItemPool;

    HTMLCellDefaultVector maDefaultList;
    HTMLCellDefaultVector::iterator maDefaultIterator;

    bool mbNewDef;

    sal_Int32 mnCellStartPara;

    sal_Int32 mnRowCnt;
    sal_Int32 mnLastEdge;
    sal_Int32 mnVMergeIdx;

    std::vector<sal_Int32> maColumnEdges;
    std::vector<sal_Int32>::iterator maLastEdge;
    std::vector<HTMLColumnVectorPtr> maRows;

    std::unique_ptr<HTMLCellDefault> mpInsDefault;
    HTMLCellDefault* mpActDefault;
    sal_Int32 mnCellInRow;

    rtl::Reference<TableModel> mxTable;

    HTMLColumnVectorPtr mxLastRow;
    // Copy assignment is forbidden and not implemented.
    SdrTableHTMLParser(const SdrTableHTMLParser&) = delete;
    SdrTableHTMLParser& operator=(const SdrTableHTMLParser&) = delete;
};

SdrTableHTMLParser::SdrTableHTMLParser(SdrTableObj& rTableObj)
    : mrTableObj(rTableObj)
    , mpOutliner(SdrMakeOutliner(OutlinerMode::TextObject, rTableObj.getSdrModelFromSdrObject()))
    , mrItemPool(rTableObj.getSdrModelFromSdrObject().GetItemPool())
    , mbNewDef(false)
    , mnCellStartPara(0)
    , mnRowCnt(0)
    , mnLastEdge(0)
    , mnVMergeIdx(0)
    , mpActDefault(nullptr)
    , mnCellInRow(-1)
    , mxTable(rTableObj.getUnoTable())
{
    mpOutliner->SetUpdateLayout(true);
    mpOutliner->SetStyleSheet(0, mrTableObj.GetStyleSheet());
    mpInsDefault.reset(new HTMLCellDefault());
}

void SdrTableHTMLParser::Read(SvStream& rStream)
{
    EditEngine& rEdit = const_cast<EditEngine&>(mpOutliner->GetEditEngine());

    Link<HtmlImportInfo&, void> aOldLink(rEdit.GetHtmlImportHdl());
    rEdit.SetHtmlImportHdl(LINK(this, SdrTableHTMLParser, HTMLImportHdl));
    mpOutliner->Read(rStream, OUString(), EETextFormat::Html);
    rEdit.SetHtmlImportHdl(aOldLink);

    FillTable();
}

IMPL_LINK(SdrTableHTMLParser, HTMLImportHdl, HtmlImportInfo&, rInfo, void)
{
    switch (rInfo.eState)
    {
        case HtmlImportState::NextToken:
            ProcToken(&rInfo);
            break;
        case HtmlImportState::End:
            if (rInfo.aSelection.end.nIndex)
            {
                mpActDefault = nullptr;
                //TODO: ??
                //                rInfo.nToken = RTF_PAR;
                rInfo.aSelection.end.nPara++;
                ProcToken(&rInfo);
            }
            break;
        case HtmlImportState::SetAttr:
        case HtmlImportState::InsertText:
        case HtmlImportState::InsertPara:
            break;
        default:
            SAL_WARN("svx.table""unknown ImportInfo.eState");
    }
}

void SdrTableHTMLParser::NextRow()
{
    mxLastRow = maRows.back();
    mnVMergeIdx = 0;
    ++mnRowCnt;
}

void SdrTableHTMLParser::InsertCell(sal_Int32 nStartPara, sal_Int32 nEndPara)
{
    HTMLCellInfoPtr xCellInfo = std::make_shared<HTMLCellInfo>(mrItemPool);
    xCellInfo->mnStartPara = nStartPara;
    xCellInfo->mnParaCount = nEndPara - nStartPara;
    xCellInfo->mnCellX = mpActDefault->mnCellX;
    xCellInfo->mnRowSpan = mpActDefault->mnRowSpan;

    if (mxLastRow != nullptr)
    {
        sal_Int32 nSize = mxLastRow->size();
        while (mnVMergeIdx < nSize && (*mxLastRow)[mnVMergeIdx]->mnCellX < xCellInfo->mnCellX)
            ++mnVMergeIdx;

        if (xCellInfo->mnRowSpan == 0 && mnVMergeIdx < nSize)
        {
            HTMLCellInfoPtr xLastCell((*mxLastRow)[mnVMergeIdx]);
            if (xLastCell->mnRowSpan)
                xCellInfo->mxVMergeCell = std::move(xLastCell);
            else
                xCellInfo->mxVMergeCell = xLastCell->mxVMergeCell;
        }
    }

    if (!maRows.empty())
    {
        HTMLColumnVectorPtr xColumn(maRows.back());
        if (xCellInfo->mxVMergeCell)
        {
            if (xColumn->empty() || xColumn->back()->mxVMergeCell != xCellInfo->mxVMergeCell)
                xCellInfo->mxVMergeCell->mnRowSpan++;
        }

        xColumn->push_back(xCellInfo);
    }
}

void SdrTableHTMLParser::InsertColumnEdge(sal_Int32 nEdge)
{
    auto aNextEdge = std::lower_bound(maLastEdge, maColumnEdges.end(), nEdge);

    if (aNextEdge == maColumnEdges.end() || nEdge != *aNextEdge)
    {
        maLastEdge = maColumnEdges.insert(aNextEdge, nEdge);
        mnLastEdge = nEdge;
    }
}

void SdrTableHTMLParser::FillTable()
{
    try
    {
        sal_Int32 nColCount = mxTable->getColumnCount();
        Reference<XTableColumns> xCols(mxTable->getColumns(), UNO_SET_THROW);
        sal_Int32 nColMax = maColumnEdges.size();
        if (nColCount < nColMax)
        {
            xCols->insertByIndex(nColCount, nColMax - nColCount);
            nColCount = mxTable->getColumnCount();
        }

        static constexpr OUStringLiteral sWidth(u"Width");
        sal_Int32 nCol, nLastEdge = 0;
        for (nCol = 0; nCol < nColCount; nCol++)
        {
            Reference<XPropertySet> xSet(xCols->getByIndex(nCol), UNO_QUERY_THROW);
            sal_Int32 nWidth = maColumnEdges[nCol] - nLastEdge;

            xSet->setPropertyValue(sWidth, Any(nWidth));
            nLastEdge += nWidth;
        }

        const sal_Int32 nRowCount = mxTable->getRowCount();
        if (nRowCount < mnRowCnt)
        {
            Reference<XTableRows> xRows(mxTable->getRows(), UNO_SET_THROW);
            xRows->insertByIndex(nRowCount, mnRowCnt - nRowCount);
        }

        for (sal_Int32 nRow = 0; nRow < static_cast<sal_Int32>(maRows.size()); nRow++)
        {
            HTMLColumnVectorPtr xColumn(maRows[nRow]);
            nCol = 0;
            auto aEdge = maColumnEdges.begin();
            for (sal_Int32 nIdx = 0;
                 nCol < nColMax && nIdx < static_cast<sal_Int32>(xColumn->size()); nIdx++)
            {
                HTMLCellInfoPtr xCellInfo((*xColumn)[nIdx]);

                CellRef xCell(mxTable->getCell(nCol, nRow));
                if (xCell.is() && xCellInfo)
                {
                    const SfxPoolItem* pPoolItem = nullptr;
                    if (xCellInfo->maItemSet.GetItemState(SDRATTR_TABLE_BORDER, false, &pPoolItem)
                        == SfxItemState::SET)
                        xCell->SetMergedItem(*pPoolItem);

                    std::optional<OutlinerParaObject> pTextObject(mpOutliner->CreateParaObject(
                        xCellInfo->mnStartPara, xCellInfo->mnParaCount));
                    if (pTextObject)
                    {
                        SdrOutliner& rOutliner = mrTableObj.ImpGetDrawOutliner();
                        rOutliner.SetUpdateLayout(true);
                        rOutliner.SetText(*pTextObject);
                        mrTableObj.NbcSetOutlinerParaObjectForText(rOutliner.CreateParaObject(),
                                                                   xCell.get());
                    }

                    sal_Int32 nLastRow = nRow;
                    if (xCellInfo->mnRowSpan)
                        nLastRow += xCellInfo->mnRowSpan - 1;

                    aEdge = std::lower_bound(aEdge, maColumnEdges.end(), xCellInfo->mnCellX);
                    sal_Int32 nLastCol = nCol;
                    if (aEdge != maColumnEdges.end())
                    {
                        nLastCol = std::distance(maColumnEdges.begin(), aEdge);
                        ++aEdge;
                    }

                    if (nLastCol > nCol || nLastRow > nRow)
                    {
                        Reference<XMergeableCellRange> xRange(
                            mxTable->createCursorByRange(
                                mxTable->getCellRangeByPosition(nCol, nRow, nLastCol, nLastRow)),
                            UNO_QUERY_THROW);
                        if (xRange->isMergeable())
                            xRange->merge();
                    }
                    nCol = nLastCol + 1;
                }
            }
        }

        tools::Rectangle aRect(mrTableObj.GetSnapRect());
        aRect.SetRight(aRect.Left() + nLastEdge);
        mrTableObj.NbcSetSnapRect(aRect);
    }
    catch (Exception&)
    {
        TOOLS_WARN_EXCEPTION("svx""");
    }
}

void SdrTableHTMLParser::NewCellRow()
{
    if (mbNewDef)
    {
        mbNewDef = false;

        maRows.push_back(std::make_shared<std::vector<std::shared_ptr<HTMLCellInfo>>>());
    }
    maDefaultIterator = maDefaultList.begin();

    NextColumn();

    DBG_ASSERT(mpActDefault, "NewCellRow: pActDefault==0");
}

void SdrTableHTMLParser::NextColumn()
{
    if (maDefaultIterator != maDefaultList.end())
        mpActDefault = (*maDefaultIterator++).get();
    else
        mpActDefault = nullptr;
}

static RowColSpan lcl_GetRowColSpan(const HTMLOptions& options)
{
    RowColSpan aRowColSpan;
    for (HTMLOptions::const_iterator optionIt = options.begin(); optionIt != options.end();
         ++optionIt)
    {
        if (optionIt->GetToken() == HtmlOptionId::COLSPAN)
        {
            aRowColSpan.mnColSpan = optionIt->GetNumber();
        }
        else if (optionIt->GetToken() == HtmlOptionId::ROWSPAN)
        {
            aRowColSpan.mnRowSpan = optionIt->GetNumber();
        }
    }
    return aRowColSpan;
}

//TODO: width is pixel - detect document pixel with to determine real width
static sal_Int32 lcl_GetWidth(const HTMLOptions& options)
{
    for (HTMLOptions::const_iterator optionIt = options.begin(); optionIt != options.end();
         ++optionIt)
    {
        if (optionIt->GetToken() == HtmlOptionId::WIDTH)
        {
            //const OUString& value = optionIt->GetString();
            //TODO: Which conversion is required?
            return 1000;
        }
    }
    return 1000;
}
static sal_Int32 lcl_GetSpan(const HTMLOptions& options)
{
    for (HTMLOptions::const_iterator optionIt = options.begin(); optionIt != options.end();
         ++optionIt)
    {
        if (optionIt->GetToken() == HtmlOptionId::SPAN)
            return optionIt->GetNumber();
    }
    return 1;
}
void SdrTableHTMLParser::ProcToken(HtmlImportInfo* pInfo)
{
    HTMLParser* pHtmlParser = static_cast<HTMLParser*>(pInfo->pParser);
    const HTMLOptions& options = pHtmlParser->GetOptions();
    switch (pInfo->nToken)
    {
        case HtmlTokenId::TABLE_ON:
            maDefaultList.clear();
            maLastEdge = maColumnEdges.begin();
            mnLastEdge = 0;
            break;
        case HtmlTokenId::TABLE_OFF:
            break;
        case HtmlTokenId::TABLEHEADER_ON:
        case HtmlTokenId::TABLEDATA_ON:
        {
            ++mnCellInRow;
            assert(mpActDefault);
            RowColSpan aRowColSpan = lcl_GetRowColSpan(options);
            mpActDefault->mnColSpan = aRowColSpan.mnColSpan;
            mpActDefault->mnRowSpan = aRowColSpan.mnRowSpan;
            mnCellStartPara = pInfo->aSelection.start.nPara;
        }
        break;
        case HtmlTokenId::TABLEDATA_OFF:
        case HtmlTokenId::TABLEHEADER_OFF:
        {
            DBG_ASSERT(mpActDefault, "TABLEDATA_OFF: pActDefault==0");
            if (mbNewDef || !mpActDefault)
                NewCellRow();
            if (!mpActDefault)
                mpActDefault = mpInsDefault.get();
            if (mpActDefault->mnColSpan > 0)
            {
                mpActDefault->mnCellX = maColumnEdges[mnCellInRow + mpActDefault->mnColSpan - 1];
                InsertCell(mnCellStartPara, pInfo->aSelection.end.nPara);
            }
            NextColumn();
        }
        break;
        case HtmlTokenId::TABLEROW_ON:
            mbNewDef = true;
            NewCellRow();
            break;
        case HtmlTokenId::TABLEROW_OFF:
        {
            NextRow();
            mnCellInRow = -1;
        }
        break;
        case HtmlTokenId::COL_ON:
        {
            std::shared_ptr<HTMLCellDefault> pDefault(mpInsDefault.release());
            maDefaultList.push_back(pDefault);

            const sal_Int32 nSize = lcl_GetWidth(options) + mnLastEdge;
            if (nSize > mnLastEdge)
                InsertColumnEdge(nSize);

            mpInsDefault.reset(new HTMLCellDefault());
            mnLastEdge = nSize;
        }
        break;
        case HtmlTokenId::COL_OFF:
            break;
        case HtmlTokenId::COLGROUP_ON:
        {
            const sal_Int32 nSpan = lcl_GetSpan(options);
            for (sal_Int32 nCol = 0; nCol < nSpan; ++nCol)
            {
                std::shared_ptr<HTMLCellDefault> pDefault(mpInsDefault.release());
                maDefaultList.push_back(pDefault);
                const sal_Int32 nSize = lcl_GetWidth(options) + mnLastEdge;
                if (nSize > mnLastEdge)
                    InsertColumnEdge(nSize);
                mnLastEdge = nSize;
                mpInsDefault.reset(new HTMLCellDefault());
            }
        }
        break;
        case HtmlTokenId::COLGROUP_OFF:
            break;

        default:
            break;
    }
}

void ImportAsHTML(SvStream& rStream, SdrTableObj& rObj)
{
    SdrTableHTMLParser aParser(rObj);
    aParser.Read(rStream);
}
}

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

Messung V0.5
C=90 H=99 G=94

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet)  ¤

*© 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 und die Messung sind noch experimentell.