/* -*- 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 // Imp->SetFirstVisPageInvalid() #include #include #include #include // _SetGetExpFld #include // PostItFld /-Type #include #include #include // SwPrintData #include #include // for RES_POOLPAGE_JAKET #include // for accessing status bar #include // -- " -- #include #include #include // MinPrtLine #include // SwShellCrsr #include // SwFmtPageDesc #include using namespace ::com::sun::star; /// Painting buffer class SwQueuedPaint { public: SwQueuedPaint *pNext; ViewShell *pSh; SwRect aRect; SwQueuedPaint( ViewShell *pNew, const SwRect &rRect ) : pNext( 0 ), pSh( pNew ), aRect( rRect ) {} }; SwQueuedPaint *SwPaintQueue::pQueue = 0; // saves some settings from the draw view class SwDrawViewSave { String sLayerNm; SdrView* pDV; sal_Bool bPrintControls; public: SwDrawViewSave( SdrView* pSdrView ); ~SwDrawViewSave(); }; void SwPaintQueue::Add( ViewShell *pNew, const SwRect &rNew ) { SwQueuedPaint *pPt; if ( 0 != (pPt = pQueue) ) { while ( pPt->pSh != pNew && pPt->pNext ) pPt = pPt->pNext; if ( pPt->pSh == pNew ) { pPt->aRect.Union( rNew ); return; } } SwQueuedPaint *pNQ = new SwQueuedPaint( pNew, rNew ); if ( pPt ) pPt->pNext = pNQ; else pQueue = pNQ; } void SwPaintQueue::Repaint() { if ( !SwRootFrm::IsInPaint() && pQueue ) { SwQueuedPaint *pPt = pQueue; do { ViewShell *pSh = pPt->pSh; SET_CURR_SHELL( pSh ); if ( pSh->IsPreView() ) { if ( pSh->GetWin() ) { // for previewing, since rows/columns are known in PaintHdl (UI) pSh->GetWin()->Invalidate(); pSh->GetWin()->Update(); } } else pSh->Paint( pPt->aRect.SVRect() ); pPt = pPt->pNext; } while ( pPt ); do { pPt = pQueue; pQueue = pQueue->pNext; delete pPt; } while ( pQueue ); } } void SwPaintQueue::Remove( ViewShell *pSh ) { SwQueuedPaint *pPt; if ( 0 != (pPt = pQueue) ) { SwQueuedPaint *pPrev = 0; while ( pPt && pPt->pSh != pSh ) { pPrev = pPt; pPt = pPt->pNext; } if ( pPt ) { if ( pPrev ) pPrev->pNext = pPt->pNext; else if ( pPt == pQueue ) pQueue = 0; delete pPt; } } } void SetSwVisArea( ViewShell *pSh, const SwRect &rRect, sal_Bool /*bPDFExport*/ ) { OSL_ENSURE( !pSh->GetWin(), "Drucken mit Window?" ); pSh->maVisArea = rRect; pSh->Imp()->SetFirstVisPageInvalid(); Point aPt( rRect.Pos() ); // calculate an offset for the rectangle of the n-th page to // move the start point of the output operation to a position // such that in the output device all pages will be painted // at the same position aPt.X() = -aPt.X(); aPt.Y() = -aPt.Y(); OutputDevice *pOut = pSh->GetOut(); MapMode aMapMode( pOut->GetMapMode() ); aMapMode.SetOrigin( aPt ); pOut->SetMapMode( aMapMode ); } void ViewShell::InitPrt( OutputDevice *pOutDev ) { // For printing we use a negative offset (exactly the offset of OutputSize). // This is necessary because the origin is in the upper left corner of the // physical page while the output uses OutputOffset as origin. if ( pOutDev ) { maPrtOffst = Point(); maPrtOffst += pOutDev->GetMapMode().GetOrigin(); MapMode aMapMode( pOutDev->GetMapMode() ); aMapMode.SetMapUnit( MAP_TWIP ); pOutDev->SetMapMode( aMapMode ); pOutDev->SetLineColor(); pOutDev->SetFillColor(); } else maPrtOffst.X() = maPrtOffst.Y() = 0; if ( !mpWin ) mpOut = pOutDev; } void ViewShell::ChgAllPageOrientation( sal_uInt16 eOri ) { OSL_ENSURE( mnStartAction, "missing an Action" ); SET_CURR_SHELL( this ); sal_uInt16 nAll = GetDoc()->GetPageDescCnt(); sal_Bool bNewOri = Orientation(eOri) == ORIENTATION_PORTRAIT ? sal_False : sal_True; for( sal_uInt16 i = 0; i < nAll; ++ i ) { const SwPageDesc& rOld = GetDoc()->GetPageDesc( i ); if( rOld.GetLandscape() != bNewOri ) { SwPageDesc aNew( rOld ); { ::sw::UndoGuard const ug(GetDoc()->GetIDocumentUndoRedo()); GetDoc()->CopyPageDesc(rOld, aNew); } aNew.SetLandscape( bNewOri ); SwFrmFmt& rFmt = aNew.GetMaster(); SwFmtFrmSize aSz( rFmt.GetFrmSize() ); // adjust size // PORTRAIT -> higher than wide // LANDSCAPE -> wider than high // Height is the VarSize, width the FixSize (per Def.) if( bNewOri ? aSz.GetHeight() > aSz.GetWidth() : aSz.GetHeight() < aSz.GetWidth() ) { SwTwips aTmp = aSz.GetHeight(); aSz.SetHeight( aSz.GetWidth() ); aSz.SetWidth( aTmp ); rFmt.SetFmtAttr( aSz ); } GetDoc()->ChgPageDesc( i, aNew ); } } } void ViewShell::ChgAllPageSize( Size &rSz ) { OSL_ENSURE( mnStartAction, "missing an Action" ); SET_CURR_SHELL( this ); SwDoc* pMyDoc = GetDoc(); sal_uInt16 nAll = pMyDoc->GetPageDescCnt(); for( sal_uInt16 i = 0; i < nAll; ++i ) { const SwPageDesc &rOld = pMyDoc->GetPageDesc( i ); SwPageDesc aNew( rOld ); { ::sw::UndoGuard const ug(GetDoc()->GetIDocumentUndoRedo()); GetDoc()->CopyPageDesc( rOld, aNew ); } SwFrmFmt& rPgFmt = aNew.GetMaster(); Size aSz( rSz ); const sal_Bool bOri = aNew.GetLandscape(); if( bOri ? aSz.Height() > aSz.Width() : aSz.Height() < aSz.Width() ) { SwTwips aTmp = aSz.Height(); aSz.Height() = aSz.Width(); aSz.Width() = aTmp; } SwFmtFrmSize aFrmSz( rPgFmt.GetFrmSize() ); aFrmSz.SetSize( aSz ); rPgFmt.SetFmtAttr( aFrmSz ); pMyDoc->ChgPageDesc( i, aNew ); } } void ViewShell::CalcPagesForPrint( sal_uInt16 nMax ) { SET_CURR_SHELL( this ); SwRootFrm* pMyLayout = GetLayout(); const SwFrm *pPage = pMyLayout->Lower(); SwLayAction aAction( pMyLayout, Imp() ); pMyLayout->StartAllAction(); for ( sal_uInt16 i = 1; pPage && i <= nMax; pPage = pPage->GetNext(), ++i ) { pPage->Calc(); SwRect aOldVis( VisArea() ); maVisArea = pPage->Frm(); Imp()->SetFirstVisPageInvalid(); aAction.Reset(); aAction.SetPaint( sal_False ); aAction.SetWaitAllowed( sal_False ); aAction.SetReschedule( sal_True ); aAction.Action(); maVisArea = aOldVis; //reset due to the paints Imp()->SetFirstVisPageInvalid(); } pMyLayout->EndAllAction(); } SwDoc * ViewShell::FillPrtDoc( SwDoc *pPrtDoc, const SfxPrinter* pPrt) { OSL_ENSURE( this->IsA( TYPE(SwFEShell) ),"ViewShell::Prt for FEShell only"); SwFEShell* pFESh = (SwFEShell*)this; pPrtDoc->LockExpFlds(); // use given printer //! Make a copy of it since it gets destroyed with the temporary document //! used for PDF export if (pPrt) pPrtDoc->setPrinter( new SfxPrinter(*pPrt), true, true ); const SfxPoolItem* pCpyItem; const SfxItemPool& rPool = GetAttrPool(); for( sal_uInt16 nWh = POOLATTR_BEGIN; nWh < POOLATTR_END; ++nWh ) if( 0 != ( pCpyItem = rPool.GetPoolDefaultItem( nWh ) ) ) pPrtDoc->GetAttrPool().SetPoolDefaultItem( *pCpyItem ); // JP 29.07.99 - Bug 67951 - set all Styles from the SourceDoc into // the PrintDoc - will be replaced! pPrtDoc->ReplaceStyles( *GetDoc() ); SwShellCrsr *pActCrsr = pFESh->_GetCrsr(); SwShellCrsr *pFirstCrsr = dynamic_cast(pActCrsr->GetNext()); if( !pActCrsr->HasMark() ) // with a multi-selection the current cursor might be empty { pActCrsr = dynamic_cast(pActCrsr->GetPrev()); } // Y-position of the first selection Point aSelPoint; if( pFESh->IsTableMode() ) { SwShellTableCrsr* pShellTblCrsr = pFESh->GetTableCrsr(); const SwCntntNode* pCntntNode = pShellTblCrsr->GetNode()->GetCntntNode(); const SwCntntFrm *pCntntFrm = pCntntNode ? pCntntNode->getLayoutFrm( GetLayout(), 0, pShellTblCrsr->Start() ) : 0; if( pCntntFrm ) { SwRect aCharRect; SwCrsrMoveState aTmpState( MV_NONE ); pCntntFrm->GetCharRect( aCharRect, *pShellTblCrsr->Start(), &aTmpState ); aSelPoint = Point( aCharRect.Left(), aCharRect.Top() ); } } else { aSelPoint = pFirstCrsr->GetSttPos(); } const SwPageFrm* pPage = GetLayout()->GetPageAtPos( aSelPoint ); OSL_ENSURE( pPage, "no page found!" ); // get page descriptor - fall back to the first one if pPage could not be found const SwPageDesc* pPageDesc = pPage ? pPrtDoc->FindPageDesc( pPage->GetPageDesc()->GetName() ) : &pPrtDoc->GetPageDesc( (sal_uInt16)0 ); if( !pFESh->IsTableMode() && pActCrsr->HasMark() ) { // Am letzten Absatz die Absatzattribute richten: SwNodeIndex aNodeIdx( *pPrtDoc->GetNodes().GetEndOfContent().StartOfSectionNode() ); SwTxtNode* pTxtNd = pPrtDoc->GetNodes().GoNext( &aNodeIdx )->GetTxtNode(); SwCntntNode *pLastNd = pActCrsr->GetCntntNode( (*pActCrsr->GetMark()) <= (*pActCrsr->GetPoint()) ); // Hier werden die Absatzattribute des ersten Absatzes uebertragen if( pLastNd && pLastNd->IsTxtNode() ) ((SwTxtNode*)pLastNd)->CopyCollFmt( *pTxtNd ); } // fill it with the selected content pFESh->Copy( pPrtDoc ); // set the page template at the first paragraph { SwNodeIndex aNodeIdx( *pPrtDoc->GetNodes().GetEndOfContent().StartOfSectionNode() ); SwCntntNode* pCNd = pPrtDoc->GetNodes().GoNext( &aNodeIdx ); // go to 1st ContentNode if( pFESh->IsTableMode() ) { SwTableNode* pTNd = pCNd->FindTableNode(); if( pTNd ) pTNd->GetTable().GetFrmFmt()->SetFmtAttr( SwFmtPageDesc( pPageDesc ) ); } else { pCNd->SetAttr( SwFmtPageDesc( pPageDesc ) ); if( pFirstCrsr->HasMark() ) { SwTxtNode *pTxtNd = pCNd->GetTxtNode(); if( pTxtNd ) { SwCntntNode *pFirstNd = pFirstCrsr->GetCntntNode( (*pFirstCrsr->GetMark()) > (*pFirstCrsr->GetPoint()) ); // copy paragraph attributes of the first paragraph if( pFirstNd && pFirstNd->IsTxtNode() ) ((SwTxtNode*)pFirstNd)->CopyCollFmt( *pTxtNd ); } } } } return pPrtDoc; } // TODO: there is already a GetPageByPageNum, but it checks some physical page // number; unsure if we want that here, should find out what that is... SwPageFrm const* sw_getPage(SwRootFrm const& rLayout, sal_Int32 const nPage) { // yes this is O(n^2) but at least it does not crash... SwPageFrm const* pPage = dynamic_cast(rLayout.Lower()); for (sal_Int32 i = nPage; pPage && (i > 0); --i) { if (1 == i) { // note: nPage is 1-based, i.e. 0 is invalid! return pPage; } pPage = dynamic_cast(pPage->GetNext()); } OSL_ENSURE(pPage, "ERROR: SwPageFrm expected"); OSL_FAIL("non-existent page requested"); return 0; } sal_Bool ViewShell::PrintOrPDFExport( OutputDevice *pOutDev, SwPrintData const& rPrintData, sal_Int32 nRenderer /* the index in the vector of pages to be printed */ ) { // CAUTION: Do also always update the printing routines in viewpg.cxx (PrintProspect)! const sal_Int32 nMaxRenderer = rPrintData.GetRenderData().GetPagesToPrint().size() - 1; OSL_ENSURE( 0 <= nRenderer && nRenderer <= nMaxRenderer, "nRenderer out of bounds"); if (!pOutDev || nMaxRenderer < 0 || nRenderer < 0 || nRenderer > nMaxRenderer) return sal_False; // save settings of OutputDevice (should be done always since the // output device is now provided by a call from outside the Writer) pOutDev->Push(); // Print/PDF export for (multi-)selection has already generated a // temporary document with the selected text. // (see XRenderable implementation in unotxdoc.cxx) // It is implemented this way because PDF export calls this Prt function // once per page and we do not like to always have the temporary document // to be created that often here. ViewShell *pShell = new ViewShell( *this, 0, pOutDev ); SdrView *pDrawView = pShell->GetDrawView(); if (pDrawView) { pDrawView->SetBufferedOutputAllowed( false ); pDrawView->SetBufferedOverlayAllowed( false ); } { // additional scope so that the CurrShell is reset before destroying the shell SET_CURR_SHELL( pShell ); //JP 01.02.99: Bug 61335 - the ReadOnly flag is never copied if( mpOpt->IsReadonly() ) pShell->mpOpt->SetReadonly( sal_True ); // save options at draw view: SwDrawViewSave aDrawViewSave( pShell->GetDrawView() ); pShell->PrepareForPrint( rPrintData ); const sal_Int32 nPage = rPrintData.GetRenderData().GetPagesToPrint()[ nRenderer ]; OSL_ENSURE( nPage < 0 || rPrintData.GetRenderData().GetValidPagesSet().count( nPage ) == 1, "ViewShell::PrintOrPDFExport: nPage not valid" ); ViewShell *const pViewSh2 = (nPage < 0) ? rPrintData.GetRenderData().m_pPostItShell.get()// post-it page : pShell; // a 'regular' page, not one from the post-it doc SwPageFrm const*const pStPage = sw_getPage(*pViewSh2->GetLayout(), abs(nPage)); OSL_ENSURE( pStPage, "failed to get start page" ); if (!pStPage) { return sal_False; } //!! applying view options and formatting the document should now only be done in getRendererCount! ::SetSwVisArea( pViewSh2, pStPage->Frm() ); pShell->InitPrt( pOutDev ); ::SetSwVisArea( pViewSh2, pStPage->Frm() ); pStPage->GetUpper()->Paint( pStPage->Frm(), &rPrintData ); SwPaintQueue::Repaint(); } delete pShell; // restore settings of OutputDevice (should be done always now since the // output device is now provided by a call from outside the Writer) pOutDev->Pop(); return sal_True; } void ViewShell::PrtOle2( SwDoc *pDoc, const SwViewOption *pOpt, const SwPrintData& rOptions, OutputDevice* pOleOut, const Rectangle& rRect ) { // For printing a shell is needed. Either the Doc already has one, than we // create a new view, or it has none, than we create the first view. ViewShell *pSh; if( pDoc->GetCurrentViewShell() ) pSh = new ViewShell( *pDoc->GetCurrentViewShell(), 0, pOleOut,VSHELLFLAG_SHARELAYOUT );//swmod 080129 else //swmod 071108//swmod 071225 pSh = new ViewShell( *pDoc, 0, pOpt, pOleOut);//swmod 080129 { SET_CURR_SHELL( pSh ); pSh->PrepareForPrint( rOptions ); pSh->SetPrtFormatOption( sal_True ); SwRect aSwRect( rRect ); pSh->maVisArea = aSwRect; if ( pSh->GetViewOptions()->getBrowseMode() && pSh->GetNext() == pSh ) { pSh->CheckBrowseView( sal_False ); pSh->GetLayout()->Lower()->InvalidateSize(); } // CalcPagesForPrint() should not be necessary here. The pages in the // visible area will be formatted in SwRootFrm::Paint(). // Removing this gives us a performance gain during saving the // document because the thumbnail creation will not trigger a complete // formatting of the document. //#39275# now Meyer wants again a Clipping pOleOut->Push( PUSH_CLIPREGION ); pOleOut->IntersectClipRegion( aSwRect.SVRect() ); pSh->GetLayout()->Paint( aSwRect ); pOleOut->Pop(); // first the CurrShell object needs to be destroyed! } delete pSh; } /// Check if the DocNodesArray contains fields. sal_Bool ViewShell::IsAnyFieldInDoc() const { const SfxPoolItem* pItem; sal_uInt32 nMaxItems = mpDoc->GetAttrPool().GetItemCount2( RES_TXTATR_FIELD ); for( sal_uInt32 n = 0; n < nMaxItems; ++n ) if( 0 != (pItem = mpDoc->GetAttrPool().GetItem2( RES_TXTATR_FIELD, n ))) { const SwFmtFld* pFmtFld = (SwFmtFld*)pItem; const SwTxtFld* pTxtFld = pFmtFld->GetTxtFld(); //#i101026# mod: do not include postits in field check const SwField* pFld = pFmtFld->GetFld(); if( pTxtFld && pTxtFld->GetTxtNode().GetNodes().IsDocNodes() && (pFld->Which() != RES_POSTITFLD)) return sal_True; } return sal_False; } /// Saves some settings at the draw view SwDrawViewSave::SwDrawViewSave( SdrView* pSdrView ) : pDV( pSdrView ) { if ( pDV ) { sLayerNm.AssignAscii( RTL_CONSTASCII_STRINGPARAM("Controls" ) ); bPrintControls = pDV->IsLayerPrintable( sLayerNm ); } } SwDrawViewSave::~SwDrawViewSave() { if ( pDV ) { pDV->SetLayerPrintable( sLayerNm, bPrintControls ); } } // OD 09.01.2003 #i6467# - method also called for page preview void ViewShell::PrepareForPrint( const SwPrintData &rOptions ) { mpOpt->SetGraphic ( sal_True == rOptions.bPrintGraphic ); mpOpt->SetTable ( sal_True == rOptions.bPrintTable ); mpOpt->SetDraw ( sal_True == rOptions.bPrintDraw ); mpOpt->SetControl ( sal_True == rOptions.bPrintControl ); mpOpt->SetPageBack( sal_True == rOptions.bPrintPageBackground ); mpOpt->SetBlackFont( sal_True == rOptions.bPrintBlackFont ); if ( HasDrawView() ) { SdrView *pDrawView = GetDrawView(); String sLayerNm; sLayerNm.AssignAscii(RTL_CONSTASCII_STRINGPARAM("Controls" )); // OD 09.01.2003 #i6467# - consider, if view shell belongs to page preview if ( !IsPreView() ) { pDrawView->SetLayerPrintable( sLayerNm, rOptions.bPrintControl ); } else { pDrawView->SetLayerVisible( sLayerNm, rOptions.bPrintControl ); } } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */