Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/sw/source/uibase/docvw/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 18 kB image not shown  

Quelle  AnnotationWin.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 <config_wasm_strip.h>

#include <AnnotationWin.hxx>

#include <PostItMgr.hxx>

#include <strings.hrc>

#include <uiobject.hxx>

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

#include <svl/undo.hxx>
#include <svtools/svparser.hxx>
#include <unotools/localedatawrapper.hxx>
#include <unotools/syslocale.hxx>
#include <svl/languageoptions.hxx>
#include <osl/diagnose.h>

#include <editeng/eeitem.hxx>
#include <editeng/postitem.hxx>
#include <editeng/fhgtitem.hxx>
#include <editeng/langitem.hxx>
#include <editeng/editund2.hxx>

#include <editeng/editview.hxx>
#include <editeng/outliner.hxx>
#include <editeng/editeng.hxx>
#include <editeng/editobj.hxx>
#include <editeng/outlobj.hxx>

#include <comphelper/lok.hxx>
#include <comphelper/random.hxx>
#include <docufld.hxx>
#include <txtfld.hxx>
#include <ndtxt.hxx>
#include <view.hxx>
#include <viewopt.hxx>
#include <wrtsh.hxx>
#include <docsh.hxx>
#include <doc.hxx>
#include <IDocumentUndoRedo.hxx>
#if ENABLE_YRS
#include <IDocumentState.hxx>
#endif
#include <SwUndoField.hxx>
#include <edtwin.hxx>
#include "ShadowOverlayObject.hxx"
#include "AnchorOverlayObject.hxx"
#include "OverlayRanges.hxx"
#include "SidebarTxtControl.hxx"
#include "SidebarWinAcc.hxx"

#include <memory>

namespace{

void collectUIInformation( const OUString& aevent , const OUString& aID )
{
    EventDescription aDescription;
    aDescription.aID =  aID;
    aDescription.aParameters = {{"" ,  ""}};
    aDescription.aAction = aevent;
    aDescription.aParent = "MainWindow";
    aDescription.aKeyWord = "SwEditWinUIObject";
    UITestLogger::getInstance().logEvent(aDescription);
}

}

namespace SwPostItHelper {

void ImportHTML(Outliner& rOutliner, const OUString& rHtml)
{
    OString sHtmlContent(rHtml.toUtf8());
    SvMemoryStream aHTMLStream(const_cast<char*>(sHtmlContent.getStr()),
                               sHtmlContent.getLength(), StreamMode::READ);
    SvKeyValueIteratorRef xValues(new SvKeyValueIterator);
    // Insert newlines for divs, not normally done, so to keep things simple
    // only enable that for this case.
    xValues->Append(SvKeyValue("newline-on-div""true"));
    xValues->Append(SvKeyValue("content-type""text/html;charset=utf-8"));
    rOutliner.Read(aHTMLStream, "", EETextFormat::Html, xValues.get());
}

}

