/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star; // Based on the request, changes to the specific layouts will be made, to // fit to the format static bool lcl_SetNewFlyPos( const SwNode& rNode, SwFormatAnchor& rAnchor, const Point& rPt ) { bool bRet = false; const SwStartNode* pStNode = rNode.FindFlyStartNode(); if( pStNode ) { SwPosition aPos( *pStNode ); rAnchor.SetAnchor( &aPos ); bRet = true; } else { const SwContentNode *pCntNd = rNode.GetContentNode(); std::pair const tmp(rPt, false); const SwContentFrame* pCFrame = pCntNd ? pCntNd->getLayoutFrame( pCntNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, &tmp) : nullptr; const SwPageFrame *pPg = pCFrame ? pCFrame->FindPageFrame() : nullptr; rAnchor.SetPageNum( pPg ? pPg->GetPhyPageNum() : 1 ); rAnchor.SetType( RndStdIds::FLY_AT_PAGE ); } return bRet; } static bool lcl_FindAnchorPos( SwDoc& rDoc, const Point& rPt, const SwFrame& rFrame, SfxItemSet& rSet ) { bool bRet = true; SwFormatAnchor aNewAnch( rSet.Get( RES_ANCHOR ) ); RndStdIds nNew = aNewAnch.GetAnchorId(); const SwFrame *pNewAnch; //determine new anchor Point aTmpPnt( rPt ); switch( nNew ) { case RndStdIds::FLY_AS_CHAR: // also include this? case RndStdIds::FLY_AT_PARA: case RndStdIds::FLY_AT_CHAR: // LAYER_IMPL { // starting from the upper-left corner of the Fly, // search nearest ContentFrame const SwFrame* pFrame = rFrame.IsFlyFrame() ? static_cast(rFrame).GetAnchorFrame() : &rFrame; pNewAnch = ::FindAnchor( pFrame, aTmpPnt ); if( pNewAnch->IsProtected() ) { bRet = false; break; } SwPosition aPos( pNewAnch->IsTextFrame() ? *static_cast(pNewAnch)->GetTextNodeForParaProps() : *static_cast(pNewAnch)->GetNode() ); if ((RndStdIds::FLY_AT_CHAR == nNew) || (RndStdIds::FLY_AS_CHAR == nNew)) { // textnode should be found, as only in those // a content bound frame can be anchored SwCursorMoveState aState( CursorMoveState::SetOnlyText ); aTmpPnt.setX(aTmpPnt.getX() - 1); // do not land in the fly! if( !pNewAnch->GetModelPositionForViewPoint( &aPos, aTmpPnt, &aState ) ) { assert(pNewAnch->IsTextFrame()); // because AT_CHAR/AS_CHAR SwTextFrame const*const pTextFrame( static_cast(pNewAnch)); if( pNewAnch->getFrameArea().Bottom() < aTmpPnt.Y() ) { aPos = pTextFrame->MapViewToModelPos(TextFrameIndex(0)); } else { aPos = pTextFrame->MapViewToModelPos( TextFrameIndex(pTextFrame->GetText().getLength())); } } else { if ( SwCursorShell::PosInsideInputField( aPos ) ) { aPos.nContent = SwCursorShell::StartOfInputFieldAtPos( aPos ); } } } aNewAnch.SetAnchor( &aPos ); } break; case RndStdIds::FLY_AT_FLY: // LAYER_IMPL { // starting from the upper-left corner of the Fly // search nearest SwFlyFrame SwCursorMoveState aState( CursorMoveState::SetOnlyText ); SwPosition aPos( rDoc.GetNodes() ); aTmpPnt.setX(aTmpPnt.getX() - 1); // do not land in the fly! rDoc.getIDocumentLayoutAccess().GetCurrentLayout()->GetModelPositionForViewPoint( &aPos, aTmpPnt, &aState ); pNewAnch = ::FindAnchor( aPos.nNode.GetNode().GetContentNode()->getLayoutFrame(rFrame.getRootFrame(), nullptr, nullptr), aTmpPnt )->FindFlyFrame(); if( pNewAnch && &rFrame != pNewAnch && !pNewAnch->IsProtected() ) { aPos.nNode = *static_cast(pNewAnch)->GetFormat()->GetContent(). GetContentIdx(); aNewAnch.SetAnchor( &aPos ); break; } } nNew = RndStdIds::FLY_AT_PAGE; aNewAnch.SetType( nNew ); [[fallthrough]]; case RndStdIds::FLY_AT_PAGE: pNewAnch = rFrame.FindPageFrame(); aNewAnch.SetPageNum( pNewAnch->GetPhyPageNum() ); break; default: OSL_ENSURE( false, "Wrong Id for new anchor." ); } rSet.Put( aNewAnch ); return bRet; } //! also used in unoframe.cxx bool sw_ChkAndSetNewAnchor( const SwFlyFrame& rFly, SfxItemSet& rSet ) { const SwFrameFormat& rFormat = *rFly.GetFormat(); const SwFormatAnchor &rOldAnch = rFormat.GetAnchor(); const RndStdIds nOld = rOldAnch.GetAnchorId(); RndStdIds nNew = rSet.Get( RES_ANCHOR ).GetAnchorId(); if( nOld == nNew ) return false; SwDoc* pDoc = const_cast(rFormat.GetDoc()); #if OSL_DEBUG_LEVEL > 0 OSL_ENSURE( !(nNew == RndStdIds::FLY_AT_PAGE && (RndStdIds::FLY_AT_PARA==nOld || RndStdIds::FLY_AT_CHAR==nOld || RndStdIds::FLY_AS_CHAR==nOld ) && pDoc->IsInHeaderFooter( rOldAnch.GetContentAnchor()->nNode )), "forbidden anchor change in Head/Foot." ); #endif return ::lcl_FindAnchorPos( *pDoc, rFly.getFrameArea().Pos(), rFly, rSet ); } void SwFEShell::SelectFlyFrame( SwFlyFrame& rFrame ) { CurrShell aCurr( this ); // The frame is new, thus select it. // !! Always select the frame, if it's not selected. // - it could be a new "old" one because the anchor was changed // - "old" frames have had to be selected previously otherwise they could // not have been changed // The frames should not be selected by the document position, because // it should have been selected! SwViewShellImp *pImpl = Imp(); if( !GetWin() ) return; OSL_ENSURE( rFrame.IsFlyFrame(), "SelectFlyFrame wants a Fly" ); // nothing to be done if the Fly already was selected if (GetSelectedFlyFrame() == &rFrame) return; // assure the anchor is drawn if( rFrame.IsFlyInContentFrame() && rFrame.GetAnchorFrame() ) rFrame.GetAnchorFrame()->SetCompletePaint(); if( pImpl->GetDrawView()->AreObjectsMarked() ) pImpl->GetDrawView()->UnmarkAll(); pImpl->GetDrawView()->MarkObj( rFrame.GetVirtDrawObj(), pImpl->GetPageView() ); rFrame.SelectionHasChanged(this); KillPams(); ClearMark(); SelFlyGrabCursor(); } // Get selected fly SwFlyFrame* SwFEShell::GetSelectedFlyFrame() const { if ( Imp()->HasDrawView() ) { // A Fly is only accessible if it is selected const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList(); if( rMrkList.GetMarkCount() != 1 ) return nullptr; SdrObject *pO = rMrkList.GetMark( 0 )->GetMarkedSdrObj(); SwVirtFlyDrawObj *pFlyObj = dynamic_cast(pO); return pFlyObj ? pFlyObj->GetFlyFrame() : nullptr; } return nullptr; } // Get current fly in which the cursor is positioned SwFlyFrame* SwFEShell::GetCurrFlyFrame(const bool bCalcFrame) const { SwContentFrame *pContent = GetCurrFrame(bCalcFrame); return pContent ? pContent->FindFlyFrame() : nullptr; } // Get selected fly, but if none Get current fly in which the cursor is positioned SwFlyFrame* SwFEShell::GetSelectedOrCurrFlyFrame() const { SwFlyFrame *pFly = GetSelectedFlyFrame(); if (pFly) return pFly; return GetCurrFlyFrame(); } // Returns non-null pointer, if the current Fly could be anchored to another one (so it is inside) const SwFrameFormat* SwFEShell::IsFlyInFly() { CurrShell aCurr( this ); if ( !Imp()->HasDrawView() ) return nullptr; const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList(); if ( !rMrkList.GetMarkCount() ) { SwFlyFrame *pFly = GetCurrFlyFrame(false); if (!pFly) return nullptr; return pFly->GetFormat(); } else if ( rMrkList.GetMarkCount() != 1 || !GetUserCall(rMrkList.GetMark( 0 )->GetMarkedSdrObj()) ) return nullptr; SdrObject *pObj = rMrkList.GetMark( 0 )->GetMarkedSdrObj(); SwFrameFormat *pFormat = FindFrameFormat( pObj ); if( pFormat && RndStdIds::FLY_AT_FLY == pFormat->GetAnchor().GetAnchorId() ) { const SwFrame* pFly; if (SwVirtFlyDrawObj* pFlyObj = dynamic_cast(pObj)) { pFly = pFlyObj->GetFlyFrame()->GetAnchorFrame(); } else { pFly = static_cast(GetUserCall(pObj))->GetAnchorFrame(pObj); } OSL_ENSURE( pFly, "IsFlyInFly: Where's my anchor?" ); OSL_ENSURE( pFly->IsFlyFrame(), "IsFlyInFly: Funny anchor!" ); return static_cast(pFly)->GetFormat(); } Point aTmpPos = pObj->GetCurrentBoundRect().TopLeft(); SwFrame *pTextFrame; { SwCursorMoveState aState( CursorMoveState::SetOnlyText ); SwNodeIndex aSwNodeIndex( GetDoc()->GetNodes() ); SwPosition aPos( aSwNodeIndex ); Point aPoint( aTmpPos ); aPoint.setX(aPoint.getX() - 1); //do not land in the fly!! GetLayout()->GetModelPositionForViewPoint( &aPos, aPoint, &aState ); // determine text frame by left-top-corner of object SwContentNode *pNd = aPos.nNode.GetNode().GetContentNode(); std::pair const tmp(aTmpPos, false); pTextFrame = pNd ? pNd->getLayoutFrame(GetLayout(), nullptr, &tmp) : nullptr; } const SwFrame *pTmp = pTextFrame ? ::FindAnchor(pTextFrame, aTmpPos) : nullptr; const SwFlyFrame *pFly = pTmp ? pTmp->FindFlyFrame() : nullptr; if( pFly ) return pFly->GetFormat(); return nullptr; } void SwFEShell::SetFlyPos( const Point& rAbsPos ) { CurrShell aCurr( this ); // Determine reference point in document coordinates SwFlyFrame *pFly = GetCurrFlyFrame(false); if (!pFly) return; //SwSaveHdl aSaveX( Imp() ); // Set an anchor starting from the absolute position for paragraph bound Flys // Anchor and new RelPos will be calculated and set by the Fly if ( pFly->IsFlyAtContentFrame() ) { if(pFly->IsFlyFreeFrame() && static_cast< SwFlyFreeFrame* >(pFly)->isTransformableSwFrame()) { // RotateFlyFrame3: When we have a change and are in transformed state (e.g. rotation used), // we need to correct the absolute position (rAbsPos) which was created in // transformed coordinates to untransformed state TransformableSwFrame* pTransformableSwFrame(static_cast(pFly)->getTransformableSwFrame()); const SwRect aUntransformedFrameArea(pTransformableSwFrame->getUntransformedFrameArea()); const Point aNewAbsPos( rAbsPos.X() + aUntransformedFrameArea.Left() - pFly->getFrameArea().Left(), rAbsPos.Y() + aUntransformedFrameArea.Top() - pFly->getFrameArea().Top()); static_cast(pFly)->SetAbsPos(aNewAbsPos); } else { static_cast(pFly)->SetAbsPos( rAbsPos ); } } else { const SwFrame *pAnch = pFly->GetAnchorFrame(); Point aOrient( pAnch->getFrameArea().Pos() ); if ( pFly->IsFlyInContentFrame() ) aOrient.setX(rAbsPos.getX()); // calculate RelPos. aOrient.setX(rAbsPos.getX() - aOrient.getX()); aOrient.setY(rAbsPos.getY() - aOrient.getY()); pFly->ChgRelPos( aOrient ); } CallChgLnk(); // call the AttrChangeNotify on the UI-side. } Point SwFEShell::FindAnchorPos( const Point& rAbsPos, bool bMoveIt ) { Point aRet; CurrShell aCurr( this ); if ( !Imp()->HasDrawView() ) return aRet; const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList(); if ( rMrkList.GetMarkCount() != 1 || !GetUserCall(rMrkList.GetMark( 0 )->GetMarkedSdrObj()) ) return aRet; SdrObject* pObj = rMrkList.GetMark( 0 )->GetMarkedSdrObj(); // #i28701# SwAnchoredObject* pAnchoredObj = ::GetUserCall( pObj )->GetAnchoredObj( pObj ); SwFrameFormat& rFormat = pAnchoredObj->GetFrameFormat(); const RndStdIds nAnchorId = rFormat.GetAnchor().GetAnchorId(); if ( RndStdIds::FLY_AS_CHAR == nAnchorId ) return aRet; bool bFlyFrame = dynamic_cast(pObj) != nullptr; bool bTextBox = false; if (rFormat.Which() == RES_DRAWFRMFMT) { bTextBox = SwTextBoxHelper::isTextBox(&rFormat, RES_DRAWFRMFMT, pObj); } SwFlyFrame* pFly = nullptr; const SwFrame* pFooterOrHeader = nullptr; if( bFlyFrame ) { // Calculate reference point in document coordinates SwContentFrame *pContent = GetCurrFrame( false ); if( !pContent ) return aRet; pFly = pContent->FindFlyFrame(); if ( !pFly ) return aRet; const SwFrame* pOldAnch = pFly->GetAnchorFrame(); if( !pOldAnch ) return aRet; if ( RndStdIds::FLY_AT_PAGE != nAnchorId ) { pFooterOrHeader = pContent->FindFooterOrHeader(); } } else if (bTextBox) { auto pFlyFormat = dynamic_cast(SwTextBoxHelper::getOtherTextBoxFormat( &rFormat, RES_DRAWFRMFMT, pObj ? pObj : rFormat.FindRealSdrObject())); if (pFlyFormat) { pFly = pFlyFormat->GetFrame(); } } // set also for drawing // objects, but not for control objects. // Necessary for moving 'anchor symbol' at the user interface inside header/footer. else if ( !::CheckControlLayer( pObj ) ) { SwContentFrame *pContent = GetCurrFrame( false ); if( !pContent ) return aRet; pFooterOrHeader = pContent->FindFooterOrHeader(); } // Search nearest SwFlyFrame starting from the upper-left corner // of the fly SwContentFrame *pTextFrame = nullptr; { SwCursorMoveState aState( CursorMoveState::SetOnlyText ); SwPosition aPos( GetDoc()->GetNodes().GetEndOfExtras() ); Point aTmpPnt( rAbsPos ); GetLayout()->GetModelPositionForViewPoint( &aPos, aTmpPnt, &aState ); if (aPos.nNode != GetDoc()->GetNodes().GetEndOfExtras().GetIndex() && (nAnchorId != RndStdIds::FLY_AT_CHAR || !PosInsideInputField(aPos))) { SwContentNode* pCNode = aPos.nNode.GetNode().GetContentNode(); assert(pCNode); pTextFrame = pCNode->getLayoutFrame(GetLayout(), &aPos, nullptr); } } const SwFrame *pNewAnch = nullptr; if( pTextFrame != nullptr ) { if ( RndStdIds::FLY_AT_PAGE == nAnchorId ) { pNewAnch = pTextFrame->FindPageFrame(); } else { pNewAnch = ::FindAnchor( pTextFrame, rAbsPos ); if( RndStdIds::FLY_AT_FLY == nAnchorId ) // LAYER_IMPL { pNewAnch = pNewAnch->FindFlyFrame(); } } } if( pNewAnch && !pNewAnch->IsProtected() ) { const SwFlyFrame* pCheck = (bFlyFrame || bTextBox) ? pNewAnch->FindFlyFrame() : nullptr; // If we land inside the frame, make sure // that the frame does not land inside its own content while( pCheck ) { if( pCheck == pFly ) break; const SwFrame *pTmp = pCheck->GetAnchorFrame(); pCheck = pTmp ? pTmp->FindFlyFrame() : nullptr; } // Do not switch from header/footer to another area, // do not switch to a header/footer if( !pCheck && pFooterOrHeader == pNewAnch->FindFooterOrHeader() ) { aRet = pNewAnch->GetFrameAnchorPos( ::HasWrap( pObj ) ); if ( bMoveIt || (nAnchorId == RndStdIds::FLY_AT_CHAR) ) { SwFormatAnchor aAnch( rFormat.GetAnchor() ); switch ( nAnchorId ) { case RndStdIds::FLY_AT_PARA: { SwPosition pos = *aAnch.GetContentAnchor(); pos.nNode = pTextFrame->IsTextFrame() ? *static_cast(pTextFrame)->GetTextNodeForParaProps() : *static_cast(pTextFrame)->GetNode(); pos.nContent.Assign(nullptr,0); aAnch.SetAnchor( &pos ); break; } case RndStdIds::FLY_AT_PAGE: { aAnch.SetPageNum( static_cast(pNewAnch)-> GetPhyPageNum() ); break; } case RndStdIds::FLY_AT_FLY: { SwPosition aPos( *static_cast(pNewAnch)->GetFormat()-> GetContent().GetContentIdx() ); aAnch.SetAnchor( &aPos ); break; } case RndStdIds::FLY_AT_CHAR: { SwPosition pos = *aAnch.GetContentAnchor(); Point aTmpPnt( rAbsPos ); if( pTextFrame->GetModelPositionForViewPoint( &pos, aTmpPnt ) ) { SwRect aTmpRect; pTextFrame->GetCharRect( aTmpRect, pos ); aRet = aTmpRect.Pos(); } else { pos = static_cast(pTextFrame)->MapViewToModelPos(TextFrameIndex(0)); } aAnch.SetAnchor( &pos ); break; } default: break; } if( bMoveIt ) { StartAllAction(); // --> handle change of anchor node: // if count of the anchor frame also change, the fly frames have to be // re-created. Thus, delete all fly frames except the before the // anchor attribute is change and re-create them afterwards. { std::unique_ptr pHandleAnchorNodeChg; SwFlyFrameFormat* pFlyFrameFormat( dynamic_cast(&rFormat) ); if ( pFlyFrameFormat ) { pHandleAnchorNodeChg.reset( new SwHandleAnchorNodeChg( *pFlyFrameFormat, aAnch )); } rFormat.GetDoc()->SetAttr( aAnch, rFormat ); if (SwTextBoxHelper::getOtherTextBoxFormat(&rFormat, RES_DRAWFRMFMT, pObj ? pObj : rFormat.FindRealSdrObject())) { if (pObj->getChildrenOfSdrObject()) { for (size_t i = 0; i < pObj->getChildrenOfSdrObject()->GetObjCount(); ++i) SwTextBoxHelper::changeAnchor( &rFormat, pObj->getChildrenOfSdrObject()->GetObj(i)); } else SwTextBoxHelper::syncFlyFrameAttr( rFormat, rFormat.GetAttrSet(), pObj ? pObj : rFormat.FindRealSdrObject()); } } // #i28701# - no call of method // for to-character anchored // Writer fly frame needed. This method call can cause a // format of the anchor frame, which is no longer intended. // Instead clear the anchor character rectangle and // the top of line values for all to-character anchored objects. pAnchoredObj->ClearCharRectAndTopOfLine(); EndAllAction(); } } SwRect aTmpRect( aRet, rAbsPos ); if( aTmpRect.HasArea() ) MakeVisible( aTmpRect ); #if OSL_DEBUG_LEVEL > 0 //TODO: That doesn't seem to be intended if( COL_TRANSPARENT != GetOut()->GetLineColor() ) { OSL_FAIL( "Hey, Joe: Where's my Null Pen?" ); GetOut()->SetLineColor( COL_TRANSPARENT ); } #endif } } return aRet; } const SwFrameFormat *SwFEShell::NewFlyFrame( const SfxItemSet& rSet, bool bAnchValid, SwFrameFormat *pParent ) { CurrShell aCurr( this ); StartAllAction(); SwPaM* pCursor = GetCursor(); const Point aPt( GetCursorDocPos() ); SwSelBoxes aBoxes; bool bMoveContent = true; if( IsTableMode() ) { GetTableSel( *this, aBoxes ); if( !aBoxes.empty() ) { // Cursor should be removed from the removal area. // Always put it after/on the table; via the // document position they will be set to the old // position ParkCursor( SwNodeIndex( *aBoxes[0]->GetSttNd() )); // #i127787# pCurrentCursor will be deleted in ParkCursor, // we better get the current pCurrentCursor instead of working with the // deleted one: pCursor = GetCursor(); } else bMoveContent = false; } else if( !pCursor->HasMark() && !pCursor->IsMultiSelection() ) bMoveContent = false; const SwPosition& rPos = *pCursor->Start(); SwFormatAnchor& rAnch = const_cast(rSet.Get( RES_ANCHOR )); RndStdIds eRndId = rAnch.GetAnchorId(); switch( eRndId ) { case RndStdIds::FLY_AT_PAGE: if( !rAnch.GetPageNum() ) //HotFix: Bug in UpdateByExample rAnch.SetPageNum( 1 ); break; case RndStdIds::FLY_AT_FLY: case RndStdIds::FLY_AT_PARA: case RndStdIds::FLY_AT_CHAR: case RndStdIds::FLY_AS_CHAR: if( !bAnchValid ) { if( RndStdIds::FLY_AT_FLY != eRndId ) { rAnch.SetAnchor( &rPos ); } else if( lcl_SetNewFlyPos( rPos.nNode.GetNode(), rAnch, aPt ) ) { eRndId = RndStdIds::FLY_AT_PAGE; } } break; default: OSL_ENSURE( false, "What is the purpose of this Fly?" ); break; } SwFlyFrameFormat *pRet; if( bMoveContent ) { GetDoc()->GetIDocumentUndoRedo().StartUndo( SwUndoId::INSLAYFMT, nullptr ); std::unique_ptr pOldAnchor; bool bHOriChgd = false, bVOriChgd = false; std::shared_ptr aOldV; std::shared_ptr aOldH; if ( RndStdIds::FLY_AT_PAGE != eRndId ) { // First as with page link. Paragraph/character link on if // everything was shifted. Then the position is valid! // JP 13.05.98: if necessary also convert the horizontal/vertical // orientation, to prevent correction during re-anchoring pOldAnchor.reset(new SwFormatAnchor( rAnch )); const_cast(rSet).Put( SwFormatAnchor( RndStdIds::FLY_AT_PAGE, 1 ) ); const SwFormatHoriOrient* pHoriOrientItem; if( (pHoriOrientItem = rSet.GetItemIfSet( RES_HORI_ORIENT, false )) && text::HoriOrientation::NONE == pHoriOrientItem->GetHoriOrient() ) { bHOriChgd = true; aOldH.reset(pHoriOrientItem->Clone()); const_cast(rSet).Put( SwFormatHoriOrient( 0, text::HoriOrientation::LEFT ) ); } const SwFormatVertOrient* pVertOrientItem; if( (pVertOrientItem = rSet.GetItemIfSet( RES_VERT_ORIENT, false )) && text::VertOrientation::NONE == pVertOrientItem->GetVertOrient() ) { bVOriChgd = true; aOldV.reset(pVertOrientItem->Clone()); const_cast(rSet).Put( SwFormatVertOrient( 0, text::VertOrientation::TOP ) ); } } pRet = GetDoc()->MakeFlyAndMove( *pCursor, rSet, &aBoxes, pParent ); KillPams(); if( pOldAnchor ) { if( pRet ) { // calculate new position // JP 24.03.97: also go via page links // anchor should not lie in the shifted area pRet->DelFrames(); const SwFrame* pAnch = ::FindAnchor( GetLayout(), aPt ); SwPosition aPos( pAnch->IsTextFrame() ? *static_cast(pAnch)->GetTextNodeForParaProps() : *static_cast(pAnch)->GetNode() ); if ( RndStdIds::FLY_AS_CHAR == eRndId ) { assert(pAnch->IsTextFrame()); aPos = static_cast(pAnch)->MapViewToModelPos(TextFrameIndex(0)); } pOldAnchor->SetAnchor( &aPos ); // shifting of table selection is not Undo-capable. therefore // changing the anchors should not be recorded bool const bDoesUndo = GetDoc()->GetIDocumentUndoRedo().DoesUndo(); SwUndoId nLastUndoId(SwUndoId::EMPTY); if (bDoesUndo && GetDoc()->GetIDocumentUndoRedo().GetLastUndoInfo(nullptr, & nLastUndoId)) { if (SwUndoId::INSLAYFMT == nLastUndoId) { GetDoc()->GetIDocumentUndoRedo().DoUndo(false); } } const_cast(rSet).Put( std::move(pOldAnchor) ); if( bHOriChgd ) const_cast(rSet).Put( *aOldH ); if( bVOriChgd ) const_cast(rSet).Put( *aOldV ); GetDoc()->SetFlyFrameAttr( *pRet, const_cast(rSet) ); GetDoc()->GetIDocumentUndoRedo().DoUndo(bDoesUndo); } } GetDoc()->GetIDocumentUndoRedo().EndUndo( SwUndoId::INSLAYFMT, nullptr ); } else /* If called from a shell try to propagate an existing adjust item from rPos to the content node of the new frame. */ pRet = GetDoc()->MakeFlySection( eRndId, &rPos, &rSet, pParent, true ); if( pRet ) { SwFlyFrame* pFrame = pRet->GetFrame( &aPt ); if( pFrame ) SelectFlyFrame( *pFrame ); else { GetLayout()->SetAssertFlyPages(); pRet = nullptr; } } EndAllActionAndCall(); return pRet; } void SwFEShell::Insert( const OUString& rGrfName, const OUString& rFltName, const Graphic* pGraphic, const SfxItemSet* pFlyAttrSet ) { SwFlyFrameFormat* pFormat = nullptr; CurrShell aCurr( this ); StartAllAction(); SwShellCursor *pStartCursor = dynamic_cast(GetCursor()); SwShellCursor *pCursor = pStartCursor; do { if (!pCursor) break; // Has the anchor not been set or been set incompletely? if( pFlyAttrSet ) { if( const SwFormatAnchor* pItem = pFlyAttrSet->GetItemIfSet( RES_ANCHOR, false ) ) { SwFormatAnchor* pAnchor = const_cast(pItem); switch( pAnchor->GetAnchorId()) { case RndStdIds::FLY_AT_PARA: case RndStdIds::FLY_AT_CHAR: // LAYER_IMPL case RndStdIds::FLY_AS_CHAR: if( !pAnchor->GetContentAnchor() ) { pAnchor->SetAnchor( pCursor->GetPoint() ); } break; case RndStdIds::FLY_AT_FLY: if( !pAnchor->GetContentAnchor() ) { lcl_SetNewFlyPos( pCursor->GetNode(), *pAnchor, GetCursorDocPos() ); } break; case RndStdIds::FLY_AT_PAGE: if( !pAnchor->GetPageNum() ) { pAnchor->SetPageNum( pCursor->GetPageNum( true, &pCursor->GetPtPos() ) ); } break; default : break; } } } pFormat = GetDoc()->getIDocumentContentOperations().InsertGraphic( *pCursor, rGrfName, rFltName, pGraphic, pFlyAttrSet, nullptr, nullptr ); OSL_ENSURE(pFormat, "IDocumentContentOperations::InsertGraphic failed."); pCursor = pCursor->GetNext(); } while( pCursor != pStartCursor ); EndAllAction(); if( !pFormat ) return; const Point aPt( GetCursorDocPos() ); SwFlyFrame* pFrame = pFormat->GetFrame( &aPt ); if( pFrame ) { // add a redline to the anchor point at tracked insertion of picture if ( IsRedlineOn() ) { SwPosition aPos(*pFormat->GetAnchor().GetContentAnchor()); SwPaM aPaM(aPos.nNode.GetNode(), aPos.nContent.GetIndex(), aPos.nNode.GetNode(), aPos.nContent.GetIndex() + 1); GetDoc()->getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Insert, aPaM ), true); } // fdo#36681: Invalidate the content and layout to refresh // the picture anchoring properly SwPageFrame* pPageFrame = pFrame->FindPageFrameOfAnchor(); pPageFrame->InvalidateFlyLayout(); pPageFrame->InvalidateContent(); SelectFlyFrame( *pFrame ); } else GetLayout()->SetAssertFlyPages(); } SwFlyFrameFormat* SwFEShell::InsertObject( const svt::EmbeddedObjectRef& xObj, SfxItemSet* pFlyAttrSet ) { SwFlyFrameFormat* pFormat = nullptr; CurrShell aCurr( this ); StartAllAction(); { for(const SwPaM& rPaM : GetCursor()->GetRingContainer()) { pFormat = GetDoc()->getIDocumentContentOperations().InsertEmbObject( rPaM, xObj, pFlyAttrSet ); OSL_ENSURE(pFormat, "IDocumentContentOperations::InsertEmbObject failed."); } } EndAllAction(); if( pFormat ) { const Point aPt( GetCursorDocPos() ); SwFlyFrame* pFrame = pFormat->GetFrame( &aPt ); if( pFrame ) SelectFlyFrame( *pFrame ); else GetLayout()->SetAssertFlyPages(); } return pFormat; } void SwFEShell::InsertDrawObj( SdrObject& rDrawObj, const Point& rInsertPosition ) { CurrShell aCurr( this ); SfxItemSet rFlyAttrSet( GetDoc()->GetAttrPool(), aFrameFormatSetRange ); rFlyAttrSet.Put( SwFormatAnchor( RndStdIds::FLY_AT_PARA )); // #i89920# rFlyAttrSet.Put( SwFormatSurround( css::text::WrapTextMode_THROUGH ) ); rDrawObj.SetLayer( getIDocumentDrawModelAccess().GetHeavenId() ); // find anchor position SwPaM aPam( mxDoc->GetNodes() ); { SwCursorMoveState aState( CursorMoveState::SetOnlyText ); Point aTmpPt( rInsertPosition ); GetLayout()->GetModelPositionForViewPoint( aPam.GetPoint(), aTmpPt, &aState ); const SwFrame* pFrame = aPam.GetContentNode()->getLayoutFrame(GetLayout(), nullptr, nullptr); const Point aRelPos( rInsertPosition.X() - pFrame->getFrameArea().Left(), rInsertPosition.Y() - pFrame->getFrameArea().Top() ); rDrawObj.SetRelativePos( aRelPos ); ::lcl_FindAnchorPos( *GetDoc(), rInsertPosition, *pFrame, rFlyAttrSet ); } // insert drawing object into the document creating a new instance SwDrawFrameFormat* pFormat = GetDoc()->getIDocumentContentOperations().InsertDrawObj( aPam, rDrawObj, rFlyAttrSet ); // move object to visible layer SwContact* pContact = static_cast(rDrawObj.GetUserCall()); if ( pContact ) { pContact->MoveObjToVisibleLayer( &rDrawObj ); } if (pFormat) { pFormat->SetName(rDrawObj.GetName()); // select drawing object Imp()->GetDrawView()->MarkObj( &rDrawObj, Imp()->GetPageView() ); } else { GetLayout()->SetAssertFlyPages(); } } void SwFEShell::GetPageObjs( std::vector& rFillArr ) { rFillArr.clear(); for( auto pFormat : *mxDoc->GetSpzFrameFormats() ) { if (RndStdIds::FLY_AT_PAGE == pFormat->GetAnchor().GetAnchorId()) { rFillArr.push_back( pFormat ); } } } void SwFEShell::SetPageObjsNewPage( std::vector& rFillArr ) { if( rFillArr.empty() ) return; StartAllAction(); StartUndo(); SwRootFrame* pTmpRootFrame = GetLayout(); sal_uInt16 nMaxPage = pTmpRootFrame->GetPageNum(); bool bTmpAssert = false; for( auto pFormat : rFillArr ) { if (mxDoc->GetSpzFrameFormats()->IsAlive(pFormat)) { // FlyFormat is still valid, therefore process SwFormatAnchor aNewAnchor( pFormat->GetAnchor() ); if (RndStdIds::FLY_AT_PAGE != aNewAnchor.GetAnchorId()) // Anchor has been changed, therefore: do not change! continue; sal_uInt16 nNewPage = aNewAnchor.GetPageNum() + 1; if (nNewPage > nMaxPage) { if ( RES_DRAWFRMFMT == pFormat->Which() ) pFormat->CallSwClientNotify(sw::DrawFrameFormatHint(sw::DrawFrameFormatHintId::PAGE_OUT_OF_BOUNDS)); else pFormat->DelFrames(); bTmpAssert = true; } aNewAnchor.SetPageNum(nNewPage); mxDoc->SetAttr( aNewAnchor, *pFormat ); } } if( bTmpAssert ) pTmpRootFrame->SetAssertFlyPages(); EndUndo(); EndAllAction(); } // All attributes in the "baskets" will be filled with the attributes of the // current FlyFrames. Attributes which cannot be filled due to being at the // wrong place or which are ambiguous (multiple selections) will be removed. bool SwFEShell::GetFlyFrameAttr( SfxItemSet &rSet ) const { SwFlyFrame *pFly = GetSelectedOrCurrFlyFrame(); if (!pFly) { OSL_ENSURE( false, "GetFlyFrameAttr, no Fly selected." ); return false; } CurrShell aCurr( const_cast(this) ); if( !rSet.Set( pFly->GetFormat()->GetAttrSet() ) ) return false; // now examine all attributes. Remove forbidden attributes, then // get all remaining attributes and enter them if( const SwFormatAnchor* pAnchor = rSet.GetItemIfSet( RES_ANCHOR, false ) ) { RndStdIds eType = pAnchor->GetAnchorId(); if ( RndStdIds::FLY_AT_PAGE != eType ) { // OD 12.11.2003 #i22341# - content anchor of anchor item is needed. // Thus, don't overwrite anchor item by default constructed anchor item. if ( RndStdIds::FLY_AS_CHAR == eType ) { rSet.ClearItem( RES_OPAQUE ); rSet.ClearItem( RES_SURROUND ); } } } rSet.SetParent( pFly->GetFormat()->GetAttrSet().GetParent() ); // attributes must be removed rSet.ClearItem( RES_FILL_ORDER ); rSet.ClearItem( RES_CNTNT ); //MA: remove first (Template by example etc.) rSet.ClearItem( RES_CHAIN ); return true; } // Attributes of the current fly will change. bool SwFEShell::SetFlyFrameAttr( SfxItemSet& rSet ) { CurrShell aCurr( this ); bool bRet = false; if( rSet.Count() ) { SwFlyFrame *pFly = GetSelectedOrCurrFlyFrame(); OSL_ENSURE(pFly, "SetFlyFrameAttr, no Fly selected."); if (pFly) { StartAllAction(); const Point aPt( pFly->getFrameArea().Pos() ); if( SfxItemState::SET == rSet.GetItemState( RES_ANCHOR, false )) sw_ChkAndSetNewAnchor( *pFly, rSet ); SwFlyFrameFormat* pFlyFormat = pFly->GetFormat(); if( GetDoc()->SetFlyFrameAttr( *pFlyFormat, rSet )) { bRet = true; SwFlyFrame* pFrame = pFlyFormat->GetFrame( &aPt ); if( pFrame ) SelectFlyFrame( *pFrame ); else GetLayout()->SetAssertFlyPages(); } EndAllActionAndCall(); } } return bRet; } SfxItemSetFixed SwFEShell::makeItemSetFromFormatAnchor(SfxItemPool& rPool, const SwFormatAnchor &rAnchor) { // The set also includes VERT/HORI_ORIENT, because the align // shall be changed in FEShell::SetFlyFrameAttr/SetFlyFrameAnchor, // possibly as a result of the anchor change. SfxItemSetFixed aSet(rPool); aSet.Put(rAnchor); return aSet; } bool SwFEShell::SetDrawingAttr( SfxItemSet& rSet ) { bool bRet = false; CurrShell aCurr( this ); if ( !rSet.Count() || !Imp()->HasDrawView() ) return bRet; const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList(); if ( rMrkList.GetMarkCount() != 1 ) return bRet; StartUndo(); SdrObject *pObj = rMrkList.GetMark( 0 )->GetMarkedSdrObj(); SwFrameFormat *pFormat = FindFrameFormat( pObj ); StartAllAction(); if( SfxItemState::SET == rSet.GetItemState( RES_ANCHOR, false )) { RndStdIds nNew = rSet.Get( RES_ANCHOR ).GetAnchorId(); if ( nNew != pFormat->GetAnchor().GetAnchorId() ) { ChgAnchor( nNew ); // #i26791# - clear anchor attribute in item set, // because method takes care of it. rSet.ClearItem( RES_ANCHOR ); } } if( GetDoc()->SetFlyFrameAttr( *pFormat, rSet )) { bRet = true; SelectObj( Point(), 0, pObj ); } EndAllActionAndCall(); EndUndo(); return bRet; } // Reset attributes contained in the set. void SwFEShell::ResetFlyFrameAttr( const SfxItemSet* pSet ) { CurrShell aCurr( this ); SwFlyFrame *pFly = GetSelectedOrCurrFlyFrame(); OSL_ENSURE( pFly, "SetFlyFrameAttr, no Fly selected." ); if( !pFly ) return; StartAllAction(); SfxItemIter aIter( *pSet ); for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem()) { if( !IsInvalidItem( pItem ) ) { sal_uInt16 nWhich = pItem->Which(); if( RES_ANCHOR != nWhich && RES_CHAIN != nWhich && RES_CNTNT != nWhich ) pFly->GetFormat()->ResetFormatAttr( nWhich ); } } EndAllActionAndCall(); GetDoc()->getIDocumentState().SetModified(); } // Returns frame-format if frame, otherwise 0 SwFrameFormat* SwFEShell::GetSelectedFrameFormat() const { SwFrameFormat* pRet = nullptr; SwLayoutFrame *pFly = GetSelectedFlyFrame(); if( pFly && ( pRet = static_cast(pFly->GetFormat()->DerivedFrom()) ) == GetDoc()->GetDfltFrameFormat() ) pRet = nullptr; return pRet; } void SwFEShell::SetFrameFormat( SwFrameFormat *pNewFormat, bool bKeepOrient, Point const * pDocPos ) { SwFlyFrame *pFly = nullptr; if(pDocPos) { const SwFrameFormat* pFormat = GetFormatFromObj( *pDocPos ); if (const SwFlyFrameFormat* pFlyFormat = dynamic_cast(pFormat)) pFly = pFlyFormat->GetFrame(); } else pFly = GetSelectedFlyFrame(); OSL_ENSURE( pFly, "SetFrameFormat: no frame" ); if( !pFly ) return; StartAllAction(); CurrShell aCurr( this ); SwFlyFrameFormat* pFlyFormat = pFly->GetFormat(); const Point aPt( pFly->getFrameArea().Pos() ); std::optional oSet; const SfxPoolItem* pItem; if( SfxItemState::SET == pNewFormat->GetItemState( RES_ANCHOR, false, &pItem )) { oSet.emplace( GetDoc()->GetAttrPool(), aFrameFormatSetRange ); oSet->Put( *pItem ); if( !sw_ChkAndSetNewAnchor( *pFly, *oSet )) { oSet.reset(); } } if( GetDoc()->SetFrameFormatToFly( *pFlyFormat, *pNewFormat, oSet ? &*oSet : nullptr, bKeepOrient )) { SwFlyFrame* pFrame = pFlyFormat->GetFrame( &aPt ); if( pFrame ) SelectFlyFrame( *pFrame ); else GetLayout()->SetAssertFlyPages(); } oSet.reset(); EndAllActionAndCall(); } const SwFrameFormat* SwFEShell::GetFlyFrameFormat() const { const SwFlyFrame* pFly = GetSelectedOrCurrFlyFrame(); if (pFly) return pFly->GetFormat(); return nullptr; } SwFrameFormat* SwFEShell::GetFlyFrameFormat() { SwFlyFrame* pFly = GetSelectedOrCurrFlyFrame(); if (pFly) return pFly->GetFormat(); return nullptr; } SwRect SwFEShell::GetFlyRect() const { SwFlyFrame *pFly = GetCurrFlyFrame(false); if (!pFly) { SwRect aRect; return aRect; } else return pFly->getFrameArea(); } SwRect SwFEShell::GetObjRect() const { if( Imp()->HasDrawView() ) return SwRect(Imp()->GetDrawView()->GetAllMarkedRect()); else { SwRect aRect; return aRect; } } void SwFEShell::SetObjRect( const SwRect& rRect ) { if ( Imp()->HasDrawView() ) { Imp()->GetDrawView()->SetAllMarkedRect( rRect.SVRect() ); CallChgLnk(); // call AttrChangeNotify on the UI-side. } } Size SwFEShell::RequestObjectResize( const SwRect &rRect, const uno::Reference < embed::XEmbeddedObject >& xObj ) { Size aResult; SwFlyFrame *pFly = FindFlyFrame( xObj ); if ( !pFly ) { aResult = rRect.SSize(); return aResult; } aResult = pFly->getFramePrintArea().SSize(); bool bPosProt = pFly->GetFormat()->GetProtect().IsPosProtected(); bool bSizeProt = pFly->GetFormat()->GetProtect().IsSizeProtected(); StartAllAction(); // MA we do not allow to clip the Fly, as the OLE server can // request various wishes. Clipping is done via the formatting. // Correct display is done by scaling. // Scaling is done by SwNoTextFrame::Format by calling // SwWrtShell::CalcAndSetScale() if ( rRect.SSize() != pFly->getFramePrintArea().SSize() && !bSizeProt ) { Size aSz( rRect.SSize() ); //JP 28.02.2001: Task 74707 - ask for fly in fly with automatic size const SwFrame* pAnchor; const SwFormatFrameSize& rFrameSz = pFly->GetFormat()->GetFrameSize(); if (m_bCheckForOLEInCaption && 0 != rFrameSz.GetWidthPercent() && nullptr != (pAnchor = pFly->GetAnchorFrame()) && pAnchor->IsTextFrame() && !pAnchor->GetNext() && !pAnchor->GetPrev() && pAnchor->GetUpper()->IsFlyFrame()) { // search for a sequence field: sw::MergedAttrIter iter(*static_cast(pAnchor)); for (SwTextAttr const* pHint = iter.NextAttr(); pHint; pHint = iter.NextAttr()) { const SfxPoolItem* pItem = &pHint->GetAttr(); if( RES_TXTATR_FIELD == pItem->Which() && SwFieldTypesEnum::Sequence == static_cast(pItem)->GetField()->GetTypeId() ) { // sequence field found SwFlyFrame* pChgFly = const_cast(static_cast(pAnchor->GetUpper())); // calculate the changed size: // width must change, height can change Size aNewSz( aSz.Width() + pChgFly->getFrameArea().Width() - pFly->getFramePrintArea().Width(), aSz.Height() ); SwFrameFormat *pFormat = pChgFly->GetFormat(); SwFormatFrameSize aFrameSz( pFormat->GetFrameSize() ); aFrameSz.SetWidth( aNewSz.Width() ); if( SwFrameSize::Minimum != aFrameSz.GetHeightSizeType() ) { aNewSz.AdjustHeight(pChgFly->getFrameArea().Height() - pFly->getFramePrintArea().Height() ); if( std::abs( aNewSz.Height() - pChgFly->getFrameArea().Height()) > 1 ) aFrameSz.SetHeight( aNewSz.Height() ); } // via Doc for the Undo! pFormat->GetDoc()->SetAttr( aFrameSz, *pFormat ); break; } } } // set the new Size at the fly themself if ( !pFly->getFramePrintArea().IsEmpty() ) { aSz.AdjustWidth(pFly->getFrameArea().Width() - pFly->getFramePrintArea().Width() ); aSz.AdjustHeight(pFly->getFrameArea().Height()- pFly->getFramePrintArea().Height() ); } aResult = pFly->ChgSize( aSz ); // if the object changes, the contour is outside the object assert(pFly->Lower()->IsNoTextFrame()); SwNoTextNode *pNd = static_cast(pFly->Lower())->GetNode()->GetNoTextNode(); assert(pNd); pNd->SetContour( nullptr ); ClrContourCache(); } // if only the size is to be adjusted, a position is transported with // allocated values Point aPt( pFly->getFramePrintArea().Pos() ); aPt += pFly->getFrameArea().Pos(); if ( rRect.Top() != LONG_MIN && rRect.Pos() != aPt && !bPosProt ) { aPt = rRect.Pos(); aPt.setX(aPt.getX() - pFly->getFramePrintArea().Left()); aPt.setY(aPt.getY() - pFly->getFramePrintArea().Top()); // in case of paragraph-bound Flys, starting from the new position, // a new anchor is to be set. The anchor and the new RelPos are // calculated by the Fly and set if( pFly->IsFlyAtContentFrame() ) static_cast(pFly)->SetAbsPos( aPt ); else { const SwFrameFormat *pFormat = pFly->GetFormat(); const SwFormatVertOrient &rVert = pFormat->GetVertOrient(); const SwFormatHoriOrient &rHori = pFormat->GetHoriOrient(); const tools::Long lXDiff = aPt.getX() - pFly->getFrameArea().Left(); const tools::Long lYDiff = aPt.getY() - pFly->getFrameArea().Top(); const Point aTmp( rHori.GetPos() + lXDiff, rVert.GetPos() + lYDiff ); pFly->ChgRelPos( aTmp ); } } SwFlyFrameFormat *pFlyFrameFormat = pFly->GetFormat(); OSL_ENSURE( pFlyFrameFormat, "fly frame format missing!" ); if ( pFlyFrameFormat ) pFlyFrameFormat->SetLastFlyFramePrtRectPos( pFly->getFramePrintArea().Pos() ); //stores the value of last Prt rect EndAllAction(); return aResult; } SwFrameFormat* SwFEShell::WizardGetFly() { // do not search the Fly via the layout. Now we can delete a frame // without a valid layout. ( e.g. for the wizards ) SwFrameFormats& rSpzArr = *mxDoc->GetSpzFrameFormats(); if( !rSpzArr.empty() ) { SwNodeIndex& rCursorNd = GetCursor()->GetPoint()->nNode; if( rCursorNd.GetIndex() > mxDoc->GetNodes().GetEndOfExtras().GetIndex() ) // Cursor is in the body area! return nullptr; for( auto pFormat : rSpzArr ) { const SwNodeIndex* pIdx = pFormat->GetContent( false ).GetContentIdx(); SwStartNode* pSttNd; if( pIdx && nullptr != ( pSttNd = pIdx->GetNode().GetStartNode() ) && pSttNd->GetIndex() < rCursorNd.GetIndex() && rCursorNd.GetIndex() < pSttNd->EndOfSectionIndex() ) { // found: return immediately return pFormat; } } } return nullptr; } void SwFEShell::SetFlyName( const OUString& rName ) { SwLayoutFrame *pFly = GetSelectedFlyFrame(); if( pFly ) GetDoc()->SetFlyName( *static_cast(pFly->GetFormat()), rName ); else { OSL_ENSURE( false, "no FlyFrame selected" ); } } OUString SwFEShell::GetFlyName() const { SwLayoutFrame *pFly = GetSelectedFlyFrame(); if( pFly ) return pFly->GetFormat()->GetName(); OSL_ENSURE( false, "no FlyFrame selected" ); return OUString(); } uno::Reference < embed::XEmbeddedObject > SwFEShell::GetOleRef() const { uno::Reference < embed::XEmbeddedObject > xObj; SwFlyFrame * pFly = GetSelectedFlyFrame(); if (pFly && pFly->Lower() && pFly->Lower()->IsNoTextFrame()) { SwOLENode *pNd = static_cast(pFly->Lower())->GetNode()->GetOLENode(); if (pNd) xObj = pNd->GetOLEObj().GetOleRef(); } return xObj; } OUString SwFEShell::GetUniqueGrfName() const { return GetDoc()->GetUniqueGrfName(); } const SwFrameFormat* SwFEShell::IsURLGrfAtPos( const Point& rPt, OUString* pURL, OUString *pTargetFrameName, OUString *pDescription ) const { if( !Imp()->HasDrawView() ) return nullptr; SdrPageView* pPV; const SwFrameFormat* pRet = nullptr; SwDrawView *pDView = const_cast(Imp()->GetDrawView()); const auto nOld = pDView->GetHitTolerancePixel(); pDView->SetHitTolerancePixel( 2 ); SdrObject* pObj = pDView->PickObj(rPt, pDView->getHitTolLog(), pPV, SdrSearchOptions::PICKMACRO); SwVirtFlyDrawObj* pFlyObj = dynamic_cast(pObj); if (pFlyObj) { SwFlyFrame *pFly = pFlyObj->GetFlyFrame(); const SwFormatURL &rURL = pFly->GetFormat()->GetURL(); if( !rURL.GetURL().isEmpty() || rURL.GetMap() ) { bool bSetTargetFrameName = pTargetFrameName != nullptr; bool bSetDescription = pDescription != nullptr; if ( rURL.GetMap() ) { IMapObject *pObject = pFly->GetFormat()->GetIMapObject( rPt, pFly ); if ( pObject && !pObject->GetURL().isEmpty() ) { if( pURL ) *pURL = pObject->GetURL(); if ( bSetTargetFrameName && !pObject->GetTarget().isEmpty() ) { bSetTargetFrameName = false; *pTargetFrameName = pObject->GetTarget(); } if ( bSetDescription ) { bSetDescription = false; *pDescription = pObject->GetAltText(); } pRet = pFly->GetFormat(); } } else { if( pURL ) { *pURL = rURL.GetURL(); if( rURL.IsServerMap() ) { // append the relative pixel position !! Point aPt( rPt ); aPt -= pFly->getFrameArea().Pos(); // without MapMode-Offset, without Offset, o ... !!!!! aPt = GetOut()->LogicToPixel( aPt, MapMode( MapUnit::MapTwip ) ); *pURL = *pURL + "?" + OUString::number( aPt.getX() ) + "," + OUString::number(aPt.getY() ); } } pRet = pFly->GetFormat(); } if ( bSetTargetFrameName ) *pTargetFrameName = rURL.GetTargetFrameName(); if ( bSetDescription ) *pDescription = pFly->GetFormat()->GetName(); } } pDView->SetHitTolerancePixel( nOld ); return pRet; } const Graphic *SwFEShell::GetGrfAtPos( const Point &rPt, OUString &rName, bool &rbLink ) const { if( !Imp()->HasDrawView() ) return nullptr; SdrPageView* pPV; SwDrawView *pDView = const_cast(Imp()->GetDrawView()); SdrObject* pObj = pDView->PickObj(rPt, pDView->getHitTolLog(), pPV); SwVirtFlyDrawObj* pFlyObj = dynamic_cast(pObj); if (pFlyObj) { SwFlyFrame *pFly = pFlyObj->GetFlyFrame(); if ( pFly->Lower() && pFly->Lower()->IsNoTextFrame() ) { SwGrfNode *const pNd = static_cast(pFly->Lower())->GetNode()->GetGrfNode(); if ( pNd ) { if ( pNd->IsGrfLink() ) { // halfway ready graphic? ::sfx2::SvLinkSource* pLnkObj = pNd->GetLink()->GetObj(); if( pLnkObj && pLnkObj->IsPending() ) return nullptr; rbLink = true; } pNd->GetFileFilterNms( &rName, nullptr ); if ( rName.isEmpty() ) rName = pFly->GetFormat()->GetName(); return &pNd->GetGrf(true); } } } return nullptr; } const SwFrameFormat* SwFEShell::GetFormatFromObj( const Point& rPt, SwRect** pRectToFill ) const { SwFrameFormat* pRet = nullptr; if( Imp()->HasDrawView() ) { SdrPageView* pPView; SwDrawView *pDView = const_cast(Imp()->GetDrawView()); const auto nOld = pDView->GetHitTolerancePixel(); // tolerance for Drawing-SS pDView->SetHitTolerancePixel( pDView->GetMarkHdlSizePixel()/2 ); SdrObject* pObj = pDView->PickObj(rPt, pDView->getHitTolLog(), pPView, SdrSearchOptions::PICKMARKABLE); if (pObj) { // first check it: if (SwVirtFlyDrawObj* pFlyObj = dynamic_cast(pObj)) pRet = pFlyObj->GetFormat(); else if ( pObj->GetUserCall() ) //not for group objects pRet = static_cast(pObj->GetUserCall())->GetFormat(); if(pRet && pRectToFill) **pRectToFill = SwRect(pObj->GetCurrentBoundRect()); } pDView->SetHitTolerancePixel( nOld ); } return pRet; } // returns a format too, if the point is over the text of any fly const SwFrameFormat* SwFEShell::GetFormatFromAnyObj( const Point& rPt ) const { const SwFrameFormat* pRet = GetFormatFromObj( rPt ); if( !pRet || RES_FLYFRMFMT == pRet->Which() ) { SwPosition aPos( *GetCursor()->GetPoint() ); Point aPt( rPt ); GetLayout()->GetModelPositionForViewPoint( &aPos, aPt ); SwContentNode *pNd = aPos.nNode.GetNode().GetContentNode(); std::pair const tmp(rPt, false); SwFrame* pFrame = pNd->getLayoutFrame(GetLayout(), nullptr, &tmp)->FindFlyFrame(); pRet = pFrame ? static_cast(pFrame)->GetFormat() : nullptr; } return pRet; } ObjCntType SwFEShell::GetObjCntType( const SdrObject& rObj ) { ObjCntType eType = OBJCNT_NONE; // investigate 'master' drawing object, if method // is called for a 'virtual' drawing object. const SdrObject* pInvestigatedObj; if (const SwDrawVirtObj* pDrawVirtObj = dynamic_cast( &rObj)) { pInvestigatedObj = &(pDrawVirtObj->GetReferencedObj()); } else { pInvestigatedObj = &rObj; } if( SdrInventor::FmForm == pInvestigatedObj->GetObjInventor() ) { eType = OBJCNT_CONTROL; uno::Reference< awt::XControlModel > xModel = static_cast(*pInvestigatedObj).GetUnoControlModel(); if( xModel.is() ) { uno::Any aVal; OUString sName("ButtonType"); uno::Reference< beans::XPropertySet > xSet(xModel, uno::UNO_QUERY); uno::Reference< beans::XPropertySetInfo > xInfo = xSet->getPropertySetInfo(); if(xInfo->hasPropertyByName( sName )) { aVal = xSet->getPropertyValue( sName ); if( aVal.hasValue() && form::FormButtonType_URL == *o3tl::doAccess(aVal) ) eType = OBJCNT_URLBUTTON; } } } else if (const SwVirtFlyDrawObj *pFlyObj = dynamic_cast(pInvestigatedObj)) { const SwFlyFrame *pFly = pFlyObj->GetFlyFrame(); if ( pFly->Lower() && pFly->Lower()->IsNoTextFrame() ) { if (static_cast(pFly->Lower())->GetNode()->GetGrfNode()) eType = OBJCNT_GRF; else eType = OBJCNT_OLE; } else eType = OBJCNT_FLY; } else if ( dynamic_cast( pInvestigatedObj) != nullptr ) { SwDrawContact* pDrawContact( dynamic_cast(GetUserCall( pInvestigatedObj ) ) ); if ( !pDrawContact ) { OSL_FAIL( " - missing draw contact object" ); eType = OBJCNT_NONE; } else { SwFrameFormat* pFrameFormat( pDrawContact->GetFormat() ); if ( !pFrameFormat ) { OSL_FAIL( " - missing frame format" ); eType = OBJCNT_NONE; } else if ( RndStdIds::FLY_AS_CHAR != pFrameFormat->GetAnchor().GetAnchorId() ) { eType = OBJCNT_GROUPOBJ; } } } else eType = OBJCNT_SIMPLE; return eType; } ObjCntType SwFEShell::GetObjCntType( const Point &rPt, SdrObject *&rpObj ) const { ObjCntType eType = OBJCNT_NONE; if( Imp()->HasDrawView() ) { SdrPageView* pPView; SwDrawView *pDView = const_cast(Imp()->GetDrawView()); const auto nOld = pDView->GetHitTolerancePixel(); // tolerance for Drawing-SS pDView->SetHitTolerancePixel( pDView->GetMarkHdlSizePixel()/2 ); SdrObject* pObj = pDView->PickObj(rPt, pDView->getHitTolLog(), pPView, SdrSearchOptions::PICKMARKABLE); if (pObj) { rpObj = pObj; eType = GetObjCntType( *rpObj ); } pDView->SetHitTolerancePixel( nOld ); } return eType; } ObjCntType SwFEShell::GetObjCntTypeOfSelection() const { ObjCntType eType = OBJCNT_NONE; if( Imp()->HasDrawView() ) { const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList(); for( size_t i = 0, nE = rMrkList.GetMarkCount(); i < nE; ++i ) { SdrObject* pObj = rMrkList.GetMark( i )->GetMarkedSdrObj(); if( !pObj ) continue; ObjCntType eTmp = GetObjCntType( *pObj ); if( !i ) { eType = eTmp; } else if( eTmp != eType ) { eType = OBJCNT_DONTCARE; // once DontCare, always DontCare! break; } } } return eType; } void SwFEShell::ReplaceSdrObj( const OUString& rGrfName, const Graphic* pGrf ) { CurrShell aCurr( this ); const SdrMarkList *pMrkList; if( !(Imp()->HasDrawView() && 1 == ( pMrkList = &Imp()->GetDrawView()->GetMarkedObjectList())->GetMarkCount()) ) return; SdrObject* pObj = pMrkList->GetMark( 0 )->GetMarkedSdrObj(); SwFrameFormat *pFormat = FindFrameFormat( pObj ); // store attributes, then set the graphic SfxItemSet aFrameSet( mxDoc->GetAttrPool(), pFormat->GetAttrSet().GetRanges() ); aFrameSet.Set( pFormat->GetAttrSet() ); // set size and position? if( dynamic_cast( pObj) == nullptr ) { // then let's do it: const tools::Rectangle &rBound = pObj->GetSnapRect(); Point aRelPos( pObj->GetRelativePos() ); const tools::Long nWidth = rBound.Right() - rBound.Left(); const tools::Long nHeight= rBound.Bottom() - rBound.Top(); aFrameSet.Put( SwFormatFrameSize( SwFrameSize::Minimum, std::max( nWidth, tools::Long(MINFLY) ), std::max( nHeight, tools::Long(MINFLY) ))); if( SfxItemState::SET != aFrameSet.GetItemState( RES_HORI_ORIENT )) aFrameSet.Put( SwFormatHoriOrient( aRelPos.getX(), text::HoriOrientation::NONE, text::RelOrientation::FRAME )); if( SfxItemState::SET != aFrameSet.GetItemState( RES_VERT_ORIENT )) aFrameSet.Put( SwFormatVertOrient( aRelPos.getY(), text::VertOrientation::NONE, text::RelOrientation::FRAME )); } pObj->GetOrdNum(); StartAllAction(); StartUndo(); // delete "Sdr-Object", insert the graphic instead DelSelectedObj(); GetDoc()->getIDocumentContentOperations().InsertGraphic( *GetCursor(), rGrfName, "", pGrf, &aFrameSet, nullptr, nullptr); EndUndo(); EndAllAction(); } static sal_uInt16 SwFormatGetPageNum(const SwFlyFrameFormat * pFormat) { OSL_ENSURE(pFormat != nullptr, "invalid argument"); SwFlyFrame * pFrame = pFormat->GetFrame(); sal_uInt16 aResult; if (pFrame != nullptr) aResult = pFrame->GetPhyPageNum(); else aResult = pFormat->GetAnchor().GetPageNum(); return aResult; } void SwFEShell::GetConnectableFrameFormats(SwFrameFormat & rFormat, const OUString & rReference, bool bSuccessors, std::vector< OUString > & aPrevPageVec, std::vector< OUString > & aThisPageVec, std::vector< OUString > & aNextPageVec, std::vector< OUString > & aRestVec) { StartAction(); SwFormatChain rChain = rFormat.GetChain(); SwFrameFormat * pOldChainNext = rChain.GetNext(); SwFrameFormat * pOldChainPrev = rChain.GetPrev(); if (pOldChainNext) mxDoc->Unchain(rFormat); if (pOldChainPrev) mxDoc->Unchain(*pOldChainPrev); const size_t nCnt = mxDoc->GetFlyCount(FLYCNTTYPE_FRM); /* potential successors resp. predecessors */ std::vector< const SwFrameFormat * > aTmpSpzArray; mxDoc->FindFlyByName(rReference); for (size_t n = 0; n < nCnt; ++n) { const SwFrameFormat & rFormat1 = *(mxDoc->GetFlyNum(n, FLYCNTTYPE_FRM)); /* pFormat is a potential successor of rFormat if it is chainable after rFormat. pFormat is a potential predecessor of rFormat if rFormat is chainable after pFormat. */ SwChainRet nChainState; if (bSuccessors) nChainState = mxDoc->Chainable(rFormat, rFormat1); else nChainState = mxDoc->Chainable(rFormat1, rFormat); if (nChainState == SwChainRet::OK) { aTmpSpzArray.push_back(&rFormat1); } } if (!aTmpSpzArray.empty()) { aPrevPageVec.clear(); aThisPageVec.clear(); aNextPageVec.clear(); aRestVec.clear(); /* number of page rFormat resides on */ sal_uInt16 nPageNum = SwFormatGetPageNum(static_cast(&rFormat)); for (const auto& rpFormat : aTmpSpzArray) { const OUString aString = rpFormat->GetName(); /* rFormat is not a valid successor or predecessor of itself */ if (aString != rReference && aString != rFormat.GetName()) { sal_uInt16 nNum1 = SwFormatGetPageNum(static_cast(rpFormat)); if (nNum1 == nPageNum -1) aPrevPageVec.push_back(aString); else if (nNum1 == nPageNum) aThisPageVec.push_back(aString); else if (nNum1 == nPageNum + 1) aNextPageVec.push_back(aString); else aRestVec.push_back(aString); } } } if (pOldChainNext) mxDoc->Chain(rFormat, *pOldChainNext); if (pOldChainPrev) mxDoc->Chain(*pOldChainPrev, rFormat); EndAction(); } // #i73249# OUString SwFEShell::GetObjTitle() const { if ( Imp()->HasDrawView() ) { const SdrMarkList *pMrkList = &Imp()->GetDrawView()->GetMarkedObjectList(); if ( pMrkList->GetMarkCount() == 1 ) { const SdrObject* pObj = pMrkList->GetMark( 0 )->GetMarkedSdrObj(); const SwFrameFormat* pFormat = FindFrameFormat( pObj ); if ( pFormat->Which() == RES_FLYFRMFMT ) { return static_cast(pFormat)->GetObjTitle(); } return pObj->GetTitle(); } } return OUString(); } void SwFEShell::SetObjTitle( const OUString& rTitle ) { if ( !Imp()->HasDrawView() ) return; const SdrMarkList *pMrkList = &Imp()->GetDrawView()->GetMarkedObjectList(); if ( pMrkList->GetMarkCount() != 1 ) return; SdrObject* pObj = pMrkList->GetMark( 0 )->GetMarkedSdrObj(); SwFrameFormat* pFormat = FindFrameFormat( pObj ); if ( pFormat->Which() == RES_FLYFRMFMT ) { GetDoc()->SetFlyFrameTitle( dynamic_cast(*pFormat), rTitle ); } else { pObj->SetTitle( rTitle ); } } OUString SwFEShell::GetObjDescription() const { if ( Imp()->HasDrawView() ) { const SdrMarkList *pMrkList = &Imp()->GetDrawView()->GetMarkedObjectList(); if ( pMrkList->GetMarkCount() == 1 ) { const SdrObject* pObj = pMrkList->GetMark( 0 )->GetMarkedSdrObj(); const SwFrameFormat* pFormat = FindFrameFormat( pObj ); if ( pFormat->Which() == RES_FLYFRMFMT ) { return dynamic_cast(*pFormat).GetObjDescription(); } return pObj->GetDescription(); } } return OUString(); } void SwFEShell::SetObjDescription( const OUString& rDescription ) { if ( !Imp()->HasDrawView() ) return; const SdrMarkList *pMrkList = &Imp()->GetDrawView()->GetMarkedObjectList(); if ( pMrkList->GetMarkCount() != 1 ) return; SdrObject* pObj = pMrkList->GetMark( 0 )->GetMarkedSdrObj(); SwFrameFormat* pFormat = FindFrameFormat( pObj ); if ( pFormat->Which() == RES_FLYFRMFMT ) { GetDoc()->SetFlyFrameDescription(dynamic_cast(*pFormat), rDescription); } else { pObj->SetDescription( rDescription ); } } void SwFEShell::AlignFormulaToBaseline( const uno::Reference < embed::XEmbeddedObject >& xObj ) { #if OSL_DEBUG_LEVEL > 0 SvGlobalName aCLSID( xObj->getClassID() ); const bool bStarMath = ( SotExchange::IsMath( aCLSID ) != 0 ); OSL_ENSURE( bStarMath, "AlignFormulaToBaseline should only be called for Math objects" ); if ( !bStarMath ) return; #endif SwFlyFrame * pFly = FindFlyFrame( xObj ); OSL_ENSURE( pFly , "No fly frame!" ); SwFrameFormat * pFrameFormat = pFly ? pFly->GetFormat() : nullptr; // baseline to baseline alignment should only be applied to formulas anchored as char if ( !pFly || !pFrameFormat || RndStdIds::FLY_AS_CHAR != pFrameFormat->GetAnchor().GetAnchorId() ) return; // get baseline from Math object uno::Any aBaseline; if( svt::EmbeddedObjectRef::TryRunningState( xObj ) ) { uno::Reference < beans::XPropertySet > xSet( xObj->getComponent(), uno::UNO_QUERY ); if ( xSet.is() ) { try { aBaseline = xSet->getPropertyValue("BaseLine"); } catch ( uno::Exception& ) { OSL_FAIL( "Baseline could not be retrieved from Starmath!" ); } } } sal_Int32 nBaseline = ::comphelper::getINT32(aBaseline); nBaseline = o3tl::toTwips( nBaseline, o3tl::Length::mm100 ); OSL_ENSURE( nBaseline > 0, "Wrong value of Baseline while retrieving from Starmath!" ); //nBaseline must be moved by aPrt position const SwFlyFrameFormat *pFlyFrameFormat = pFly->GetFormat(); OSL_ENSURE( pFlyFrameFormat, "fly frame format missing!" ); if ( pFlyFrameFormat ) nBaseline += pFlyFrameFormat->GetLastFlyFramePrtRectPos().Y(); const SwFormatVertOrient &rVert = pFrameFormat->GetVertOrient(); SwFormatVertOrient aVert( rVert ); aVert.SetPos( -nBaseline ); aVert.SetVertOrient( css::text::VertOrientation::NONE ); pFrameFormat->LockModify(); pFrameFormat->SetFormatAttr( aVert ); pFrameFormat->UnlockModify(); pFly->InvalidatePos(); } void SwFEShell::AlignAllFormulasToBaseline() { StartAllAction(); SwStartNode *pStNd; SwNodeIndex aIdx( *GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 ); while ( nullptr != (pStNd = aIdx.GetNode().GetStartNode()) ) { ++aIdx; SwOLENode *pOleNode = dynamic_cast< SwOLENode * >( &aIdx.GetNode() ); if ( pOleNode ) { const uno::Reference < embed::XEmbeddedObject > & xObj( pOleNode->GetOLEObj().GetOleRef() ); if (xObj.is()) { SvGlobalName aCLSID( xObj->getClassID() ); if ( SotExchange::IsMath( aCLSID ) ) AlignFormulaToBaseline( xObj ); } } aIdx.Assign( *pStNd->EndOfSectionNode(), + 1 ); } EndAllAction(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */