/* -*- 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/.
 *
 */
 
#include <GraphicSizeCheck.hxx>
#include <svx/strings.hrc>
#include <svx/svdobj.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/dispatch.hxx>
 
#include <ModelTraverser.hxx>
#include <ndgrf.hxx>
#include <IDocumentSettingAccess.hxx>
#include <fmtfsize.hxx>
#include <view.hxx>
#include <wrtsh.hxx>
#include <cmdid.h>
 
using namespace css;
 
namespace sw
{
GraphicSizeViolation::GraphicSizeViolation(sal_Int32 nDPI, const SwGrfNode* pGraphicNode)
    : m_pGraphicNode(pGraphicNode)
{
    constexpr double fLowPercentage = 110;
    constexpr double fHighPercentage = 50;
 
    m_nLowDPILimit = sal_Int32(100.0 / fLowPercentage * nDPI);
    m_nHighDPILimit = sal_Int32(100.0 / fHighPercentage * nDPI);
}
 
bool GraphicSizeViolation::check()
{
    auto pFrameFormat = m_pGraphicNode->GetFlyFormat();
    Graphic aGraphic = m_pGraphicNode->GetGraphic();
    Size aSizePixel = aGraphic.GetSizePixel();
    Size aFrameSize(pFrameFormat->GetFrameSize().GetSize());
 
    double nSizeXInch
        = o3tl::convert(double(aFrameSize.Width()), o3tl::Length::twip, o3tl::Length::in);
    double nSizeYInch
        = o3tl::convert(double(aFrameSize.Height()), o3tl::Length::twip, o3tl::Length::in);
 
    m_nDPIX = sal_Int32(aSizePixel.Width() / nSizeXInch);
    m_nDPIY = sal_Int32(aSizePixel.Height() / nSizeYInch);
 
    return isDPITooLow() || isDPITooHigh();
}
 
const OUString& GraphicSizeViolation::getGraphicName()
{
    return m_pGraphicNode->GetFlyFormat()->GetName();
}
 
namespace
{
class GraphicSizeCheckHandler : public ModelTraverseHandler
{
private:
    sal_Int32 m_nDPI;
    std::vector<std::unique_ptr<GraphicSizeViolation>>& m_rGraphicSizeViolationList;
 
public:
    GraphicSizeCheckHandler(
        sal_Int32 nDPI,
        std::vector<std::unique_ptr<GraphicSizeViolation>>& rGraphicSizeViolationList)
        : m_nDPI(nDPI)
        , m_rGraphicSizeViolationList(rGraphicSizeViolationList)
    {
    }
 
    void handleNode(SwNode* pNode) override
    {
        if (!pNode->IsGrfNode())
            return;
 
        auto pEntry = std::make_unique<GraphicSizeViolation>(m_nDPI, pNode->GetGrfNode());
        if (pEntry->check())
        {
            m_rGraphicSizeViolationList.push_back(std::move(pEntry));
        }
    }
 
    void handleSdrObject(SdrObject* /*pObject*/) override {}
};
 
} // end anonymous namespace
 
void GraphicSizeCheck::check()
{
    sal_Int32 nDPI = m_pDocument->getIDocumentSettingAccess().getImagePreferredDPI();
    if (nDPI == 0)
        return;
 
    auto pHandler = std::make_shared<GraphicSizeCheckHandler>(nDPI, m_aGraphicSizeViolationList);
    ModelTraverser aModelTraverser(m_pDocument);
    aModelTraverser.addNodeHandler(pHandler);
    aModelTraverser.traverse();
}
 
OUString GraphicSizeCheckGUIEntry::getText()
{
    OUString sText;
 
    if (m_pViolation->isDPITooLow())
    {
        sText = SwResId(STR_WARNING_GRAPHIC_PIXEL_COUNT_LOW);
    }
    else if (m_pViolation->isDPITooHigh())
    {
        sText = SwResId(STR_WARNING_GRAPHIC_PIXEL_COUNT_HIGH);
    }
 
    sText = sText.replaceAll("%NAME%", m_pViolation->getGraphicName());
    sText = sText.replaceAll("%DPIX%", OUString::number(m_pViolation->getDPIX()));
    sText = sText.replaceAll("%DPIY%", OUString::number(m_pViolation->getDPIY()));
 
    return sText;
}
 
void GraphicSizeCheckGUIEntry::markObject()
{
    SwWrtShell* pWrtShell = m_pDocument->GetDocShell()->GetWrtShell();
    pWrtShell->GotoFly(m_pViolation->getGraphicName(), FLYCNTTYPE_ALL, true);
}
 
void GraphicSizeCheckGUIEntry::runProperties()
{
    markObject();
    SwWrtShell* pWrtShell = m_pDocument->GetDocShell()->GetWrtShell();
    pWrtShell->GetView().GetViewFrame().GetDispatcher()->Execute(FN_FORMAT_GRAFIC_DLG,
                                                                 SfxCallMode::SYNCHRON);
}
 
GraphicSizeCheckGUIResult::GraphicSizeCheckGUIResult(SwDoc* pDocument)
{
    GraphicSizeCheck aCheck(pDocument);
    aCheck.check();
 
    auto& rCollection = getCollection();
    for (auto& rpViolation : aCheck.getViolationList())
    {
        auto rGUIEntry
            = std::make_unique<GraphicSizeCheckGUIEntry>(pDocument, std::move(rpViolation));
        rCollection.push_back(std::move(rGUIEntry));
    }
}
 
OUString GraphicSizeCheckGUIResult::getTitle()
{
    return SwResId(STR_GRAPHIC_SIZE_CHECK_DIALOG_TITLE);
}
 
} // end sw namespace
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V530 The return value of function 'Execute' is required to be utilized.