namespace sw::annotation {

// see AnnotationContents in sd for something similar
SwAnnotationWin::SwAnnotationWin( SwEditWin& rEditWin,
                                  SwPostItMgr& aMgr,
                                  SwAnnotationItem& rSidebarItem,
                                  SwFormatField* aField )
    : InterimItemWindow(&rEditWin, u"modules/swriter/ui/annotation.ui"_ustr, u"Annotation"_ustr)
    , mrMgr(aMgr)
    , mrView(rEditWin.GetView())
    , mnDeleteEventId(nullptr)
    , meSidebarPosition(sw::sidebarwindows::SidebarPosition::NONE)
    , mPageBorder(0)
    , mbAnchorRectChanged(false)
    , mbResolvedStateUpdated(false)
    , mbMouseOver(false)
    , mLayoutStatus(SwPostItHelper::INVISIBLE)
    , mbReadonly(false)
    , mbIsFollow(false)
    , mpSidebarItem(&rSidebarItem)
    , mpAnchorFrame(rSidebarItem.maLayoutInfo.mpAnchorFrame)
    , mpFormatField(aField)
    , mpField( static_cast<SwPostItField*>(aField->GetField()))
{
    set_id("Comment"+OUString::number(mpField->GetPostItId()));

    m_xContainer->connect_mouse_move(LINK(this, SwAnnotationWin, MouseMoveHdl));

    mpShadow = sidebarwindows::ShadowOverlayObject::CreateShadowOverlayObject( mrView );
    if ( mpShadow )
    {
        mpShadow->setVisible(false);
    }

#if !ENABLE_WASM_STRIP_ACCESSIBILITY
    if (rSidebarItem.maLayoutInfo.mpAnchorFrame)
    {
        mrMgr.ConnectSidebarWinToFrame( *(rSidebarItem.maLayoutInfo.mpAnchorFrame),
                                      mpSidebarItem->GetFormatField(),
                                      *this );
    }
#endif

    if (SupportsDoubleBuffering())
        // When double-buffering, allow parents to paint on our area. That's
        // necessary when parents paint the complete buffer.
        SetParentClipMode(ParentClipMode::NoClip);
}

SwAnnotationWin::~SwAnnotationWin()
{
    disposeOnce();
}

void SwAnnotationWin::dispose()
{
#if !ENABLE_WASM_STRIP_ACCESSIBILITY
    mrMgr.DisconnectSidebarWinFromFrame( *(mpSidebarItem->maLayoutInfo.mpAnchorFrame),
                                       *this );
#endif
    Disable();

    mxSidebarTextControlWin.reset();
    mxSidebarTextControl.reset();

    mxMetadataAuthor.reset();
    mxMetadataResolved.reset();
    mxMetadataDate.reset();
    mxVScrollbar.reset();

    mpAnchor.reset();
    mpShadow.reset();

    mpTextRangeOverlay.reset();

    mxMenuButton.reset();

    if (mnDeleteEventId)
        Application::RemoveUserEvent(mnDeleteEventId);

    mpOutliner.reset();
    mpOutlinerView.reset();

    InterimItemWindow::dispose();
}

void SwAnnotationWin::SetPostItText()
{
    //If the cursor was visible, then make it visible again after
    //changing text, e.g. fdo#33599
    vcl::Cursor *pCursor = GetOutlinerView()->GetEditView().GetCursor();
    bool bCursorVisible = pCursor && pCursor->IsVisible();

    //If the new text is the same as the old text, keep the same insertion
    //point .e.g. fdo#33599
    mpField = static_cast<SwPostItField*>(mpFormatField->GetField());
    OUString sNewText = mpField->GetPar2();
    bool bTextUnchanged = sNewText == mpOutliner->GetEditEngine().GetText();
    ESelection aOrigSelection(GetOutlinerView()->GetEditView().GetSelection());

    // get text from SwPostItField and insert into our textview
    mpOutliner->SetModifyHdl( Link<LinkParamNone*,void>() );
    mpOutliner->EnableUndo( false );
#if ENABLE_YRS
    auto const mode = mrView.GetDocShell()->GetDoc()->getIDocumentState().SetYrsMode(IYrsTransactionSupplier::Mode::Replay);
#endif
    if( mpField->GetTextObject() )
        mpOutliner->SetText( *mpField->GetTextObject() );
    else
    {
        mpOutliner->Clear();
        GetOutlinerView()->SetStyleSheet(SwResId(STR_POOLCOLL_COMMENT));
        GetOutlinerView()->InsertText(sNewText);
    }
#if ENABLE_YRS
    mrView.GetDocShell()->GetDoc()->getIDocumentState().SetYrsMode(mode);
#endif

    mpOutliner->ClearModifyFlag();
    mpOutliner->GetUndoManager().Clear();
    mpOutliner->EnableUndo( true );
    mpOutliner->SetModifyHdl( LINK( this, SwAnnotationWin, ModifyHdl ) );
    if (bTextUnchanged)
        GetOutlinerView()->GetEditView().SetSelection(aOrigSelection);
    if (bCursorVisible)
        GetOutlinerView()->ShowCursor();
    Invalidate();
}

void SwAnnotationWin::GeneratePostItName()
{
    if (mpField && mpField->GetName().isEmpty())
    {
        mpField->SetName(sw::mark::MarkBase::GenerateNewName(u"__Annotation__"));
    }
}

void SwAnnotationWin::SetResolved(bool resolved)
{
    bool oldState = IsResolved();
    static_cast<SwPostItField*>(mpFormatField->GetField())->SetResolved(resolved);
    if (SwWrtShell* pWrtShell = mrView.GetWrtShellPtr())
    {
        const SwViewOption* pVOpt = pWrtShell->GetViewOptions();
        mpSidebarItem->mbShow = !IsResolved() || (pVOpt->IsResolvedPostIts());
    }

    mpTextRangeOverlay.reset();

    if(IsResolved())
        mxMetadataResolved->show();
    else
        mxMetadataResolved->hide();

    if(IsResolved() != oldState)
        mbResolvedStateUpdated = true;
    UpdateData();
    Invalidate();
    collectUIInformation(u"SETRESOLVED"_ustr,get_id());
#if ENABLE_YRS
    mrView.GetDocShell()->GetDoc()->getIDocumentState().YrsNotifySetResolved(
        GetOutlinerView()->GetEditView().GetYrsCommentId(),
        *static_cast<SwPostItField const*>(mpFormatField->GetField()));
#endif
}

void SwAnnotationWin::ToggleResolved()
{
    SetResolved(!IsResolved());
}

void SwAnnotationWin::ToggleResolvedForThread()
{
    auto pTop = GetTopReplyNote();
    pTop->ToggleResolved();
    mrMgr.UpdateResolvedStatus(pTop);
    mrMgr.LayoutPostIts();
}

sal_uInt32 SwAnnotationWin::GetParaId()
{
    auto pField = static_cast<SwPostItField*>(mpFormatField->GetField());
    auto nParaId = pField->GetParaId();
    if (nParaId == 0)
    {
        // The parent annotation does not have a paraId. This happens when the annotation was just
        // created, and not imported. paraIds are regenerated upon export, thus this new paraId
        // is only generated so that children annotations can refer to it
        nParaId = CreateUniqueParaId();
        pField->SetParaId(nParaId);
    }
    return nParaId;
}

sal_uInt32 SwAnnotationWin::CreateUniqueParaId()
{
    return comphelper::rng::uniform_uint_distribution(0, std::numeric_limits<sal_uInt32>::max());
}

void SwAnnotationWin::DeleteThread()
{
    // Go to the top and delete each comment one by one
    SwAnnotationWin* topNote = GetTopReplyNote();
    for (SwAnnotationWin* current = topNote;;)
    {
        SwAnnotationWin* next = mrMgr.GetNextPostIt(KEY_PAGEDOWN, current);
        current->mnDeleteEventId = Application::PostUserEvent( LINK( current, SwAnnotationWin, DeleteHdl), nullptr, true );
        if (!next || next->GetTopReplyNote() != topNote)
            return;
        current = next;
    }
}

bool SwAnnotationWin::IsResolved() const
{
    return static_cast<SwPostItField*>(mpFormatField->GetField())->GetResolved();
}

bool SwAnnotationWin::IsThreadResolved()
{
    /// First Get the top note
    // then iterate downwards checking resolved status
    SwAnnotationWin* topNote = GetTopReplyNote();
    for (SwAnnotationWin* current = topNote;;)
    {
        if (!current->IsResolved())
            return false;
        current = mrMgr.GetNextPostIt(KEY_PAGEDOWN, current);
        if (!current || current->GetTopReplyNote() != topNote)
            return true;
    }
}

bool SwAnnotationWin::IsRootNote() const
{
    return static_cast<SwPostItField*>(mpFormatField->GetField())->GetParentPostItId() == 0;
}

void SwAnnotationWin::SetAsRoot()
{
    if (!IsRootNote())
    {
        SwPostItField* pPostIt = static_cast<SwPostItField*>(mpFormatField->GetField());
        pPostIt->SetParentId(0);
        pPostIt->SetParentPostItId(0);
        pPostIt->SetParentName(SwMarkName());
        mrMgr.MoveSubthreadToRoot(this);
        mpFormatField->Broadcast(SwFormatFieldHint(nullptr, SwFormatFieldHintWhich::CHANGED));
    }
}

void SwAnnotationWin::UpdateData()
{
    if ( mpOutliner->IsModified() || mbResolvedStateUpdated )
    {
        IDocumentUndoRedo & rUndoRedo(
            mrView.GetDocShell()->GetDoc()->GetIDocumentUndoRedo());
        std::unique_ptr<SwField> pOldField;
        if (rUndoRedo.DoesUndo())
        {
            pOldField = mpField->Copy();
        }
        mpField->SetPar2(mpOutliner->GetEditEngine().GetText());
        mpField->SetTextObject(mpOutliner->CreateParaObject());
        if (rUndoRedo.DoesUndo())
        {
            SwTextField *const pTextField = mpFormatField->GetTextField();
            SwPosition aPosition( pTextField->GetTextNode(), pTextField->GetStart() );
            rUndoRedo.AppendUndo(
                std::make_unique<SwUndoFieldFromDoc>(aPosition, *pOldField, *mpField, true));
        }
        // so we get a new layout of notes (anchor position is still the same and we would otherwise not get one)
        mrMgr.SetLayout();
        // #i98686# if we have several views, all notes should update their text
        if(mbResolvedStateUpdated)
            mpFormatField->Broadcast(SwFormatFieldHint( nullptr, SwFormatFieldHintWhich::RESOLVED));
        else
            mpFormatField->Broadcast(SwFormatFieldHint( nullptr, SwFormatFieldHintWhich::CHANGED));
        mrView.GetDocShell()->SetModified();
    }
    mpOutliner->ClearModifyFlag();
    mpOutliner->GetUndoManager().Clear();
    mbResolvedStateUpdated = false;
}

void SwAnnotationWin::Delete()
{
    collectUIInformation(u"DELETE"_ustr,get_id());
    SwWrtShell* pWrtShell = mrView.GetWrtShellPtr();
    if (!(pWrtShell && pWrtShell->GotoField(*mpFormatField)))
        return;

    if ( mrMgr.GetActiveSidebarWin() == this)
    {
        mrMgr.SetActiveSidebarWin(nullptr);
        // if the note is empty, the previous line will send a delete event, but we are already there
        if (mnDeleteEventId)
        {
            Application::RemoveUserEvent(mnDeleteEventId);
            mnDeleteEventId = nullptr;
        }
    }
    // we delete the field directly, the Mgr cleans up the PostIt by listening
    GrabFocusToDocument();
    pWrtShell->ClearMark();
    auto restoreGuard = mrMgr.ConfigureForCommentDelete();
    pWrtShell->DelRight();
}

void SwAnnotationWin::GotoPos()
{
    mrView.GetDocShell()->GetWrtShell()->GotoField(*mpFormatField);
}

sal_uInt32 SwAnnotationWin::MoveCaret()
{
    // if this is an answer, do not skip over all following ones, but insert directly behind the current one
    // but when just leaving a note, skip all following ones as well to continue typing
    return mrMgr.IsAnswer()
           ? 1
           : 1 + CountFollowing();
}

// counts how many SwPostItField we have right after the current one
sal_uInt32 SwAnnotationWin::CountFollowing()
{
    SwTextField* pTextField = mpFormatField->GetTextField();
    SwPosition aPosition( pTextField->GetTextNode(), pTextField->GetStart() );

    for (sal_Int32 n = 1;; ++n)
    {
        SwTextAttr * pTextAttr = pTextField->GetTextNode().GetTextAttrForCharAt(
                                            aPosition.GetContentIndex() + n,
                                            RES_TXTATR_ANNOTATION );
        if (!pTextAttr)
            return n - 1;
        const SwField* pField = pTextAttr->GetFormatField().GetField();
        if (!pField || pField->Which() != SwFieldIds::Postit)
            return n - 1;
    }
}

void SwAnnotationWin::InitAnswer(OutlinerParaObject const & rText)
{
    // If tiled annotations is off in lok case, skip adding additional reply text.
    if (comphelper::LibreOfficeKit::isActive() && !comphelper::LibreOfficeKit::isTiledAnnotations())
        return;

    //collect our old meta data
    SwAnnotationWin* pWin = mrMgr.GetNextPostIt(KEY_PAGEUP, this);
    if (!pWin)
        return;

    const SvtSysLocale aSysLocale;
    const LocaleDataWrapper& rLocalData = aSysLocale.GetLocaleData();
    SwRewriter aRewriter;
    aRewriter.AddRule(UndoArg1, pWin->GetAuthor());
    const OUString aText = aRewriter.Apply(SwResId(STR_REPLY))
            + " (" + rLocalData.getDate( pWin->GetDate())
            + ", " + rLocalData.getTime( pWin->GetTime(), false)
            + "): \"";
    GetOutlinerView()->InsertText(aText);

    // insert old, selected text or "..."
    // TODO: iterate over all paragraphs, not only first one to find out if it is empty
    if (rText.GetTextObject().HasText(0))
        GetOutlinerView()->GetEditView().InsertText(rText.GetTextObject());
    else
        GetOutlinerView()->InsertText(u"..."_ustr);
    GetOutlinerView()->InsertText(u"\"\n"_ustr);

    GetOutlinerView()->SetSelection(ESelection::All());
    SfxItemSet aAnswerSet( mrView.GetDocShell()->GetPool() );
    aAnswerSet.Put(SvxFontHeightItem(200,80,EE_CHAR_FONTHEIGHT));
    aAnswerSet.Put(SvxPostureItem(ITALIC_NORMAL,EE_CHAR_ITALIC));
    GetOutlinerView()->SetAttribs(aAnswerSet);
    GetOutlinerView()->SetSelection(ESelection::AtEnd());

    //remove all attributes and reset our standard ones
    GetOutlinerView()->GetEditView().RemoveAttribsKeepLanguages(true);
    // let's insert an undo step so the initial text can be easily deleted
    // but do not use UpdateData() directly, would set modified state again and reentrance into Mgr
    mpOutliner->SetModifyHdl( Link<LinkParamNone*,void>() );
    IDocumentUndoRedo & rUndoRedo(
        mrView.GetDocShell()->GetDoc()->GetIDocumentUndoRedo());
    std::unique_ptr<SwField> pOldField;
    if (rUndoRedo.DoesUndo())
    {
        pOldField = mpField->Copy();
    }
    mpField->SetPar2(mpOutliner->GetEditEngine().GetText());
    mpField->SetTextObject(mpOutliner->CreateParaObject());
    if (rUndoRedo.DoesUndo())
    {
        SwTextField *const pTextField = mpFormatField->GetTextField();
        SwPosition aPosition( pTextField->GetTextNode(), pTextField->GetStart() );
        rUndoRedo.AppendUndo(
            std::make_unique<SwUndoFieldFromDoc>(aPosition, *pOldField, *mpField, true));
    }
    mpOutliner->SetModifyHdl( LINK( this, SwAnnotationWin, ModifyHdl ) );
    mpOutliner->ClearModifyFlag();
    mpOutliner->GetUndoManager().Clear();
}

void SwAnnotationWin::UpdateText(const OUString& aText)
{
    mpOutliner->Clear();
    GetOutlinerView()->InsertText(aText);
    UpdateData();
}

void SwAnnotationWin::UpdateHTML(const OUString& rHtml)
{
    mpOutliner->Clear();
    SwPostItHelper::ImportHTML(*mpOutliner, rHtml);
    UpdateData();
}

OString SwAnnotationWin::GetSimpleHtml() const
{
    return GetOutlinerView()->GetEditView().GetSimpleHtml();
}

bool SwAnnotationWin::IsReadOnly() const
{
    return mbReadonly;
}

bool SwAnnotationWin::IsReadOnlyOrProtected() const
{
    return IsReadOnly() ||
           GetLayoutStatus() == SwPostItHelper::DELETED ||
           ( mpFormatField && mpFormatField->IsProtect() );
}

OUString SwAnnotationWin::GetAuthor() const
{
    return mpField->GetPar1();
}

Date SwAnnotationWin::GetDate() const
{
    return mpField->GetDate();
}

tools::Time SwAnnotationWin::GetTime() const
{
    return mpField->GetTime();
}

FactoryFunction SwAnnotationWin::GetUITestFactory() const
{
    return CommentUIObject::create;
}

// end of namespace sw::annotation

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

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

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© 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.