Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/sd/source/ui/slidesorter/model/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 20 kB image not shown  

Quelle  SlideSorterModel.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 <model/SlideSorterModel.hxx>

#include <SlideSorter.hxx>
#include <sal/log.hxx>
#include <model/SlsPageDescriptor.hxx>
#include <model/SlsPageEnumerationProvider.hxx>
#include <controller/SlideSorterController.hxx>
#include <controller/SlsPageSelector.hxx>
#include <controller/SlsCurrentSlideManager.hxx>
#include <controller/SlsSlotManager.hxx>
#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
#include <com/sun/star/drawing/XMasterPagesSupplier.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/frame/XController.hpp>

#include <vcl/uitest/logger.hxx>
#include <vcl/uitest/eventdescription.hxx>

#include <ViewShellBase.hxx>
#include <DrawDocShell.hxx>
#include <drawdoc.hxx>
#include <sdpage.hxx>
#include <FrameView.hxx>

#include <o3tl/safeint.hxx>
#include <comphelper/diagnose_ex.hxx>

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

namespace sd::slidesorter::model {

namespace {
    bool PrintModel (const SlideSorterModel& rModel)
    {
        for (sal_Int32 nIndex=0,nCount=rModel.GetPageCount(); nIndex<nCount; ++nIndex)
        {
            SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex));
            if (pDescriptor)
            {
                SAL_INFO(
                    "sd.sls",
                    nIndex << " " << pDescriptor->GetPageIndex() << " "
                        << pDescriptor->GetVisualState().mnPageId << " "
                        << FromCoreIndex(pDescriptor->GetPage()->GetPageNum())
                        << " " << pDescriptor->GetPage());
            }
            else
            {
                SAL_INFO("sd.sls", nIndex);
            }
        }

        return true;
    }
    bool CheckModel (const SlideSorterModel& rModel)
    {
        for (sal_Int32 nIndex=0,nCount=rModel.GetPageCount(); nIndex<nCount; ++nIndex)
        {
            SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex));
            if ( ! pDescriptor)
            {
                PrintModel(rModel);
                assert(pDescriptor);
                return false;
            }
            if (nIndex != pDescriptor->GetPageIndex())
            {
                PrintModel(rModel);
                assert(nIndex == pDescriptor->GetPageIndex());
                return false;
            }
            if (nIndex != pDescriptor->GetVisualState().mnPageId)
            {
                PrintModel(rModel);
                assert(nIndex == pDescriptor->GetVisualState().mnPageId);
                return false;
            }
        }

        return true;
    }
}

namespace {

void collectUIInformation(const OUString& num, const OUString& rAction)
{
    EventDescription aDescription;
    aDescription.aID = "impress_win_or_draw_win";
    aDescription.aParameters = {{"POS", num}};
    aDescription.aAction = rAction;
    aDescription.aKeyWord = "ImpressWindowUIObject";
    aDescription.aParent = "MainWindow";

    UITestLogger::getInstance().logEvent(aDescription);
}

}

SlideSorterModel::SlideSorterModel (SlideSorter& rSlideSorter)
    : mrSlideSorter(rSlideSorter),
      meEditMode(EditMode::Page),
      maPageDescriptors(0)
{
}

SlideSorterModel::~SlideSorterModel()
{
    ClearDescriptorList ();
}

void SlideSorterModel::Dispose()
{
    ClearDescriptorList ();
}

SdDrawDocument* SlideSorterModel::GetDocument()
{
    if (mrSlideSorter.GetViewShellBase() != nullptr)
        return mrSlideSorter.GetViewShellBase()->GetDocument();
    else
         return nullptr;
}

bool SlideSorterModel::SetEditMode (EditMode eEditMode)
{
    bool bEditModeChanged = false;
    if (meEditMode != eEditMode)
    {
        meEditMode = eEditMode;
        UpdatePageList();
        bEditModeChanged = true;
    }
    return bEditModeChanged;
}

sal_Int32 SlideSorterModel::GetPageCount() const
{
    return maPageDescriptors.size();
}

