/* -*- 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 #include #include #include #include #include #include using namespace com::sun::star; using namespace com::sun::star::uno; using namespace sdr::table; namespace sd { View::View( SdDrawDocument& rDrawDoc, OutputDevice* pOutDev, ViewShell* pViewShell) : FmFormView(rDrawDoc, pOutDev), mrDoc(rDrawDoc), mpDocSh(rDrawDoc.GetDocSh()), mpViewSh(pViewShell), mpDropMarkerObj(nullptr), mnDragSrcPgNum(SDRPAGE_NOTFOUND), mnAction(DND_ACTION_NONE), maDropErrorIdle("sd View DropError"), maDropInsertFileIdle("sd View DropInsertFile"), mnLockRedrawSmph(0), mbIsDropAllowed(true), maSmartTags(*this), mpClipboard (new ViewClipboard (*this)) { // #i73602# Use default from the configuration SetBufferedOverlayAllowed(SvtOptionsDrawinglayer::IsOverlayBuffer_DrawImpress()); // #i74769#, #i75172# Use default from the configuration SetBufferedOutputAllowed(SvtOptionsDrawinglayer::IsPaintBuffer_DrawImpress()); EnableExtendedKeyInputDispatcher(false); EnableExtendedMouseEventDispatcher(false); SetUseIncompatiblePathCreateInterface(false); SetMinMoveDistancePixel(2); SetHitTolerancePixel(2); SetMeasureLayer(sUNO_LayerName_measurelines); // Timer for delayed drop (has to be for MAC) maDropErrorIdle.SetInvokeHandler( LINK(this, View, DropErrorHdl) ); maDropInsertFileIdle.SetInvokeHandler( LINK(this, View, DropInsertFileHdl) ); } void View::ImplClearDrawDropMarker() { mpDropMarker.reset(); } View::~View() { maSmartTags.Dispose(); // release content of selection clipboard, if we own the content ClearSelectionClipboard(); if (mxDropMediaSizeListener) { mxDropMediaSizeListener->dispose(); mxDropMediaSizeListener.clear(); } maDropErrorIdle.Stop(); maDropInsertFileIdle.Stop(); ImplClearDrawDropMarker(); while(PaintWindowCount()) { // remove all registered OutDevs // cid#1485150 silence Uncaught exception suppress_fun_call_w_exception(DeleteWindowFromPaintView(GetFirstOutputDevice())); } } namespace { class ViewRedirector : public sdr::contact::ViewObjectContactRedirector { public: ViewRedirector(); // all default implementations just call the same methods at the original. To do something // different, override the method and at least do what the method does. virtual void createRedirectedPrimitive2DSequence( const sdr::contact::ViewObjectContact& rOriginal, const sdr::contact::DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) override; }; } ViewRedirector::ViewRedirector() { } void ViewRedirector::createRedirectedPrimitive2DSequence( const sdr::contact::ViewObjectContact& rOriginal, const sdr::contact::DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) { SdrObject* pObject = rOriginal.GetViewContact().TryToGetSdrObject(); SdrPage* pSdrPage = pObject ? pObject->getSdrPageFromSdrObject() : nullptr; if(!pObject || !pSdrPage) { // not a SdrObject visualisation (maybe e.g. page) or no page sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo, rVisitor); return; } const bool bDoCreateGeometry(pSdrPage->checkVisibility( rOriginal, rDisplayInfo, true )); if(!bDoCreateGeometry && (( pObject->GetObjInventor() != SdrInventor::Default ) || ( pObject->GetObjIdentifier() != SdrObjKind::Page )) ) return; PresObjKind eKind(PresObjKind::NONE); const bool bSubContentProcessing(rDisplayInfo.GetSubContentActive()); const bool bIsMasterPageObject(pSdrPage->IsMasterPage()); const bool bIsPrinting(rOriginal.GetObjectContact().isOutputToPrinter()); const SdrPageView* pPageView = rOriginal.GetObjectContact().TryToGetSdrPageView(); const SdrPage* pVisualizedPage = GetSdrPageFromXDrawPage(rOriginal.GetObjectContact().getViewInformation2D().getVisualizedPage()); const SdPage* pObjectsSdPage = dynamic_cast< SdPage* >(pSdrPage); const bool bIsInsidePageObj(pPageView && pPageView->GetPage() != pVisualizedPage); // check if we need to draw a placeholder border. Never do it for // objects inside a SdrPageObj and never when printing if(!bIsInsidePageObj && !bIsPrinting) { bool bCreateOutline(false); if( pObject->IsEmptyPresObj() && dynamic_cast< SdrTextObj *>( pObject ) != nullptr ) { if( !bSubContentProcessing || !pObject->IsNotVisibleAsMaster() ) { eKind = pObjectsSdPage ? pObjectsSdPage->GetPresObjKind(pObject) : PresObjKind::NONE; bCreateOutline = true; } } else if( ( pObject->GetObjInventor() == SdrInventor::Default ) && ( pObject->GetObjIdentifier() == SdrObjKind::Text ) ) { if( pObjectsSdPage ) { eKind = pObjectsSdPage->GetPresObjKind(pObject); if((eKind == PresObjKind::Footer) || (eKind == PresObjKind::Header) || (eKind == PresObjKind::DateTime) || (eKind == PresObjKind::SlideNumber) ) { if( !bSubContentProcessing ) { // only draw a boundary for header&footer objects on the masterpage itself bCreateOutline = true; } } } } else if( ( pObject->GetObjInventor() == SdrInventor::Default ) && ( pObject->GetObjIdentifier() == SdrObjKind::Page ) ) { // only for handout page, else this frame will be created for each // page preview object in SlideSorter and PagePane if(pObjectsSdPage && PageKind::Handout == pObjectsSdPage->GetPageKind()) { bCreateOutline = true; } } if(bCreateOutline) { // empty presentation objects get a gray frame const svtools::ColorConfig aColorConfig; const svtools::ColorConfigValue aColor( aColorConfig.GetColorValue( svtools::OBJECTBOUNDARIES ) ); if( aColor.bIsVisible ) { // get basic object transformation const basegfx::BColor aRGBColor(aColor.nColor.getBColor()); basegfx::B2DHomMatrix aObjectMatrix; basegfx::B2DPolyPolygon aObjectPolyPolygon; pObject->TRGetBaseGeometry(aObjectMatrix, aObjectPolyPolygon); // create dashed border { // create object polygon basegfx::B2DPolygon aPolygon(basegfx::utils::createUnitPolygon()); aPolygon.transform(aObjectMatrix); // create line and stroke attribute ::std::vector< double > aDotDashArray { 160.0, 80.0 }; const double fFullDotDashLen(::std::accumulate(aDotDashArray.begin(), aDotDashArray.end(), 0.0)); const drawinglayer::attribute::LineAttribute aLine(aRGBColor); const drawinglayer::attribute::StrokeAttribute aStroke(std::move(aDotDashArray), fFullDotDashLen); // create primitive and add const drawinglayer::primitive2d::Primitive2DReference xRef(new drawinglayer::primitive2d::PolygonStrokePrimitive2D( aPolygon, aLine, aStroke)); rVisitor.visit(xRef); } // now paint the placeholder description, but only when masterpage // is displayed as page directly (MasterPage view) if(!bSubContentProcessing && bIsMasterPageObject) { OUString aObjectString; switch( eKind ) { case PresObjKind::Title: { if(pObjectsSdPage && pObjectsSdPage->GetPageKind() == PageKind::Standard) { static OUString aTitleAreaStr(SdResId(STR_PLACEHOLDER_DESCRIPTION_TITLE)); aObjectString = aTitleAreaStr; } break; } case PresObjKind::Outline: { static OUString aOutlineAreaStr(SdResId(STR_PLACEHOLDER_DESCRIPTION_OUTLINE)); aObjectString = aOutlineAreaStr; break; } case PresObjKind::Footer: { static OUString aFooterAreaStr(SdResId(STR_PLACEHOLDER_DESCRIPTION_FOOTER)); aObjectString = aFooterAreaStr; break; } case PresObjKind::Header: { static OUString aHeaderAreaStr(SdResId(STR_PLACEHOLDER_DESCRIPTION_HEADER)); aObjectString = aHeaderAreaStr; break; } case PresObjKind::DateTime: { static OUString aDateTimeStr(SdResId(STR_PLACEHOLDER_DESCRIPTION_DATETIME)); aObjectString = aDateTimeStr; break; } case PresObjKind::Notes: { static OUString aDateTimeStr(SdResId(STR_PLACEHOLDER_DESCRIPTION_NOTES)); aObjectString = aDateTimeStr; break; } case PresObjKind::SlideNumber: { if(pObjectsSdPage && pObjectsSdPage->GetPageKind() == PageKind::Standard) { static OUString aSlideAreaStr(SdResId(STR_PLACEHOLDER_DESCRIPTION_SLIDE)); aObjectString = aSlideAreaStr; } else { static OUString aNumberAreaStr(SdResId(STR_PLACEHOLDER_DESCRIPTION_NUMBER)); aObjectString = aNumberAreaStr; } break; } default: { break; } } if( !aObjectString.isEmpty() ) { // decompose object matrix to be able to place text correctly basegfx::B2DTuple aScale; basegfx::B2DTuple aTranslate; double fRotate, fShearX; aObjectMatrix.decompose(aScale, aTranslate, fRotate, fShearX); // create font SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( pObject ); const SdrTextVertAdjust eTVA(pTextObj ? pTextObj->GetTextVerticalAdjust() : SDRTEXTVERTADJUST_CENTER); vcl::Font aScaledVclFont; // use a text size factor to get more reliable text sizes from the text layouter // (and from vcl), tipp from HDU static const sal_uInt32 nTextSizeFactor(100); // use a factor to get more linear text size calculations aScaledVclFont.SetFontHeight( 500 * nTextSizeFactor ); // get basic geometry and get text size drawinglayer::primitive2d::TextLayouterDevice aTextLayouter; aTextLayouter.setFont(aScaledVclFont); const sal_Int32 nTextLength(aObjectString.getLength()); // do not forget to use the factor again to get the width for the 500 const double fTextWidth(aTextLayouter.getTextWidth(aObjectString, 0, nTextLength) * (1.0 / nTextSizeFactor)); const double fTextHeight(aTextLayouter.getTextHeight() * (1.0 / nTextSizeFactor)); // calculate text primitive position. If text is at bottom, use top for // the extra text and vice versa const double fHorDist(125); const double fVerDist(125); const double fPosX((aTranslate.getX() + aScale.getX()) - fTextWidth - fHorDist); const double fPosY((SDRTEXTVERTADJUST_BOTTOM == eTVA) ? aTranslate.getY() - fVerDist + fTextHeight : (aTranslate.getY() + aScale.getY()) - fVerDist); // get font attributes; use normally scaled font vcl::Font aVclFont; basegfx::B2DVector aTextSizeAttribute; aVclFont.SetFontHeight( 500 ); const drawinglayer::attribute::FontAttribute aFontAttribute( drawinglayer::primitive2d::getFontAttributeFromVclFont( aTextSizeAttribute, aVclFont, false, false)); // fill text matrix const basegfx::B2DHomMatrix aTextMatrix(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix( aTextSizeAttribute.getX(), aTextSizeAttribute.getY(), fShearX, fRotate, fPosX, fPosY)); // create DXTextArray (can be empty one) ::std::vector< double > aDXArray{}; // create locale; this may need some more information in the future const css::lang::Locale aLocale; // create primitive and add const drawinglayer::primitive2d::Primitive2DReference xRef( new drawinglayer::primitive2d::TextSimplePortionPrimitive2D( aTextMatrix, aObjectString, 0, nTextLength, std::move(aDXArray), aFontAttribute, aLocale, aRGBColor)); rVisitor.visit(xRef); } } } } } if(bDoCreateGeometry) { sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence( rOriginal, rDisplayInfo, rVisitor); } } /** * The event will be forwarded to the View */ void View::CompleteRedraw(OutputDevice* pOutDev, const vcl::Region& rReg, sdr::contact::ViewObjectContactRedirector* pRedirector /*=0*/) { // execute ?? if (mnLockRedrawSmph != 0) return; SdrPageView* pPgView = GetSdrPageView(); if (pPgView) { SdPage* pPage = static_cast( pPgView->GetPage() ); if( pPage ) { SdrOutliner& rOutl = mrDoc.GetDrawOutliner(); bool bScreenDisplay(true); // #i75566# printing; suppress AutoColor BackgroundColor generation // for visibility reasons by giving GetPageBackgroundColor() // the needed hint // #i75566# PDF export; suppress AutoColor BackgroundColor generation (see printing) if (pOutDev && ((OUTDEV_PRINTER == pOutDev->GetOutDevType()) || (OUTDEV_PDF == pOutDev->GetOutDevType()))) bScreenDisplay = false; // #i75566# Name change GetBackgroundColor -> GetPageBackgroundColor and // hint value if screen display. Only then the AutoColor mechanisms shall be applied rOutl.SetBackgroundColor( pPage->GetPageBackgroundColor(pPgView, bScreenDisplay) ); } } ViewRedirector aViewRedirector; FmFormView::CompleteRedraw(pOutDev, rReg, pRedirector ? pRedirector : &aViewRedirector); } void View::MarkListHasChanged() { FmFormView::MarkListHasChanged(); if( GetMarkedObjectCount() > 0 ) maSmartTags.deselect(); } bool View::SetAttributes(const SfxItemSet& rSet, bool bReplaceAll, bool /*bSlide*/, bool /*bMaster*/) { bool bOk = FmFormView::SetAttributes(rSet, bReplaceAll); return bOk; } void View::GetAttributes( SfxItemSet& rTargetSet, bool bOnlyHardAttr ) const { FmFormView::GetAttributes( rTargetSet, bOnlyHardAttr ); } /** * Is a presentation object selected? */ bool View::IsPresObjSelected(bool bOnPage, bool bOnMasterPage, bool bCheckPresObjListOnly, bool bCheckLayoutOnly) const { SdrMarkList* pMarkList; if (mnDragSrcPgNum != SDRPAGE_NOTFOUND && mnDragSrcPgNum != GetSdrPageView()->GetPage()->GetPageNum()) { /* Drag&Drop is in progress Source and destination page are different: we use the saved mark list */ pMarkList = mpDragSrcMarkList.get(); } else { // We use the current mark list pMarkList = new SdrMarkList(GetMarkedObjectList()); } SdrMark* pMark; SdPage* pPage; bool bSelected = false; bool bMasterPage = false; for (size_t nMark = pMarkList->GetMarkCount(); nMark && !bSelected; ) { --nMark; // Backwards through mark list pMark = pMarkList->GetMark(nMark); SdrObject* pObj = pMark->GetMarkedSdrObj(); if ( pObj && ( bCheckPresObjListOnly || pObj->IsEmptyPresObj() || pObj->GetUserCall() ) ) { pPage = static_cast( pObj->getSdrPageFromSdrObject() ); bMasterPage = pPage && pPage->IsMasterPage(); if ( (bMasterPage && bOnMasterPage) || (!bMasterPage && bOnPage) ) { if ( pPage && pPage->IsPresObj(pObj) ) { if( bCheckLayoutOnly ) { PresObjKind eKind = pPage->GetPresObjKind(pObj); if((eKind != PresObjKind::Footer) && (eKind != PresObjKind::Header) && (eKind != PresObjKind::DateTime) && (eKind != PresObjKind::SlideNumber) ) bSelected = true; } else { bSelected = true; } } } } } if (pMarkList != mpDragSrcMarkList.get()) { delete pMarkList; } return bSelected; } void View::SelectAll() { if ( IsTextEdit() ) { OutlinerView* pOLV = GetTextEditOutlinerView(); const ::Outliner* pOutliner = GetTextEditOutliner(); pOLV->SelectRange( 0, pOutliner->GetParagraphCount() ); } else { MarkAll(); } } bool View::SetStyleSheet(SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr) { // forward to SdrView FmFormView::SetStyleSheet(pStyleSheet, bDontRemoveHardAttr); return true; } /** * Start text input */ static void SetSpellOptions( const SdDrawDocument& rDoc, EEControlBits& rCntrl ) { bool bOnlineSpell = rDoc.GetOnlineSpell(); if( bOnlineSpell ) rCntrl |= EEControlBits::ONLINESPELLING; else rCntrl &= ~EEControlBits::ONLINESPELLING; } void OutlinerMasterViewFilter::Start(SdrOutliner *pOutl) { m_pOutl = pOutl; OutlinerView* pOutlView = m_pOutl->GetView(0); m_bReadOnly = pOutlView->IsReadOnly(); pOutlView->SetReadOnly(true); } void OutlinerMasterViewFilter::End() { if (m_pOutl) { OutlinerView* pOutlView = m_pOutl->GetView(0); pOutlView->SetReadOnly(m_bReadOnly); m_pOutl = nullptr; } } SfxViewShell* View::GetSfxViewShell() const { SfxViewShell* pRet = nullptr; if (mpViewSh) pRet = &mpViewSh->GetViewShellBase(); return pRet; } // Create a new view-local UndoManager manager for Impress/Draw std::unique_ptr View::createLocalTextUndoManager() { std::unique_ptr pUndoManager(new sd::UndoManager); pUndoManager->SetDocShell(mpDocSh); return pUndoManager; } bool View::SdrBeginTextEdit( SdrObject* pObj, SdrPageView* pPV, vcl::Window* pWin, bool bIsNewObj, SdrOutliner* pOutl, OutlinerView* pGivenOutlinerView, bool bDontDeleteOutliner, bool bOnlyOneView, bool bGrabFocus ) { SdrPage* pPage = pObj ? pObj->getSdrPageFromSdrObject() : nullptr; bool bMasterPage = pPage && pPage->IsMasterPage(); GetViewShell()->GetViewShellBase().GetEventMultiplexer()->MultiplexEvent( EventMultiplexerEventId::BeginTextEdit, static_cast(pObj) ); if( pOutl==nullptr && pObj ) pOutl = SdrMakeOutliner(OutlinerMode::TextObject, pObj->getSdrModelFromSdrObject()).release(); // make draw&impress specific initialisations if( pOutl ) { pOutl->SetStyleSheetPool(static_cast( mrDoc.GetStyleSheetPool() )); pOutl->SetCalcFieldValueHdl(LINK(SD_MOD(), SdModule, CalcFieldValueHdl)); EEControlBits nCntrl = pOutl->GetControlWord(); nCntrl |= EEControlBits::ALLOWBIGOBJS; nCntrl |= EEControlBits::MARKFIELDS; nCntrl |= EEControlBits::AUTOCORRECT; nCntrl &= ~EEControlBits::ULSPACESUMMATION; if ( mrDoc.IsSummationOfParagraphs() ) nCntrl |= EEControlBits::ULSPACESUMMATION; SetSpellOptions( mrDoc, nCntrl ); pOutl->SetControlWord(nCntrl); Reference< linguistic2::XSpellChecker1 > xSpellChecker( LinguMgr::GetSpellChecker() ); if ( xSpellChecker.is() ) pOutl->SetSpeller( xSpellChecker ); Reference< linguistic2::XHyphenator > xHyphenator( LinguMgr::GetHyphenator() ); if( xHyphenator.is() ) pOutl->SetHyphenator( xHyphenator ); pOutl->SetDefaultLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() ); } bool bReturn = FmFormView::SdrBeginTextEdit( pObj, pPV, pWin, bIsNewObj, pOutl, pGivenOutlinerView, bDontDeleteOutliner, bOnlyOneView, bGrabFocus); if ( mpViewSh ) { mpViewSh->GetViewShellBase().GetDrawController().FireSelectionChangeListener(); if (pObj && pObj->GetObjIdentifier() == SdrObjKind::Table) mpViewSh->UpdateScrollBars(); if (comphelper::LibreOfficeKit::isActive()) { if (OutlinerView* pView = GetTextEditOutlinerView()) { ::tools::Rectangle aRectangle = pView->GetOutputArea(); if (pWin && pWin->GetMapMode().GetMapUnit() == MapUnit::Map100thMM) { aRectangle = o3tl::convert(aRectangle, o3tl::Length::mm100, o3tl::Length::twip); } OString sRectangle = aRectangle.toString(); SfxLokHelper::notifyOtherViews(&mpViewSh->GetViewShellBase(), LOK_CALLBACK_VIEW_LOCK, "rectangle", sRectangle); } } } if (::Outliner* pOL = bReturn ? GetTextEditOutliner() : nullptr) { if (pObj) { if( pObj->GetObjInventor() == SdrInventor::Default && pObj->GetObjIdentifier() == SdrObjKind::Table ) { Color aBackground = GetTextEditBackgroundColor(*this); pOL->SetBackgroundColor( aBackground ); } else { pObj->setSuitableOutlinerBg(*pOL); } } pOL->SetParaInsertedHdl(LINK(this, View, OnParagraphInsertedHdl)); pOL->SetParaRemovingHdl(LINK(this, View, OnParagraphRemovingHdl)); } if (bMasterPage && bReturn && pOutl) { const SdrTextObj* pTextObj = pOutl->GetTextObj(); const SdPage* pSdPage = pTextObj ? static_cast(pTextObj->getSdrPageFromSdrObject()) : nullptr; const PresObjKind eKind = pSdPage ? pSdPage->GetPresObjKind(const_cast(pTextObj)) : PresObjKind::NONE; switch (eKind) { case PresObjKind::Title: case PresObjKind::Outline: case PresObjKind::Text: maMasterViewFilter.Start(pOutl); break; default: break; } } return bReturn; } /** ends current text editing */ SdrEndTextEditKind View::SdrEndTextEdit(bool bDontDeleteReally) { maMasterViewFilter.End(); ::tools::WeakReference xObj( GetTextEditObject() ); bool bDefaultTextRestored = RestoreDefaultText( xObj.get() ); SdrEndTextEditKind eKind = FmFormView::SdrEndTextEdit(bDontDeleteReally); if( bDefaultTextRestored ) { if( xObj.is() && !xObj->IsEmptyPresObj() ) { xObj->SetEmptyPresObj( true ); } else { eKind = SdrEndTextEditKind::Unchanged; } } else if( xObj.is() && xObj->IsEmptyPresObj() ) { SdrTextObj* pObj = xObj.get(); if( pObj && pObj->HasText() ) { SdrPage* pPage = pObj->getSdrPageFromSdrObject(); if( !pPage || !pPage->IsMasterPage() ) pObj->SetEmptyPresObj( false ); } } GetViewShell()->GetViewShellBase().GetEventMultiplexer()->MultiplexEvent( EventMultiplexerEventId::EndTextEdit, static_cast(xObj.get()) ); if( xObj.is() ) { if ( mpViewSh ) { mpViewSh->GetViewShellBase().GetDrawController().FireSelectionChangeListener(); if (comphelper::LibreOfficeKit::isActive()) SfxLokHelper::notifyOtherViews(&mpViewSh->GetViewShellBase(), LOK_CALLBACK_VIEW_LOCK, "rectangle", "EMPTY"); } SdPage* pPage = dynamic_cast< SdPage* >( xObj->getSdrPageFromSdrObject() ); if( pPage ) pPage->onEndTextEdit( xObj.get() ); } return eKind; } /** restores the default text if the given text object is currently in edit mode and no text has been entered already. Is only useful just before text edit ends. */ bool View::RestoreDefaultText( SdrTextObj* pTextObj ) { bool bRestored = false; if( pTextObj && (pTextObj == GetTextEditObject()) ) { if( !pTextObj->HasText() ) { SdPage* pPage = dynamic_cast< SdPage* >( pTextObj->getSdrPageFromSdrObject() ); if(pPage) { bRestored = pPage->RestoreDefaultText( pTextObj ); if( bRestored ) { SdrOutliner* pOutliner = GetTextEditOutliner(); pTextObj->SetTextEditOutliner( pOutliner ); OutlinerParaObject* pParaObj = pTextObj->GetOutlinerParaObject(); if (pOutliner) pOutliner->SetText(*pParaObj); } } } } return bRestored; } /** * Sets the original size of the marked objects. */ void View::SetMarkedOriginalSize() { std::unique_ptr pUndoGroup(new SdrUndoGroup(mrDoc)); const size_t nCount = GetMarkedObjectCount(); bool bOK = false; for( size_t i = 0; i < nCount; ++i ) { SdrObject* pObj = GetMarkedObjectByIndex(i); if( pObj->GetObjInventor() == SdrInventor::Default ) { if( pObj->GetObjIdentifier() == SdrObjKind::OLE2 ) { uno::Reference < embed::XEmbeddedObject > xObj = static_cast(pObj)->GetObjRef(); if( xObj.is() ) { // TODO/LEAN: working with VisualArea can switch object to running state sal_Int64 nAspect = static_cast(pObj)->GetAspect(); Size aOleSize; if ( nAspect == embed::Aspects::MSOLE_ICON ) { MapMode aMap100( MapUnit::Map100thMM ); aOleSize = static_cast(pObj)->GetOrigObjSize( &aMap100 ); bOK = true; } else { MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) ); try { awt::Size aSz = xObj->getVisualAreaSize( nAspect ); aOleSize = OutputDevice::LogicToLogic(Size(aSz.Width, aSz.Height), MapMode(aUnit), MapMode(MapUnit::Map100thMM)); bOK = true; } catch( embed::NoVisualAreaSizeException& ) {} } if ( bOK ) { ::tools::Rectangle aDrawRect( pObj->GetLogicRect() ); pUndoGroup->AddAction( mrDoc.GetSdrUndoFactory().CreateUndoGeoObject( *pObj ) ); pObj->Resize( aDrawRect.TopLeft(), Fraction( aOleSize.Width(), aDrawRect.GetWidth() ), Fraction( aOleSize.Height(), aDrawRect.GetHeight() ) ); } } } else if( pObj->GetObjIdentifier() == SdrObjKind::Graphic ) { const SdrGrafObj* pSdrGrafObj = static_cast< const SdrGrafObj* >(pObj); const Size aSize = pSdrGrafObj->getOriginalSize( ); pUndoGroup->AddAction( GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj ) ); ::tools::Rectangle aRect( pObj->GetLogicRect() ); aRect.SetSize( aSize ); pObj->SetLogicRect( aRect ); bOK = true; } } } if( bOK ) { pUndoGroup->SetComment(SdResId(STR_UNDO_ORIGINALSIZE)); mpDocSh->GetUndoManager()->AddUndoAction(std::move(pUndoGroup)); } } /** * Connect OLE object to client. */ void View::DoConnect(SdrOle2Obj* pObj) { if (!mpViewSh) return; uno::Reference < embed::XEmbeddedObject > xObj( pObj->GetObjRef() ); if( !xObj.is() ) return; ::sd::Window* pWindow = mpViewSh->GetActiveWindow(); SfxInPlaceClient* pSdClient = mpViewSh-> GetViewShellBase().FindIPClient( xObj, pWindow ); if ( pSdClient ) return; pSdClient = new Client(pObj, mpViewSh, pWindow); ::tools::Rectangle aRect = pObj->GetLogicRect(); { // TODO/LEAN: working with visual area can switch object to running state Size aDrawSize = aRect.GetSize(); MapMode aMapMode( mrDoc.GetScaleUnit() ); Size aObjAreaSize = pObj->GetOrigObjSize( &aMapMode ); Fraction aScaleWidth (aDrawSize.Width(), aObjAreaSize.Width() ); Fraction aScaleHeight(aDrawSize.Height(), aObjAreaSize.Height() ); aScaleWidth.ReduceInaccurate(10); // compatible to SdrOle2Obj aScaleHeight.ReduceInaccurate(10); pSdClient->SetSizeScale(aScaleWidth, aScaleHeight); // visible area is only changed in-place! // the object area must be set after the scaling, since it triggers resize aRect.SetSize(aObjAreaSize); pSdClient->SetObjArea(aRect); } } bool View::IsMorphingAllowed() const { const SdrMarkList& rMarkList = GetMarkedObjectList(); bool bRet = false; if ( rMarkList.GetMarkCount() == 2 ) { const SdrObject* pObj1 = rMarkList.GetMark( 0 )->GetMarkedSdrObj(); const SdrObject* pObj2 = rMarkList.GetMark( 1 )->GetMarkedSdrObj(); const SdrObjKind nKind1 = pObj1->GetObjIdentifier(); const SdrObjKind nKind2 = pObj2->GetObjIdentifier(); if ( ( nKind1 != SdrObjKind::Text && nKind2 != SdrObjKind::Text ) && ( nKind1 != SdrObjKind::TitleText && nKind2 != SdrObjKind::TitleText ) && ( nKind1 != SdrObjKind::OutlineText && nKind2 != SdrObjKind::OutlineText ) && ( nKind1 != SdrObjKind::Group && nKind2 != SdrObjKind::Group ) && ( nKind1 != SdrObjKind::Line && nKind2 != SdrObjKind::Line ) && ( nKind1 != SdrObjKind::PolyLine && nKind2 != SdrObjKind::PolyLine ) && ( nKind1 != SdrObjKind::PathLine && nKind2 != SdrObjKind::PathLine ) && ( nKind1 != SdrObjKind::FreehandLine && nKind2 != SdrObjKind::FreehandLine ) && ( nKind1 != SdrObjKind::PathPolyLine && nKind2 != SdrObjKind::PathPolyLine ) && ( nKind1 != SdrObjKind::Measure && nKind2 != SdrObjKind::Measure ) && ( nKind1 != SdrObjKind::Edge && nKind2 != SdrObjKind::Edge ) && ( nKind1 != SdrObjKind::Graphic && nKind2 != SdrObjKind::Graphic ) && ( nKind1 != SdrObjKind::OLE2 && nKind2 != SdrObjKind::OLE2 ) && ( nKind1 != SdrObjKind::Caption && nKind2 != SdrObjKind::Caption ) && dynamic_cast< const E3dObject *>( pObj1 ) == nullptr && dynamic_cast< const E3dObject *>( pObj2 ) == nullptr ) { SfxItemSetFixed aSet1( mrDoc.GetPool() ); SfxItemSetFixed aSet2( mrDoc.GetPool() ); aSet1.Put(pObj1->GetMergedItemSet()); aSet2.Put(pObj2->GetMergedItemSet()); const drawing::FillStyle eFillStyle1 = aSet1.Get( XATTR_FILLSTYLE ).GetValue(); const drawing::FillStyle eFillStyle2 = aSet2.Get( XATTR_FILLSTYLE ).GetValue(); if( ( eFillStyle1 == drawing::FillStyle_NONE || eFillStyle1 == drawing::FillStyle_SOLID ) && ( eFillStyle2 == drawing::FillStyle_NONE || eFillStyle2 == drawing::FillStyle_SOLID ) ) bRet = true; } } return bRet; } bool View::IsVectorizeAllowed() const { const SdrMarkList& rMarkList = GetMarkedObjectList(); bool bRet = false; if( rMarkList.GetMarkCount() == 1 ) { const SdrGrafObj* pObj = dynamic_cast< const SdrGrafObj* >(rMarkList.GetMark( 0 )->GetMarkedSdrObj()); if(pObj) { if(GraphicType::Bitmap == pObj->GetGraphicType() && !pObj->isEmbeddedVectorGraphicData()) { bRet = true; } } } return bRet; } void View::onAccessibilityOptionsChanged() { if( !mpViewSh ) return; ::sd::Window* pWindow = mpViewSh->GetActiveWindow(); if( !pWindow ) return; const StyleSettings& rStyleSettings = pWindow->GetSettings().GetStyleSettings(); if( mpViewSh->GetViewFrame() && mpViewSh->GetViewFrame()->GetDispatcher() ) { sal_uInt16 nOutputSlot, nPreviewSlot; if( rStyleSettings.GetHighContrastMode() ) { nOutputSlot = SID_OUTPUT_QUALITY_CONTRAST; } else { nOutputSlot = SID_OUTPUT_QUALITY_COLOR; } if( rStyleSettings.GetHighContrastMode() && officecfg::Office::Common::Accessibility::IsForPagePreviews::get() ) { nPreviewSlot = SID_PREVIEW_QUALITY_CONTRAST; } else { nPreviewSlot = SID_PREVIEW_QUALITY_COLOR; } mpViewSh->GetViewFrame()->GetDispatcher()->Execute( nOutputSlot, SfxCallMode::ASYNCHRON ); mpViewSh->GetViewFrame()->GetDispatcher()->Execute( nPreviewSlot, SfxCallMode::ASYNCHRON ); } mpViewSh->Invalidate(); } IMPL_LINK( View, OnParagraphInsertedHdl, ::Outliner::ParagraphHdlParam, aParam, void ) { SdrObject* pObj = GetTextEditObject(); if( aParam.pPara && pObj ) { SdPage* pPage = dynamic_cast< SdPage* >( pObj->getSdrPageFromSdrObject() ); if( pPage ) pPage->onParagraphInserted( aParam.pOutliner, aParam.pPara, pObj ); } } /** * Handler for the deletion of the pages (paragraphs). */ IMPL_LINK( View, OnParagraphRemovingHdl, ::Outliner::ParagraphHdlParam, aParam, void ) { SdrObject* pObj = GetTextEditObject(); if( aParam.pPara && pObj ) { SdPage* pPage = dynamic_cast< SdPage* >( pObj->getSdrPageFromSdrObject() ); if( pPage ) pPage->onParagraphRemoving( aParam.pOutliner, aParam.pPara, pObj ); } } bool View::isRecordingUndo() const { if( mrDoc.IsUndoEnabled() ) { sd::UndoManager* pUndoManager = mrDoc.GetUndoManager(); return pUndoManager && pUndoManager->IsInListAction(); } else { return false; } } void View::AddCustomHdl() { maSmartTags.addCustomHandles( maHdlList ); } void View::updateHandles() { AdjustMarkHdl(); } SdrViewContext View::GetContext() const { SdrViewContext eContext = SdrViewContext::Standard; if( maSmartTags.getContext( eContext ) ) return eContext; else return FmFormView::GetContext(); } bool View::HasMarkablePoints() const { if( maSmartTags.HasMarkablePoints() ) return true; else return FmFormView::HasMarkablePoints(); } sal_Int32 View::GetMarkablePointCount() const { sal_Int32 nCount = FmFormView::GetMarkablePointCount(); nCount += maSmartTags.GetMarkablePointCount(); return nCount; } bool View::HasMarkedPoints() const { if( maSmartTags.HasMarkedPoints() ) return true; else return FmFormView::HasMarkedPoints(); } bool View::MarkPoint(SdrHdl& rHdl, bool bUnmark ) { if( maSmartTags.MarkPoint( rHdl, bUnmark ) ) return true; else return FmFormView::MarkPoint( rHdl, bUnmark ); } bool View::MarkPoints(const ::tools::Rectangle* pRect, bool bUnmark) { if( maSmartTags.MarkPoints( pRect, bUnmark ) ) return true; else return FmFormView::MarkPoints( pRect, bUnmark ); } void View::CheckPossibilities() { FmFormView::CheckPossibilities(); maSmartTags.CheckPossibilities(); } void View::OnBeginPasteOrDrop( PasteOrDropInfos* pInfo ) { SdrOutliner* pOutliner = GetTextEditOutliner(); if (!pOutliner) return; // Turn character attributes of the paragraph of the insert position into // character-level attributes, so they are not lost when OnEndPasteOrDrop() // sets the paragraph stylesheet. SfxItemSet aSet(pOutliner->GetParaAttribs(pInfo->nStartPara)); pOutliner->SetCharAttribs(pInfo->nStartPara, aSet); } /** this is called after a paste or drop operation, make sure that the newly inserted paragraphs get the correct style sheet. */ void View::OnEndPasteOrDrop( PasteOrDropInfos* pInfo ) { /* Style Sheet handling */ SdrTextObj* pTextObj = GetTextEditObject(); SdrOutliner* pOutliner = GetTextEditOutliner(); if( !pOutliner || !pTextObj || !pTextObj->getSdrPageFromSdrObject() ) return; SdPage* pPage = static_cast< SdPage* >( pTextObj->getSdrPageFromSdrObject() ); const PresObjKind eKind = pPage->GetPresObjKind(pTextObj); // outline kinds are taken care of in Outliner::ImplSetLevelDependentStyleSheet if( eKind == PresObjKind::Outline ) return; SfxStyleSheet* pStyleSheet = nullptr; if( eKind != PresObjKind::NONE ) pStyleSheet = pPage->GetStyleSheetForPresObj(eKind); else pStyleSheet = pTextObj->GetStyleSheet(); // just put the object style on each new paragraph for ( sal_Int32 nPara = pInfo->nStartPara; nPara <= pInfo->nEndPara; nPara++ ) { pOutliner->SetStyleSheet( nPara, pStyleSheet ); } } bool View::ShouldToggleOn( const bool bBulletOnOffMode, const bool bNormalBullet) { // If setting bullets/numbering by the dialog, always should toggle on. if (!bBulletOnOffMode) return true; SdrModel* pSdrModel = GetModel(); if (!pSdrModel) return false; bool bToggleOn = false; std::unique_ptr pOutliner(SdrMakeOutliner(OutlinerMode::TextObject, *pSdrModel)); const size_t nMarkCount = GetMarkedObjectCount(); for (size_t nIndex = 0; nIndex < nMarkCount && !bToggleOn; ++nIndex) { SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >(GetMarkedObjectByIndex(nIndex)); if (!pTextObj || pTextObj->IsTextEditActive()) continue; if( dynamic_cast< const SdrTableObj *>( pTextObj ) != nullptr) { SdrTableObj* pTableObj = dynamic_cast< SdrTableObj* >(pTextObj); if (!pTableObj) continue; CellPos aStart, aEnd; SvxTableController* pTableController = dynamic_cast< SvxTableController* >(getSelectionController().get()); if (pTableController) { pTableController->getSelectedCells(aStart, aEnd); } else { aStart = SdrTableObj::getFirstCell(); aEnd = pTableObj->getLastCell(); } sal_Int32 nColCount = pTableObj->getColumnCount(); for (sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow && !bToggleOn; nRow++) { for (sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol && !bToggleOn; nCol++) { sal_Int32 nCellIndex = nRow * nColCount + nCol; SdrText* pText = pTableObj->getText(nCellIndex); if (!pText || !pText->GetOutlinerParaObject()) continue; pOutliner->SetText(*(pText->GetOutlinerParaObject())); sal_Int16 nStatus = pOutliner->GetBulletsNumberingStatus(); bToggleOn = (bNormalBullet && nStatus != 0) || (!bNormalBullet && nStatus != 1); pOutliner->Clear(); } } } else { OutlinerParaObject* pParaObj = pTextObj->GetOutlinerParaObject(); if (!pParaObj) continue; pOutliner->SetText(*pParaObj); sal_Int16 nStatus = pOutliner->GetBulletsNumberingStatus(); bToggleOn = (bNormalBullet && nStatus != 0) || (!bNormalBullet && nStatus != 1); pOutliner->Clear(); } } return bToggleOn; } void View::ChangeMarkedObjectsBulletsNumbering( const bool bToggle, const bool bHandleBullets, const SvxNumRule* pNumRule ) { SdrModel* pSdrModel = GetModel(); OutputDevice* pOut = GetFirstOutputDevice(); vcl::Window* pWindow = pOut ? pOut->GetOwnerWindow() : nullptr; if (!pSdrModel || !pWindow) return; const bool bUndoEnabled = pSdrModel->IsUndoEnabled(); std::unique_ptr pUndoGroup(bUndoEnabled ? new SdrUndoGroup(*pSdrModel) : nullptr); const bool bToggleOn = ShouldToggleOn( bToggle, bHandleBullets ); std::unique_ptr pOutliner(SdrMakeOutliner(OutlinerMode::TextObject, *pSdrModel)); OutlinerView aOutlinerView(pOutliner.get(), pWindow); const size_t nMarkCount = GetMarkedObjectCount(); for (size_t nIndex = 0; nIndex < nMarkCount; ++nIndex) { SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >(GetMarkedObjectByIndex(nIndex)); if (!pTextObj || pTextObj->IsTextEditActive()) continue; if( dynamic_cast< SdrTableObj *>( pTextObj ) != nullptr) { SdrTableObj* pTableObj = dynamic_cast< SdrTableObj* >(pTextObj); if (!pTableObj) continue; CellPos aStart, aEnd; SvxTableController* pTableController = dynamic_cast< SvxTableController* >(getSelectionController().get()); if (pTableController) { pTableController->getSelectedCells(aStart, aEnd); } else { aStart = SdrTableObj::getFirstCell(); aEnd = pTableObj->getLastCell(); } sal_Int32 nColCount = pTableObj->getColumnCount(); for (sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++) { for (sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++) { sal_Int32 nCellIndex = nRow * nColCount + nCol; SdrText* pText = pTableObj->getText(nCellIndex); if (!pText || !pText->GetOutlinerParaObject()) continue; pOutliner->SetText(*(pText->GetOutlinerParaObject())); if (bUndoEnabled) { pUndoGroup->AddAction(pSdrModel->GetSdrUndoFactory().CreateUndoObjectSetText(*pTextObj, nCellIndex)); } if ( !bToggleOn ) { aOutlinerView.SwitchOffBulletsNumbering(); } else { aOutlinerView.ApplyBulletsNumbering( bHandleBullets, pNumRule, bToggle ); } sal_uInt32 nParaCount = pOutliner->GetParagraphCount(); pText->SetOutlinerParaObject(pOutliner->CreateParaObject(0, static_cast(nParaCount))); pOutliner->Clear(); } } // Broadcast the object change event. if (!pTextObj->AdjustTextFrameWidthAndHeight()) { pTextObj->SetChanged(); pTextObj->BroadcastObjectChange(); } } else { OutlinerParaObject* pParaObj = pTextObj->GetOutlinerParaObject(); if (!pParaObj) continue; pOutliner->SetText(*pParaObj); if (bUndoEnabled) { pUndoGroup->AddAction( pSdrModel->GetSdrUndoFactory().CreateUndoObjectSetText(*pTextObj, 0)); } if ( !bToggleOn ) { aOutlinerView.SwitchOffBulletsNumbering(); } else { aOutlinerView.ApplyBulletsNumbering( bHandleBullets, pNumRule, bToggle ); } sal_uInt32 nParaCount = pOutliner->GetParagraphCount(); pTextObj->SetOutlinerParaObject(pOutliner->CreateParaObject(0, static_cast(nParaCount))); pOutliner->Clear(); } } if ( bUndoEnabled && pUndoGroup->GetActionCount() > 0 ) { pSdrModel->BegUndo(); pSdrModel->AddUndo(std::move(pUndoGroup)); pSdrModel->EndUndo(); } } } // end of namespace sd /* vim:set shiftwidth=4 softtabstop=4 expandtab: */