/* -*- 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/itemset.hxx>
#include <vcl/virdev.hxx>
 
#include <undostyl.hxx>
#include <docsh.hxx>
#include <docpool.hxx>
#include <stlpool.hxx>
#include <printfun.hxx>
#include <scmod.hxx>
#include <inputhdl.hxx>
#include <globstr.hrc>
#include <scresid.hxx>
 
//      modify style (cell or page style)
 
ScStyleSaveData::ScStyleSaveData()
{
}
 
ScStyleSaveData::ScStyleSaveData( const ScStyleSaveData& rOther ) :
    aName( rOther.aName ),
    aParent( rOther.aParent )
{
    if (rOther.xItems)
        xItems.reset(new SfxItemSet(*rOther.xItems));
}
 
ScStyleSaveData& ScStyleSaveData::operator=( const ScStyleSaveData& rOther )
{
    aName   = rOther.aName;
    aParent = rOther.aParent;
    xItems.reset(rOther.xItems ? new SfxItemSet(*rOther.xItems) : nullptr);
 
    return *this;
}
 
void ScStyleSaveData::InitFromStyle( const SfxStyleSheetBase* pSource )
{
    if ( pSource )
    {
        aName   = pSource->GetName();
        aParent = pSource->GetParent();
        xItems.reset(new SfxItemSet(const_cast<SfxStyleSheetBase*>(pSource)->GetItemSet()));
    }
    else
        *this = ScStyleSaveData();      // empty
}
 
ScUndoModifyStyle::ScUndoModifyStyle( ScDocShell* pDocSh, SfxStyleFamily eFam,
                    const ScStyleSaveData& rOld, const ScStyleSaveData& rNew ) :
    ScSimpleUndo( pDocSh ),
    eFamily( eFam ),
    aOldData( rOld ),
    aNewData( rNew )
{
}
 
ScUndoModifyStyle::~ScUndoModifyStyle()
{
}
 
OUString ScUndoModifyStyle::GetComment() const
{
    const char* pId = (eFamily == SfxStyleFamily::Para) ?
                                STR_UNDO_EDITCELLSTYLE :
                                STR_UNDO_EDITPAGESTYLE;
    return ScResId(pId);
}
 
static void lcl_DocStyleChanged( ScDocument* pDoc, const SfxStyleSheetBase* pStyle, bool bRemoved )
{
    //! move to document or docshell
 
    ScopedVclPtrInstance< VirtualDevice > pVDev;
    Point aLogic = pVDev->LogicToPixel(Point(1000,1000), MapMode(MapUnit::MapTwip));
    double nPPTX = aLogic.X() / 1000.0;
    double nPPTY = aLogic.Y() / 1000.0;
    Fraction aZoom(1,1);
    pDoc->StyleSheetChanged( pStyle, bRemoved, pVDev, nPPTX, nPPTY, aZoom, aZoom );
 
    ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
    if (pHdl)
        pHdl->ForgetLastPattern();
}
 
void ScUndoModifyStyle::DoChange( ScDocShell* pDocSh, const OUString& rName,
                                    SfxStyleFamily eStyleFamily, const ScStyleSaveData& rData )
{
    ScDocument& rDoc = pDocSh->GetDocument();
    ScStyleSheetPool* pStlPool = rDoc.GetStyleSheetPool();
    const OUString& aNewName = rData.GetName();
    bool bDelete = aNewName.isEmpty();         // no new name -> delete style
    bool bNew = ( rName.isEmpty() && !bDelete );   // creating new style
 
    SfxStyleSheetBase* pStyle = nullptr;
    if ( !rName.isEmpty() )
    {
        // find old style to modify
        pStyle = pStlPool->Find( rName, eStyleFamily );
        OSL_ENSURE( pStyle, "style not found" );
 
        if ( pStyle && !bDelete )
        {
            // set new name
            pStyle->SetName( aNewName );
        }
    }
    else if ( !bDelete )
    {
        // create style (with new name)
        pStyle = &pStlPool->Make( aNewName, eStyleFamily, SfxStyleSearchBits::UserDefined );
 
        if ( eStyleFamily == SfxStyleFamily::Para )
            rDoc.GetPool()->CellStyleCreated( aNewName, &rDoc );
    }
 
    if ( pStyle )
    {
        if ( bDelete )
        {
            if ( eStyleFamily == SfxStyleFamily::Para )
                lcl_DocStyleChanged( &rDoc, pStyle, true );      // TRUE: remove usage of style
            else
                rDoc.RemovePageStyleInUse( rName );
 
            // delete style
            pStlPool->Remove( pStyle );
        }
        else
        {
            // modify style
 
            const OUString& aNewParent = rData.GetParent();
            if ( aNewParent != pStyle->GetParent() )
                pStyle->SetParent( aNewParent );
 
            SfxItemSet& rStyleSet = pStyle->GetItemSet();
            const SfxItemSet* pNewSet = rData.GetItems();
            OSL_ENSURE( pNewSet, "no ItemSet for style" );
            if (pNewSet)
                rStyleSet.Set( *pNewSet, false );
 
            if ( eStyleFamily == SfxStyleFamily::Para )
            {
                lcl_DocStyleChanged( &rDoc, pStyle, false );     // cell styles: row heights
            }
            else
            {
                // page styles
 
                if ( bNew && aNewName != rName )
                    rDoc.RenamePageStyleInUse( rName, aNewName );
 
                if (pNewSet)
                    rDoc.ModifyStyleSheet( *pStyle, *pNewSet );
 
                pDocSh->PageStyleModified( aNewName, true );
            }
        }
    }
 
    pDocSh->PostPaint( 0,0,0, MAXCOL,MAXROW,MAXTAB, PaintPartFlags::Grid|PaintPartFlags::Left );
 
    //! undo/redo document modifications for deleted styles
    //! undo/redo modifications of number formatter
}
 
void ScUndoModifyStyle::Undo()
{
    BeginUndo();
    DoChange( pDocShell, aNewData.GetName(), eFamily, aOldData );
    EndUndo();
}
 
void ScUndoModifyStyle::Redo()
{
    BeginRedo();
    DoChange( pDocShell, aOldData.GetName(), eFamily, aNewData );
    EndRedo();
}
 
void ScUndoModifyStyle::Repeat(SfxRepeatTarget& /* rTarget */)
{
}
 