SharedPageDescriptor SlideSorterModel::GetPageDescriptor (
    const sal_Int32 nPageIndex,
    const bool bCreate) const
{
    ::osl::MutexGuard aGuard (maMutex);

    SharedPageDescriptor pDescriptor;

    if (nPageIndex>=0 && nPageIndex<GetPageCount())
    {
        pDescriptor = maPageDescriptors[nPageIndex];
        if (pDescriptor == nullptr && bCreate && mxSlides.is())
        {
            SdPage* pPage = GetPage(nPageIndex);
            pDescriptor = std::make_shared<PageDescriptor>(
                Reference<drawing::XDrawPage>(mxSlides->getByIndex(nPageIndex),UNO_QUERY),
                pPage,
                nPageIndex);
            maPageDescriptors[nPageIndex] = pDescriptor;
        }
    }

    return pDescriptor;
}

sal_Int32 SlideSorterModel::GetIndex (const Reference<drawing::XDrawPage>& rxSlideconst
{
    ::osl::MutexGuard aGuard (maMutex);

    // First try to guess the right index.
    Reference<beans::XPropertySet> xSet (rxSlide, UNO_QUERY);
    if (xSet.is())
    {
        try
        {
            const Any aNumber (xSet->getPropertyValue(u"Number"_ustr));
            sal_Int16 nNumber (-1);
            aNumber >>= nNumber;
            nNumber -= 1;
            SharedPageDescriptor pDescriptor (GetPageDescriptor(nNumber, false));
            if (pDescriptor
                && pDescriptor->GetXDrawPage() == rxSlide)
            {
                return nNumber;
            }
        }
        catch (uno::Exception&)
        {
            DBG_UNHANDLED_EXCEPTION("sd");
        }
    }

    // Guess was wrong, iterate over all slides and search for the right
    // one.
    const sal_Int32 nCount (maPageDescriptors.size());
    for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex)
    {
        SharedPageDescriptor pDescriptor (maPageDescriptors[nIndex]);

        // Make sure that the descriptor exists.  Without it the given slide
        // can not be found.
        if (!pDescriptor)
        {
            // Call GetPageDescriptor() to create the missing descriptor.
            pDescriptor = GetPageDescriptor(nIndex);
        }

        if (pDescriptor->GetXDrawPage() == rxSlide)
            return nIndex;
    }

    return  -1;
}

sal_Int32 SlideSorterModel::GetIndex (const SdrPage* pPage) const
{
    if (pPage == nullptr)
        return -1;

    ::osl::MutexGuard aGuard (maMutex);

    // First try to guess the right index.
    sal_Int16 nNumber ((pPage->GetPageNum()-1)/2);
    SharedPageDescriptor pDescriptor (GetPageDescriptor(nNumber, false));
    if (pDescriptor
        && pDescriptor->GetPage() == pPage)
    {
        return nNumber;
    }

    // Guess was wrong, iterate over all slides and search for the right
    // one.
    const sal_Int32 nCount (maPageDescriptors.size());
    for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex)
    {
        pDescriptor = maPageDescriptors[nIndex];

        // Make sure that the descriptor exists.  Without it the given slide
        // can not be found.
        if (!pDescriptor)
        {
            // Call GetPageDescriptor() to create the missing descriptor.
            pDescriptor = GetPageDescriptor(nIndex);
        }

        if (pDescriptor->GetPage() == pPage)
            return nIndex;
    }

    return  -1;
}

sal_uInt16 SlideSorterModel::GetCoreIndex (const sal_Int32 nIndex) const
{
    SharedPageDescriptor pDescriptor (GetPageDescriptor(nIndex));
    if (pDescriptor)
        return pDescriptor->GetPage()->GetPageNum();
    else
        return mxSlides->getCount()*2+1;
}

/** For now this method uses a trivial algorithm: throw away all descriptors
    and create them anew (on demand).  The main problem that we are facing
    when designing a better algorithm is that we can not compare pointers to
    pages stored in the PageDescriptor objects and those obtained from the
    document: pages may have been deleted and others may have been created
    at the exact same memory locations.
*/

void SlideSorterModel::Resync()
{
    ::osl::MutexGuard aGuard (maMutex);

    // Check if document and this model really differ.
    bool bIsUpToDate (true);
    SdDrawDocument* pDocument = GetDocument();
    if (pDocument!=nullptr && maPageDescriptors.size()==pDocument->GetSdPageCount(PageKind::Standard))
    {
        for (sal_Int32 nIndex=0,nCount=maPageDescriptors.size(); nIndex<nCount; ++nIndex)
        {
            if (maPageDescriptors[nIndex]
                && maPageDescriptors[nIndex]->GetPage()
                != GetPage(nIndex))
            {
                SAL_INFO("sd.sls""page " << nIndex << " differs");
                bIsUpToDate = false;
                break;
            }
        }
    }
    else
    {
        bIsUpToDate = false;
    }

    if ( ! bIsUpToDate)
    {
        SynchronizeDocumentSelection(); // Try to make the current selection persistent.
        ClearDescriptorList ();
        AdaptSize();
        SynchronizeModelSelection();
        mrSlideSorter.GetController().GetPageSelector().CountSelectedPages();
    }
    CheckModel(*this);
}

void SlideSorterModel::ClearDescriptorList()
{
    ::std::vector<SharedPageDescriptor> aDescriptors;

    {
        ::osl::MutexGuard aGuard (maMutex);
        aDescriptors.swap(maPageDescriptors);
    }

    for (auto& rxDescriptor : aDescriptors)
    {
        if (rxDescriptor != nullptr)
        {
            if (rxDescriptor.use_count() > 1)
            {
                SAL_INFO(
                    "sd.sls",
                    "trying to delete page descriptor that is still used with"
                        " count " << rxDescriptor.use_count());
                // No assertion here because that can hang the office when
                // opening a dialog from here.
            }
            rxDescriptor.reset();
        }
    }
}

void SlideSorterModel::SynchronizeDocumentSelection()
{
    ::osl::MutexGuard aGuard (maMutex);

    PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this));
    while (aAllPages.HasMoreElements())
    {
        SharedPageDescriptor pDescriptor (aAllPages.GetNextElement());
        const bool bIsSelected (pDescriptor->HasState(PageDescriptor::ST_Selected));
        pDescriptor->GetPage()->SetSelected(bIsSelected);
    }
}

void SlideSorterModel::SynchronizeModelSelection()
{
    ::osl::MutexGuard aGuard (maMutex);

    PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this));
    while (aAllPages.HasMoreElements())
    {
        SharedPageDescriptor pDescriptor (aAllPages.GetNextElement());
        const bool bIsSelected (pDescriptor->GetPage()->IsSelected());
        pDescriptor->SetState(PageDescriptor::ST_Selected, bIsSelected);
    }
}

void SlideSorterModel::SetDocumentSlides (
    const Reference<container::XIndexAccess>& rxSlides)
{
    ::osl::MutexGuard aGuard (maMutex);

    // Make the current selection persistent and then release the
    // current set of pages.
    SynchronizeDocumentSelection();
    mxSlides = nullptr;
    ClearDescriptorList ();

    // Reset the current page to cause everybody to release references to it.
    mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(-1);

    // Set the new set of pages.
    mxSlides = rxSlides;
    AdaptSize();
    SynchronizeModelSelection();
    mrSlideSorter.GetController().GetPageSelector().CountSelectedPages();

    model::PageEnumeration aSelectedPages (
        model::PageEnumerationProvider::CreateSelectedPagesEnumeration(*this));
    if (aSelectedPages.HasMoreElements())
    {
        SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
        mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(
            pDescriptor->GetPage());
    }

    ViewShell& rViewShell = mrSlideSorter.GetViewShell();
    SdPage* pPage = rViewShell.getCurrentPage();
    if (pPage != nullptr)
        mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(
            pPage);
    else
    {
        // No current page.  This can only be when the slide sorter is
        // the main view shell.  Get current slide form frame view.
        const FrameView* pFrameView = rViewShell.GetFrameView();
        if (pFrameView != nullptr)
            mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(
                pFrameView->GetSelectedPage());
        else
        {
            // No frame view.  As a last resort use the first slide as
            // current slide.
            mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange(
                sal_Int32(0));
        }
    }

    mrSlideSorter.GetController().GetSlotManager()->NotifyEditModeChange();
}

Reference<container::XIndexAccess> SlideSorterModel::GetDocumentSlides() const
{
    ::osl::MutexGuard aGuard (maMutex);
    return mxSlides;
}

void SlideSorterModel::UpdatePageList()
{
    ::osl::MutexGuard aGuard (maMutex);

    Reference<container::XIndexAccess> xPages;

    // Get the list of pages according to the edit mode.
    Reference<frame::XController> xController (mrSlideSorter.GetXController());
    if (xController.is())
    {
        switch (meEditMode)
        {
            case EditMode::MasterPage:
            {
                Reference<drawing::XMasterPagesSupplier> xSupplier (
                    xController->getModel(), UNO_QUERY);
                if (xSupplier.is())
                {
                    xPages = xSupplier->getMasterPages();
                }
            }
            break;

            case EditMode::Page:
            {
                Reference<drawing::XDrawPagesSupplier> xSupplier (
                    xController->getModel(), UNO_QUERY);
                if (xSupplier.is())
                {
                    xPages = xSupplier->getDrawPages();
                }
            }
            break;

            default:
                // We should never get here.
                assert(false);
                break;
        }
    }

    mrSlideSorter.GetController().SetDocumentSlides(xPages);
}

void SlideSorterModel::AdaptSize()
{
    if (mxSlides.is())
        maPageDescriptors.resize(mxSlides->getCount());
    else
        maPageDescriptors.resize(0);
}

bool SlideSorterModel::IsReadOnly() const
{
    if (mrSlideSorter.GetViewShellBase() != nullptr
        && mrSlideSorter.GetViewShellBase()->GetDocShell())
        return mrSlideSorter.GetViewShellBase()->GetDocShell()->IsReadOnly();
    else
        return true;
}

void SlideSorterModel::SaveCurrentSelection()
{
    PageEnumeration aPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this));
    while (aPages.HasMoreElements())
    {
        SharedPageDescriptor pDescriptor (aPages.GetNextElement());
        pDescriptor->SetState(
            PageDescriptor::ST_WasSelected,
            pDescriptor->HasState(PageDescriptor::ST_Selected));
    }
}

vcl::Region SlideSorterModel::RestoreSelection()
{
    vcl::Region aRepaintRegion;
    PageEnumeration aPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this));
    while (aPages.HasMoreElements())
    {
        SharedPageDescriptor pDescriptor (aPages.GetNextElement());
        if (pDescriptor->SetState(
            PageDescriptor::ST_Selected,
            pDescriptor->HasState(PageDescriptor::ST_WasSelected)))
        {
            aRepaintRegion.Union(pDescriptor->GetBoundingBox());
        }
    }
    return aRepaintRegion;
}

bool SlideSorterModel::NotifyPageEvent (const SdrPage* pSdrPage)
{
    ::osl::MutexGuard aGuard (maMutex);

    SdPage* pPage = const_cast<SdPage*>(dynamic_cast<const SdPage*>(pSdrPage));
    if (pPage == nullptr)
        return false;

    // We are only interested in pages that are currently served by this
    // model.
    if (pPage->GetPageKind() != PageKind::Standard)
        return false;
    if (pPage->IsMasterPage() != (meEditMode==EditMode::MasterPage))
        return false;

    //NotifyPageEvent is called for add, remove, *and* change position so for
    //the change position case we must ensure we don't end up with the slide
    //duplicated in our list
    bool bSelected = DeleteSlide(pPage);
    if (pPage->IsInserted())
    {
        InsertSlide(pPage, bSelected);
    }
    CheckModel(*this);

    return true;
}