bool ScUndoModifyStyle::CanRepeat(SfxRepeatTarget& /* rTarget */) const
{
    return false;       // no repeat possible
}
 
//      apply page style
 
ScUndoApplyPageStyle::ApplyStyleEntry::ApplyStyleEntry( SCTAB nTab, const OUString& rOldStyle ) :
    mnTab( nTab ),
    maOldStyle( rOldStyle )
{
}
 
ScUndoApplyPageStyle::ScUndoApplyPageStyle( ScDocShell* pDocSh, const OUString& rNewStyle ) :
    ScSimpleUndo( pDocSh ),
    maNewStyle( rNewStyle )
{
}
 
ScUndoApplyPageStyle::~ScUndoApplyPageStyle()
{
}
 
void ScUndoApplyPageStyle::AddSheetAction( SCTAB nTab, const OUString& rOldStyle )
{
    maEntries.emplace_back( nTab, rOldStyle );
}
 
OUString ScUndoApplyPageStyle::GetComment() const
{
    return ScResId( STR_UNDO_APPLYPAGESTYLE );
}
 
void ScUndoApplyPageStyle::Undo()
{
    BeginUndo();
    for( ApplyStyleVec::const_iterator aIt = maEntries.begin(), aEnd = maEntries.end(); aIt != aEnd; ++aIt )
    {
        pDocShell->GetDocument().SetPageStyle( aIt->mnTab, aIt->maOldStyle );
        ScPrintFunc( pDocShell, pDocShell->GetPrinter(), aIt->mnTab ).UpdatePages();
    }
    EndUndo();
}
 
void ScUndoApplyPageStyle::Redo()
{
    BeginRedo();
    for( ApplyStyleVec::const_iterator aIt = maEntries.begin(), aEnd = maEntries.end(); aIt != aEnd; ++aIt )
    {
        pDocShell->GetDocument().SetPageStyle( aIt->mnTab, maNewStyle );
        ScPrintFunc( pDocShell, pDocShell->GetPrinter(), aIt->mnTab ).UpdatePages();
    }
    EndRedo();
}
 
void ScUndoApplyPageStyle::Repeat(SfxRepeatTarget& /* rTarget */)
{
    //! set same page style to current tab
}
 
bool ScUndoApplyPageStyle::CanRepeat(SfxRepeatTarget& /* rTarget */) const
{
    return false;
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V794 The assignment operator should be protected from the case of 'this == &rOther'.