void SlideSorterModel::InsertSlide(SdPage* pPage, bool bMarkSelected)
{
    // Find the index at which to insert the given page.
    sal_uInt16 nCoreIndex (pPage->GetPageNum());
    sal_Int32 nIndex (FromCoreIndex(nCoreIndex));
    if (pPage != GetPage(nIndex))
        return;

    // Check that the pages in the document before and after the given page
    // are present in this model.
    if (nIndex>0)
        if (GetPage(nIndex-1) != GetPageDescriptor(nIndex-1)->GetPage())
            return;
    if (nIndex < static_cast<sal_Int32>(maPageDescriptors.size()) -1)
        if (GetPage(nIndex+1) != GetPageDescriptor(nIndex)->GetPage())
            return;

    auto iter = maPageDescriptors.begin() + nIndex;

    // Insert the given page at index nIndex
    iter = maPageDescriptors.insert(
        iter,
        std::make_shared<PageDescriptor>(
                Reference<drawing::XDrawPage>(mxSlides->getByIndex(nIndex),UNO_QUERY),
                pPage,
                nIndex));

    if (bMarkSelected)
        (*iter)->SetState(PageDescriptor::ST_Selected, true);

    // Update page indices.
    UpdateIndices(nIndex+1);
}

bool SlideSorterModel::DeleteSlide (const SdPage* pPage)
{
    sal_Int32 nIndex(0);

    // Caution, GetIndex() may be negative since it uses GetPageNumber()-1
    // for calculation, so do this only when page is inserted, else the
    // GetPageNumber() will be zero and thus GetIndex() == -1
    if(pPage->IsInserted())
    {
        nIndex = GetIndex(pPage);
    }
    else
    {
        // if not inserted, search for page
        for(; nIndex < static_cast<sal_Int32>(maPageDescriptors.size()); nIndex++)
        {
            if(maPageDescriptors[nIndex]->GetPage() == pPage)
            {
                break;
            }
        }
    }

    bool bMarkedSelected(false);

    if(nIndex >= 0 && o3tl::make_unsigned(nIndex) < maPageDescriptors.size())
    {
        if (maPageDescriptors[nIndex])
            if (maPageDescriptors[nIndex]->GetPage() != pPage)
                return false;

        auto iter = maPageDescriptors.begin() + nIndex;
        bMarkedSelected = (*iter)->HasState(PageDescriptor::ST_Selected);
        maPageDescriptors.erase(iter);
        UpdateIndices(nIndex);

        collectUIInformation(OUString::number(nIndex + 1), u"Delete_Slide_or_Page"_ustr);
    }
    return bMarkedSelected;
}

void SlideSorterModel::UpdateIndices (const sal_Int32 nFirstIndex)
{
    for (sal_Int32 nDescriptorIndex=0,nCount=maPageDescriptors.size();
         nDescriptorIndex<nCount;
         ++nDescriptorIndex)
    {
        SharedPageDescriptor& rpDescriptor (maPageDescriptors[nDescriptorIndex]);
        if (rpDescriptor)
        {
            if (nDescriptorIndex < nFirstIndex)
            {
                if (rpDescriptor->GetPageIndex()!=nDescriptorIndex)
                {
                    assert(rpDescriptor->GetPageIndex()==nDescriptorIndex);
                }
            }
            else
            {
                rpDescriptor->SetPageIndex(nDescriptorIndex);
            }
        }
    }
}

SdPage* SlideSorterModel::GetPage (const sal_Int32 nSdIndex) const
{
    SdDrawDocument* pModel = const_cast<SlideSorterModel*>(this)->GetDocument();
    if (pModel != nullptr)
    {
        if (meEditMode == EditMode::Page)
            return pModel->GetSdPage (static_cast<sal_uInt16>(nSdIndex), PageKind::Standard);
        else
            return pModel->GetMasterSdPage (static_cast<sal_uInt16>(nSdIndex), PageKind::Standard);
    }
    else
        return nullptr;
}

// end of namespace ::sd::slidesorter::model

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

Messung V0.5
C=94 H=95 G=94

¤ Dauer der Verarbeitung: 0.11 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.