diff options
Diffstat (limited to 'sw/source/uibase/uiview')
22 files changed, 18314 insertions, 0 deletions
diff --git a/sw/source/uibase/uiview/formatclipboard.cxx b/sw/source/uibase/uiview/formatclipboard.cxx new file mode 100644 index 000000000..16e72e40b --- /dev/null +++ b/sw/source/uibase/uiview/formatclipboard.cxx @@ -0,0 +1,579 @@ +/* -*- 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 <memory> +#include <utility> + +#include <formatclipboard.hxx> + +#include <cmdid.h> +#include <charfmt.hxx> +#include <frmfmt.hxx> +#include <docstyle.hxx> +#include <fchrfmt.hxx> +#include <svx/svdview.hxx> +#include <editeng/brushitem.hxx> +#include <editeng/shaditem.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/formatbreakitem.hxx> +#include <fmtlsplt.hxx> +#include <editeng/keepitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <fmtpdsc.hxx> +#include <fmtrowsplt.hxx> +#include <frmatr.hxx> + +namespace +{ + +std::unique_ptr<SfxItemSet> lcl_CreateEmptyItemSet( SelectionType nSelectionType, SfxItemPool& rPool, bool bNoParagraphFormats = false ) +{ + std::unique_ptr<SfxItemSet> pItemSet; + if( nSelectionType & (SelectionType::Frame | SelectionType::Ole | SelectionType::Graphic) ) + { + pItemSet = std::make_unique<SfxItemSetFixed< + RES_FRMATR_BEGIN, RES_FILL_ORDER, + // no RES_FRM_SIZE + RES_PAPER_BIN, RES_SURROUND, + // no RES_VERT_ORIENT + // no RES_HORI_ORIENT + // no RES_ANCHOR + RES_BACKGROUND, RES_SHADOW, + // no RES_FRMMACRO + RES_COL, RES_KEEP, + // no RES_URL + RES_EDIT_IN_READONLY, RES_LAYOUT_SPLIT, + // no RES_CHAIN + RES_TEXTGRID, RES_FRMATR_END - 1>>(rPool); + } + else if( nSelectionType & SelectionType::DrawObject ) + { + //is handled different + } + else if( nSelectionType & SelectionType::Text ) + { + if( bNoParagraphFormats ) + pItemSet = std::make_unique<SfxItemSetFixed + <RES_CHRATR_BEGIN, RES_CHRATR_END - 1>>(rPool); + else + pItemSet = std::make_unique<SfxItemSetFixed< + RES_CHRATR_BEGIN, RES_CHRATR_END - 1, + RES_PARATR_BEGIN, RES_FILL_ORDER, + // no RES_FRM_SIZE + RES_PAPER_BIN, RES_SURROUND, + // no RES_VERT_ORIENT + // no RES_HORI_ORIENT + // no RES_ANCHOR + RES_BACKGROUND, RES_SHADOW, + // no RES_FRMMACRO + RES_COL, RES_KEEP, + // no RES_URL + RES_EDIT_IN_READONLY, RES_LAYOUT_SPLIT, + // no RES_CHAIN + RES_TEXTGRID, RES_FRMATR_END - 1>>(rPool); + } + return pItemSet; +} + +void lcl_getTableAttributes( SfxItemSet& rSet, SwWrtShell &rSh ) +{ + std::unique_ptr<SvxBrushItem> aBrush(std::make_unique<SvxBrushItem>(RES_BACKGROUND)); + rSh.GetBoxBackground(aBrush); + rSet.Put( *aBrush ); + if(rSh.GetRowBackground(aBrush)) + { + aBrush->SetWhich(SID_ATTR_BRUSH_ROW); + rSet.Put( *aBrush ); + } + else + rSet.InvalidateItem(SID_ATTR_BRUSH_ROW); + rSh.GetTabBackground(aBrush); + aBrush->SetWhich(SID_ATTR_BRUSH_TABLE); + rSet.Put( *aBrush ); + + SvxBoxInfoItem aBoxInfo( SID_ATTR_BORDER_INNER ); + rSet.Put(aBoxInfo); + rSh.GetTabBorders( rSet ); + + std::unique_ptr<SvxFrameDirectionItem> aBoxDirection(std::make_unique<SvxFrameDirectionItem>(SvxFrameDirection::Environment, RES_FRAMEDIR)); + if(rSh.GetBoxDirection( aBoxDirection )) + { + aBoxDirection->SetWhich(FN_TABLE_BOX_TEXTORIENTATION); + rSet.Put(std::move(aBoxDirection)); + } + + rSet.Put(SfxUInt16Item(FN_TABLE_SET_VERT_ALIGN, rSh.GetBoxAlign())); + + rSet.Put( SfxUInt16Item( FN_PARAM_TABLE_HEADLINE, rSh.GetRowsToRepeat() ) ); + + SwFrameFormat *pFrameFormat = rSh.GetTableFormat(); + if(pFrameFormat) + { + rSet.Put( pFrameFormat->GetShadow() ); + rSet.Put( pFrameFormat->GetBreak() ); + rSet.Put( pFrameFormat->GetPageDesc() ); + rSet.Put( pFrameFormat->GetLayoutSplit() ); + rSet.Put( pFrameFormat->GetKeep() ); + rSet.Put( pFrameFormat->GetFrameDir() ); + } + + std::unique_ptr<SwFormatRowSplit> pSplit = rSh.GetRowSplit(); + if(pSplit) + rSet.Put(std::move(pSplit)); +} + +void lcl_setTableAttributes( const SfxItemSet& rSet, SwWrtShell &rSh ) +{ + bool bBorder = ( SfxItemState::SET == rSet.GetItemState( RES_BOX ) || + SfxItemState::SET == rSet.GetItemState( SID_ATTR_BORDER_INNER ) ); + const SvxBrushItem* pBackgroundItem = rSet.GetItemIfSet( RES_BACKGROUND, false ); + const SvxBrushItem* pRowItem = rSet.GetItemIfSet( SID_ATTR_BRUSH_ROW, false ); + const SvxBrushItem* pTableItem = rSet.GetItemIfSet( SID_ATTR_BRUSH_TABLE, false ); + bool bBackground = pBackgroundItem || pRowItem || pTableItem; + + if(bBackground) + { + if(pBackgroundItem) + rSh.SetBoxBackground( *pBackgroundItem ); + if(pRowItem) + { + std::unique_ptr<SvxBrushItem> aBrush(pRowItem->Clone()); + aBrush->SetWhich(RES_BACKGROUND); + rSh.SetRowBackground(*aBrush); + } + if(pTableItem) + { + std::unique_ptr<SvxBrushItem> aBrush(pTableItem->Clone()); + aBrush->SetWhich(RES_BACKGROUND); + rSh.SetTabBackground(*aBrush); + } + } + if(bBorder) + rSh.SetTabBorders( rSet ); + + if( const SfxUInt16Item* pHeadlineItem = rSet.GetItemIfSet( FN_PARAM_TABLE_HEADLINE, false) ) + rSh.SetRowsToRepeat( pHeadlineItem->GetValue() ); + + SwFrameFormat* pFrameFormat = rSh.GetTableFormat(); + if(pFrameFormat) + { + //RES_SHADOW + const SfxPoolItem* pItem = rSet.GetItemIfSet(rSet.GetPool()->GetWhich(RES_SHADOW), false); + if(pItem) + pFrameFormat->SetFormatAttr( *pItem ); + + //RES_BREAK + pItem = rSet.GetItemIfSet(rSet.GetPool()->GetWhich(RES_BREAK), false); + if(pItem) + pFrameFormat->SetFormatAttr( *pItem ); + + //RES_PAGEDESC + pItem = rSet.GetItemIfSet(rSet.GetPool()->GetWhich(RES_PAGEDESC), false); + if(pItem) + pFrameFormat->SetFormatAttr( *pItem ); + + //RES_LAYOUT_SPLIT + pItem = rSet.GetItemIfSet(rSet.GetPool()->GetWhich(RES_LAYOUT_SPLIT), false); + if(pItem) + pFrameFormat->SetFormatAttr( *pItem ); + + //RES_KEEP + pItem = rSet.GetItemIfSet(rSet.GetPool()->GetWhich(RES_KEEP), false); + if(pItem) + pFrameFormat->SetFormatAttr( *pItem ); + + //RES_FRAMEDIR + pItem = rSet.GetItemIfSet(rSet.GetPool()->GetWhich(RES_FRAMEDIR), false); + if(pItem) + pFrameFormat->SetFormatAttr( *pItem ); + } + + if( const SvxFrameDirectionItem* pTextOriItem = rSet.GetItemIfSet( FN_TABLE_BOX_TEXTORIENTATION, false ) ) + { + SvxFrameDirectionItem aDirection( SvxFrameDirection::Environment, RES_FRAMEDIR ); + aDirection.SetValue(pTextOriItem->GetValue()); + rSh.SetBoxDirection(aDirection); + } + + if( const SfxUInt16Item* pVertAlignItem = rSet.GetItemIfSet( FN_TABLE_SET_VERT_ALIGN, false )) + rSh.SetBoxAlign(pVertAlignItem->GetValue()); + + if( const SwFormatRowSplit* pSplitItem = rSet.GetItemIfSet( RES_ROW_SPLIT, false ) ) + rSh.SetRowSplit(*pSplitItem); +} +}//end anonymous namespace + +SwFormatClipboard::SwFormatClipboard() + : m_nSelectionType(SelectionType::NONE) + , m_bPersistentCopy(false) +{ +} + +bool SwFormatClipboard::HasContent() const +{ + return m_pItemSet_TextAttr!=nullptr + || m_pItemSet_ParAttr!=nullptr + || m_pTableItemSet != nullptr + || !m_aCharStyle.isEmpty() + || !m_aParaStyle.isEmpty() + ; +} +bool SwFormatClipboard::HasContentForThisType( SelectionType nSelectionType ) const +{ + if( !HasContent() ) + return false; + + if( m_nSelectionType == nSelectionType ) + return true; + + if( ( nSelectionType & (SelectionType::Frame | SelectionType::Ole | SelectionType::Graphic) ) + && + ( m_nSelectionType & (SelectionType::Frame | SelectionType::Ole | SelectionType::Graphic) ) + ) + return true; + + if( nSelectionType & SelectionType::Text && m_nSelectionType & SelectionType::Text ) + return true; + + return false; +} + +bool SwFormatClipboard::CanCopyThisType( SelectionType nSelectionType ) +{ + return bool(nSelectionType + & (SelectionType::Frame | SelectionType::Ole | SelectionType::Graphic + | SelectionType::Text | SelectionType::DrawObject | SelectionType::Table | SelectionType::TableCell )); +} + +void SwFormatClipboard::Copy( SwWrtShell& rWrtShell, SfxItemPool& rPool, bool bPersistentCopy ) +{ + // first clear the previously stored attributes + Erase(); + m_bPersistentCopy = bPersistentCopy; + + SelectionType nSelectionType = rWrtShell.GetSelectionType(); + auto pItemSet_TextAttr = lcl_CreateEmptyItemSet( nSelectionType, rPool, true ); + auto pItemSet_ParAttr = lcl_CreateEmptyItemSet( nSelectionType, rPool ); + + rWrtShell.StartAction(); + rWrtShell.Push(); + + // modify the "Point and Mark" of the cursor + // in order to select only the last character of the + // selection(s) and then to get the attributes of this single character + if( nSelectionType == SelectionType::Text ) + { + // get the current PaM, the cursor + // if there several selection it currently point + // on the last (sort by there creation time) selection + SwPaM* pCursor = rWrtShell.GetCursor(); + + bool bHasSelection = pCursor->HasMark(); + bool bForwardSelection = false; + + if(!bHasSelection && pCursor->IsMultiSelection()) + { + // if cursor has multiple selections + + // clear all the selections except the last + rWrtShell.KillPams(); + + // reset the cursor to the remaining selection + pCursor = rWrtShell.GetCursor(); + bHasSelection = true; + } + + bool dontMove = false; + if (bHasSelection) + { + bForwardSelection = (*pCursor->GetPoint()) > (*pCursor->GetMark()); + + // clear the selection leaving just the cursor + pCursor->DeleteMark(); + pCursor->SetMark(); + } + else + { + bool rightToLeft = rWrtShell.IsInRightToLeftText(); + // if there were no selection (only a cursor) and the cursor was at + // the end of the paragraph then don't move + if ( rWrtShell.IsEndPara() && !rightToLeft ) + dontMove = true; + + // revert left and right + if ( rightToLeft ) + { + if (pCursor->GetPoint()->nContent == 0) + dontMove = true; + else + bForwardSelection = !bForwardSelection; + } + } + + // move the cursor in order to select one character + if (!dontMove) + pCursor->Move( bForwardSelection ? fnMoveBackward : fnMoveForward ); + } + + if(pItemSet_TextAttr) + { + if( nSelectionType & (SelectionType::Frame | SelectionType::Ole | SelectionType::Graphic) ) + rWrtShell.GetFlyFrameAttr(*pItemSet_TextAttr); + else + { + // get the text attributes from named and automatic formatting + rWrtShell.GetCurAttr(*pItemSet_TextAttr); + + if( nSelectionType & SelectionType::Text ) + { + // get the paragraph attributes (could be character properties) + // from named and automatic formatting + rWrtShell.GetCurParAttr(*pItemSet_ParAttr); + } + } + } + else if ( nSelectionType & SelectionType::DrawObject ) + { + SdrView* pDrawView = rWrtShell.GetDrawView(); + if(pDrawView) + { + if( pDrawView->AreObjectsMarked() ) + { + pItemSet_TextAttr = std::make_unique<SfxItemSet>( pDrawView->GetAttrFromMarked(true/*bOnlyHardAttr*/) ); + //remove attributes defining the type/data of custom shapes + pItemSet_TextAttr->ClearItem(SDRATTR_CUSTOMSHAPE_ENGINE); + pItemSet_TextAttr->ClearItem(SDRATTR_CUSTOMSHAPE_DATA); + pItemSet_TextAttr->ClearItem(SDRATTR_CUSTOMSHAPE_GEOMETRY); + } + } + } + + if( nSelectionType & SelectionType::TableCell )//only copy table attributes if really cells are selected (not only text in tables) + { + m_pTableItemSet = std::make_unique<SfxItemSetFixed< + RES_PAGEDESC, RES_BREAK, + RES_BACKGROUND, RES_SHADOW, // RES_BOX is inbetween + RES_KEEP, RES_KEEP, + RES_LAYOUT_SPLIT, RES_LAYOUT_SPLIT, + RES_FRAMEDIR, RES_FRAMEDIR, + RES_ROW_SPLIT, RES_ROW_SPLIT, + SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_SHADOW, + // SID_ATTR_BORDER_OUTER is inbetween + SID_ATTR_BRUSH_ROW, SID_ATTR_BRUSH_TABLE, + FN_TABLE_SET_VERT_ALIGN, FN_TABLE_SET_VERT_ALIGN, + FN_TABLE_BOX_TEXTORIENTATION, FN_TABLE_BOX_TEXTORIENTATION, + FN_PARAM_TABLE_HEADLINE, FN_PARAM_TABLE_HEADLINE>>(rPool); + lcl_getTableAttributes( *m_pTableItemSet, rWrtShell ); + } + + m_nSelectionType = nSelectionType; + m_pItemSet_TextAttr = std::move(pItemSet_TextAttr); + m_pItemSet_ParAttr = std::move(pItemSet_ParAttr); + + if( nSelectionType & SelectionType::Text ) + { + // if text is selected save the named character format + SwFormat* pFormat = rWrtShell.GetCurCharFormat(); + if( pFormat ) + m_aCharStyle = pFormat->GetName(); + + // and the named paragraph format + pFormat = rWrtShell.GetCurTextFormatColl(); + if( pFormat ) + m_aParaStyle = pFormat->GetName(); + } + + rWrtShell.Pop(SwCursorShell::PopMode::DeleteCurrent); + rWrtShell.EndAction(); +} + +typedef std::vector< std::unique_ptr< SfxPoolItem > > ItemVector; +// collect all PoolItems from the applied styles +static void lcl_AppendSetItems( ItemVector& rItemVector, const SfxItemSet& rStyleAttrSet ) +{ + const WhichRangesContainer& pRanges = rStyleAttrSet.GetRanges(); + for(const auto & rPair : pRanges) + { + for ( sal_uInt16 nWhich = rPair.first; nWhich <= rPair.second; ++nWhich ) + { + const SfxPoolItem* pItem; + if( SfxItemState::SET == rStyleAttrSet.GetItemState( nWhich, false, &pItem ) ) + { + rItemVector.emplace_back( pItem->Clone() ); + } + } + } +} +// remove all items that are inherited from the styles +static void lcl_RemoveEqualItems( SfxItemSet& rTemplateItemSet, const ItemVector& rItemVector ) +{ + for( const auto& rItem : rItemVector ) + { + const SfxPoolItem* pItem; + if( SfxItemState::SET == rTemplateItemSet.GetItemState( rItem->Which(), true, &pItem ) && + *pItem == *rItem ) + { + rTemplateItemSet.ClearItem( rItem->Which() ); + } + } +} + +void SwFormatClipboard::Paste( SwWrtShell& rWrtShell, SfxStyleSheetBasePool* pPool + , bool bNoCharacterFormats, bool bNoParagraphFormats ) +{ + SelectionType nSelectionType = rWrtShell.GetSelectionType(); + if( !HasContentForThisType(nSelectionType) ) + { + if(!m_bPersistentCopy) + Erase(); + return; + } + + rWrtShell.StartAction(); + rWrtShell.StartUndo(SwUndoId::INSATTR); + + ItemVector aItemVector; + + if( nSelectionType & SelectionType::Text ) + { + // apply the named text and paragraph formatting + if( pPool ) + { + // if there is a named text format recorded and the user wants to apply it + if(!m_aCharStyle.isEmpty() && !bNoCharacterFormats ) + { + // look for the named text format in the pool + SwDocStyleSheet* pStyle = static_cast<SwDocStyleSheet*>(pPool->Find(m_aCharStyle, SfxStyleFamily::Char)); + + // if the style is found + if( pStyle ) + { + SwFormatCharFormat aFormat(pStyle->GetCharFormat()); + // store the attributes from this style in aItemVector in order + // not to apply them as automatic formatting attributes later in the code + lcl_AppendSetItems( aItemVector, aFormat.GetCharFormat()->GetAttrSet()); + + // apply the named format + rWrtShell.SetAttrItem( aFormat ); + } + } + + // if there is a named paragraph format recorded and the user wants to apply it + if(!m_aParaStyle.isEmpty() && !bNoParagraphFormats ) + { + // look for the named paragraph format in the pool + SwDocStyleSheet* pStyle = static_cast<SwDocStyleSheet*>(pPool->Find(m_aParaStyle, SfxStyleFamily::Para)); + if( pStyle ) + { + // store the attributes from this style in aItemVector in order + // not to apply them as automatic formatting attributes later in the code + lcl_AppendSetItems( aItemVector, pStyle->GetCollection()->GetAttrSet()); + + // apply the named format + rWrtShell.SetTextFormatColl( pStyle->GetCollection() ); + } + } + } + + // apply the paragraph automatic attributes + if ( m_pItemSet_ParAttr && m_pItemSet_ParAttr->Count() != 0 && !bNoParagraphFormats ) + { + // temporary SfxItemSet + std::unique_ptr<SfxItemSet> pTemplateItemSet(lcl_CreateEmptyItemSet( + nSelectionType, *m_pItemSet_ParAttr->GetPool())); + // no need to verify the existence of pTemplateItemSet as we + // know that here the selection type is SEL_TXT + + pTemplateItemSet->Put( *m_pItemSet_ParAttr ); + + // remove attribute that were applied by named text and paragraph formatting + lcl_RemoveEqualItems( *pTemplateItemSet, aItemVector ); + + // apply the paragraph automatic attributes to all the nodes in the selection + rWrtShell.SetAttrSet(*pTemplateItemSet); + + // store the attributes in aItemVector in order not to apply them as + // text automatic formatting attributes later in the code + lcl_AppendSetItems( aItemVector, *pTemplateItemSet); + } + } + + if(m_pItemSet_TextAttr) + { + if( nSelectionType & SelectionType::DrawObject ) + { + SdrView* pDrawView = rWrtShell.GetDrawView(); + if(pDrawView) + { + pDrawView->SetAttrToMarked(*m_pItemSet_TextAttr, true/*bReplaceAll*/); + } + } + else + { + // temporary SfxItemSet + std::unique_ptr<SfxItemSet> pTemplateItemSet(lcl_CreateEmptyItemSet( + nSelectionType, *m_pItemSet_TextAttr->GetPool(), true )); + + if(pTemplateItemSet) + { + // copy the stored automatic text attributes in a temporary SfxItemSet + pTemplateItemSet->Put( *m_pItemSet_TextAttr ); + + // only attributes that were not apply by named style attributes and automatic + // paragraph attributes should be applied + lcl_RemoveEqualItems( *pTemplateItemSet, aItemVector ); + + // apply the character automatic attributes + if( nSelectionType & (SelectionType::Frame | SelectionType::Ole | SelectionType::Graphic) ) + rWrtShell.SetFlyFrameAttr(*pTemplateItemSet); + else if ( !bNoCharacterFormats ) + rWrtShell.SetAttrSet(*pTemplateItemSet); + } + } + } + + if( m_pTableItemSet && nSelectionType & (SelectionType::Table | SelectionType::TableCell) ) + lcl_setTableAttributes( *m_pTableItemSet, rWrtShell ); + + rWrtShell.EndUndo(SwUndoId::INSATTR); + rWrtShell.EndAction(); + + if(!m_bPersistentCopy) + Erase(); +} + +void SwFormatClipboard::Erase() +{ + m_nSelectionType = SelectionType::NONE; + + m_pItemSet_TextAttr.reset(); + + m_pItemSet_ParAttr.reset(); + + m_pTableItemSet.reset(); + + if( !m_aCharStyle.isEmpty() ) + m_aCharStyle.clear(); + if( !m_aParaStyle.isEmpty() ) + m_aParaStyle.clear(); + + m_bPersistentCopy = false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/uiview/pview.cxx b/sw/source/uibase/uiview/pview.cxx new file mode 100644 index 000000000..4ae41bb68 --- /dev/null +++ b/sw/source/uibase/uiview/pview.cxx @@ -0,0 +1,1897 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <config_wasm_strip.h> + +#include <sfx2/objface.hxx> +#include <vcl/help.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <vcl/syswin.hxx> +#include <vcl/weld.hxx> + +#include <svl/whiter.hxx> +#include <svl/slstitm.hxx> +#include <svl/eitem.hxx> +#include <sfx2/printer.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/request.hxx> +#include <sfx2/dispatch.hxx> +#include <editeng/paperinf.hxx> +#include <svx/svdview.hxx> +#include <svx/zoomslideritem.hxx> +#include <tools/svborder.hxx> +#include <osl/diagnose.h> + +#include <globdoc.hxx> +#include <wdocsh.hxx> +#include <pvprtdat.hxx> +#include <swmodule.hxx> +#include <wrtsh.hxx> +#include <docsh.hxx> +#include <viewopt.hxx> +#include <doc.hxx> +#include <IDocumentDeviceAccess.hxx> +#include <pview.hxx> +#include <view.hxx> +#include <scroll.hxx> +#include <prtopt.hxx> +#include <usrpref.hxx> +#include "viewfunc.hxx" + +#include <helpids.h> +#include <cmdid.h> +#include <strings.hrc> + +#define ShellClass_SwPagePreview +#include <sfx2/msg.hxx> +#include <swslots.hxx> +#include <pagepreviewlayout.hxx> + +#include <svx/svxdlg.hxx> + +#include <memory> +#include <vcl/EnumContext.hxx> +#include <vcl/notebookbar/notebookbar.hxx> + +using namespace ::com::sun::star; +SFX_IMPL_NAMED_VIEWFACTORY(SwPagePreview, "PrintPreview") +{ + SFX_VIEW_REGISTRATION(SwDocShell); + SFX_VIEW_REGISTRATION(SwWebDocShell); + SFX_VIEW_REGISTRATION(SwGlobalDocShell); +} + +SFX_IMPL_INTERFACE(SwPagePreview, SfxViewShell) + +void SwPagePreview::InitInterface_Impl() +{ + GetStaticInterface()->RegisterPopupMenu("preview"); + GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_OBJECT, + SfxVisibilityFlags::Standard|SfxVisibilityFlags::Client|SfxVisibilityFlags::FullScreen|SfxVisibilityFlags::ReadonlyDoc, + ToolbarId::PView_Toolbox); +} + + +#define SWVIEWFLAGS SfxViewShellFlags::HAS_PRINTOPTIONS + +#define MIN_PREVIEW_ZOOM 25 +#define MAX_PREVIEW_ZOOM 600 + +static sal_uInt16 lcl_GetNextZoomStep(sal_uInt16 nCurrentZoom, bool bZoomIn) +{ + static const sal_uInt16 aZoomArr[] = + { + 25, 50, 75, 100, 150, 200, 400, 600 + }; + const int nZoomArrSize = static_cast<int>(SAL_N_ELEMENTS(aZoomArr)); + if (bZoomIn) + { + for(sal_uInt16 i : aZoomArr) + { + if(nCurrentZoom < i) + return i; + } + } + else + { + for(int i = nZoomArrSize - 1; i >= 0; --i) + { + if(nCurrentZoom > aZoomArr[i] || !i) + return aZoomArr[i]; + } + } + return bZoomIn ? MAX_PREVIEW_ZOOM : MIN_PREVIEW_ZOOM; +}; + +static void lcl_InvalidateZoomSlots(SfxBindings& rBindings) +{ + static sal_uInt16 const aInval[] = + { + SID_ATTR_ZOOM, SID_ZOOM_OUT, SID_ZOOM_IN, SID_ATTR_ZOOMSLIDER, FN_PREVIEW_ZOOM, FN_STAT_ZOOM, + 0 + }; + rBindings.Invalidate( aInval ); +} + +namespace { + +// At first the zoom dialog +class SwPreviewZoomDlg : public weld::GenericDialogController +{ + SwPagePreviewWin& m_rParent; + std::unique_ptr<weld::SpinButton> m_xRowEdit; + std::unique_ptr<weld::SpinButton> m_xColEdit; + +public: + SwPreviewZoomDlg(SwPagePreviewWin& rParent) + : GenericDialogController(rParent.GetFrameWeld(), "modules/swriter/ui/previewzoomdialog.ui", "PreviewZoomDialog") + , m_rParent(rParent) + , m_xRowEdit(m_xBuilder->weld_spin_button("rows")) + , m_xColEdit(m_xBuilder->weld_spin_button("cols")) + { + m_xRowEdit->set_value(rParent.GetRow()); + m_xColEdit->set_value(rParent.GetCol()); + } + + void execute() + { + if (run() == RET_OK) + { + m_rParent.CalcWish(sal_uInt8(m_xRowEdit->get_value()), sal_uInt8(m_xColEdit->get_value())); + } + } +}; + +} + +// all for SwPagePreviewWin +SwPagePreviewWin::SwPagePreviewWin( vcl::Window *pParent, SwPagePreview& rPView ) + : Window(pParent, WinBits(WB_CLIPCHILDREN)) + , mpViewShell(nullptr) + , mrView(rPView) + , mbCalcScaleForPreviewLayout(true) + , maPaintedPreviewDocRect(tools::Rectangle(0,0,0,0)) + , mpPgPreviewLayout(nullptr) +{ + GetOutDev()->SetOutDevViewType( OutDevViewType::PrintPreview ); + SetHelpId(HID_PAGEPREVIEW); + GetOutDev()->SetFillColor( GetBackground().GetColor() ); + GetOutDev()->SetLineColor( GetBackground().GetColor()); + SetMapMode( MapMode(MapUnit::MapTwip) ); + + const SwMasterUsrPref *pUsrPref = SW_MOD()->GetUsrPref(false); + mnRow = pUsrPref->GetPagePrevRow(); // 1 row + mnCol = pUsrPref->GetPagePrevCol(); // 1 column + mnSttPage = USHRT_MAX; +} + +SwPagePreviewWin::~SwPagePreviewWin() +{ +} + +void SwPagePreviewWin::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) +{ + if (!mpViewShell || !mpViewShell->GetLayout()) + return; + + if (USHRT_MAX == mnSttPage) // was never calculated ? (Init-Phase!) + { + // This is the size to which I always relate. + if (!maPxWinSize.Height() || !maPxWinSize.Width()) + maPxWinSize = GetOutputSizePixel(); + + tools::Rectangle aRect(rRenderContext.LogicToPixel(rRect)); + mpPgPreviewLayout->Prepare(1, Point(0,0), maPxWinSize, + mnSttPage, maPaintedPreviewDocRect); + SetSelectedPage(1); + mpPgPreviewLayout->Paint(rRenderContext, rRenderContext.PixelToLogic(aRect)); + SetPagePreview(mnRow, mnCol); + } + else + { + MapMode aMM(rRenderContext.GetMapMode()); + aMM.SetScaleX(maScale); + aMM.SetScaleY(maScale); + rRenderContext.SetMapMode(aMM); + mpPgPreviewLayout->GetParentViewShell().setOutputToWindow(true); + mpPgPreviewLayout->Paint(rRenderContext, rRect); + mpPgPreviewLayout->GetParentViewShell().setOutputToWindow(false); + } +} + +void SwPagePreviewWin::CalcWish( sal_uInt8 nNewRow, sal_uInt8 nNewCol ) +{ + if( !mpViewShell || !mpViewShell->GetLayout() ) + return; + + const sal_uInt8 nOldCol = mnCol; + mnRow = nNewRow; + mnCol = nNewCol; + const sal_uInt16 nPages = mnRow * mnCol; + const sal_uInt16 nLastSttPg = mrView.GetPageCount()+1 > nPages + ? mrView.GetPageCount()+1 - nPages : 0; + if( mnSttPage > nLastSttPg ) + mnSttPage = nLastSttPg; + + mpPgPreviewLayout->Init( mnCol, mnRow, maPxWinSize ); + mpPgPreviewLayout->Prepare( mnSttPage, Point(0,0), maPxWinSize, + mnSttPage, maPaintedPreviewDocRect ); + SetSelectedPage( mnSttPage ); + SetPagePreview(mnRow, mnCol); + maScale = GetMapMode().GetScaleX(); + + // If changes have taken place at the columns, the special case "single column" + // must be considered and corrected if necessary. + if( (1 == nOldCol) != (1 == mnCol) ) + mrView.ScrollDocSzChg(); + + // Order must be maintained! + // additional invalidate page status. + static sal_uInt16 aInval[] = + { + SID_ATTR_ZOOM, SID_ZOOM_OUT, SID_ZOOM_IN, + FN_PREVIEW_ZOOM, + FN_START_OF_DOCUMENT, FN_END_OF_DOCUMENT, FN_PAGEUP, FN_PAGEDOWN, + FN_STAT_PAGE, FN_STAT_ZOOM, + FN_SHOW_TWO_PAGES, FN_SHOW_MULTIPLE_PAGES, + 0 + }; + SfxBindings& rBindings = mrView.GetViewFrame()->GetBindings(); + rBindings.Invalidate( aInval ); + rBindings.Update( FN_SHOW_TWO_PAGES ); + rBindings.Update( FN_SHOW_MULTIPLE_PAGES ); + // adjust scrollbars + mrView.ScrollViewSzChg(); +} + +// mnSttPage is Absolute +bool SwPagePreviewWin::MovePage( int eMoveMode ) +{ + // number of pages up + const sal_uInt16 nPages = mnRow * mnCol; + sal_uInt16 nNewSttPage = mnSttPage; + const sal_uInt16 nPageCount = mrView.GetPageCount(); + const sal_uInt16 nDefSttPg = GetDefSttPage(); + bool bPaintPageAtFirstCol = true; + + switch( eMoveMode ) + { + case MV_PAGE_UP: + { + const sal_uInt16 nRelSttPage = mpPgPreviewLayout->ConvertAbsoluteToRelativePageNum( mnSttPage ); + const sal_uInt16 nNewAbsSttPage = nRelSttPage - nPages > 0 ? + mpPgPreviewLayout->ConvertRelativeToAbsolutePageNum( nRelSttPage - nPages ) : + nDefSttPg; + nNewSttPage = nNewAbsSttPage; + + const sal_uInt16 nRelSelPage = mpPgPreviewLayout->ConvertAbsoluteToRelativePageNum( SelectedPage() ); + const sal_uInt16 nNewRelSelPage = nRelSelPage - nPages > 0 ? + nRelSelPage - nPages : + 1; + SetSelectedPage( mpPgPreviewLayout->ConvertRelativeToAbsolutePageNum( nNewRelSelPage ) ); + + break; + } + case MV_PAGE_DOWN: + { + const sal_uInt16 nRelSttPage = mpPgPreviewLayout->ConvertAbsoluteToRelativePageNum( mnSttPage ); + const sal_uInt16 nNewAbsSttPage = mpPgPreviewLayout->ConvertRelativeToAbsolutePageNum( nRelSttPage + nPages ); + nNewSttPage = std::min(nNewAbsSttPage, nPageCount); + + const sal_uInt16 nRelSelPage = mpPgPreviewLayout->ConvertAbsoluteToRelativePageNum( SelectedPage() ); + const sal_uInt16 nNewAbsSelPage = mpPgPreviewLayout->ConvertRelativeToAbsolutePageNum( nRelSelPage + nPages ); + SetSelectedPage( std::min(nNewAbsSelPage, nPageCount) ); + + break; + } + case MV_DOC_STT: + nNewSttPage = nDefSttPg; + SetSelectedPage( mpPgPreviewLayout->ConvertRelativeToAbsolutePageNum( nNewSttPage ? nNewSttPage : 1 ) ); + break; + case MV_DOC_END: + // correct calculation of new start page. + nNewSttPage = nPageCount; + SetSelectedPage( nPageCount ); + break; + + case MV_SELPAGE: + // <nNewSttPage> and <SelectedPage()> are already set. + // not start at first column, only if the + // complete preview layout columns doesn't fit into window. + if ( !mpPgPreviewLayout->DoesPreviewLayoutColsFitIntoWindow() ) + bPaintPageAtFirstCol = false; + break; + case MV_SCROLL: + // check, if paint page at first column + // has to be avoided + if ( !mpPgPreviewLayout->DoesPreviewLayoutRowsFitIntoWindow() || + !mpPgPreviewLayout->DoesPreviewLayoutColsFitIntoWindow() ) + bPaintPageAtFirstCol = false; + break; + case MV_NEWWINSIZE: + // nothing special to do. + break; + case MV_CALC: + // re-init page preview layout. + mpPgPreviewLayout->ReInit(); + + // correct calculation of new start page. + if( nNewSttPage > nPageCount ) + nNewSttPage = nPageCount; + + // correct selected page number + if( SelectedPage() > nPageCount ) + SetSelectedPage( nNewSttPage ? nNewSttPage : 1 ); + } + + mpPgPreviewLayout->Prepare( nNewSttPage, Point(0,0), maPxWinSize, + nNewSttPage, + maPaintedPreviewDocRect, bPaintPageAtFirstCol ); + if( nNewSttPage == mnSttPage && + eMoveMode != MV_SELPAGE ) + return false; + + SetPagePreview(mnRow, mnCol); + mnSttPage = nNewSttPage; + + // additional invalidate page status. + static sal_uInt16 aInval[] = + { + FN_START_OF_DOCUMENT, FN_END_OF_DOCUMENT, FN_PAGEUP, FN_PAGEDOWN, + FN_STAT_PAGE, 0 + }; + + SfxBindings& rBindings = mrView.GetViewFrame()->GetBindings(); + rBindings.Invalidate( aInval ); + + return true; +} + +void SwPagePreviewWin::SetWinSize( const Size& rNewSize ) +{ + // We always want the size as pixel units. + maPxWinSize = LogicToPixel( rNewSize ); + + if( USHRT_MAX == mnSttPage ) + { + mnSttPage = GetDefSttPage(); + SetSelectedPage( GetDefSttPage() ); + } + + if ( mbCalcScaleForPreviewLayout ) + { + mpPgPreviewLayout->Init( mnCol, mnRow, maPxWinSize ); + maScale = GetMapMode().GetScaleX(); + } + mpPgPreviewLayout->Prepare( mnSttPage, Point(0,0), maPxWinSize, + mnSttPage, maPaintedPreviewDocRect ); + if ( mbCalcScaleForPreviewLayout ) + { + SetSelectedPage( mnSttPage ); + mbCalcScaleForPreviewLayout = false; + } + SetPagePreview(mnRow, mnCol); + maScale = GetMapMode().GetScaleX(); +} + +OUString SwPagePreviewWin::GetStatusStr( sal_uInt16 nPageCnt ) const +{ + // show physical and virtual page number of + // selected page, if it's visible. + const sal_uInt16 nPageNum = mpPgPreviewLayout->IsPageVisible( mpPgPreviewLayout->SelectedPage() ) + ? mpPgPreviewLayout->SelectedPage() : std::max<sal_uInt16>(mnSttPage, 1); + + OUString aStatusStr; + const sal_uInt16 nVirtPageNum = mpPgPreviewLayout->GetVirtPageNumByPageNum( nPageNum ); + if( nVirtPageNum && nVirtPageNum != nPageNum ) + { + aStatusStr = OUString::number(nVirtPageNum) + " " ; + } + return aStatusStr + OUString::number(nPageNum) + " / " + OUString::number(nPageCnt); +} + +void SwPagePreviewWin::KeyInput( const KeyEvent &rKEvt ) +{ + const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode(); + bool bHandled = false; + if(!rKeyCode.GetModifier()) + { + sal_uInt16 nSlot = 0; + switch(rKeyCode.GetCode()) + { + case KEY_ADD : nSlot = SID_ZOOM_OUT; break; + case KEY_ESCAPE: nSlot = FN_CLOSE_PAGEPREVIEW; break; + case KEY_SUBTRACT : nSlot = SID_ZOOM_IN; break; + } + if(nSlot) + { + bHandled = true; + mrView.GetViewFrame()->GetDispatcher()->Execute( + nSlot, SfxCallMode::ASYNCHRON ); + } + } + if( !bHandled && !mrView.KeyInput( rKEvt ) ) + Window::KeyInput( rKEvt ); +} + +void SwPagePreviewWin::Command( const CommandEvent& rCEvt ) +{ + bool bCallBase = true; + switch( rCEvt.GetCommand() ) + { + case CommandEventId::ContextMenu: + SfxDispatcher::ExecutePopup(); + bCallBase = false; + break; + + case CommandEventId::Wheel: + case CommandEventId::StartAutoScroll: + case CommandEventId::AutoScroll: + { + const CommandWheelData* pData = rCEvt.GetWheelData(); + if( pData ) + { + const CommandWheelData aDataNew(pData->GetDelta(),pData->GetNotchDelta(),COMMAND_WHEEL_PAGESCROLL, + pData->GetMode(),pData->GetModifier(),pData->IsHorz(), pData->IsDeltaPixel()); + const CommandEvent aEvent( rCEvt.GetMousePosPixel(),rCEvt.GetCommand(),rCEvt.IsMouseEvent(),&aDataNew); + bCallBase = !mrView.HandleWheelCommands( aEvent ); + } + else + bCallBase = !mrView.HandleWheelCommands( rCEvt ); + } + break; + default: + ; + } + + if( bCallBase ) + Window::Command( rCEvt ); +} + +void SwPagePreviewWin::MouseButtonDown( const MouseEvent& rMEvt ) +{ + // consider single-click to set selected page + if( MOUSE_LEFT != ( rMEvt.GetModifier() + rMEvt.GetButtons() ) ) + return; + + Point aPreviewPos( PixelToLogic( rMEvt.GetPosPixel() ) ); + Point aDocPos; + bool bPosInEmptyPage; + sal_uInt16 nNewSelectedPage; + bool bIsDocPos = + mpPgPreviewLayout->IsPreviewPosInDocPreviewPage( aPreviewPos, + aDocPos, bPosInEmptyPage, nNewSelectedPage ); + if ( bIsDocPos && rMEvt.GetClicks() == 2 ) + { + // close page preview, set new cursor position and switch to + // normal view. + OUString sNewCursorPos = OUString::number( aDocPos.X() ) + ";" + + OUString::number( aDocPos.Y() ) + ";"; + mrView.SetNewCursorPos( sNewCursorPos ); + + SfxViewFrame *pTmpFrame = mrView.GetViewFrame(); + pTmpFrame->GetBindings().Execute( SID_VIEWSHELL0, nullptr, + SfxCallMode::ASYNCHRON ); + } + else if ( bIsDocPos || bPosInEmptyPage ) + { + // show clicked page as the selected one + mpPgPreviewLayout->MarkNewSelectedPage( nNewSelectedPage ); + GetViewShell()->ShowPreviewSelection( nNewSelectedPage ); + // adjust position at vertical scrollbar. + if ( mpPgPreviewLayout->DoesPreviewLayoutRowsFitIntoWindow() ) + { + mrView.SetVScrollbarThumbPos( nNewSelectedPage ); + } + // invalidate page status. + static sal_uInt16 aInval[] = + { + FN_STAT_PAGE, 0 + }; + SfxBindings& rBindings = mrView.GetViewFrame()->GetBindings(); + rBindings.Invalidate( aInval ); + } +} + +// Set user prefs or view options + +void SwPagePreviewWin::SetPagePreview( sal_uInt8 nRow, sal_uInt8 nCol ) +{ + SwMasterUsrPref *pOpt = const_cast<SwMasterUsrPref *>(SW_MOD()->GetUsrPref(false)); + + if (nRow != pOpt->GetPagePrevRow() || nCol != pOpt->GetPagePrevCol()) + { + pOpt->SetPagePrevRow( nRow ); + pOpt->SetPagePrevCol( nCol ); + pOpt->SetModified(); + + // Update scrollbar! + mrView.ScrollViewSzChg(); + } +} + +/** get selected page in document preview */ +sal_uInt16 SwPagePreviewWin::SelectedPage() const +{ + return mpPgPreviewLayout->SelectedPage(); +} + +/** set selected page number in document preview */ +void SwPagePreviewWin::SetSelectedPage( sal_uInt16 _nSelectedPageNum ) +{ + mpPgPreviewLayout->SetSelectedPage( _nSelectedPageNum ); +} + +/** method to enable/disable book preview */ +bool SwPagePreviewWin::SetBookPreviewMode( const bool _bBookPreview ) +{ + return mpPgPreviewLayout->SetBookPreviewMode( _bBookPreview, + mnSttPage, + maPaintedPreviewDocRect ); +} + +void SwPagePreviewWin::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::DataChanged( rDCEvt ); + + switch( rDCEvt.GetType() ) + { + case DataChangedEventType::SETTINGS: + // Rearrange the scrollbars or trigger resize, because the + // size of the scrollbars may have be changed. Also the + // size of the scrollbars has to be retrieved from the settings + // out of the resize handler. + if( rDCEvt.GetFlags() & AllSettingsFlags::STYLE ) + mrView.InvalidateBorder(); // Scrollbar widths + // zoom has to be disabled if Accessibility support is switched on + lcl_InvalidateZoomSlots(mrView.GetViewFrame()->GetBindings()); + break; + + case DataChangedEventType::PRINTER: + case DataChangedEventType::DISPLAY: + case DataChangedEventType::FONTS: + case DataChangedEventType::FONTSUBSTITUTION: + mrView.GetDocShell()->UpdateFontList(); // Font change + mpViewShell->InvalidateLayout(true); + if ( mpViewShell->GetWin() ) + mpViewShell->GetWin()->Invalidate(); + break; + default: break; + } +} + +/** help method to execute SfxRequest FN_PAGEUP and FN_PAGEDOWN */ +void SwPagePreview::ExecPgUpAndPgDown( const bool _bPgUp, + SfxRequest* _pReq ) +{ + SwPagePreviewLayout* pPagePreviewLay = GetViewShell()->PagePreviewLayout(); + // check, if top/bottom of preview is *not* already visible. + if( pPagePreviewLay->GetWinPagesScrollAmount( _bPgUp ? -1 : 1 ) != 0 ) + { + if ( pPagePreviewLay->DoesPreviewLayoutRowsFitIntoWindow() && + pPagePreviewLay->DoesPreviewLayoutColsFitIntoWindow() ) + { + const int eMvMode = _bPgUp ? + SwPagePreviewWin::MV_PAGE_UP : + SwPagePreviewWin::MV_PAGE_DOWN; + if ( ChgPage( eMvMode ) ) + m_pViewWin->Invalidate(); + } + else + { + SwTwips nScrollAmount; + sal_uInt16 nNewSelectedPageNum = 0; + const sal_uInt16 nVisPages = m_pViewWin->GetRow() * m_pViewWin->GetCol(); + if( _bPgUp ) + { + if ( pPagePreviewLay->DoesPreviewLayoutRowsFitIntoWindow() ) + { + nScrollAmount = pPagePreviewLay->GetWinPagesScrollAmount( -1 ); + if ( (m_pViewWin->SelectedPage() - nVisPages) > 0 ) + nNewSelectedPageNum = m_pViewWin->SelectedPage() - nVisPages; + else + nNewSelectedPageNum = 1; + } + else + nScrollAmount = - std::min( m_pViewWin->GetOutDev()->GetOutputSize().Height(), + m_pViewWin->GetPaintedPreviewDocRect().Top() ); + } + else + { + if ( pPagePreviewLay->DoesPreviewLayoutRowsFitIntoWindow() ) + { + nScrollAmount = pPagePreviewLay->GetWinPagesScrollAmount( 1 ); + if ( (m_pViewWin->SelectedPage() + nVisPages) <= mnPageCount ) + nNewSelectedPageNum = m_pViewWin->SelectedPage() + nVisPages; + else + nNewSelectedPageNum = mnPageCount; + } + else + nScrollAmount = std::min( m_pViewWin->GetOutDev()->GetOutputSize().Height(), + ( pPagePreviewLay->GetPreviewDocSize().Height() - + m_pViewWin->GetPaintedPreviewDocRect().Bottom() ) ); + } + m_pViewWin->Scroll( 0, nScrollAmount ); + if ( nNewSelectedPageNum != 0 ) + { + m_pViewWin->SetSelectedPage( nNewSelectedPageNum ); + } + ScrollViewSzChg(); + // additional invalidate page status. + static sal_uInt16 aInval[] = + { + FN_START_OF_DOCUMENT, FN_END_OF_DOCUMENT, FN_PAGEUP, FN_PAGEDOWN, + FN_STAT_PAGE, 0 + }; + SfxBindings& rBindings = GetViewFrame()->GetBindings(); + rBindings.Invalidate( aInval ); + m_pViewWin->Invalidate(); + } + } + + if ( _pReq ) + _pReq->Done(); +} + +// Then all for the SwPagePreview +void SwPagePreview::Execute( SfxRequest &rReq ) +{ + int eMvMode = SwPagePreviewWin::MV_DOC_END; + sal_uInt8 nRow = 1; + bool bRefresh = true; + + switch(rReq.GetSlot()) + { + case SID_REFRESH_VIEW: + case FN_STAT_PAGE: + case FN_STAT_ZOOM: + break; + + case FN_SHOW_MULTIPLE_PAGES: + { + const SfxItemSet *pArgs = rReq.GetArgs(); + if( pArgs && pArgs->Count() >= 2 ) + { + sal_uInt8 nCols = static_cast<sal_uInt8>(pArgs->Get(SID_ATTR_TABLE_COLUMN).GetValue()); + sal_uInt8 nRows = static_cast<sal_uInt8>(pArgs->Get(SID_ATTR_TABLE_ROW).GetValue()); + m_pViewWin->CalcWish( nRows, nCols ); + + } + else + { + SwPreviewZoomDlg aDlg(*m_pViewWin); + aDlg.execute(); + } + } + break; + case FN_SHOW_BOOKVIEW: + { + const SfxItemSet* pArgs = rReq.GetArgs(); + const SfxPoolItem* pItem; + bool bBookPreview = GetViewShell()->GetViewOptions()->IsPagePrevBookview(); + if( pArgs && SfxItemState::SET == pArgs->GetItemState( FN_SHOW_BOOKVIEW, false, &pItem ) ) + { + bBookPreview = static_cast< const SfxBoolItem* >( pItem )->GetValue(); + const_cast<SwViewOption*>(GetViewShell()->GetViewOptions())->SetPagePrevBookview( bBookPreview ); + // cast is not gentleman like, but it's common use in writer and in this case + } + if ( m_pViewWin->SetBookPreviewMode( bBookPreview ) ) + { + // book preview mode changed. Thus, adjust scrollbars and + // invalidate corresponding states. + ScrollViewSzChg(); + static sal_uInt16 aInval[] = + { + FN_START_OF_DOCUMENT, FN_END_OF_DOCUMENT, FN_PAGEUP, FN_PAGEDOWN, + FN_STAT_PAGE, FN_SHOW_BOOKVIEW, 0 + }; + SfxBindings& rBindings = GetViewFrame()->GetBindings(); + rBindings.Invalidate( aInval ); + m_pViewWin->Invalidate(); + } + + } + break; + case FN_SHOW_TWO_PAGES: + m_pViewWin->CalcWish( nRow, 2 ); + break; + + case FN_SHOW_SINGLE_PAGE: + m_pViewWin->CalcWish( nRow, 1 ); + break; + + case FN_PREVIEW_ZOOM: + case SID_ATTR_ZOOM: + { + const SfxItemSet *pArgs = rReq.GetArgs(); + ScopedVclPtr<AbstractSvxZoomDialog> pDlg; + if(!pArgs) + { + SfxItemSetFixed<SID_ATTR_ZOOM, SID_ATTR_ZOOM> aCoreSet(GetPool()); + const SwViewOption* pVOpt = GetViewShell()->GetViewOptions(); + SvxZoomItem aZoom( pVOpt->GetZoomType(), pVOpt->GetZoom() ); + aZoom.SetValueSet( + SvxZoomEnableFlags::N50| + SvxZoomEnableFlags::N75| + SvxZoomEnableFlags::N100| + SvxZoomEnableFlags::N150| + SvxZoomEnableFlags::N200| + SvxZoomEnableFlags::WHOLEPAGE); + aCoreSet.Put( aZoom ); + + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + pDlg.disposeAndReset(pFact->CreateSvxZoomDialog(GetViewFrame()->GetFrameWeld(), aCoreSet)); + pDlg->SetLimits( MINZOOM, MAXZOOM ); + + if( pDlg->Execute() != RET_CANCEL ) + pArgs = pDlg->GetOutputItemSet(); + } + if( pArgs ) + { + SvxZoomType eType = SvxZoomType::PERCENT; + sal_uInt16 nZoomFactor = USHRT_MAX; + if(const SvxZoomItem* pZoomItem = pArgs->GetItemIfSet(SID_ATTR_ZOOM)) + { + eType = pZoomItem->GetType(); + nZoomFactor = pZoomItem->GetValue(); + } + else if(const SfxUInt16Item* pPreviewItem = pArgs->GetItemIfSet(FN_PREVIEW_ZOOM)) + nZoomFactor = pPreviewItem->GetValue(); + if(USHRT_MAX != nZoomFactor) + SetZoom(eType, nZoomFactor); + } + } + break; + case SID_ATTR_ZOOMSLIDER : + { + const SfxItemSet *pArgs = rReq.GetArgs(); + const SvxZoomSliderItem* pItem; + + if ( pArgs && (pItem = pArgs->GetItemIfSet(SID_ATTR_ZOOMSLIDER ) ) ) + { + const sal_uInt16 nCurrentZoom = pItem->GetValue(); + SetZoom( SvxZoomType::PERCENT, nCurrentZoom ); + } + } + break; + case SID_ZOOM_IN: + case SID_ZOOM_OUT: + { + const SwViewOption* pVOpt = GetViewShell()->GetViewOptions(); + SetZoom(SvxZoomType::PERCENT, + lcl_GetNextZoomStep(pVOpt->GetZoom(), SID_ZOOM_IN == rReq.GetSlot())); + } + break; + case FN_CHAR_LEFT: + case FN_CHAR_RIGHT: + case FN_LINE_UP: + case FN_LINE_DOWN: + { + SwPagePreviewLayout* pPagePreviewLay = GetViewShell()->PagePreviewLayout(); + sal_uInt16 nNewSelectedPage; + sal_uInt16 nNewStartPage; + Point aNewStartPos; + sal_Int16 nHoriMove = 0; + sal_Int16 nVertMove = 0; + switch(rReq.GetSlot()) + { + case FN_CHAR_LEFT: nHoriMove = -1; break; + case FN_CHAR_RIGHT: nHoriMove = 1; break; + case FN_LINE_UP: nVertMove = -1; break; + case FN_LINE_DOWN: nVertMove = 1; break; + } + pPagePreviewLay->CalcStartValuesForSelectedPageMove( nHoriMove, nVertMove, + nNewSelectedPage, nNewStartPage, aNewStartPos ); + if ( m_pViewWin->SelectedPage() != nNewSelectedPage ) + { + if ( pPagePreviewLay->IsPageVisible( nNewSelectedPage ) ) + { + pPagePreviewLay->MarkNewSelectedPage( nNewSelectedPage ); + // adjust position at vertical scrollbar. + SetVScrollbarThumbPos( nNewSelectedPage ); + bRefresh = false; + } + else + { + m_pViewWin->SetSelectedPage( nNewSelectedPage ); + m_pViewWin->SetSttPage( nNewStartPage ); + bRefresh = ChgPage( SwPagePreviewWin::MV_SELPAGE ); + } + GetViewShell()->ShowPreviewSelection( nNewSelectedPage ); + // invalidate page status. + static sal_uInt16 aInval[] = + { + FN_STAT_PAGE, 0 + }; + SfxBindings& rBindings = GetViewFrame()->GetBindings(); + rBindings.Invalidate( aInval ); + rReq.Done(); + } + else + { + bRefresh = false; + } + break; + } + case FN_PAGEUP: + case FN_PAGEDOWN: + { + ExecPgUpAndPgDown( rReq.GetSlot() == FN_PAGEUP, &rReq ); + break; + } + case SID_JUMP_TO_SPECIFIC_PAGE: + { + const SfxItemSet *pArgs = rReq.GetArgs(); + if( pArgs && pArgs->Count()) + { + sal_uInt16 nPageNum = static_cast<const SfxUInt16Item &>(pArgs->Get(SID_JUMP_TO_SPECIFIC_PAGE)).GetValue(); + + if( nPageNum > 0 && nPageNum <= mnPageCount ) + { + m_pViewWin->SetSttPage( nPageNum); + m_pViewWin->SetSelectedPage( nPageNum ); + ChgPage( SwPagePreviewWin::MV_SPECIFIC_PAGE, false ); + ScrollViewSzChg(); + } + } + } + break; + case FN_START_OF_LINE: + case FN_START_OF_DOCUMENT: + eMvMode = SwPagePreviewWin::MV_DOC_STT; + [[fallthrough]]; + case FN_END_OF_LINE: + case FN_END_OF_DOCUMENT: + m_pViewWin->SetSelectedPage(eMvMode == SwPagePreviewWin::MV_DOC_STT ? 1 : mnPageCount); + { + bool bRet = ChgPage( eMvMode ); + // return value for Basic + rReq.SetReturnValue(SfxBoolItem(rReq.GetSlot(), !bRet)); + + bRefresh = bRet; + rReq.Done(); + } + break; + + case FN_PRINT_PAGEPREVIEW: + { + const SwPagePreviewPrtData* pPPVPD = m_pViewWin->GetViewShell()->GetDoc()->GetPreviewPrtData(); + // The thing with the orientation + if(pPPVPD) + { + SfxPrinter* pPrinter = GetPrinter( true ); + if((pPrinter->GetOrientation() == Orientation::Landscape) + != pPPVPD->GetLandscape()) + pPrinter->SetOrientation(pPPVPD->GetLandscape() ? Orientation::Landscape : Orientation::Portrait); + } + ::SetAppPrintOptions( m_pViewWin->GetViewShell(), false ); + m_bNormalPrint = false; + rReq.SetSlot( SID_PRINTDOC ); + SfxViewShell::ExecuteSlot( rReq, SfxViewShell::GetInterface() ); + rReq.SetSlot( FN_PRINT_PAGEPREVIEW ); + return; + } + case SID_PRINTDOCDIRECT: + case SID_PRINTDOC: + ::SetAppPrintOptions( m_pViewWin->GetViewShell(), false ); + m_bNormalPrint = true; + SfxViewShell::ExecuteSlot( rReq, SfxViewShell::GetInterface() ); + return; + case FN_CLOSE_PAGEPREVIEW: + case SID_PRINTPREVIEW: + // print preview is now always in the same frame as the tab view + // -> always switch this frame back to normal view + // (ScTabViewShell ctor reads stored view data) + GetViewFrame()->GetDispatcher()->Execute( SID_VIEWSHELL0, SfxCallMode::ASYNCHRON ); + break; + case FN_INSERT_BREAK: + { + sal_uInt16 nSelPage = m_pViewWin->SelectedPage(); + //if a dummy page is selected (e.g. a non-existing right/left page) + //the direct neighbor is used + if(GetViewShell()->IsDummyPage( nSelPage ) && GetViewShell()->IsDummyPage( --nSelPage )) + nSelPage +=2; + m_nNewPage = nSelPage; + SfxViewFrame *pTmpFrame = GetViewFrame(); + pTmpFrame->GetBindings().Execute( SID_VIEWSHELL0, nullptr, + SfxCallMode::ASYNCHRON ); + } + break; + default: + OSL_ENSURE(false, "wrong dispatcher"); + return; + } + + if( bRefresh ) + m_pViewWin->Invalidate(); +} + +void SwPagePreview::GetState( SfxItemSet& rSet ) +{ + SfxWhichIter aIter(rSet); + sal_uInt16 nWhich = aIter.FirstWhich(); + OSL_ENSURE(nWhich, "empty set"); + SwPagePreviewLayout* pPagePreviewLay = GetViewShell()->PagePreviewLayout(); + + while(nWhich) + { + switch(nWhich) + { + case SID_BROWSER_MODE: + case FN_PRINT_LAYOUT: + rSet.DisableItem(nWhich); + break; + case FN_START_OF_DOCUMENT: + { + if ( pPagePreviewLay->IsPageVisible( 1 ) ) + rSet.DisableItem(nWhich); + break; + } + case FN_END_OF_DOCUMENT: + { + if ( pPagePreviewLay->IsPageVisible( mnPageCount ) ) + rSet.DisableItem(nWhich); + break; + } + case FN_PAGEUP: + { + if( pPagePreviewLay->GetWinPagesScrollAmount( -1 ) == 0 ) + rSet.DisableItem(nWhich); + break; + } + case FN_PAGEDOWN: + { + if( pPagePreviewLay->GetWinPagesScrollAmount( 1 ) == 0 ) + rSet.DisableItem(nWhich); + break; + } + + case FN_STAT_PAGE: + { + std::vector<OUString> aStringList + { + m_sPageStr + m_pViewWin->GetStatusStr(mnPageCount), + OUString() + }; + rSet.Put(SfxStringListItem(FN_STAT_PAGE, &aStringList)); + } + break; + + case SID_ATTR_ZOOM: + case FN_STAT_ZOOM: + { + const SwViewOption* pVOpt = GetViewShell()->GetViewOptions(); + SvxZoomItem aZoom(pVOpt->GetZoomType(), pVOpt->GetZoom()); + aZoom.SetValueSet( + SvxZoomEnableFlags::N50| + SvxZoomEnableFlags::N75| + SvxZoomEnableFlags::N100| + SvxZoomEnableFlags::N150| + SvxZoomEnableFlags::N200); + rSet.Put( aZoom ); + } + break; + case SID_ATTR_ZOOMSLIDER : + { + const SwViewOption* pVOpt = GetViewShell()->GetViewOptions(); + const sal_uInt16 nCurrentZoom = pVOpt->GetZoom(); + SvxZoomSliderItem aZoomSliderItem( nCurrentZoom, MINZOOM, MAXZOOM ); + aZoomSliderItem.AddSnappingPoint( 100 ); + rSet.Put( aZoomSliderItem ); + } + break; + case FN_PREVIEW_ZOOM: + { + const SwViewOption* pVOpt = GetViewShell()->GetViewOptions(); + rSet.Put(SfxUInt16Item(nWhich, pVOpt->GetZoom())); + } + break; + case SID_ZOOM_IN: + case SID_ZOOM_OUT: + { + const SwViewOption* pVOpt = GetViewShell()->GetViewOptions(); + if((SID_ZOOM_IN == nWhich && pVOpt->GetZoom() >= MAX_PREVIEW_ZOOM) || + (SID_ZOOM_OUT == nWhich && pVOpt->GetZoom() <= MIN_PREVIEW_ZOOM)) + { + rSet.DisableItem(nWhich); + } + } + break; + case FN_SHOW_MULTIPLE_PAGES: + // should never be disabled + break; + case FN_SHOW_BOOKVIEW: + { + bool b = GetViewShell()->GetViewOptions()->IsPagePrevBookview(); + rSet.Put(SfxBoolItem(nWhich, b)); + } + break; + + case FN_SHOW_TWO_PAGES: + if( 2 == m_pViewWin->GetCol() && 1 == m_pViewWin->GetRow() ) + rSet.DisableItem( nWhich ); + break; + + case FN_PRINT_PAGEPREVIEW: + // has the same status like the normal printing + { + const SfxPoolItem* pItem; + SfxItemSetFixed<SID_PRINTDOC, SID_PRINTDOC> aSet( *rSet.GetPool() ); + GetSlotState( SID_PRINTDOC, SfxViewShell::GetInterface(), &aSet ); + if( SfxItemState::DISABLED == aSet.GetItemState( SID_PRINTDOC, false )) + rSet.DisableItem( nWhich ); + else if( SfxItemState::SET == aSet.GetItemState( SID_PRINTDOC, + false, &pItem )) + { + const_cast<SfxPoolItem*>(pItem)->SetWhich( FN_PRINT_PAGEPREVIEW ); + rSet.Put( *pItem ); + } + } + break; + + case SID_PRINTPREVIEW: + rSet.Put( SfxBoolItem( nWhich, true ) ); + break; + + case SID_PRINTDOC: + case SID_PRINTDOCDIRECT: + GetSlotState( nWhich, SfxViewShell::GetInterface(), &rSet ); + break; + } + nWhich = aIter.NextWhich(); + } +} + +void SwPagePreview::StateUndo(SfxItemSet& rSet) +{ + SfxWhichIter aIter(rSet); + sal_uInt16 nWhich = aIter.FirstWhich(); + + while (nWhich) + { + rSet.DisableItem(nWhich); + nWhich = aIter.NextWhich(); + } +} + +void SwPagePreview::Init() +{ + if ( GetViewShell()->HasDrawView() ) + GetViewShell()->GetDrawView()->SetAnimationEnabled( false ); + + m_bNormalPrint = true; + + // Check and process the DocSize. The shell could not be found via + // the handler, because the shell is unknown to the SFX management + // within the CTOR phase. + + const SwViewOption * pPrefs = SW_MOD()->GetUsrPref(false); + + mbHScrollbarEnabled = pPrefs->IsViewHScrollBar(); + mbVScrollbarEnabled = pPrefs->IsViewVScrollBar(); + + // Update the fields + // ATTENTION: Do cast the EditShell up, to use the SS. + // At the methods the current shell will be queried! + SwEditShell* pESh = dynamic_cast<SwEditShell*>(GetViewShell()); + bool bIsModified = pESh != nullptr && pESh->IsModified(); + + SwViewOption aOpt( *pPrefs ); + aOpt.SetPagePreview(true); + aOpt.SetTab( false ); + aOpt.SetBlank( false ); + aOpt.SetHardBlank( false ); + aOpt.SetParagraph( false ); + aOpt.SetLineBreak( false ); + aOpt.SetPageBreak( false ); + aOpt.SetColumnBreak( false ); + aOpt.SetSoftHyph( false ); + aOpt.SetFieldName( false ); + aOpt.SetPostIts( false ); + aOpt.SetShowBookmarks( false ); + aOpt.SetShowHiddenChar( false ); + aOpt.SetShowHiddenField( false ); + aOpt.SetShowHiddenPara( false ); + aOpt.SetViewHRuler( false ); + aOpt.SetViewVRuler( false ); + aOpt.SetGraphic( true ); + aOpt.SetTable( true ); + aOpt.SetSnap( false ); + aOpt.SetGridVisible( false ); + aOpt.SetOnlineSpell( false ); + aOpt.SetHideWhitespaceMode( false ); + + GetViewShell()->ApplyViewOptions( aOpt ); +#if !ENABLE_WASM_STRIP_ACCESSIBILITY + GetViewShell()->ApplyAccessibilityOptions(SW_MOD()->GetAccessibilityOptions()); +#endif + + // adjust view shell option to the same as for print + SwPrintData const aPrintOptions = *SW_MOD()->GetPrtOptions(false); + GetViewShell()->AdjustOptionsForPagePreview( aPrintOptions ); + + GetViewShell()->CalcLayout(); + DocSzChgd( GetViewShell()->GetDocSize() ); + + if( !bIsModified && pESh != nullptr ) + pESh->ResetModified(); +} + +SwPagePreview::SwPagePreview(SfxViewFrame *pViewFrame, SfxViewShell* pOldSh): + SfxViewShell( pViewFrame, SWVIEWFLAGS ), + m_pViewWin( VclPtr<SwPagePreviewWin>::Create(&GetViewFrame()->GetWindow(), *this ) ), + m_nNewPage(USHRT_MAX), + m_sPageStr(SwResId(STR_PAGE)), + m_pHScrollbar(nullptr), + m_pVScrollbar(nullptr), + m_pScrollFill(VclPtr<ScrollBarBox>::Create( &pViewFrame->GetWindow(), WB_SIZEABLE )), + mnPageCount( 0 ), + mbResetFormDesignMode( false ), + mbFormDesignModeToReset( false ) +{ + SetName("PageView"); + SetWindow( m_pViewWin ); + CreateScrollbar( true ); + CreateScrollbar( false ); + + //notify notebookbar change in context + SfxShell::SetContextBroadcasterEnabled(true); + SfxShell::SetContextName(vcl::EnumContext::GetContextName(vcl::EnumContext::Context::Printpreview)); + SfxShell::BroadcastContextForActivation(true); + //removelisteners for notebookbar + if (SfxViewFrame* pCurrent = SfxViewFrame::Current()) + if (auto& pBar = pCurrent->GetWindow().GetSystemWindow()->GetNotebookBar()) + pBar->ControlListenerForCurrentController(false); + + SfxObjectShell* pObjShell = pViewFrame->GetObjectShell(); + if ( !pOldSh ) + { + // Exists already a view on the document? + SfxViewFrame *pF = SfxViewFrame::GetFirst( pObjShell ); + if ( pF == pViewFrame ) + pF = SfxViewFrame::GetNext( *pF, pObjShell ); + if ( pF ) + pOldSh = pF->GetViewShell(); + } + + SwViewShell *pVS, *pNew; + + if (SwPagePreview* pPagePreview = dynamic_cast<SwPagePreview*>(pOldSh)) + pVS = pPagePreview->GetViewShell(); + else + { + if (SwView* pView = dynamic_cast<SwView *>(pOldSh)) + { + pVS = pView->GetWrtShellPtr(); + // save the current ViewData of the previous SwView + pOldSh->WriteUserData( m_sSwViewData ); + } + else + pVS = GetDocShell()->GetWrtShell(); + if( pVS ) + { + // Set the current page as the first. + sal_uInt16 nPhysPg, nVirtPg; + static_cast<SwCursorShell*>(pVS)->GetPageNum( nPhysPg, nVirtPg, true, false ); + if( 1 != m_pViewWin->GetCol() && 1 == nPhysPg ) + --nPhysPg; + m_pViewWin->SetSttPage( nPhysPg ); + } + } + + // for form shell remember design mode of draw view + // of previous view shell + if ( pVS && pVS->HasDrawView() ) + { + mbResetFormDesignMode = true; + mbFormDesignModeToReset = pVS->GetDrawView()->IsDesignMode(); + } + + if( pVS ) + pNew = new SwViewShell( *pVS, m_pViewWin, nullptr, VSHELLFLAG_ISPREVIEW ); + else + pNew = new SwViewShell( + *static_cast<SwDocShell*>(pViewFrame->GetObjectShell())->GetDoc(), + m_pViewWin, nullptr, nullptr, VSHELLFLAG_ISPREVIEW ); + + m_pViewWin->SetViewShell( pNew ); + pNew->SetSfxViewShell( this ); + Init(); +} + +SwPagePreview::~SwPagePreview() +{ + SetWindow( nullptr ); + SwViewShell* pVShell = m_pViewWin->GetViewShell(); + pVShell->SetWin(nullptr); + delete pVShell; + + m_pViewWin.disposeAndClear(); + if (SfxViewFrame* pCurrent = SfxViewFrame::Current()) + if (auto& pBar = pCurrent->GetWindow().GetSystemWindow()->GetNotebookBar()) + pBar->ControlListenerForCurrentController(true); // start listening now + m_pScrollFill.disposeAndClear(); + m_pHScrollbar.disposeAndClear(); + m_pVScrollbar.disposeAndClear(); +} + +SwDocShell* SwPagePreview::GetDocShell() +{ + return dynamic_cast<SwDocShell*>( GetViewFrame()->GetObjectShell() ); +} + +void SwPagePreview::CreateScrollbar( bool bHori ) +{ + vcl::Window *pMDI = &GetViewFrame()->GetWindow(); + VclPtr<SwScrollbar>& ppScrollbar = bHori ? m_pHScrollbar : m_pVScrollbar; + + assert(!ppScrollbar); //check beforehand! + + ppScrollbar = VclPtr<SwScrollbar>::Create( pMDI, bHori ); + + ScrollDocSzChg(); + ppScrollbar->EnableDrag(); + ppScrollbar->SetEndScrollHdl( LINK( this, SwPagePreview, EndScrollHdl )); + + ppScrollbar->SetScrollHdl( LINK( this, SwPagePreview, ScrollHdl )); + + InvalidateBorder(); + ppScrollbar->ExtendedShow(); +} + +bool SwPagePreview::ChgPage( int eMvMode, bool bUpdateScrollbar ) +{ + tools::Rectangle aPixVisArea( m_pViewWin->LogicToPixel( m_aVisArea ) ); + bool bChg = m_pViewWin->MovePage( eMvMode ) || + eMvMode == SwPagePreviewWin::MV_CALC || + eMvMode == SwPagePreviewWin::MV_NEWWINSIZE; + m_aVisArea = m_pViewWin->PixelToLogic( aPixVisArea ); + + if( bChg ) + { + // Update statusbar + SfxBindings& rBindings = GetViewFrame()->GetBindings(); + + if( bUpdateScrollbar ) + { + ScrollViewSzChg(); + + static sal_uInt16 aInval[] = + { + FN_START_OF_DOCUMENT, FN_END_OF_DOCUMENT, + FN_PAGEUP, FN_PAGEDOWN, 0 + }; + rBindings.Invalidate( aInval ); + } + std::vector<OUString> aStringList + { + m_sPageStr + m_pViewWin->GetStatusStr(mnPageCount), + OUString() + }; + rBindings.SetState(SfxStringListItem(FN_STAT_PAGE, &aStringList)); + } + return bChg; +} + +// From here, everything was taken from the SwView. +void SwPagePreview::CalcAndSetBorderPixel( SvBorder &rToFill ) +{ + const StyleSettings &rSet = m_pViewWin->GetSettings().GetStyleSettings(); + const tools::Long nTmp = rSet.GetScrollBarSize(); + if ( m_pVScrollbar->IsVisible( true ) ) + rToFill.Right() = nTmp; + if ( m_pHScrollbar->IsVisible( true ) ) + rToFill.Bottom() = nTmp; + SetBorderPixel( rToFill ); +} + +void SwPagePreview::InnerResizePixel( const Point &rOfst, const Size &rSize, bool ) +{ + SvBorder aBorder; + CalcAndSetBorderPixel( aBorder ); + tools::Rectangle aRect( rOfst, rSize ); + aRect += aBorder; + ViewResizePixel( *m_pViewWin->GetOutDev(), aRect.TopLeft(), aRect.GetSize(), + m_pViewWin->GetOutputSizePixel(), + *m_pVScrollbar, *m_pHScrollbar, *m_pScrollFill ); + + // Never set EditWin ! + // Never set VisArea ! +} + +void SwPagePreview::OuterResizePixel( const Point &rOfst, const Size &rSize ) +{ + SvBorder aBorder; + CalcAndSetBorderPixel( aBorder ); + + // Never set EditWin ! + + Size aTmpSize( m_pViewWin->GetOutputSizePixel() ); + Point aBottomRight( m_pViewWin->PixelToLogic( Point( aTmpSize.Width(), aTmpSize.Height() ) ) ); + SetVisArea( tools::Rectangle( Point(), aBottomRight ) ); + + // Call of the DocSzChgd-Method of the scrollbars is necessary, + // because from the maximum scroll range half the height of the + // VisArea is always deducted. + if ( m_pVScrollbar && !aTmpSize.IsEmpty() ) + { + ScrollDocSzChg(); + } + + SvBorder aBorderNew; + CalcAndSetBorderPixel( aBorderNew ); + ViewResizePixel( *m_pViewWin->GetOutDev(), rOfst, rSize, m_pViewWin->GetOutputSizePixel(), + *m_pVScrollbar, *m_pHScrollbar, *m_pScrollFill ); +} + +void SwPagePreview::SetVisArea( const tools::Rectangle &rRect ) +{ + const Point aTopLeft(AlignToPixel(rRect.TopLeft())); + const Point aBottomRight(AlignToPixel(rRect.BottomRight())); + tools::Rectangle aLR(aTopLeft,aBottomRight); + + if(aLR == m_aVisArea) + return; + // No negative position, no negative size + + if(aLR.Top() < 0) + { + aLR.AdjustBottom(std::abs(aLR.Top()) ); + aLR.SetTop( 0 ); + } + + if(aLR.Left() < 0) + { + aLR.AdjustRight(std::abs(aLR.Left()) ); + aLR.SetLeft( 0 ); + } + if(aLR.Right() < 0) aLR.SetRight( 0 ); + if(aLR.Bottom() < 0) aLR.SetBottom( 0 ); + if(aLR == m_aVisArea || + // Ignore empty rectangle + ( 0 == aLR.Bottom() - aLR.Top() && 0 == aLR.Right() - aLR.Left() ) ) + return; + + if( aLR.Left() > aLR.Right() || aLR.Top() > aLR.Bottom() ) + return; + + // Before the data can be changed call an update if necessary. + // Thereby ensured, that adjacent paints are correctly converted into + // document coordinates. + // As a precaution, we do this only when at the shell runs an action, + // because then we do not really paint but the rectangles are just + // bookmarked (in document coordinates). + if( GetViewShell()->ActionPend() ) + m_pViewWin->PaintImmediately(); + + // Set at View-Win the current size + m_aVisArea = aLR; + m_pViewWin->SetWinSize( aLR.GetSize() ); + ChgPage( SwPagePreviewWin::MV_NEWWINSIZE ); + + m_pViewWin->Invalidate(); +} + +IMPL_LINK( SwPagePreview, ScrollHdl, ScrollBar *, p, void ) +{ + SwScrollbar* pScrollbar = static_cast<SwScrollbar*>(p); + if(!GetViewShell()) + return; + if( !pScrollbar->IsHoriScroll() && + pScrollbar->GetType() == ScrollType::Drag && + Help::IsQuickHelpEnabled() && + GetViewShell()->PagePreviewLayout()->DoesPreviewLayoutRowsFitIntoWindow()) + { + // Scroll how many pages?? + OUString sStateStr(m_sPageStr); + tools::Long nThmbPos = pScrollbar->GetThumbPos(); + if( 1 == m_pViewWin->GetCol() || !nThmbPos ) + ++nThmbPos; + sStateStr += OUString::number( nThmbPos ); + Point aPos = pScrollbar->GetParent()->OutputToScreenPixel( + pScrollbar->GetPosPixel()); + aPos.setY( pScrollbar->OutputToScreenPixel(pScrollbar->GetPointerPosPixel()).Y() ); + tools::Rectangle aRect; + aRect.SetLeft( aPos.X() -8 ); + aRect.SetRight( aRect.Left() ); + aRect.SetTop( aPos.Y() ); + aRect.SetBottom( aRect.Top() ); + + Help::ShowQuickHelp(pScrollbar, aRect, sStateStr, + QuickHelpFlags::Right|QuickHelpFlags::VCenter); + + } + else + EndScrollHdl( pScrollbar ); +} + +IMPL_LINK( SwPagePreview, EndScrollHdl, ScrollBar *, p, void ) +{ + SwScrollbar* pScrollbar = static_cast<SwScrollbar*>(p); + if(!GetViewShell()) + return; + + // boolean to avoid unnecessary invalidation of the window. + bool bInvalidateWin = true; + + if( !pScrollbar->IsHoriScroll() ) // scroll vertically + { + if ( Help::IsQuickHelpEnabled() ) + Help::ShowQuickHelp(pScrollbar, tools::Rectangle(), OUString()); + if ( GetViewShell()->PagePreviewLayout()->DoesPreviewLayoutRowsFitIntoWindow() ) + { + // Scroll how many pages ?? + const sal_uInt16 nThmbPos = o3tl::narrowing<sal_uInt16>(pScrollbar->GetThumbPos()); + // adjust to new preview functionality + if( nThmbPos != m_pViewWin->SelectedPage() ) + { + // consider case that page <nThmbPos> + // is already visible + SwPagePreviewLayout* pPagePreviewLay = GetViewShell()->PagePreviewLayout(); + if ( pPagePreviewLay->IsPageVisible( nThmbPos ) ) + { + pPagePreviewLay->MarkNewSelectedPage( nThmbPos ); + // invalidation of window is unnecessary + bInvalidateWin = false; + } + else + { + // consider whether layout columns + // fit or not. + if ( !pPagePreviewLay->DoesPreviewLayoutColsFitIntoWindow() ) + { + m_pViewWin->SetSttPage( nThmbPos ); + m_pViewWin->SetSelectedPage( nThmbPos ); + ChgPage( SwPagePreviewWin::MV_SCROLL, false ); + // update scrollbars + ScrollViewSzChg(); + } + else + { + // correct scroll amount + const sal_Int16 nPageDiff = nThmbPos - m_pViewWin->SelectedPage(); + const sal_uInt16 nVisPages = m_pViewWin->GetRow() * m_pViewWin->GetCol(); + sal_Int16 nWinPagesToScroll = nPageDiff / nVisPages; + if ( nPageDiff % nVisPages ) + { + // decrease/increase number of preview pages to scroll + nPageDiff < 0 ? --nWinPagesToScroll : ++nWinPagesToScroll; + } + m_pViewWin->SetSelectedPage( nThmbPos ); + m_pViewWin->Scroll( 0, pPagePreviewLay->GetWinPagesScrollAmount( nWinPagesToScroll ) ); + } + } + // update accessibility + GetViewShell()->ShowPreviewSelection( nThmbPos ); + } + else + { + // invalidation of window is unnecessary + bInvalidateWin = false; + } + } + else + { + tools::Long nThmbPos = pScrollbar->GetThumbPos(); + m_pViewWin->Scroll(0, nThmbPos - m_pViewWin->GetPaintedPreviewDocRect().Top()); + } + } + else + { + tools::Long nThmbPos = pScrollbar->GetThumbPos(); + m_pViewWin->Scroll(nThmbPos - m_pViewWin->GetPaintedPreviewDocRect().Left(), 0); + } + // additional invalidate page status. + static sal_uInt16 aInval[] = + { + FN_START_OF_DOCUMENT, FN_END_OF_DOCUMENT, FN_PAGEUP, FN_PAGEDOWN, + FN_STAT_PAGE, 0 + }; + SfxBindings& rBindings = GetViewFrame()->GetBindings(); + rBindings.Invalidate( aInval ); + // control invalidation of window + if ( bInvalidateWin ) + { + m_pViewWin->Invalidate(); + } +} + +Point SwPagePreview::AlignToPixel(const Point &rPt) const +{ + return m_pViewWin->PixelToLogic( m_pViewWin->LogicToPixel( rPt ) ); +} + +void SwPagePreview::DocSzChgd( const Size &rSz ) +{ + if( m_aDocSize == rSz ) + return; + + m_aDocSize = rSz; + + // #i96726# + // Due to the multiple page layout it is needed to trigger recalculation + // of the page preview layout, even if the count of pages is not changing. + mnPageCount = GetViewShell()->GetNumPages(); + + if( m_aVisArea.GetWidth() ) + { + ChgPage( SwPagePreviewWin::MV_CALC ); + ScrollDocSzChg(); + + m_pViewWin->Invalidate(); + } +} + +void SwPagePreview::ScrollViewSzChg() +{ + if(!GetViewShell()) + return ; + + bool bShowVScrollbar = false, bShowHScrollbar = false; + + if(m_pVScrollbar) + { + if(GetViewShell()->PagePreviewLayout()->DoesPreviewLayoutRowsFitIntoWindow()) + { + //vertical scrolling by row + // adjust to new preview functionality + const sal_uInt16 nVisPages = m_pViewWin->GetRow() * m_pViewWin->GetCol(); + + m_pVScrollbar->SetVisibleSize( nVisPages ); + // set selected page as scroll bar position, + // if it is visible. + SwPagePreviewLayout* pPagePreviewLay = GetViewShell()->PagePreviewLayout(); + if ( pPagePreviewLay->IsPageVisible( m_pViewWin->SelectedPage() ) ) + { + m_pVScrollbar->SetThumbPos( m_pViewWin->SelectedPage() ); + } + else + { + m_pVScrollbar->SetThumbPos( m_pViewWin->GetSttPage() ); + } + m_pVScrollbar->SetLineSize( m_pViewWin->GetCol() ); + m_pVScrollbar->SetPageSize( nVisPages ); + // calculate and set scrollbar range + Range aScrollbarRange( 1, mnPageCount ); + // increase range by one, because left-top-corner is left blank. + ++aScrollbarRange.Max(); + // increase range in order to access all pages + aScrollbarRange.Max() += ( nVisPages - 1 ); + m_pVScrollbar->SetRange( aScrollbarRange ); + + bShowVScrollbar = nVisPages < mnPageCount; + } + else //vertical scrolling by pixel + { + const tools::Rectangle& rDocRect = m_pViewWin->GetPaintedPreviewDocRect(); + const Size& rPreviewSize = + GetViewShell()->PagePreviewLayout()->GetPreviewDocSize(); + m_pVScrollbar->SetRangeMax(rPreviewSize.Height()) ; + tools::Long nVisHeight = rDocRect.GetHeight(); + m_pVScrollbar->SetVisibleSize( nVisHeight ); + m_pVScrollbar->SetThumbPos( rDocRect.Top() ); + m_pVScrollbar->SetLineSize( nVisHeight / 10 ); + m_pVScrollbar->SetPageSize( nVisHeight / 2 ); + + bShowVScrollbar = true; + } + + if (!mbVScrollbarEnabled) + bShowVScrollbar = false; + + ShowVScrollbar(bShowVScrollbar); + } + if(m_pHScrollbar) + { + const tools::Rectangle& rDocRect = m_pViewWin->GetPaintedPreviewDocRect(); + const Size& rPreviewSize = + GetViewShell()->PagePreviewLayout()->GetPreviewDocSize(); + Range aRange(0,0); + + if(rDocRect.GetWidth() < rPreviewSize.Width()) + { + bShowHScrollbar = true; + + tools::Long nVisWidth = rDocRect.GetWidth(); + tools::Long nThumb = rDocRect.Left(); + aRange = Range(0, rPreviewSize.Width()); + + m_pHScrollbar->SetRange( aRange ); + m_pHScrollbar->SetVisibleSize( nVisWidth ); + m_pHScrollbar->SetThumbPos( nThumb ); + m_pHScrollbar->SetLineSize( nVisWidth / 10 ); + m_pHScrollbar->SetPageSize( nVisWidth / 2 ); + } + + if (!mbHScrollbarEnabled) + bShowHScrollbar = false; + + ShowHScrollbar(bShowHScrollbar); + } + m_pScrollFill->Show(bShowVScrollbar && bShowHScrollbar); +} + +void SwPagePreview::ScrollDocSzChg() +{ + ScrollViewSzChg(); +} + +// All about printing +SfxPrinter* SwPagePreview::GetPrinter( bool bCreate ) +{ + return m_pViewWin->GetViewShell()->getIDocumentDeviceAccess().getPrinter( bCreate ); +} + +sal_uInt16 SwPagePreview::SetPrinter( SfxPrinter *pNew, SfxPrinterChangeFlags nDiffFlags ) +{ + SwViewShell &rSh = *GetViewShell(); + SfxPrinter* pOld = rSh.getIDocumentDeviceAccess().getPrinter( false ); + if ( pOld && pOld->IsPrinting() ) + return SFX_PRINTERROR_BUSY; + + SwEditShell &rESh = static_cast<SwEditShell&>(rSh); //Buh... + if( ( SfxPrinterChangeFlags::PRINTER | SfxPrinterChangeFlags::JOBSETUP ) & nDiffFlags ) + { + rSh.getIDocumentDeviceAccess().setPrinter( pNew, true, true ); + if( nDiffFlags & SfxPrinterChangeFlags::PRINTER ) + rESh.SetModified(); + } + if ( ( nDiffFlags & SfxPrinterChangeFlags::OPTIONS ) == SfxPrinterChangeFlags::OPTIONS ) + ::SetPrinter( &rSh.getIDocumentDeviceAccess(), pNew, false ); + + const bool bChgOri = bool(nDiffFlags & SfxPrinterChangeFlags::CHG_ORIENTATION); + const bool bChgSize = bool(nDiffFlags & SfxPrinterChangeFlags::CHG_SIZE); + if ( bChgOri || bChgSize ) + { + rESh.StartAllAction(); + if ( bChgOri ) + rSh.ChgAllPageOrientation( pNew->GetOrientation() ); + if ( bChgSize ) + { + Size aSz( SvxPaperInfo::GetPaperSize( pNew ) ); + rSh.ChgAllPageSize( aSz ); + } + if( !m_bNormalPrint ) + m_pViewWin->CalcWish( m_pViewWin->GetRow(), m_pViewWin->GetCol() ); + rESh.SetModified(); + rESh.EndAllAction(); + + static sal_uInt16 aInval[] = + { + SID_ATTR_LONG_ULSPACE, SID_ATTR_LONG_LRSPACE, + SID_RULER_BORDERS, SID_RULER_PAGE_POS, 0 + }; +#if OSL_DEBUG_LEVEL > 0 + { + const sal_uInt16* pPtr = aInval + 1; + do { + OSL_ENSURE( *(pPtr - 1) < *pPtr, "wrong sorting!" ); + } while( *++pPtr ); + } +#endif + + GetViewFrame()->GetBindings().Invalidate(aInval); + } + + return 0; +} + +bool SwPagePreview::HasPrintOptionsPage() const +{ + return true; +} + +std::unique_ptr<SfxTabPage> SwPagePreview::CreatePrintOptionsPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet &rOptions) +{ + return ::CreatePrintOptionsPage(pPage, pController, rOptions, !m_bNormalPrint); +} + +void SwPagePreviewWin::SetViewShell( SwViewShell* pShell ) +{ + mpViewShell = pShell; + if ( mpViewShell && mpViewShell->IsPreview() ) + { + mpPgPreviewLayout = mpViewShell->PagePreviewLayout(); + } +} + +void SwPagePreviewWin::RepaintCoreRect( const SwRect& rRect ) +{ + // #i24183# + if ( mpPgPreviewLayout->PreviewLayoutValid() ) + { + mpPgPreviewLayout->Repaint( tools::Rectangle( rRect.Pos(), rRect.SSize() ) ); + } +} + +/** method to adjust preview to a new zoom factor + + #i19975# also consider zoom type - adding parameter <_eZoomType> +*/ +void SwPagePreviewWin::AdjustPreviewToNewZoom( const sal_uInt16 _nZoomFactor, + const SvxZoomType _eZoomType ) +{ + // #i19975# consider zoom type + if ( _eZoomType == SvxZoomType::WHOLEPAGE ) + { + mnRow = 1; + mnCol = 1; + mpPgPreviewLayout->Init( mnCol, mnRow, maPxWinSize ); + mpPgPreviewLayout->Prepare( mnSttPage, Point(0,0), maPxWinSize, + mnSttPage, maPaintedPreviewDocRect ); + SetSelectedPage( mnSttPage ); + SetPagePreview(mnRow, mnCol); + maScale = GetMapMode().GetScaleX(); + } + else if ( _nZoomFactor != 0 ) + { + // calculate new scaling and set mapping mode appropriately. + Fraction aNewScale( _nZoomFactor, 100 ); + MapMode aNewMapMode = GetMapMode(); + aNewMapMode.SetScaleX( aNewScale ); + aNewMapMode.SetScaleY( aNewScale ); + SetMapMode( aNewMapMode ); + + // calculate new start position for preview paint + Size aNewWinSize = PixelToLogic( maPxWinSize ); + Point aNewPaintStartPos = + mpPgPreviewLayout->GetPreviewStartPosForNewScale( aNewScale, maScale, aNewWinSize ); + + // remember new scaling and prepare preview paint + // Note: paint of preview will be performed by a corresponding invalidate + // due to property changes. + maScale = aNewScale; + mpPgPreviewLayout->Prepare( 0, aNewPaintStartPos, maPxWinSize, + mnSttPage, maPaintedPreviewDocRect ); + } + +} + +/** + * pixel scrolling - horizontally always or vertically + * when less than the desired number of rows fits into + * the view + */ +void SwPagePreviewWin::Scroll(tools::Long nXMove, tools::Long nYMove, ScrollFlags /*nFlags*/) +{ + maPaintedPreviewDocRect.Move(nXMove, nYMove); + mpPgPreviewLayout->Prepare( 0, maPaintedPreviewDocRect.TopLeft(), + maPxWinSize, mnSttPage, + maPaintedPreviewDocRect ); + +} + +bool SwPagePreview::HandleWheelCommands( const CommandEvent& rCEvt ) +{ + bool bOk = false; + const CommandWheelData* pWData = rCEvt.GetWheelData(); + if( pWData && CommandWheelMode::ZOOM == pWData->GetMode() ) + { + //only the Preference shouldn't control the Zoom, it is better to detect AT tools running. So the bridge can be used here + if (!Application::GetSettings().GetMiscSettings().GetEnableATToolSupport()) + { + sal_uInt16 nFactor = GetViewShell()->GetViewOptions()->GetZoom(); + const sal_uInt16 nOffset = 10; + if( 0L > pWData->GetDelta() ) + { + nFactor -= nOffset; + if(nFactor < MIN_PREVIEW_ZOOM) + nFactor = MIN_PREVIEW_ZOOM; + } + else + { + nFactor += nOffset; + if(nFactor > MAX_PREVIEW_ZOOM) + nFactor = MAX_PREVIEW_ZOOM; + } + SetZoom(SvxZoomType::PERCENT, nFactor); + } + bOk = true; + } + else + bOk = m_pViewWin->HandleScrollCommand( rCEvt, m_pHScrollbar, m_pVScrollbar ); + return bOk; +} + +uno::Reference< css::accessibility::XAccessible > + SwPagePreviewWin::CreateAccessible() +{ + SolarMutexGuard aGuard; // this should have happened already!!! +#if !ENABLE_WASM_STRIP_ACCESSIBILITY + OSL_ENSURE( GetViewShell() != nullptr, "We need a view shell" ); + css::uno::Reference< css::accessibility::XAccessible > xAcc = GetAccessible( false ); + if (xAcc.is()) + { + return xAcc; + } + if (mpViewShell) + { + css::uno::Reference< css::accessibility::XAccessible > xAccPreview = mpViewShell->CreateAccessiblePreview(); + SetAccessible(xAccPreview); + } +#endif + return GetAccessible( false ); +} + +void SwPagePreview::ApplyAccessibilityOptions(SvtAccessibilityOptions const & rAccessibilityOptions) +{ + GetViewShell()->ApplyAccessibilityOptions(rAccessibilityOptions); +} + +void SwPagePreview::ShowHScrollbar(bool bShow) +{ + m_pHScrollbar->Show(bShow); + InvalidateBorder(); +} + +void SwPagePreview::ShowVScrollbar(bool bShow) +{ + m_pVScrollbar->Show(bShow); + InvalidateBorder(); +} + +void SwPagePreview::EnableHScrollbar(bool bEnable) +{ + if (mbHScrollbarEnabled != bEnable) + { + mbHScrollbarEnabled = bEnable; + ScrollViewSzChg(); + } +} + +void SwPagePreview::EnableVScrollbar(bool bEnable) +{ + if (mbVScrollbarEnabled != bEnable) + { + mbVScrollbarEnabled = bEnable; + ScrollViewSzChg(); + } +} + +void SwPagePreview::SetZoom(SvxZoomType eType, sal_uInt16 nFactor) +{ + SwViewShell& rSh = *GetViewShell(); + SwViewOption aOpt(*rSh.GetViewOptions()); + // perform action only on changes of zoom or zoom type. + if ( aOpt.GetZoom() != nFactor || + aOpt.GetZoomType() != eType ) + { + aOpt.SetZoom(nFactor); + aOpt.SetZoomType(eType); + rSh.ApplyViewOptions( aOpt ); + lcl_InvalidateZoomSlots(GetViewFrame()->GetBindings()); + // #i19975# also consider zoom type + m_pViewWin->AdjustPreviewToNewZoom( nFactor, eType ); + ScrollViewSzChg(); + } +} + +/** adjust position of vertical scrollbar */ +void SwPagePreview::SetVScrollbarThumbPos( const sal_uInt16 _nNewThumbPos ) +{ + if ( m_pVScrollbar ) + { + m_pVScrollbar->SetThumbPos( _nNewThumbPos ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/uiview/scroll.cxx b/sw/source/uibase/uiview/scroll.cxx new file mode 100644 index 000000000..a277a5972 --- /dev/null +++ b/sw/source/uibase/uiview/scroll.cxx @@ -0,0 +1,119 @@ +/* -*- 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 <scroll.hxx> + +#define SCROLL_LINE_SIZE 250 + +SwScrollbar::SwScrollbar( vcl::Window *pWin, bool bHoriz ) : + ScrollBar( pWin, + WinBits( WB_3DLOOK | WB_HIDE | ( bHoriz ? WB_HSCROLL : WB_VSCROLL) ) ), + m_bHori( bHoriz ), + m_bAuto( false ), + m_bVisible(false), + m_bSizeSet(false) +{ + // No mirroring for horizontal scrollbars + if( bHoriz ) + EnableRTL( false ); +} + + SwScrollbar::~SwScrollbar() {} + +// Will be called after a change of the document size +// to refresh the range of the scrollbars. + +void SwScrollbar::DocSzChgd( const Size &rSize ) +{ + m_aDocSz = rSize; + SetRange( Range( 0, m_bHori ? rSize.Width() : rSize.Height()) ); + const sal_uLong nVisSize = GetVisibleSize(); + SetLineSize( SCROLL_LINE_SIZE ); + SetPageSize( nVisSize * 77 / 100 ); +} + +// Will be called after a change of the visible view section. + +void SwScrollbar::ViewPortChgd( const tools::Rectangle &rRect ) +{ + tools::Long nThumb, nVisible; + if( m_bHori ) + { + nThumb = rRect.Left(); + nVisible = rRect.GetWidth(); + } + else + { + nThumb = rRect.Top(); + nVisible = rRect.GetHeight(); + } + + SetVisibleSize( nVisible ); + DocSzChgd(m_aDocSz); + SetThumbPos( nThumb ); + if(m_bAuto) + AutoShow(); +} + +void SwScrollbar::ExtendedShow( bool bSet ) +{ + m_bVisible = bSet; + if( (!bSet || !m_bAuto) && IsUpdateMode() && m_bSizeSet) + ScrollBar::Show(bSet); +} + +void SwScrollbar::SetPosSizePixel( const Point& rNewPos, const Size& rNewSize ) +{ + ScrollBar::SetPosSizePixel(rNewPos, rNewSize); + m_bSizeSet = true; + if(m_bVisible) + ExtendedShow(); + +} + +void SwScrollbar::SetAuto(bool bSet) +{ + if(m_bAuto != bSet) + { + m_bAuto = bSet; + + // hide automatically - then show + if(!m_bAuto && m_bVisible && !ScrollBar::IsVisible()) + ExtendedShow(); + else if(m_bAuto) + AutoShow(); // or hide automatically + } +} + +void SwScrollbar::AutoShow() +{ + tools::Long nVis = GetVisibleSize(); + tools::Long nLen = GetRange().Len(); + if( nVis >= nLen - 1) + { + if(ScrollBar::IsVisible()) + ScrollBar::Show(false); + } + else if ( !ScrollBar::IsVisible() ) + { + ScrollBar::Show(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/uiview/srcview.cxx b/sw/source/uibase/uiview/srcview.cxx new file mode 100644 index 000000000..a143493fe --- /dev/null +++ b/sw/source/uibase/uiview/srcview.cxx @@ -0,0 +1,838 @@ +/* -*- 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 <rtl/tencinfo.h> +#include <osl/diagnose.h> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <unotools/tempfile.hxx> +#include <tools/urlobj.hxx> +#include <vcl/errinf.hxx> +#include <vcl/weld.hxx> +#include <vcl/textview.hxx> +#include <vcl/svapp.hxx> +#include <svl/intitem.hxx> +#include <svl/stritem.hxx> +#include <svl/undo.hxx> +#include <svl/eitem.hxx> +#include <svl/whiter.hxx> +#include <vcl/transfer.hxx> +#include <svtools/strings.hrc> +#include <svtools/svtresid.hxx> +#include <svtools/htmlcfg.hxx> +#include <sfx2/app.hxx> +#include <sfx2/objface.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/docfilt.hxx> +#include <sfx2/fcontnr.hxx> +#include <sfx2/request.hxx> +#include <sfx2/docfile.hxx> +#include <svx/srchdlg.hxx> +#include <svl/srchitem.hxx> +#include <sfx2/sfxhtml.hxx> +#include <swtypes.hxx> +#include <docsh.hxx> +#include <wdocsh.hxx> +#include <srcview.hxx> +#include "viewfunc.hxx" +#include <doc.hxx> +#include <IDocumentDeviceAccess.hxx> +#include <IDocumentState.hxx> +#include <sfx2/msg.hxx> +#include <shellio.hxx> + +#include <cmdid.h> +#include <strings.hrc> +#include <com/sun/star/ui/dialogs/XFilePicker3.hpp> +#include <sfx2/filedlghelper.hxx> +#define ShellClass_SwSrcView +#include <swslots.hxx> + +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::i18n; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ui::dialogs; +using namespace ::sfx2; + +#define SWSRCVIEWFLAGS SfxViewShellFlags::NO_NEWWINDOW + +#define SRC_SEARCHOPTIONS (SearchOptionFlags::ALL & ~SearchOptionFlags(SearchOptionFlags::FORMAT|SearchOptionFlags::FAMILIES|SearchOptionFlags::SEARCHALL)) + +// Printing margins -> like Basic - Ide +#define LMARGPRN 1700 +#define RMARGPRN 900 +#define TMARGPRN 2000 +#define BMARGPRN 1000 +#define BORDERPRN 300 + +SFX_IMPL_NAMED_VIEWFACTORY(SwSrcView, "SourceView") +{ + SFX_VIEW_REGISTRATION(SwWebDocShell); +} + +SFX_IMPL_SUPERCLASS_INTERFACE(SwSrcView, SfxViewShell) + +void SwSrcView::InitInterface_Impl() +{ + GetStaticInterface()->RegisterPopupMenu("source"); + + GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_TOOLS, + SfxVisibilityFlags::Standard|SfxVisibilityFlags::Server, + ToolbarId::Webtools_Toolbox); + + GetStaticInterface()->RegisterChildWindow(SvxSearchDialogWrapper::GetChildWindowId()); +} + + +static void lcl_PrintHeader( vcl::RenderContext &rOutDev, sal_Int32 nPages, sal_Int32 nCurPage, const OUString& rTitle ) +{ + short nLeftMargin = LMARGPRN; + Size aSz = rOutDev.GetOutputSize(); + short nBorder = BORDERPRN; + + Color aOldFillColor( rOutDev.GetFillColor() ); + vcl::Font aOldFont( rOutDev.GetFont() ); + + rOutDev.SetFillColor( COL_TRANSPARENT ); + + vcl::Font aFont( aOldFont ); + aFont.SetWeight( WEIGHT_BOLD ); + aFont.SetAlignment( ALIGN_BOTTOM ); + rOutDev.SetFont( aFont ); + + tools::Long nFontHeight = rOutDev.GetTextHeight(); + + // 1.Border => Line, 2+3 Border = Space. + tools::Long nYTop = TMARGPRN-3*nBorder-nFontHeight; + + tools::Long nXLeft = nLeftMargin-nBorder; + tools::Long nXRight = aSz.Width()-RMARGPRN+nBorder; + + rOutDev.DrawRect( tools::Rectangle( + Point( nXLeft, nYTop ), + Size( nXRight-nXLeft, aSz.Height() - nYTop - BMARGPRN + nBorder ) ) ); + + tools::Long nY = TMARGPRN-2*nBorder; + Point aPos( nLeftMargin, nY ); + rOutDev.DrawText( aPos, rTitle ); + if ( nPages != 1 ) + { + aFont.SetWeight( WEIGHT_NORMAL ); + rOutDev.SetFont( aFont ); + OUString aPageStr = " [" + SwResId( STR_PAGE ) + " " + OUString::number( nCurPage ) + "]"; + aPos.AdjustX(rOutDev.GetTextWidth( rTitle ) ); + rOutDev.DrawText( aPos, aPageStr ); + } + + nY = TMARGPRN-nBorder; + + rOutDev.DrawLine( Point( nXLeft, nY ), Point( nXRight, nY ) ); + + rOutDev.SetFont( aOldFont ); + rOutDev.SetFillColor( aOldFillColor ); +} + +static rtl_TextEncoding lcl_GetStreamCharSet(rtl_TextEncoding eLoadEncoding) +{ + rtl_TextEncoding eRet = eLoadEncoding; + if(RTL_TEXTENCODING_DONTKNOW == eRet) + { + eRet = RTL_TEXTENCODING_UTF8; + } + return eRet; +} + +static OUString lcl_ConvertTabsToSpaces( const OUString& sLine ) +{ + if (sLine.isEmpty()) + return sLine; + + OUString aRet = sLine; + const sal_Unicode aPadSpaces[4] = {' ', ' ', ' ', ' '}; + sal_Int32 nPos = 0; + for (;;) + { + nPos = aRet.indexOf('\t', nPos); + if (nPos<0) + { + break; + } + // Not 4 blanks, but on 4th TabPos: + const sal_Int32 nPadLen = 4 - (nPos % 4); + aRet = aRet.replaceAt(nPos, 1, std::u16string_view{aPadSpaces, static_cast<size_t>(nPadLen)}); + nPos += nPadLen; + } + return aRet; +} + +SwSrcView::SwSrcView(SfxViewFrame* pViewFrame, SfxViewShell*) : + SfxViewShell( pViewFrame, SWSRCVIEWFLAGS ), + m_aEditWin( VclPtr<SwSrcEditWindow>::Create( &pViewFrame->GetWindow(), this ) ), + m_bSourceSaved(false), + m_eLoadEncoding(RTL_TEXTENCODING_DONTKNOW) +{ + Init(); +} + +SwSrcView::~SwSrcView() +{ + SwDocShell* pDocShell = GetDocShell(); + assert(dynamic_cast<SwWebDocShell*>( pDocShell) && "Why no WebDocShell?" ); + const TextSelection& rSel = m_aEditWin->GetTextView()->GetSelection(); + static_cast<SwWebDocShell*>(pDocShell)->SetSourcePara( static_cast< sal_uInt16 >( rSel.GetStart().GetPara() ) ); + + uno::Reference<document::XDocumentPropertiesSupplier> xDPS( + pDocShell->GetModel(), uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> xDocProps + = xDPS->getDocumentProperties(); + OUString url = xDocProps->getAutoloadURL(); + sal_Int32 delay = xDocProps->getAutoloadSecs(); + pDocShell->SetAutoLoad(INetURLObject(url), delay, + (delay != 0) || !url.isEmpty()); + EndListening(*pDocShell); + m_pSearchItem.reset(); + + m_aEditWin.disposeAndClear(); +} + +void SwSrcView::SaveContentTo(SfxMedium& rMed) +{ + SvStream* pOutStream = rMed.GetOutStream(); + pOutStream->SetStreamCharSet(lcl_GetStreamCharSet(m_eLoadEncoding)); + m_aEditWin->Write( *pOutStream ); +} + +void SwSrcView::Init() +{ + SetName("Source"); + SetWindow( m_aEditWin.get() ); + SwDocShell* pDocShell = GetDocShell(); + // If the doc is still loading, then the DocShell must fire up + // the Load if the loading is completed. + if(!pDocShell->IsLoading()) + Load(pDocShell); + else + { + m_aEditWin->SetReadonly(true); + } + + SetNewWindowAllowed( false ); + StartListening(*pDocShell, DuplicateHandling::Prevent); +} + +SwDocShell* SwSrcView::GetDocShell() +{ + SfxObjectShell* pObjShell = GetViewFrame()->GetObjectShell(); + return dynamic_cast<SwDocShell*>( pObjShell ); +} + +void SwSrcView::SaveContent(const OUString& rTmpFile) +{ + SfxMedium aMedium( rTmpFile, StreamMode::WRITE); + SvStream* pOutStream = aMedium.GetOutStream(); + pOutStream->SetStreamCharSet( lcl_GetStreamCharSet(m_eLoadEncoding) ); + m_aEditWin->Write(*pOutStream); + aMedium.Commit(); +} + +void SwSrcView::Execute(SfxRequest& rReq) +{ + TextView* pTextView = m_aEditWin->GetTextView(); + switch( rReq.GetSlot() ) + { + case SID_SAVEACOPY: + case SID_SAVEASDOC: + { + // filesave dialog with autoextension + FileDialogHelper aDlgHelper( + TemplateDescription::FILESAVE_AUTOEXTENSION, + FileDialogFlags::NONE, m_aEditWin->GetFrameWeld()); + uno::Reference < XFilePicker3 > xFP = aDlgHelper.GetFilePicker(); + + // search for an html filter for export + SfxFilterContainer* pFilterCont = GetObjectShell()->GetFactory().GetFilterContainer(); + std::shared_ptr<const SfxFilter> pFilter = + pFilterCont->GetFilter4Extension( "html", SfxFilterFlags::EXPORT ); + if ( pFilter ) + { + // filter found -> use its uiname and wildcard + const OUString& rUIName = pFilter->GetUIName(); + const WildCard& rCard = pFilter->GetWildcard(); + xFP->appendFilter( rUIName, rCard.getGlob() ); + xFP->setCurrentFilter( rUIName ) ; + } + else + { + // filter not found + OUString sHtml("HTML"); + xFP->appendFilter( sHtml, "*.html;*.htm" ); + xFP->setCurrentFilter( sHtml ) ; + } + + if( aDlgHelper.Execute() == ERRCODE_NONE) + { + SfxMedium aMedium( xFP->getSelectedFiles().getConstArray()[0], + StreamMode::WRITE | StreamMode::SHARE_DENYNONE ); + SvStream* pOutStream = aMedium.GetOutStream(); + pOutStream->SetStreamCharSet(lcl_GetStreamCharSet(m_eLoadEncoding)); + m_aEditWin->Write( *pOutStream ); + aMedium.Commit(); + } + } + break; + case SID_SAVEDOC: + { + SwDocShell* pDocShell = GetDocShell(); + assert(pDocShell); + SfxMedium* pMed = nullptr; + if(pDocShell->HasName()) + pMed = pDocShell->GetMedium(); + else + { + const SfxBoolItem* pItem = static_cast<const SfxBoolItem*>(pDocShell->ExecuteSlot(rReq, pDocShell->GetInterface())); + if(pItem && pItem->GetValue()) + pMed = pDocShell->GetMedium(); + } + if(pMed) + { + SvStream* pOutStream = pMed->GetOutStream(); + pOutStream->Seek(0); + pOutStream->SetStreamSize(0); + pOutStream->SetStreamCharSet(lcl_GetStreamCharSet(m_eLoadEncoding)); + m_aEditWin->Write( *pOutStream ); + pMed->CloseOutStream(); + pMed->Commit(); + pDocShell->GetDoc()->getIDocumentState().ResetModified(); + m_bSourceSaved = true; + m_aEditWin->ClearModifyFlag(); + } + } + break; + case FID_SEARCH_NOW: + { + const SfxItemSet* pTmpArgs = rReq.GetArgs(); + + const sal_uInt16 nWhich = pTmpArgs->GetWhichByPos( 0 ); + OSL_ENSURE( nWhich, "Which for SearchItem ?" ); + const SfxPoolItem& rItem = pTmpArgs->Get( nWhich ); + SetSearchItem( static_cast<const SvxSearchItem&>(rItem)); + StartSearchAndReplace( static_cast<const SvxSearchItem&>(rItem), rReq.IsAPI() ); + if(m_aEditWin->IsModified()) + { + SwDocShell* pDocShell = GetDocShell(); + assert(pDocShell); + pDocShell->GetDoc()->getIDocumentState().SetModified(); + } + } + break; + case FN_REPEAT_SEARCH: + { + SvxSearchItem* pSrchItem = GetSearchItem(); + if(pSrchItem) + { + StartSearchAndReplace( *pSrchItem, rReq.IsAPI() ); + if(m_aEditWin->IsModified()) + GetDocShell()->GetDoc()->getIDocumentState().SetModified(); + } + } + break; + case SID_PRINTDOC: + case SID_PRINTDOCDIRECT: + { + SfxViewShell::ExecuteSlot( rReq, SfxViewShell::GetInterface() ); + } + break; + case SID_UNDO: + pTextView->Undo(); + GetViewFrame()->GetBindings().InvalidateAll(false); + break; + case SID_REDO: + pTextView->Redo(); + GetViewFrame()->GetBindings().InvalidateAll(false); + break; + case SID_REPEAT: + break; + case SID_CUT: + if(pTextView->HasSelection()) + pTextView->Cut(); + break; + case SID_COPY: + if(pTextView->HasSelection()) + pTextView->Copy(); + break; + case SID_PASTE: + pTextView->Paste(); + break; + case SID_SELECTALL: + pTextView->SetSelection( TextSelection( TextPaM( 0, 0 ), TextPaM( TEXT_PARA_ALL, TEXT_INDEX_ALL ) ) ); + break; + } + m_aEditWin->Invalidate(); +} + +void SwSrcView::GetState(SfxItemSet& rSet) +{ + SfxWhichIter aIter(rSet); + sal_uInt16 nWhich = aIter.FirstWhich(); + TextView* pTextView = m_aEditWin->GetTextView(); + + while(nWhich) + { + switch(nWhich) + { + case SID_SAVEASDOC: + rSet.Put(SfxStringItem(nWhich, SwResId(STR_SAVEAS_SRC))); + break; + case SID_SAVEACOPY: + rSet.Put(SfxStringItem(nWhich, SwResId(STR_SAVEACOPY_SRC))); + break; + case SID_SAVEDOC: + { + SwDocShell* pDocShell = GetDocShell(); + assert(pDocShell); + if(!pDocShell->IsModified()) + rSet.DisableItem(nWhich); + } + break; + case SID_PRINTDOC: + case SID_PRINTDOCDIRECT: + break; + case SID_TABLE_CELL: + { + OUString aPos( SwResId(STR_SRCVIEW_ROW) ); + TextSelection aSel = pTextView->GetSelection(); + aPos += OUString::number( aSel.GetEnd().GetPara()+1 ); + aPos += " : " + + SwResId(STR_SRCVIEW_COL); + aPos += OUString::number( aSel.GetEnd().GetIndex()+1 ); + SfxStringItem aItem( nWhich, aPos ); + rSet.Put( aItem ); + } + break; + case SID_SEARCH_OPTIONS: + { + SearchOptionFlags nOpt = SRC_SEARCHOPTIONS; + SwDocShell* pDocShell = GetDocShell(); + assert(pDocShell); + if (pDocShell->IsReadOnly()) + nOpt &= ~SearchOptionFlags(SearchOptionFlags::REPLACE|SearchOptionFlags::REPLACE_ALL); + + rSet.Put( SfxUInt16Item( SID_SEARCH_OPTIONS, static_cast<sal_uInt16>(nOpt) ) ); + } + break; + case SID_SEARCH_ITEM: + { + OUString sSelected; + if ( !pTextView->HasSelection() ) + { + const TextSelection& rSel = pTextView->GetSelection(); + sSelected = m_aEditWin->GetTextEngine()->GetWord( rSel.GetStart()); + } + else + { + sSelected = pTextView->GetSelected(); + } + SvxSearchItem * pSrchItem = GetSearchItem(); + pSrchItem->SetSearchString( sSelected ); + rSet.Put( *pSrchItem ); + } + break; + case FN_REPEAT_SEARCH: + { + if(!GetSearchItem()) + rSet.DisableItem(nWhich); + } + break; + case SID_UNDO: + case SID_REDO: + { + SfxUndoManager& rMgr = pTextView->GetTextEngine()->GetUndoManager(); + sal_uInt16 nCount = 0; + if(nWhich == SID_UNDO) + { + nCount = rMgr.GetUndoActionCount(); + if(nCount) + { + OUString aStr(SvtResId( STR_UNDO)); + aStr += rMgr.GetUndoActionComment(--nCount); + rSet.Put(SfxStringItem(nWhich, aStr)); + } + else + rSet.DisableItem(nWhich); + } + else + { + nCount = rMgr.GetRedoActionCount(); + if(nCount) + { + OUString aStr(SvtResId( STR_REDO)); + aStr += rMgr.GetRedoActionComment(--nCount); + rSet.Put(SfxStringItem(nWhich,aStr)); + } + else + rSet.DisableItem(nWhich); + } + } + break; + case SID_MAIL_SENDDOCASPDF: + case SID_MAIL_SENDDOC : + case SID_EXPORTDOCASPDF: + case SID_DIRECTEXPORTDOCASPDF: + case SID_EXPORTDOC: + case SID_REPEAT: + case SID_BROWSER_MODE: + case FN_PRINT_LAYOUT: + rSet.DisableItem(nWhich); + break; + case SID_CUT: + case SID_COPY: + if(!pTextView->HasSelection()) + rSet.DisableItem(nWhich); + break; + case SID_PASTE: + { + TransferableDataHelper aDataHelper( + TransferableDataHelper::CreateFromSystemClipboard( + m_aEditWin.get()) ); + bool bDisable = !aDataHelper.GetXTransferable().is() || + 0 == aDataHelper.GetFormatCount(); + if( bDisable ) + rSet.DisableItem(nWhich); + } + break; + } + nWhich = aIter.NextWhich(); + } +} + +SvxSearchItem* SwSrcView::GetSearchItem() +{ + if(!m_pSearchItem) + { + m_pSearchItem.reset(new SvxSearchItem(SID_SEARCH_ITEM)); + } + return m_pSearchItem.get(); +} + +void SwSrcView::SetSearchItem( const SvxSearchItem& rItem ) +{ + m_pSearchItem.reset(rItem.Clone()); +} + +void SwSrcView::StartSearchAndReplace(const SvxSearchItem& rSearchItem, + bool bApi, + bool bRecursive) +{ + TextView* pTextView = m_aEditWin->GetTextView(); + TextPaM aPaM; + + bool bForward = !rSearchItem.GetBackward(); + bool bAtStart = pTextView->GetSelection() == TextSelection( aPaM, aPaM ); + + if( !bForward ) + aPaM = TextPaM( TEXT_PARA_ALL, TEXT_INDEX_ALL ); + + i18nutil::SearchOptions2 aSearchOpt( rSearchItem.GetSearchOptions() ); + aSearchOpt.Locale = GetAppLanguageTag().getLocale(); + + sal_uInt16 nFound; + bool bAll = false; + switch( rSearchItem.GetCommand() ) + { + case SvxSearchCmd::FIND: + case SvxSearchCmd::FIND_ALL: + nFound = pTextView->Search( aSearchOpt, bForward ) ? 1 : 0; + break; + + case SvxSearchCmd::REPLACE_ALL: bAll = true; + [[fallthrough]]; + case SvxSearchCmd::REPLACE: + nFound = pTextView->Replace( aSearchOpt, bAll, bForward ); + break; + + default: + nFound = 0; + } + + if( nFound ) + return; + + bool bNotFoundMessage = false; + if(!bRecursive) + { + bNotFoundMessage = bAtStart; + } + else if(bAtStart) + { + bNotFoundMessage = true; + } + + if(bApi) + return; + + if(bNotFoundMessage) + { + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(nullptr, "modules/swriter/ui/infonotfounddialog.ui")); + std::unique_ptr<weld::MessageDialog> xInfoBox(xBuilder->weld_message_dialog("InfoNotFoundDialog")); + xInfoBox->run(); + } + else if(!bRecursive) + { + int nRet; + + if (!bForward) + { + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(nullptr, "modules/swriter/ui/querycontinueenddialog.ui")); + std::unique_ptr<weld::MessageDialog> xQueryBox(xBuilder->weld_message_dialog("QueryContinueEndDialog")); + nRet = xQueryBox->run(); + } + else + { + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(nullptr, "modules/swriter/ui/querycontinuebegindialog.ui")); + std::unique_ptr<weld::MessageDialog> xQueryBox(xBuilder->weld_message_dialog("QueryContinueBeginDialog")); + nRet = xQueryBox->run(); + } + + if (nRet == RET_YES) + { + pTextView->SetSelection( TextSelection( aPaM, aPaM ) ); + StartSearchAndReplace( rSearchItem, false, true ); + } + } +} + +sal_uInt16 SwSrcView::SetPrinter(SfxPrinter* pNew, SfxPrinterChangeFlags nDiffFlags ) +{ + SwDocShell* pDocSh = GetDocShell(); + assert(pDocSh); + if ( (SfxPrinterChangeFlags::JOBSETUP | SfxPrinterChangeFlags::PRINTER) & nDiffFlags ) + { + pDocSh->GetDoc()->getIDocumentDeviceAccess().setPrinter( pNew, true, true ); + if ( nDiffFlags & SfxPrinterChangeFlags::PRINTER ) + pDocSh->SetModified(); + } + if ( nDiffFlags & SfxPrinterChangeFlags::OPTIONS ) + ::SetPrinter( &pDocSh->getIDocumentDeviceAccess(), pNew, true ); + + const bool bChgOri = bool(nDiffFlags & SfxPrinterChangeFlags::CHG_ORIENTATION); + const bool bChgSize = bool(nDiffFlags & SfxPrinterChangeFlags::CHG_SIZE); + if ( bChgOri || bChgSize ) + { + pDocSh->SetModified(); + } + return 0; +} + +SfxPrinter* SwSrcView::GetPrinter( bool bCreate ) +{ + SwDocShell* pDocSh = GetDocShell(); + assert(pDocSh); + return pDocSh->GetDoc()->getIDocumentDeviceAccess().getPrinter(bCreate); +} + +sal_Int32 SwSrcView::PrintSource( + OutputDevice *pOutDev, + sal_Int32 nPage, + bool bCalcNumPagesOnly ) +{ + if (!pOutDev || nPage <= 0) + return 0; + + //! This algorithm for printing the n-th page is very poor since it + //! needs to go over the text of all previous pages to get to the correct one. + //! But since HTML source code is expected to be just a small number of pages + //! even this poor algorithm should be enough... + + pOutDev->Push(); + + TextEngine* pTextEngine = m_aEditWin->GetTextEngine(); + pOutDev->SetMapMode(MapMode(MapUnit::Map100thMM)); + vcl::Font aFont( m_aEditWin->GetOutWin()->GetFont() ); + Size aSize( aFont.GetFontSize() ); + aSize = m_aEditWin->GetOutWin()->PixelToLogic(aSize, MapMode(MapUnit::Map100thMM)); + aFont.SetFontSize( aSize ); + aFont.SetColor( COL_BLACK ); + pOutDev->SetFont( aFont ); + + OUString aTitle( GetViewFrame()->GetWindow().GetText() ); + + const tools::Long nLineHeight = pOutDev->GetTextHeight(); // slightly more + const tools::Long nParaSpace = 10; + + Size aPaperSz = pOutDev->GetOutputSize(); + aPaperSz.AdjustWidth( -(LMARGPRN + RMARGPRN) ); + aPaperSz.AdjustHeight( -(TMARGPRN + BMARGPRN) ); + + // nLinepPage is not true, if lines have to be wrapped... + const tools::Long nLinespPage = nLineHeight ? aPaperSz.Height() / nLineHeight : 1; + const tools::Long nCharWidth = pOutDev->GetTextWidth("X"); + const sal_Int32 nCharspLine = nCharWidth ? static_cast<sal_Int32>(aPaperSz.Width() / nCharWidth) : 1; + const sal_uInt32 nParas = pTextEngine->GetParagraphCount(); + + const sal_Int32 nPages = static_cast<sal_Int32>(nParas / nLinespPage + 1 ); + sal_Int32 nCurPage = 1; + + // Print header... + if (!bCalcNumPagesOnly && nPage == nCurPage) + lcl_PrintHeader( *pOutDev, nPages, nCurPage, aTitle ); + const Point aStartPos( LMARGPRN, TMARGPRN ); + Point aPos( aStartPos ); + for ( sal_uInt32 nPara = 0; nPara < nParas; ++nPara ) + { + const OUString aLine( lcl_ConvertTabsToSpaces(pTextEngine->GetText( nPara )) ); + const sal_Int32 nLineLen = aLine.getLength(); + const sal_Int32 nLines = (nLineLen+nCharspLine-1) / nCharspLine; + for ( sal_Int32 nLine = 0; nLine < nLines; ++nLine ) + { + aPos.AdjustY(nLineHeight ); + if ( aPos.Y() > ( aPaperSz.Height() + TMARGPRN - nLineHeight/2 ) ) + { + ++nCurPage; + if (!bCalcNumPagesOnly && nPage == nCurPage) + lcl_PrintHeader( *pOutDev, nPages, nCurPage, aTitle ); + aPos = aStartPos; + } + if (!bCalcNumPagesOnly && nPage == nCurPage) + { + const sal_Int32 nStart = nLine * nCharspLine; + const sal_Int32 nLen = std::min(nLineLen-nStart, nCharspLine); + pOutDev->DrawText( aPos, aLine.copy(nStart, nLen) ); + } + } + aPos.AdjustY(nParaSpace ); + } + + pOutDev->Pop(); + + OSL_ENSURE( bCalcNumPagesOnly || nPage <= nCurPage, "page number out of range" ); + return nCurPage; +} + +void SwSrcView::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) +{ + if (rHint.GetId() == SfxHintId::ModeChanged || rHint.GetId() == SfxHintId::TitleChanged) + { + const SwDocShell* pDocSh = GetDocShell(); + assert(pDocSh); + if (!(rHint.GetId() == SfxHintId::TitleChanged + && (pDocSh->IsReadOnly() || !m_aEditWin->IsReadonly()))) + { + // Broadcast only comes once! + const bool bReadonly = pDocSh->IsReadOnly(); + m_aEditWin->SetReadonly(bReadonly); + } + } + SfxViewShell::Notify(rBC, rHint); +} + +void SwSrcView::Load(SwDocShell* pDocShell) +{ + rtl_TextEncoding eDestEnc = RTL_TEXTENCODING_UTF8; + + m_aEditWin->SetReadonly(pDocShell->IsReadOnly()); + m_aEditWin->SetTextEncoding(eDestEnc); + SfxMedium* pMedium = pDocShell->GetMedium(); + + std::shared_ptr<const SfxFilter> pFilter = pMedium->GetFilter(); + bool bHtml = pFilter && pFilter->GetUserData() == "HTML"; + bool bDocModified = pDocShell->IsModified(); + if(bHtml && !bDocModified && pDocShell->HasName()) + { + SvStream* pStream = pMedium->GetInStream(); + if(pStream && ERRCODE_NONE == pStream->GetError() ) + { + rtl_TextEncoding eHeaderEnc = + SfxHTMLParser::GetEncodingByHttpHeader( + pDocShell->GetHeaderAttributes() ); + if( RTL_TEXTENCODING_DONTKNOW == eHeaderEnc ) + { + const char *pTmpCharSet = + rtl_getBestMimeCharsetFromTextEncoding( RTL_TEXTENCODING_ISO_8859_1 ); + eHeaderEnc = rtl_getTextEncodingFromMimeCharset( pTmpCharSet ); + } + if( RTL_TEXTENCODING_DONTKNOW != eHeaderEnc && + eDestEnc != eHeaderEnc ) + { + eDestEnc = eHeaderEnc; + m_aEditWin->SetTextEncoding(eDestEnc); + } + pStream->SetStreamCharSet( eDestEnc ); + pStream->Seek(0); + TextEngine* pTextEngine = m_aEditWin->GetTextEngine(); + pTextEngine->EnableUndo(false); + m_aEditWin->Read(*pStream); + pTextEngine->EnableUndo(true); + } + else + { + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetViewFrame()->GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SwResId(STR_ERR_SRCSTREAM))); + xBox->run(); + } + } + else + { + utl::TempFile aTempFile; + aTempFile.EnableKillingFile(); + const OUString sFileURL( aTempFile.GetURL() ); + + { + SfxMedium aMedium( sFileURL,StreamMode::READWRITE ); + SwWriter aWriter( aMedium, *pDocShell->GetDoc() ); + WriterRef xWriter; + ::GetHTMLWriter(std::u16string_view(), aMedium.GetBaseURL( true ), xWriter); + const OUString sWriteName = pDocShell->HasName() + ? pMedium->GetName() + : sFileURL; + ErrCode nRes = aWriter.Write(xWriter, &sWriteName); + if(nRes) + { + ErrorHandler::HandleError(nRes); + m_aEditWin->SetReadonly(true); + } + aMedium.Commit(); + SvStream* pInStream = aMedium.GetInStream(); + pInStream->Seek(0); + pInStream->SetStreamCharSet( eDestEnc ); + + m_aEditWin->Read(*pInStream); + } + } + m_aEditWin->ClearModifyFlag(); + + m_eLoadEncoding = eDestEnc; + + if(bDocModified) + pDocShell->SetModified();// The flag will be reset in between times. + // Disable AutoLoad + pDocShell->SetAutoLoad(INetURLObject(), 0, false); + assert(dynamic_cast<SwWebDocShell*>( pDocShell) && "Why no WebDocShell?" ); + sal_uInt16 nLine = static_cast<SwWebDocShell*>(pDocShell)->GetSourcePara(); + m_aEditWin->SetStartLine(nLine); + m_aEditWin->GetTextEngine()->ResetUndo(); + m_aEditWin->GetOutWin()->GrabFocus(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/uiview/swcli.cxx b/sw/source/uibase/uiview/swcli.cxx new file mode 100644 index 000000000..b8c7fc7b7 --- /dev/null +++ b/sw/source/uibase/uiview/swcli.cxx @@ -0,0 +1,193 @@ +/* -*- 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 <com/sun/star/embed/NoVisualAreaSizeException.hpp> +#include <com/sun/star/embed/XEmbeddedObject.hpp> +#include <wrtsh.hxx> +#include <doc.hxx> +#include <IDocumentSettingAccess.hxx> +#include <view.hxx> +#include <edtwin.hxx> +#include <swcli.hxx> +#include <svtools/embedhlp.hxx> +#include <osl/diagnose.h> + +#include <toolkit/helper/vclunohelper.hxx> + +#include <ndole.hxx> + +using namespace com::sun::star; + +SwOleClient::SwOleClient(SwView *pView, SwEditWin *pWin, const svt::EmbeddedObjectRef& xObj) + : SfxInPlaceClient( pView, pWin, xObj.GetViewAspect() ) + , m_IsInDoVerb(false) + , m_IsOldCheckForOLEInCaption(pView->GetWrtShell().IsCheckForOLEInCaption()) +{ + SetObject( xObj.GetObject() ); +} + +void SwOleClient::RequestNewObjectArea( tools::Rectangle& aLogRect ) +{ + // The server wants to change the client size. + // We put the desired size in the core. The attributes of the frame + // are set to the desired value. This value will be passed on to the + // InPlaceClient. + // The core accepts or formats the adjusted values not necessarily. + // If the Ole-Frame is formatted, then the CalcAndSetScale() of the WrtShell + // will be called. There the scaling of the SwOleClient is set if necessary. + + SwWrtShell &rSh = static_cast<SwView*>(GetViewShell())->GetWrtShell(); + + rSh.StartAllAction(); + + // the aLogRect will get the preliminary size now + aLogRect.SetSize( rSh.RequestObjectResize( SwRect( aLogRect ), GetObject() ) ); + + // the EndAllAction() call will trigger CalcAndSetScale() call, + // so the embedded object must get the correct size before + if ( aLogRect.GetSize() != GetScaledObjArea().GetSize() ) + { + // size has changed, so first change visual area of the object before we resize its view + // without this the object always would be scaled - now it has the choice + + // TODO/LEAN: getMapUnit can switch object to running state + MapMode aObjectMap( VCLUnoHelper::UnoEmbed2VCLMapUnit( GetObject()->getMapUnit( GetAspect() ) ) ); + MapMode aClientMap( GetEditWin()->GetMapMode().GetMapUnit() ); + + Size aNewObjSize( tools::Long( aLogRect.GetWidth() / GetScaleWidth() ), + tools::Long( aLogRect.GetHeight() / GetScaleHeight() ) ); + + // convert to logical coordinates of the embedded object + Size aNewSize = GetEditWin()->LogicToLogic( aNewObjSize, &aClientMap, &aObjectMap ); + GetObject()->setVisualAreaSize( GetAspect(), awt::Size( aNewSize.Width(), aNewSize.Height() ) ); + } + + rSh.EndAllAction(); + + SwRect aFrame( rSh.GetAnyCurRect( CurRectType::FlyEmbedded, nullptr, GetObject() )), + aPrt( rSh.GetAnyCurRect( CurRectType::FlyEmbeddedPrt, nullptr, GetObject() )); + aLogRect.SetPos( aPrt.Pos() + aFrame.Pos() ); + aLogRect.SetSize( aPrt.SSize() ); +} + +void SwOleClient::ObjectAreaChanged() +{ + SwWrtShell &rSh = static_cast<SwView*>(GetViewShell())->GetWrtShell(); + SwRect aFrame( rSh.GetAnyCurRect( CurRectType::FlyEmbedded, nullptr, GetObject() )); + if ( !aFrame.Overlaps( rSh.VisArea() ) ) + rSh.MakeVisible( aFrame ); +} + +void SwOleClient::ViewChanged() +{ + if (m_IsInDoVerb) + return; + + if ( GetAspect() == embed::Aspects::MSOLE_ICON ) + { + // the iconified object seems not to need such a scaling handling + // since the replacement image and the size a completely controlled by the container + // TODO/LATER: when the icon exchange is implemented the scaling handling + // might be required again here + return; + } + + SwWrtShell &rSh = static_cast<SwView*>(GetViewShell())->GetWrtShell(); + + // Adjust the size of the object in the core. The Scaling must + // be considered. Repercussions on the object are considered by + // CalcAndSetScale() of the WrtShell if the size / position of + // the frame in the core changes. + + // TODO/LEAN: getMapUnit can switch object to running state + awt::Size aSz; + try + { + aSz = GetObject()->getVisualAreaSize( GetAspect() ); + } + catch (const embed::NoVisualAreaSizeException&) + { + // Nothing will be done + } + catch (const uno::Exception&) + { + OSL_FAIL( "Something goes wrong on requesting object size!" ); + } + + Size aVisSize( aSz.Width, aSz.Height ); + + // As long as from the object comes no reasonable size + // nothing can be scaled. + if( !aVisSize.Width() || !aVisSize.Height() ) + return; + + // first convert to TWIPS before scaling, because scaling factors are calculated for + // the TWIPS mapping and so they will produce the best results if applied to TWIPS based + // coordinates + const MapMode aMyMap ( MapUnit::MapTwip ); + const MapMode aObjMap( VCLUnoHelper::UnoEmbed2VCLMapUnit( GetObject()->getMapUnit( GetAspect() ) ) ); + aVisSize = OutputDevice::LogicToLogic( aVisSize, aObjMap, aMyMap ); + + aVisSize.setWidth( tools::Long(aVisSize.Width() * GetScaleWidth()) ); + aVisSize.setHeight( tools::Long(aVisSize.Height() * GetScaleHeight()) ); + + SwRect aRect( Point( LONG_MIN, LONG_MIN ), aVisSize ); + rSh.LockView( true ); // Prevent scrolling in the EndAction + rSh.StartAllAction(); + rSh.RequestObjectResize( aRect, GetObject() ); + rSh.EndAllAction(); + rSh.LockView( false ); +} + +void SwOleClient::FormatChanged() +{ + const uno::Reference < embed::XEmbeddedObject >& xObj( GetObject() ); + SwView * pView = dynamic_cast< SwView * >( GetViewShell() ); + if ( pView && xObj.is() && SotExchange::IsMath( xObj->getClassID() ) ) + { + SwWrtShell & rWrtSh = pView->GetWrtShell(); + if (rWrtSh.GetDoc()->getIDocumentSettingAccess().get( DocumentSettingId::MATH_BASELINE_ALIGNMENT )) + rWrtSh.AlignFormulaToBaseline( xObj ); + } +} + +bool SwOleClient::IsProtected() const +{ + auto pView = dynamic_cast<SwView*>(GetViewShell()); + if (!pView) + { + return false; + } + + SwWrtShell& rWrtSh = pView->GetWrtShell(); + if (rWrtSh.IsTableMode()) + { + return false; + } + + SwOLENode* pOLENode = rWrtSh.GetCursor()->GetNode().GetOLENode(); + if (!pOLENode) + { + return false; + } + + return pOLENode->GetOLEObj().IsProtected(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/uiview/uivwimp.cxx b/sw/source/uibase/uiview/uivwimp.cxx new file mode 100644 index 000000000..cea09ed3b --- /dev/null +++ b/sw/source/uibase/uiview/uivwimp.cxx @@ -0,0 +1,324 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <config_features.h> +#include <config_fuzzers.h> + +#include <cmdid.h> + +#include <com/sun/star/scanner/XScannerManager2.hpp> +#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp> +#include <comphelper/propertysequence.hxx> +#include <comphelper/servicehelper.hxx> +#include <vcl/weld.hxx> +#include <vcl/svapp.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/docfile.hxx> + +#include <sfx2/docinsert.hxx> +#include <sfx2/request.hxx> +#include <uivwimp.hxx> +#include <unotxvw.hxx> +#include <unodispatch.hxx> +#include <swmodule.hxx> +#include <swdtflvr.hxx> + +#include <strings.hrc> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::scanner; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::datatransfer::clipboard; + +SwView_Impl::SwView_Impl(SwView* pShell) + : m_pView(pShell) + , m_eShellMode(ShellMode::Text) + , m_nParam(0) + , m_bSelectObject(false) + , m_bEditingPositionSet(false) +{ + mxXTextView = new SwXTextView(m_pView); + m_xDispatchProviderInterceptor = new SwXDispatchProviderInterceptor(*m_pView); +} + +SwView_Impl::~SwView_Impl() +{ + auto pInterceptor = comphelper::getFromUnoTunnel<SwXDispatchProviderInterceptor>(m_xDispatchProviderInterceptor); + if(pInterceptor) + pInterceptor->Invalidate(); + view::XSelectionSupplier* pTextView = mxXTextView.get(); + static_cast<SwXTextView*>(pTextView)->Invalidate(); + mxXTextView.clear(); + if( mxScanEvtLstnr.is() ) + mxScanEvtLstnr->ViewDestroyed(); + if( mxClipEvtLstnr.is() ) + { + mxClipEvtLstnr->AddRemoveListener( false ); + mxClipEvtLstnr->ViewDestroyed(); + } +#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS + m_xConfigItem.reset(); +#endif + m_pDocInserter.reset(); + m_pRequest.reset(); +} + +void SwView_Impl::SetShellMode(ShellMode eSet) +{ + m_eShellMode = eSet; +} + +view::XSelectionSupplier* SwView_Impl::GetUNOObject() +{ + return mxXTextView.get(); +} + +SwXTextView* SwView_Impl::GetUNOObject_Impl() +{ + view::XSelectionSupplier* pTextView = mxXTextView.get(); + return static_cast<SwXTextView*>(pTextView); +} + +void SwView_Impl::ExecuteScan( SfxRequest& rReq ) +{ + switch(rReq.GetSlot()) + { + case SID_TWAIN_SELECT: + { + bool bDone = false; + Reference< XScannerManager2 > xScanMgr = SW_MOD()->GetScannerManager(); + + if( xScanMgr.is() ) + { + try + { + SwScannerEventListener& rListener = GetScannerEventListener(); + const Sequence< ScannerContext > + aContexts( xScanMgr->getAvailableScanners() ); + + if( aContexts.hasElements() ) + { + Reference< XEventListener > xLstner = &rListener; + ScannerContext aContext( aContexts.getConstArray()[ 0 ] ); + + Reference<lang::XInitialization> xInit(xScanMgr, UNO_QUERY); + if (xInit.is()) + { + // initialize dialog + weld::Window* pWindow = rReq.GetFrameWeld(); + uno::Sequence<uno::Any> aSeq(comphelper::InitAnyPropertySequence( + { + {"ParentWindow", pWindow ? uno::Any(pWindow->GetXWindow()) : uno::Any(Reference<awt::XWindow>())} + })); + xInit->initialize( aSeq ); + } + + bDone = xScanMgr->configureScannerAndScan( aContext, xLstner ); + } + } + catch(...) + { + } + + } + if( bDone ) + rReq.Done(); + else + { + rReq.Ignore(); + } + } + break; + + case SID_TWAIN_TRANSFER: + { + bool bDone = false; + + Reference< XScannerManager2 > xScanMgr = SW_MOD()->GetScannerManager(); + if( xScanMgr.is() ) + { + SwScannerEventListener& rListener = GetScannerEventListener(); + try + { + const Sequence< scanner::ScannerContext >aContexts( xScanMgr->getAvailableScanners() ); + if( aContexts.hasElements() ) + { + Reference< XEventListener > xLstner = &rListener; + xScanMgr->startScan( aContexts.getConstArray()[ 0 ], xLstner ); + bDone = true; + } + } + catch(...) + { + } + } + + if( !bDone ) + { + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(rReq.GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SwResId(STR_SCAN_NOSOURCE))); + xBox->run(); + rReq.Ignore(); + } + else + { + rReq.Done(); + SfxBindings& rBind = m_pView->GetViewFrame()->GetBindings(); + rBind.Invalidate( SID_TWAIN_SELECT ); + rBind.Invalidate( SID_TWAIN_TRANSFER ); + } + } + break; + } +} + +SwScannerEventListener& SwView_Impl::GetScannerEventListener() +{ + if(!mxScanEvtLstnr.is()) + mxScanEvtLstnr = new SwScannerEventListener(*m_pView); + return *mxScanEvtLstnr; +} + +void SwView_Impl::AddClipboardListener() +{ + if(!mxClipEvtLstnr.is()) + { + mxClipEvtLstnr = new SwClipboardChangeListener( *m_pView ); + mxClipEvtLstnr->AddRemoveListener( true ); + } +} + +void SwView_Impl::Invalidate() +{ + GetUNOObject_Impl()->Invalidate(); + for (const auto& xTransferable: mxTransferables) + { + auto pTransferable = comphelper::getFromUnoTunnel<SwTransferable>(xTransferable.get()); + if(pTransferable) + pTransferable->Invalidate(); + } +} + +void SwView_Impl::AddTransferable(SwTransferable& rTransferable) +{ + //prevent removing of the non-referenced SwTransferable + osl_atomic_increment(&rTransferable.m_refCount); + { + // Remove previously added, but no longer existing weak references. + mxTransferables.erase(std::remove_if(mxTransferables.begin(), mxTransferables.end(), + [](const css::uno::WeakReference<css::lang::XUnoTunnel>& rTunnel) { + uno::Reference<lang::XUnoTunnel> xTunnel(rTunnel.get(), uno::UNO_QUERY); + return !xTunnel.is(); + }), mxTransferables.end()); + + mxTransferables.emplace_back(&rTransferable); + } + osl_atomic_decrement(&rTransferable.m_refCount); +} + +void SwView_Impl::StartDocumentInserter( + const OUString& rFactory, + const Link<sfx2::FileDialogHelper*,void>& rEndDialogHdl, + const sal_uInt16 nSlotId +) +{ + sfx2::DocumentInserter::Mode mode {sfx2::DocumentInserter::Mode::Insert}; + switch( nSlotId ) + { + case SID_DOCUMENT_MERGE: + mode = sfx2::DocumentInserter::Mode::Merge; + break; + case SID_DOCUMENT_COMPARE: + mode = sfx2::DocumentInserter::Mode::Compare; + break; + default: + break; + } + + m_pDocInserter.reset(new ::sfx2::DocumentInserter(m_pView->GetFrameWeld(), rFactory, mode)); + m_pDocInserter->StartExecuteModal( rEndDialogHdl ); +} + +std::unique_ptr<SfxMedium> SwView_Impl::CreateMedium() +{ + return m_pDocInserter->CreateMedium(); +} + +void SwView_Impl::InitRequest( const SfxRequest& rRequest ) +{ + m_pRequest.reset(new SfxRequest( rRequest )); +} + +SwScannerEventListener::~SwScannerEventListener() +{ +} + +void SAL_CALL SwScannerEventListener::disposing( const EventObject& /*rEventObject*/) +{ +#if defined(_WIN32) || defined UNX + SolarMutexGuard aGuard; + if( m_pView ) + m_pView->ScannerEventHdl(); +#endif +} + +SwClipboardChangeListener::~SwClipboardChangeListener() +{ +} + +void SAL_CALL SwClipboardChangeListener::disposing( const EventObject& /*rEventObject*/ ) +{ + SolarMutexGuard aGuard; + m_pView = nullptr; // so we don't touch the view if changedContents somehow fires afterwards +} + +void SAL_CALL SwClipboardChangeListener::changedContents( const css::datatransfer::clipboard::ClipboardEvent& rEventObject ) + +{ + const SolarMutexGuard aGuard; + if( !m_pView ) + return; + + { + TransferableDataHelper aDataHelper( rEventObject.Contents ); + SwWrtShell& rSh = m_pView->GetWrtShell(); + + m_pView->m_nLastPasteDestination = SwTransferable::GetSotDestination( rSh ); + m_pView->m_bPasteState = aDataHelper.GetXTransferable().is() && + SwTransferable::IsPaste( rSh, aDataHelper ); + + m_pView->m_bPasteSpecialState = aDataHelper.GetXTransferable().is() && + SwTransferable::IsPasteSpecial( rSh, aDataHelper ); + } + + SfxBindings& rBind = m_pView->GetViewFrame()->GetBindings(); + rBind.Invalidate( SID_PASTE ); + rBind.Invalidate( SID_PASTE_SPECIAL ); + rBind.Invalidate( SID_CLIPBOARD_FORMAT_ITEMS ); +} + +void SwClipboardChangeListener::AddRemoveListener( bool bAdd ) +{ + m_pView->AddRemoveClipboardListener( Reference< XClipboardListener >( this ), bAdd ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/uiview/view.cxx b/sw/source/uibase/uiview/view.cxx new file mode 100644 index 000000000..ceb0de4c3 --- /dev/null +++ b/sw/source/uibase/uiview/view.cxx @@ -0,0 +1,1989 @@ +/* -*- 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 <sal/config.h> + +#include <string_view> + +#include <config_features.h> +#include <config_wasm_strip.h> + +#include <stdlib.h> +#include <hintids.hxx> +#include <comphelper/string.hxx> +#include <o3tl/any.hxx> +#include <o3tl/string_view.hxx> +#include <officecfg/Office/Common.hxx> +#include <vcl/graph.hxx> +#include <vcl/inputctx.hxx> +#include <svl/eitem.hxx> +#include <unotools/configmgr.hxx> +#include <unotools/lingucfg.hxx> +#include <unotools/useroptions.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/objface.hxx> +#include <sfx2/request.hxx> +#include <svx/ruler.hxx> +#include <svx/srchdlg.hxx> +#include <svx/fmshell.hxx> +#include <svx/extrusionbar.hxx> +#include <svx/fontworkbar.hxx> +#include <svx/fmview.hxx> +#include <unotxvw.hxx> +#include <cmdid.h> +#include <svl/hint.hxx> +#include <swmodule.hxx> +#include <inputwin.hxx> +#include <uivwimp.hxx> +#include <edtwin.hxx> +#include <textsh.hxx> +#include <listsh.hxx> +#include <tabsh.hxx> +#include <grfsh.hxx> +#include <mediash.hxx> +#include <docsh.hxx> +#include <frmsh.hxx> +#include <olesh.hxx> +#include <drawsh.hxx> +#include <drawbase.hxx> +#include <drformsh.hxx> +#include <drwtxtsh.hxx> +#include <beziersh.hxx> +#include <navsh.hxx> +#include <globdoc.hxx> +#include <scroll.hxx> +#include <gloshdl.hxx> +#include <usrpref.hxx> +#include <srcview.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <IDocumentSettingAccess.hxx> +#include <IDocumentDrawModelAccess.hxx> +#include <DocumentFieldsManager.hxx> +#include <IDocumentState.hxx> +#include <IDocumentLayoutAccess.hxx> +#include <drawdoc.hxx> +#include <wdocsh.hxx> +#include <wrtsh.hxx> +#include <barcfg.hxx> +#include <pview.hxx> +#include <swdtflvr.hxx> +#include <prtopt.hxx> +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <com/sun/star/frame/XLayoutManager.hpp> +#include <com/sun/star/scanner/ScannerContext.hpp> +#include <com/sun/star/scanner/XScannerManager2.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/sdb/XDatabaseContext.hpp> +#include <com/sun/star/sdb/DatabaseContext.hpp> +#include <toolkit/helper/vclunohelper.hxx> +#include <sal/log.hxx> + +#include <formatclipboard.hxx> +#include <PostItMgr.hxx> +#include <annotsh.hxx> +#include <swruler.hxx> + +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> + +#include <comphelper/propertyvalue.hxx> +#include <sfx2/lokhelper.hxx> +#include <LibreOfficeKit/LibreOfficeKitEnums.h> +#include <svtools/embedhlp.hxx> +#include <tools/UnitConversion.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::scanner; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; + +#define SWVIEWFLAGS SfxViewShellFlags::HAS_PRINTOPTIONS + +// Statics. OMG. + +bool bDocSzUpdated = true; + +SvxSearchItem* SwView::s_pSrchItem = nullptr; + +bool SwView::s_bExtra = false; +bool SwView::s_bFound = false; +bool SwView::s_bJustOpened = false; + +std::unique_ptr<SearchAttrItemList> SwView::s_xSearchList; +std::unique_ptr<SearchAttrItemList> SwView::s_xReplaceList; + +SfxDispatcher &SwView::GetDispatcher() +{ + return *GetViewFrame()->GetDispatcher(); +} + +void SwView::ImpSetVerb( SelectionType nSelType ) +{ + bool bResetVerbs = m_bVerbsActive; + if ( !GetViewFrame()->GetFrame().IsInPlace() && + (SelectionType::Ole|SelectionType::Graphic) & nSelType ) + { + FlyProtectFlags eProtectFlags = m_pWrtShell->IsSelObjProtected(FlyProtectFlags::Content); + if (eProtectFlags == FlyProtectFlags::NONE || nSelType & SelectionType::Ole) + { + if ( nSelType & SelectionType::Ole ) + { + SetVerbs( GetWrtShell().GetOLEObject()->getSupportedVerbs() ); + m_bVerbsActive = true; + bResetVerbs = false; + } + } + } + if ( bResetVerbs ) + { + SetVerbs( Sequence< embed::VerbDescriptor >() ); + m_bVerbsActive = false; + } +} + +// Called by the SwEditWin when it gets the focus. + +void SwView::GotFocus() const +{ + // if we got the focus, and the form shell *is* on the top of the dispatcher + // stack, then we need to rebuild the stack (the form shell doesn't belong to + // the top then) + const SfxDispatcher& rDispatcher = const_cast< SwView* >( this )->GetDispatcher(); + SfxShell* pTopShell = rDispatcher.GetShell( 0 ); + FmFormShell* pAsFormShell = dynamic_cast<FmFormShell*>( pTopShell ); + if ( pAsFormShell ) + { + pAsFormShell->ForgetActiveControl(); + const_cast< SwView* >( this )->AttrChangedNotify(nullptr); + } + else if ( m_pPostItMgr ) + { + SwAnnotationShell* pAsAnnotationShell = dynamic_cast<SwAnnotationShell*>( pTopShell ); + if ( pAsAnnotationShell ) + { + m_pPostItMgr->SetActiveSidebarWin(nullptr); + const_cast< SwView* >( this )->AttrChangedNotify(nullptr); + } + } + if( GetWrtShellPtr() ) + { + SwWrtShell& rWrtShell = GetWrtShell(); + rWrtShell.GetDoc()->getIDocumentLayoutAccess().SetCurrentViewShell( GetWrtShellPtr() ); + rWrtShell.GetDoc()->getIDocumentSettingAccess().set( DocumentSettingId::BROWSE_MODE, + rWrtShell.GetViewOptions()->getBrowseMode() ); + } +} + +// called by the FormShell when a form control is focused. This is +// a request to put the form shell on the top of the dispatcher stack + +IMPL_LINK_NOARG(SwView, FormControlActivated, LinkParamNone*, void) +{ + // if a form control has been activated, and the form shell is not on the top + // of the dispatcher stack, then we need to activate it + const SfxDispatcher& rDispatcher = GetDispatcher(); + const SfxShell* pTopShell = rDispatcher.GetShell( 0 ); + const FmFormShell* pAsFormShell = dynamic_cast<const FmFormShell*>( pTopShell ); + if ( !pAsFormShell ) + { + // if we're editing text currently, cancel this + SdrView *pSdrView = m_pWrtShell ? m_pWrtShell->GetDrawView() : nullptr; + if ( pSdrView && pSdrView->IsTextEdit() ) + pSdrView->SdrEndTextEdit( true ); + + AttrChangedNotify(nullptr); + } +} + +namespace +{ +uno::Reference<frame::XLayoutManager> getLayoutManager(const SfxViewFrame& rViewFrame) +{ + uno::Reference<frame::XLayoutManager> xLayoutManager; + uno::Reference<beans::XPropertySet> xPropSet(rViewFrame.GetFrame().GetFrameInterface(), + uno::UNO_QUERY); + if (xPropSet.is()) + { + try + { + xLayoutManager.set(xPropSet->getPropertyValue("LayoutManager"), uno::UNO_QUERY); + } + catch (const Exception& e) + { + SAL_WARN("sw.ui", "Failure getting layout manager: " + e.Message); + } + } + return xLayoutManager; +} +} + +void SwView::ShowUIElement(const OUString& sElementURL) const +{ + if (auto xLayoutManager = getLayoutManager(*GetViewFrame())) + { + if (!xLayoutManager->getElement(sElementURL).is()) + { + xLayoutManager->createElement(sElementURL); + xLayoutManager->showElement(sElementURL); + } + } +} + +void SwView::SelectShell() +{ + // Attention: Maintain the SelectShell for the WebView additionally + + if(m_bInDtor) + return; + + // Decision if the UpdateTable has to be called + bool bUpdateTable = false; + const SwFrameFormat* pCurTableFormat = m_pWrtShell->GetTableFormat(); + if(pCurTableFormat && pCurTableFormat != m_pLastTableFormat) + { + bUpdateTable = true; // can only be executed later + } + m_pLastTableFormat = pCurTableFormat; + + //SEL_TBL and SEL_TBL_CELLS can be ORed! + SelectionType nNewSelectionType = m_pWrtShell->GetSelectionType() + & ~SelectionType::TableCell; + + // Determine if a different fly frame was selected. + bool bUpdateFly = false; + const SwFrameFormat* pCurFlyFormat = nullptr; + if (m_nSelectionType & SelectionType::Ole || m_nSelectionType & SelectionType::Graphic) + { + pCurFlyFormat = m_pWrtShell->GetFlyFrameFormat(); + } + if (pCurFlyFormat && pCurFlyFormat != m_pLastFlyFormat) + { + bUpdateFly = true; + } + m_pLastFlyFormat = pCurFlyFormat; + + if ( m_pFormShell && m_pFormShell->IsActiveControl() ) + nNewSelectionType |= SelectionType::FormControl; + + if ( nNewSelectionType == m_nSelectionType ) + { + GetViewFrame()->GetBindings().InvalidateAll( false ); + if ( m_nSelectionType & SelectionType::Ole || + m_nSelectionType & SelectionType::Graphic ) + // For graphs and OLE the verb can be modified of course! + ImpSetVerb( nNewSelectionType ); + + if (bUpdateFly) + { + SfxViewFrame* pViewFrame = GetViewFrame(); + if (pViewFrame) + { + uno::Reference<frame::XFrame> xFrame = pViewFrame->GetFrame().GetFrameInterface(); + if (xFrame.is()) + { + // Invalidate cached dispatch objects. + xFrame->contextChanged(); + } + } + } + } + else + { + + SfxDispatcher &rDispatcher = GetDispatcher(); + SwToolbarConfigItem *pBarCfg = SW_MOD()->GetToolbarConfig(); + + if ( m_pShell ) + { + rDispatcher.Flush(); // Really erase all cached shells + //Remember to the old selection which toolbar was visible + ToolbarId eId = rDispatcher.GetObjectBarId(SFX_OBJECTBAR_OBJECT); + if (eId != ToolbarId::None) + pBarCfg->SetTopToolbar(m_nSelectionType, eId); + + for ( sal_uInt16 i = 0; true; ++i ) + { + SfxShell *pSfxShell = rDispatcher.GetShell( i ); + if ( dynamic_cast< const SwBaseShell *>( pSfxShell ) != nullptr + || dynamic_cast< const SwDrawTextShell *>( pSfxShell ) != nullptr + || dynamic_cast< const svx::ExtrusionBar*>( pSfxShell ) != nullptr + || dynamic_cast< const svx::FontworkBar*>( pSfxShell ) != nullptr + || dynamic_cast< const SwAnnotationShell *>( pSfxShell ) != nullptr + ) + { + rDispatcher.Pop( *pSfxShell, SfxDispatcherPopFlags::POP_DELETE ); + } + else if ( dynamic_cast< const FmFormShell *>( pSfxShell ) != nullptr ) + { + rDispatcher.Pop( *pSfxShell ); + } + else + break; + } + } + + bool bInitFormShell = false; + if (!m_pFormShell) + { + bInitFormShell = true; + m_pFormShell = new FmFormShell( this ); + m_pFormShell->SetControlActivationHandler( LINK( this, SwView, FormControlActivated ) ); + StartListening(*m_pFormShell); + } + + bool bSetExtInpCntxt = false; + m_nSelectionType = nNewSelectionType; + ShellMode eShellMode; + + if ( !( m_nSelectionType & SelectionType::FormControl ) ) + rDispatcher.Push( *m_pFormShell ); + + m_pShell = new SwNavigationShell( *this ); + rDispatcher.Push( *m_pShell ); + + if ( m_nSelectionType & SelectionType::Ole ) + { + eShellMode = ShellMode::Object; + m_pShell = new SwOleShell( *this ); + rDispatcher.Push( *m_pShell ); + } + else if ( m_nSelectionType & SelectionType::Frame + || m_nSelectionType & SelectionType::Graphic) + { + eShellMode = ShellMode::Frame; + m_pShell = new SwFrameShell( *this ); + rDispatcher.Push( *m_pShell ); + if(m_nSelectionType & SelectionType::Graphic ) + { + eShellMode = ShellMode::Graphic; + m_pShell = new SwGrfShell( *this ); + rDispatcher.Push( *m_pShell ); + } + } + else if ( m_nSelectionType & SelectionType::DrawObject ) + { + eShellMode = ShellMode::Draw; + m_pShell = new SwDrawShell( *this ); + rDispatcher.Push( *m_pShell ); + + if ( m_nSelectionType & SelectionType::Ornament ) + { + eShellMode = ShellMode::Bezier; + m_pShell = new SwBezierShell( *this ); + rDispatcher.Push( *m_pShell ); + } +#if HAVE_FEATURE_AVMEDIA + else if( m_nSelectionType & SelectionType::Media ) + { + eShellMode = ShellMode::Media; + m_pShell = new SwMediaShell( *this ); + rDispatcher.Push( *m_pShell ); + } +#endif + if (m_nSelectionType & SelectionType::ExtrudedCustomShape) + { + eShellMode = ShellMode::ExtrudedCustomShape; + m_pShell = new svx::ExtrusionBar(this); + rDispatcher.Push( *m_pShell ); + } + if (m_nSelectionType & SelectionType::FontWork) + { + eShellMode = ShellMode::FontWork; + m_pShell = new svx::FontworkBar(this); + rDispatcher.Push( *m_pShell ); + } + } + else if ( m_nSelectionType & SelectionType::DbForm ) + { + eShellMode = ShellMode::DrawForm; + m_pShell = new SwDrawFormShell( *this ); + + rDispatcher.Push( *m_pShell ); + } + else if ( m_nSelectionType & SelectionType::DrawObjectEditMode ) + { + bSetExtInpCntxt = true; + eShellMode = ShellMode::DrawText; + rDispatcher.Push( *(new SwBaseShell( *this )) ); + m_pShell = new SwDrawTextShell( *this ); + rDispatcher.Push( *m_pShell ); + } + else if ( m_nSelectionType & SelectionType::PostIt ) + { + eShellMode = ShellMode::PostIt; + m_pShell = new SwAnnotationShell( *this ); + rDispatcher.Push( *m_pShell ); + } + else + { + bSetExtInpCntxt = true; + eShellMode = ShellMode::Text; + if ( m_nSelectionType & SelectionType::NumberList ) + { + eShellMode = ShellMode::ListText; + m_pShell = new SwListShell( *this ); + rDispatcher.Push( *m_pShell ); + } + m_pShell = new SwTextShell(*this); + rDispatcher.Push( *m_pShell ); + if ( m_nSelectionType & SelectionType::Table ) + { + eShellMode = eShellMode == ShellMode::ListText ? ShellMode::TableListText + : ShellMode::TableText; + m_pShell = new SwTableShell( *this ); + rDispatcher.Push( *m_pShell ); + } + } + + if ( m_nSelectionType & SelectionType::FormControl ) + rDispatcher.Push( *m_pFormShell ); + + m_pViewImpl->SetShellMode(eShellMode); + ImpSetVerb( m_nSelectionType ); + + if( !GetDocShell()->IsReadOnly() ) + { + if( bSetExtInpCntxt && GetWrtShell().HasReadonlySel() ) + bSetExtInpCntxt = false; + + InputContext aCntxt( GetEditWin().GetInputContext() ); + aCntxt.SetOptions( bSetExtInpCntxt + ? (aCntxt.GetOptions() | + ( InputContextFlags::Text | + InputContextFlags::ExtText )) + : (aCntxt.GetOptions() & ~ + InputContextFlags( InputContextFlags::Text | + InputContextFlags::ExtText )) ); + GetEditWin().SetInputContext( aCntxt ); + } + + // Show Mail Merge toolbar initially for documents with Database fields + if (!m_bInitOnceCompleted && GetWrtShell().IsAnyDatabaseFieldInDoc()) + ShowUIElement("private:resource/toolbar/mailmerge"); + + // Activate the toolbar to the new selection which also was active last time. + // Before a flush () must be, but does not affect the UI according to MBA and + // is not a performance problem. + // TODO/LATER: maybe now the Flush() command is superfluous?! + rDispatcher.Flush(); + + Point aPnt = GetEditWin().OutputToScreenPixel(GetEditWin().GetPointerPosPixel()); + aPnt = GetEditWin().PixelToLogic(aPnt); + GetEditWin().UpdatePointer(aPnt); + + SdrView* pDView = GetWrtShell().GetDrawView(); + if ( bInitFormShell && pDView ) + m_pFormShell->SetView(dynamic_cast<FmFormView*>( pDView) ); + + } + // Opportune time for the communication with OLE objects? + if ( GetDocShell()->GetDoc()->IsOLEPrtNotifyPending() ) + GetDocShell()->GetDoc()->PrtOLENotify( false ); + + // now the table-update + if(bUpdateTable) + m_pWrtShell->UpdateTable(); + + GetViewImpl()->GetUNOObject_Impl()->NotifySelChanged(); + + m_bInitOnceCompleted = true; +} + +// Interaction: AttrChangedNotify() and TimeoutHdl. +// No Update if actions are still open, since the cursor on the core side +// can be somewhere in no man's land. +// But since we can no longer supply status and we want instead lock +// the dispatcher. + +extern "C" +{ + static int lcl_CmpIds( const void *pFirst, const void *pSecond) + { + return *static_cast<sal_uInt16 const *>(pFirst) - *static_cast<sal_uInt16 const *>(pSecond); + } +} + +IMPL_LINK_NOARG(SwView, AttrChangedNotify, LinkParamNone*, void) +{ + if ( GetEditWin().IsChainMode() ) + GetEditWin().SetChainMode( false ); + + if (!m_pWrtShell || !GetDocShell()) + { + return; + } + + //Opt: Not if PaintLocked. During unlock a notify will be once more triggered. + if( !m_pWrtShell->IsPaintLocked() && !g_bNoInterrupt && + GetDocShell()->IsReadOnly() ) + CheckReadonlyState(); + + if( !m_pWrtShell->IsPaintLocked() && !g_bNoInterrupt ) + CheckReadonlySelection(); + + if( !m_bAttrChgNotified ) + { + if (m_pWrtShell->ActionPend() || g_bNoInterrupt || + GetDispatcher().IsLocked() || //do not confuse the SFX + GetViewFrame()->GetBindings().IsInUpdate() )//do not confuse the SFX + { + m_bAttrChgNotified = true; + m_aTimer.Start(); + + const SfxBoolItem *pItem = + GetObjectShell()->GetMedium()->GetItemSet()-> + GetItemIfSet( SID_HIDDEN, false ); + if ( !pItem || !pItem->GetValue() ) + { + GetViewFrame()->GetBindings().ENTERREGISTRATIONS(); + m_bAttrChgNotifiedWithRegistrations = true; + } + + } + else + SelectShell(); + + } + + // change ui if cursor is at a SwPostItField + if (m_pPostItMgr) + { + // only perform the code that is needed to determine, if at the + // actual cursor position is a post-it field + m_pPostItMgr->SetShadowState( m_pWrtShell->GetPostItFieldAtCursor() ); + } +} + +IMPL_LINK_NOARG(SwView, TimeoutHdl, Timer *, void) +{ + if (m_pWrtShell->ActionPend() || g_bNoInterrupt) + { + m_aTimer.Start(); + return; + } + + if ( m_bAttrChgNotifiedWithRegistrations ) + { + GetViewFrame()->GetBindings().LEAVEREGISTRATIONS(); + m_bAttrChgNotifiedWithRegistrations = false; + } + + CheckReadonlyState(); + CheckReadonlySelection(); + + bool bOldUndo = m_pWrtShell->DoesUndo(); + m_pWrtShell->DoUndo( false ); + SelectShell(); + m_pWrtShell->DoUndo( bOldUndo ); + m_bAttrChgNotified = false; + GetViewImpl()->GetUNOObject_Impl()->NotifySelChanged(); +} + +void SwView::CheckReadonlyState() +{ + SfxDispatcher &rDis = GetDispatcher(); + // To be able to recognize if it is already disabled! + SfxItemState eStateRO, eStateProtAll; + const SfxPoolItem *pItem; + // Query the status from a slot which is only known to us. + // Otherwise the slot is known from other; like the BasicIde + eStateRO = rDis.QueryState( FN_INSERT_BOOKMARK, pItem ); + eStateProtAll = rDis.QueryState( FN_EDIT_REGION, pItem ); + bool bChgd = false; + + if ( !m_pWrtShell->IsCursorReadonly() ) + { + static sal_uInt16 aROIds[] = + { + SID_DELETE, FN_BACKSPACE, FN_SHIFT_BACKSPACE, + SID_UNDO, + SID_REDO, SID_REPEAT, SID_PASTE, + SID_PASTE_UNFORMATTED, FN_PASTE_NESTED_TABLE, FN_TABLE_PASTE_ROW_BEFORE, + FN_TABLE_PASTE_COL_BEFORE, SID_PASTE_SPECIAL, SID_SBA_BRW_INSERT, + SID_BACKGROUND_COLOR, FN_INSERT_BOOKMARK, SID_CHARMAP_CONTROL, + SID_CHARMAP, SID_EMOJI_CONTROL, FN_INSERT_SOFT_HYPHEN, + FN_INSERT_HARDHYPHEN, FN_INSERT_HARD_SPACE, FN_INSERT_NNBSP, + FN_INSERT_BREAK, FN_INSERT_LINEBREAK, FN_INSERT_COLUMN_BREAK, + FN_INSERT_BREAK_DLG, FN_INSERT_CONTENT_CONTROL, FN_INSERT_CHECKBOX_CONTENT_CONTROL, + FN_INSERT_DROPDOWN_CONTENT_CONTROL, FN_INSERT_PICTURE_CONTENT_CONTROL, + FN_INSERT_DATE_CONTENT_CONTROL, + FN_DELETE_SENT, FN_DELETE_BACK_SENT, FN_DELETE_WORD, + FN_DELETE_BACK_WORD, FN_DELETE_LINE, FN_DELETE_BACK_LINE, + FN_DELETE_PARA, FN_DELETE_BACK_PARA, FN_DELETE_WHOLE_LINE, + FN_CALCULATE, FN_FORMAT_RESET, + FN_POSTIT, FN_JAVAEDIT, SID_ATTR_PARA_ADJUST_LEFT, + SID_ATTR_PARA_ADJUST_RIGHT, SID_ATTR_PARA_ADJUST_CENTER,SID_ATTR_PARA_ADJUST_BLOCK, + SID_ATTR_PARA_LINESPACE_10, SID_ATTR_PARA_LINESPACE_15, SID_ATTR_PARA_LINESPACE_20, + SID_ATTR_CHAR_FONT, SID_ATTR_CHAR_FONTHEIGHT, SID_ATTR_CHAR_COLOR_BACKGROUND, + SID_ATTR_CHAR_COLOR_BACKGROUND_EXT, SID_ATTR_CHAR_COLOR_EXT, + SID_ATTR_CHAR_COLOR, SID_ATTR_CHAR_WEIGHT, SID_ATTR_CHAR_POSTURE, + SID_ATTR_CHAR_OVERLINE, + SID_ATTR_CHAR_UNDERLINE, SID_ATTR_FLASH, SID_ATTR_CHAR_STRIKEOUT, + SID_ULINE_VAL_SINGLE, SID_ULINE_VAL_DOUBLE, SID_ULINE_VAL_DOTTED, + SID_ATTR_CHAR_CONTOUR, SID_ATTR_CHAR_SHADOWED, + SID_ATTR_CHAR_AUTOKERN, SID_ATTR_CHAR_ESCAPEMENT, FN_SET_SUPER_SCRIPT, + FN_SET_SUB_SCRIPT, SID_ATTR_CHAR_CASEMAP, SID_ATTR_CHAR_LANGUAGE, + SID_ATTR_CHAR_KERNING, SID_CHAR_DLG, SID_ATTR_CHAR_WORDLINEMODE, + FN_GROW_FONT_SIZE, FN_SHRINK_FONT_SIZE, FN_TXTATR_INET, + FN_FORMAT_DROPCAPS, SID_ATTR_PARA_ADJUST, SID_ATTR_PARA_LINESPACE, + SID_ATTR_PARA_SPLIT, SID_ATTR_PARA_KEEP, SID_ATTR_PARA_WIDOWS, + SID_ATTR_PARA_ORPHANS, + SID_ATTR_PARA_MODEL, SID_PARA_DLG, + FN_SELECT_PARA, SID_DEC_INDENT, + SID_INC_INDENT + }; + static bool bFirst = true; + if ( bFirst ) + { + qsort( static_cast<void*>(aROIds), SAL_N_ELEMENTS(aROIds), sizeof(sal_uInt16), lcl_CmpIds ); + bFirst = false; + } + if ( SfxItemState::DISABLED == eStateRO ) + { + rDis.SetSlotFilter( SfxSlotFilterState::ENABLED_READONLY, aROIds ); + bChgd = true; + } + } + else if( m_pWrtShell->IsAllProtect() ) + { + if ( SfxItemState::DISABLED == eStateProtAll ) + { + static sal_uInt16 aAllProtIds[] = { SID_SAVEDOC, FN_EDIT_REGION }; + static bool bAllProtFirst = true; + if ( bAllProtFirst ) + { + qsort( static_cast<void*>(aAllProtIds), SAL_N_ELEMENTS(aAllProtIds), sizeof(sal_uInt16), lcl_CmpIds ); + bAllProtFirst = false; + } + rDis.SetSlotFilter( SfxSlotFilterState::ENABLED_READONLY, aAllProtIds ); + bChgd = true; + } + } + else if ( SfxItemState::DISABLED != eStateRO || + SfxItemState::DISABLED != eStateProtAll ) + { + bChgd = true; + rDis.SetSlotFilter(); + } + if ( bChgd ) + GetViewFrame()->GetBindings().InvalidateAll(true); +} + +void SwView::CheckReadonlySelection() +{ + SfxDisableFlags nDisableFlags = SfxDisableFlags::NONE; + SfxDispatcher &rDis = GetDispatcher(); + + if( m_pWrtShell->HasReadonlySel() && + ( !m_pWrtShell->GetDrawView() || + !m_pWrtShell->GetDrawView()->GetMarkedObjectList().GetMarkCount() )) + nDisableFlags |= SfxDisableFlags::SwOnProtectedCursor; + + if( (SfxDisableFlags::SwOnProtectedCursor & nDisableFlags ) != + (SfxDisableFlags::SwOnProtectedCursor & rDis.GetDisableFlags() ) ) + { + // Additionally move at the Window the InputContext, so that + // in japanese / chinese versions the external input will be + // turned on or off. This but only if the correct shell is on + // the stack. + switch( m_pViewImpl->GetShellMode() ) + { + case ShellMode::Text: + case ShellMode::ListText: + case ShellMode::TableText: + case ShellMode::TableListText: + { +// Temporary solution!!! Should set the font of the current insertion point +// at each cursor movement, so outside of this "if". But TH does not +// evaluates the font at this time and the "purchase" appears to me +// as too expensive. +// Moreover, we don't have a font, but only attributes from which the +// text formatting and the correct font will be build together. + + InputContext aCntxt( GetEditWin().GetInputContext() ); + aCntxt.SetOptions( SfxDisableFlags::SwOnProtectedCursor & nDisableFlags + ? (aCntxt.GetOptions() & ~ + InputContextFlags( InputContextFlags::Text | + InputContextFlags::ExtText )) + : (aCntxt.GetOptions() | + ( InputContextFlags::Text | + InputContextFlags::ExtText )) ); + GetEditWin().SetInputContext( aCntxt ); + } + break; + default: + ; + } + + } + + if( nDisableFlags != rDis.GetDisableFlags() ) + { + rDis.SetDisableFlags( nDisableFlags ); + GetViewFrame()->GetBindings().InvalidateAll( true ); + } +} + +SwView::SwView( SfxViewFrame *_pFrame, SfxViewShell* pOldSh ) + : SfxViewShell( _pFrame, SWVIEWFLAGS ), + m_aTimer( "sw::SwView m_aTimer" ), + m_nNewPage(USHRT_MAX), + m_nOldPageNum(0), + m_pNumRuleNodeFromDoc(nullptr), + m_pEditWin( VclPtr<SwEditWin>::Create( &_pFrame->GetWindow(), *this ) ), + m_pShell(nullptr), + m_pFormShell(nullptr), + m_pHScrollbar(nullptr), + m_pVScrollbar(nullptr), + m_pScrollFill(VclPtr<ScrollBarBox>::Create( &_pFrame->GetWindow(), WB_SIZEABLE )), + m_pVRuler(VclPtr<SvxRuler>::Create(&GetViewFrame()->GetWindow(), m_pEditWin, + SvxRulerSupportFlags::TABS | SvxRulerSupportFlags::PARAGRAPH_MARGINS_VERTICAL| + SvxRulerSupportFlags::BORDERS | SvxRulerSupportFlags::REDUCED_METRIC, + GetViewFrame()->GetBindings(), + WB_VSCROLL | WB_EXTRAFIELD | WB_BORDER )), + m_pLastTableFormat(nullptr), + m_pLastFlyFormat(nullptr), + m_pFormatClipboard(new SwFormatClipboard()), + m_nSelectionType( SelectionType::All ), + m_nPageCnt(0), + m_nDrawSfxId( USHRT_MAX ), + m_nFormSfxId( USHRT_MAX ), + m_eFormObjKind(SdrObjKind::NONE), + m_nLastPasteDestination( static_cast<SotExchangeDest>(0xFFFF) ), + m_nLeftBorderDistance( 0 ), + m_nRightBorderDistance( 0 ), + m_eLastSearchCommand( static_cast<SvxSearchCmd>(0xFFFF) ), + m_bWheelScrollInProgress(false), + m_bCenterCursor(false), + m_bTopCursor(false), + m_bTabColFromDoc(false), + m_bTabRowFromDoc(false), + m_bSetTabColFromDoc(false), + m_bSetTabRowFromDoc(false), + m_bAttrChgNotified(false), + m_bAttrChgNotifiedWithRegistrations(false), + m_bVerbsActive(false), + m_bDrawRotate(false), + m_bDrawSelMode(true), + m_bShowAtResize(true), + m_bInOuterResizePixel(false), + m_bInInnerResizePixel(false), + m_bPasteState(false), + m_bPasteSpecialState(false), + m_bInMailMerge(false), + m_bInDtor(false), + m_bOldShellWasPagePreview(false), + m_bIsPreviewDoubleClick(false), + m_bMakeSelectionVisible(false), + m_bForceChangesToolbar(true), + m_nLOKPageUpDownOffset(0) +{ + static bool bRequestDoubleBuffering = getenv("VCL_DOUBLEBUFFERING_ENABLE"); + if (bRequestDoubleBuffering) + m_pEditWin->RequestDoubleBuffering(true); + + // According to discussion with MBA and further + // investigations, no old SfxViewShell will be set as parameter <pOldSh>, + // if function "New Window" is performed to open an additional view beside + // an already existing one. + // If the view is switch from one to another, the 'old' view is given by + // parameter <pOldSh>. + + bDocSzUpdated = true; + + CreateScrollbar( true ); + CreateScrollbar( false ); + + m_pViewImpl.reset(new SwView_Impl(this)); + SetName("View"); + SetWindow( m_pEditWin ); + + m_aTimer.SetTimeout( 120 ); + + SwDocShell& rDocSh = dynamic_cast<SwDocShell&>(*_pFrame->GetObjectShell()); + bool bOldModifyFlag = rDocSh.IsEnableSetModified(); + if (bOldModifyFlag) + rDocSh.EnableSetModified( false ); + // HACK: SwDocShell has some cached font info, VCL informs about font updates, + // but loading of docs with embedded fonts happens after SwDocShell is created + // but before SwEditWin (which handles the VCL event) is created. So update + // manually. + if (rDocSh.GetDoc()->getIDocumentSettingAccess().get( DocumentSettingId::EMBED_FONTS )) + rDocSh.UpdateFontList(); + bool bWebDShell = dynamic_cast<const SwWebDocShell*>(&rDocSh) != nullptr; + + const SwMasterUsrPref *pUsrPref = SW_MOD()->GetUsrPref(bWebDShell); + SwViewOption aUsrPref( *pUsrPref); + + //! get lingu options without loading lingu DLL + SvtLinguOptions aLinguOpt; + SvtLinguConfig().GetOptions( aLinguOpt ); + aUsrPref.SetOnlineSpell( aLinguOpt.bIsSpellAuto ); + + bool bOldShellWasSrcView = false; + + // determine if there is an existing view for + // document + SfxViewShell* pExistingSh = nullptr; + if ( pOldSh ) + { + pExistingSh = pOldSh; + // determine type of existing view + if (SwPagePreview* pPagePreview = dynamic_cast<SwPagePreview *>(pExistingSh)) + { + m_sSwViewData = pPagePreview->GetPrevSwViewData(); + m_sNewCursorPos = pPagePreview->GetNewCursorPos(); + m_nNewPage = pPagePreview->GetNewPage(); + m_bOldShellWasPagePreview = true; + m_bIsPreviewDoubleClick = !m_sNewCursorPos.isEmpty() || m_nNewPage != USHRT_MAX; + } + else if (dynamic_cast<const SwSrcView *>(pExistingSh) != nullptr) + bOldShellWasSrcView = true; + } + + SAL_INFO( "sw.ui", "before create WrtShell" ); + if (SwView *pView = dynamic_cast<SwView*>(pExistingSh)) + { + m_pWrtShell.reset(new SwWrtShell(*pView->m_pWrtShell, m_pEditWin, *this)); + } + else if (SwWrtShell *pWrtShell = dynamic_cast<SwWrtShell*>(rDocSh.GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell())) + { + m_pWrtShell.reset(new SwWrtShell(*pWrtShell, m_pEditWin, *this)); + } + else + { + SwDoc& rDoc = *rDocSh.GetDoc(); + + if( !bOldShellWasSrcView && bWebDShell && !m_bOldShellWasPagePreview ) + aUsrPref.setBrowseMode( true ); + else + aUsrPref.setBrowseMode( rDoc.getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE) ); + + //For the BrowseMode we do not assume a factor. + if( aUsrPref.getBrowseMode() && aUsrPref.GetZoomType() != SvxZoomType::PERCENT ) + { + aUsrPref.SetZoomType( SvxZoomType::PERCENT ); + aUsrPref.SetZoom( 100 ); + } + if (rDocSh.IsPreview()) + { + aUsrPref.SetZoomType( SvxZoomType::WHOLEPAGE ); + aUsrPref.SetViewLayoutBookMode( false ); + aUsrPref.SetViewLayoutColumns( 1 ); + } + m_pWrtShell.reset(new SwWrtShell(rDoc, m_pEditWin, *this, &aUsrPref)); + // creating an SwView from a SwPagePreview needs to + // add the SwViewShell to the ring of the other SwViewShell(s) + if(m_bOldShellWasPagePreview) + { + SwViewShell& rPreviewViewShell = *static_cast<SwPagePreview*>(pExistingSh)->GetViewShell(); + m_pWrtShell->MoveTo(&rPreviewViewShell); + // to update the field command et.al. if necessary + const SwViewOption* pPreviewOpt = rPreviewViewShell.GetViewOptions(); + if( pPreviewOpt->IsFieldName() != aUsrPref.IsFieldName() || + pPreviewOpt->IsShowHiddenField() != aUsrPref.IsShowHiddenField() || + pPreviewOpt->IsShowHiddenPara() != aUsrPref.IsShowHiddenPara() || + pPreviewOpt->IsShowHiddenChar() != aUsrPref.IsShowHiddenChar() ) + rPreviewViewShell.ApplyViewOptions(aUsrPref); + // reset design mode at draw view for form + // shell, if needed. + if ( static_cast<SwPagePreview*>(pExistingSh)->ResetFormDesignMode() && + m_pWrtShell->HasDrawView() ) + { + SdrView* pDrawView = m_pWrtShell->GetDrawView(); + pDrawView->SetDesignMode( static_cast<SwPagePreview*>(pExistingSh)->FormDesignModeToReset() ); + } + } + } + SAL_INFO( "sw.ui", "after create WrtShell" ); + m_pHRuler = VclPtr<SwCommentRuler>::Create(m_pWrtShell.get(), &GetViewFrame()->GetWindow(), m_pEditWin, + SvxRulerSupportFlags::TABS | + SvxRulerSupportFlags::PARAGRAPH_MARGINS | + SvxRulerSupportFlags::BORDERS | + SvxRulerSupportFlags::NEGATIVE_MARGINS| + SvxRulerSupportFlags::REDUCED_METRIC, + GetViewFrame()->GetBindings(), + WB_STDRULER | WB_EXTRAFIELD | WB_BORDER); + + // assure that modified state of document + // isn't reset, if document is already modified. + const bool bIsDocModified = m_pWrtShell->GetDoc()->getIDocumentState().IsModified(); + + // Thus among other things, the HRuler is not displayed in the read-only case. + aUsrPref.SetReadonly( m_pWrtShell->GetViewOptions()->IsReadonly() ); + + // no margin for OLE! + Size aBrwsBorder; + if( SfxObjectCreateMode::EMBEDDED != rDocSh.GetCreateMode() ) + aBrwsBorder = GetMargin(); + + m_pWrtShell->SetBrowseBorder( aBrwsBorder ); + + // In CTOR no shell changes may take place, which must be temporarily stored + // with the timer. Otherwise, the SFX removes them from the stack! + bool bOld = g_bNoInterrupt; + g_bNoInterrupt = true; + + m_pHRuler->SetActive(); + m_pVRuler->SetActive(); + + SfxViewFrame* pViewFrame = GetViewFrame(); + + StartListening(*pViewFrame, DuplicateHandling::Prevent); + StartListening(rDocSh, DuplicateHandling::Prevent); + + // Set Zoom-factor from HRuler + Fraction aZoomFract( aUsrPref.GetZoom(), 100 ); + m_pHRuler->SetZoom( aZoomFract ); + m_pVRuler->SetZoom( aZoomFract ); + m_pHRuler->SetDoubleClickHdl(LINK( this, SwView, ExecRulerClick )); + FieldUnit eMetric = pUsrPref->GetHScrollMetric(); + m_pHRuler->SetUnit( eMetric ); + + eMetric = pUsrPref->GetVScrollMetric(); + m_pVRuler->SetUnit( eMetric ); + + m_pHRuler->SetCharWidth( 371 ); // default character width + m_pVRuler->SetLineHeight( 551 ); // default line height + + // Set DocShell + m_xGlueDocShell.reset(new SwViewGlueDocShell(*this, rDocSh)); + m_pPostItMgr.reset(new SwPostItMgr(this)); + + // Check and process the DocSize. Via the handler, the shell could not + // be found, because the shell is not known in the SFX management + // within the CTOR phase. + DocSzChgd( m_pWrtShell->GetDocSize() ); + + // Set AttrChangedNotify link + m_pWrtShell->SetChgLnk(LINK(this, SwView, AttrChangedNotify)); + + if (rDocSh.GetCreateMode() == SfxObjectCreateMode::EMBEDDED && + !rDocSh.GetVisArea(ASPECT_CONTENT).IsEmpty()) + SetVisArea(rDocSh.GetVisArea(ASPECT_CONTENT),false); + + SAL_WARN_IF( + officecfg::Office::Common::Undo::Steps::get() <= 0, + "sw.ui", "/org.openoffice.Office.Common/Undo/Steps <= 0"); + if (!utl::ConfigManager::IsFuzzing() && 0 < officecfg::Office::Common::Undo::Steps::get()) + { + m_pWrtShell->DoUndo(); + } + + const bool bBrowse = m_pWrtShell->GetViewOptions()->getBrowseMode(); + // Disable "multiple window" + SetNewWindowAllowed(!bBrowse); + // End of disabled multiple window + + m_bVScrollbarEnabled = aUsrPref.IsViewVScrollBar(); + m_bHScrollbarEnabled = aUsrPref.IsViewHScrollBar(); + m_pHScrollbar->SetAuto(bBrowse); + if( aUsrPref.IsViewHRuler() ) + CreateTab(); + if( aUsrPref.IsViewVRuler() ) + CreateVRuler(); + + m_pWrtShell->SetUIOptions( aUsrPref ); + m_pWrtShell->SetReadOnlyAvailable( aUsrPref.IsCursorInProtectedArea() ); +#if !ENABLE_WASM_STRIP_ACCESSIBILITY + m_pWrtShell->ApplyAccessibilityOptions(SW_MOD()->GetAccessibilityOptions()); +#endif + + if( m_pWrtShell->GetDoc()->getIDocumentState().IsUpdateExpField() ) + { + if (m_pWrtShell->GetDoc()->GetDocumentFieldsManager().containsUpdatableFields()) + { + CurrShell aCurr(m_pWrtShell.get()); + m_pWrtShell->StartAction(); + m_pWrtShell->CalcLayout(); + m_pWrtShell->GetDoc()->getIDocumentFieldsAccess().UpdateFields(false); + m_pWrtShell->EndAction(); + } + m_pWrtShell->GetDoc()->getIDocumentState().SetUpdateExpFieldStat( false ); + } + + // Update all tables if necessary: + if( m_pWrtShell->GetDoc()->IsUpdateTOX() ) + { + SfxRequest aSfxRequest( FN_UPDATE_TOX, SfxCallMode::SLOT, GetPool() ); + Execute( aSfxRequest ); + m_pWrtShell->GetDoc()->SetUpdateTOX( false ); // reset again + m_pWrtShell->SttEndDoc(true); + } + + // No ResetModified, if there is already a view to this doc. + SfxViewFrame* pVFrame = GetViewFrame(); + SfxViewFrame* pFirst = SfxViewFrame::GetFirst(&rDocSh); + // Currently(360) the view is registered firstly after the CTOR, + // the following expression is also working if this changes. + // If the modification cannot be canceled by undo, then do NOT set + // the modify back. + // no reset of modified state, if document + // was already modified. + if (!m_pWrtShell->GetDoc()->GetIDocumentUndoRedo().IsUndoNoResetModified() && + ( !pFirst || pFirst == pVFrame ) && + !bIsDocModified ) + { + m_pWrtShell->ResetModified(); + } + + g_bNoInterrupt = bOld; + + // If a new GlobalDoc will be created, the navigator will also be generated. + if( dynamic_cast<const SwGlobalDocShell*>(&rDocSh) != nullptr && + !pVFrame->GetChildWindow( SID_NAVIGATOR )) + { + SfxBoolItem aNavi(SID_NAVIGATOR, true); + GetDispatcher().ExecuteList(SID_NAVIGATOR, SfxCallMode::ASYNCHRON, { &aNavi }); + } + + uno::Reference< frame::XFrame > xFrame = pVFrame->GetFrame().GetFrameInterface(); + + uno::Reference< frame::XFrame > xBeamerFrame = xFrame->findFrame( + "_beamer", frame::FrameSearchFlag::CHILDREN); + if(xBeamerFrame.is()) + { + SwDBData aData = m_pWrtShell->GetDBData(); + SwModule::ShowDBObj( *this, aData ); + } + + // has anybody calls the attrchanged handler in the constructor? + if( m_bAttrChgNotifiedWithRegistrations ) + { + GetViewFrame()->GetBindings().LEAVEREGISTRATIONS(); + if( m_aTimer.IsActive() ) + m_aTimer.Stop(); + } + + m_aTimer.SetInvokeHandler(LINK(this, SwView, TimeoutHdl)); + m_bAttrChgNotified = m_bAttrChgNotifiedWithRegistrations = false; + if (bOldModifyFlag) + rDocSh.EnableSetModified(); + InvalidateBorder(); + + if( !m_pHScrollbar->IsVisible( true ) ) + ShowHScrollbar( false ); + if( !m_pVScrollbar->IsVisible( true ) ) + ShowVScrollbar( false ); + + if (m_pWrtShell && m_pWrtShell->GetViewOptions()->IsShowOutlineContentVisibilityButton()) + m_pWrtShell->InvalidateOutlineContentVisibility(); + + GetViewFrame()->GetWindow().AddChildEventListener( LINK( this, SwView, WindowChildEventListener ) ); +} + +SwViewGlueDocShell::SwViewGlueDocShell(SwView& rView, SwDocShell& rDocSh) + : m_rView(rView) +{ + // Set DocShell + rDocSh.SetView(&m_rView); + SW_MOD()->SetView(&m_rView); +} + +SwViewGlueDocShell::~SwViewGlueDocShell() +{ + SwDocShell* pDocSh = m_rView.GetDocShell(); + if (pDocSh && pDocSh->GetView() == &m_rView) + pDocSh->SetView(nullptr); + if (SW_MOD()->GetView() == &m_rView) + SW_MOD()->SetView(nullptr); +} + +SwView::~SwView() +{ + // Notify other LOK views that we are going away. + SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_VIEW_CURSOR_VISIBLE, "visible", "false"); + SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", ""); + SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "selection", "EMPTY"); + + // Need to remove activated field's button before disposing EditWin. + GetWrtShell().getIDocumentMarkAccess()->ClearFieldActivation(); + + GetViewFrame()->GetWindow().RemoveChildEventListener( LINK( this, SwView, WindowChildEventListener ) ); + m_pPostItMgr.reset(); + + m_bInDtor = true; + m_pEditWin->Hide(); // prevent problems with painting + + // Set pointer in SwDocShell to the view again + m_xGlueDocShell.reset(); + + if( m_aTimer.IsActive() && m_bAttrChgNotifiedWithRegistrations ) + GetViewFrame()->GetBindings().LEAVEREGISTRATIONS(); + + // the last view must end the text edit + SdrView *pSdrView = m_pWrtShell ? m_pWrtShell->GetDrawView() : nullptr; + if( pSdrView && pSdrView->IsTextEdit() ) + pSdrView->SdrEndTextEdit( true ); + else if (pSdrView) + { + pSdrView->DisposeUndoManager(); + } + + SetWindow( nullptr ); + + m_pViewImpl->Invalidate(); + EndListening(*GetViewFrame()); + EndListening(*GetDocShell()); + m_pScrollFill.disposeAndClear(); + m_pWrtShell.reset(); // reset here so that it is not accessible by the following dtors. + m_pHScrollbar.disposeAndClear(); + m_pVScrollbar.disposeAndClear(); + m_pHRuler.disposeAndClear(); + m_pVRuler.disposeAndClear(); + m_pGlosHdl.reset(); + m_pViewImpl.reset(); + + // If this was enabled in the ctor for the frame, then disable it here. + static bool bRequestDoubleBuffering = getenv("VCL_DOUBLEBUFFERING_ENABLE"); + if (bRequestDoubleBuffering) + m_pEditWin->RequestDoubleBuffering(false); + m_pEditWin.disposeAndClear(); + + m_pFormatClipboard.reset(); +} + +SwDocShell* SwView::GetDocShell() +{ + SfxObjectShell* pDocShell = GetViewFrame()->GetObjectShell(); + return dynamic_cast<SwDocShell*>( pDocShell ); +} + +// Remember CursorPos + +void SwView::WriteUserData( OUString &rUserData, bool bBrowse ) +{ + // The browse flag will be passed from Sfx when documents are browsed + // (not to be confused with the BrowseMode). + // Then that stored data are not persistent! + + const SwRect& rRect = m_pWrtShell->GetCharRect(); + const tools::Rectangle& rVis = GetVisArea(); + + rUserData = OUString::number( rRect.Left() ); + rUserData += ";"; + rUserData += OUString::number( rRect.Top() ); + rUserData += ";"; + rUserData += OUString::number( m_pWrtShell->GetViewOptions()->GetZoom() ); + rUserData += ";"; + rUserData += OUString::number( rVis.Left() ); + rUserData += ";"; + rUserData += OUString::number( rVis.Top() ); + rUserData += ";"; + rUserData += OUString::number( bBrowse ? SAL_MIN_INT32 : rVis.Right()); + rUserData += ";"; + rUserData += OUString::number( bBrowse ? SAL_MIN_INT32 : rVis.Bottom()); + rUserData += ";"; + rUserData += OUString::number( + static_cast<sal_uInt16>(m_pWrtShell->GetViewOptions()->GetZoomType()));//eZoom; + rUserData += ";"; + rUserData += FrameTypeFlags::NONE == m_pWrtShell->GetSelFrameType() ? std::u16string_view(u"0") : std::u16string_view(u"1"); +} + +// Set CursorPos + +static bool lcl_IsOwnDocument( SwView& rView ) +{ + uno::Reference<document::XDocumentPropertiesSupplier> xDPS( + rView.GetDocShell()->GetModel(), uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> xDocProps + = xDPS->getDocumentProperties(); + OUString Created = xDocProps->getAuthor(); + OUString Changed = xDocProps->getModifiedBy(); + OUString FullName = SW_MOD()->GetUserOptions().GetFullName(); + return !FullName.isEmpty() + && (Changed == FullName || (Changed.isEmpty() && Created == FullName)); +} + +void SwView::ReadUserData( const OUString &rUserData, bool bBrowse ) +{ + if ( !(rUserData.indexOf(';')>=0 && // more than one token + // For document without layout only in the onlinelayout or + // while forward/backward + (!m_pWrtShell->IsNewLayout() || m_pWrtShell->GetViewOptions()->getBrowseMode() || bBrowse)) ) + return; + + bool bIsOwnDocument = lcl_IsOwnDocument( *this ); + + CurrShell aCurr(m_pWrtShell.get()); + + sal_Int32 nPos = 0; + + // No it is *not* a good idea to call GetToken within Point constr. immediately, + // because which parameter is evaluated first? + tools::Long nX = o3tl::toInt32(o3tl::getToken(rUserData, 0, ';', nPos )), + nY = o3tl::toInt32(o3tl::getToken(rUserData, 0, ';', nPos )); + Point aCursorPos( nX, nY ); + + sal_uInt16 nZoomFactor = + static_cast< sal_uInt16 >( o3tl::toInt32(o3tl::getToken(rUserData, 0, ';', nPos )) ); + + tools::Long nLeft = o3tl::toInt32(o3tl::getToken(rUserData, 0, ';', nPos )), + nTop = o3tl::toInt32(o3tl::getToken(rUserData, 0, ';', nPos )), + nRight = o3tl::toInt32(o3tl::getToken(rUserData, 0, ';', nPos )), + nBottom= o3tl::toInt32(o3tl::getToken(rUserData, 0, ';', nPos )); + + const tools::Long nAdd = m_pWrtShell->GetViewOptions()->getBrowseMode() ? DOCUMENTBORDER : DOCUMENTBORDER*2; + if ( nBottom > (m_pWrtShell->GetDocSize().Height()+nAdd) ) + return; + + m_pWrtShell->EnableSmooth( false ); + + const tools::Rectangle aVis( nLeft, nTop, nRight, nBottom ); + + sal_Int32 nOff = 0; + SvxZoomType eZoom; + if( !m_pWrtShell->GetViewOptions()->getBrowseMode() ) + eZoom = static_cast<SvxZoomType>(o3tl::narrowing<sal_uInt16>(o3tl::toInt32(o3tl::getToken(rUserData, nOff, ';', nPos )))); + else + { + eZoom = SvxZoomType::PERCENT; + ++nOff; + } + + bool bSelectObj = (0 != o3tl::toInt32(o3tl::getToken(rUserData, nOff, ';', nPos ))) + && m_pWrtShell->IsObjSelectable( aCursorPos ); + + // restore editing position + m_pViewImpl->SetRestorePosition(aCursorPos, bSelectObj); + // set flag value to avoid macro execution. + bool bSavedFlagValue = m_pWrtShell->IsMacroExecAllowed(); + m_pWrtShell->SetMacroExecAllowed( false ); +// os: changed: The user data has to be read if the view is switched back from page preview +// go to the last editing position when opening own files + if(m_bOldShellWasPagePreview || bIsOwnDocument) + { + m_pWrtShell->SwCursorShell::SetCursor( aCursorPos, !bSelectObj ); + if( bSelectObj ) + { + m_pWrtShell->SelectObj( aCursorPos ); + m_pWrtShell->EnterSelFrameMode( &aCursorPos ); + } + } + + // reset flag value + m_pWrtShell->SetMacroExecAllowed( bSavedFlagValue ); + + // set visible area before applying + // information from print preview. Otherwise, the applied information + // is lost. +// os: changed: The user data has to be read if the view is switched back from page preview +// go to the last editing position when opening own files + if(m_bOldShellWasPagePreview || bIsOwnDocument ) + { + if ( bBrowse ) + SetVisArea( aVis.TopLeft() ); + else + SetVisArea( aVis ); + } + + //apply information from print preview - if available + if( !m_sNewCursorPos.isEmpty() ) + { + sal_Int32 nIdx{ 0 }; + const tools::Long nXTmp = o3tl::toInt32(o3tl::getToken(m_sNewCursorPos, 0, ';', nIdx )); + const tools::Long nYTmp = o3tl::toInt32(o3tl::getToken(m_sNewCursorPos, 0, ';', nIdx )); + Point aCursorPos2( nXTmp, nYTmp ); + bSelectObj = m_pWrtShell->IsObjSelectable( aCursorPos2 ); + + m_pWrtShell->SwCursorShell::SetCursor( aCursorPos2 ); + if( bSelectObj ) + { + m_pWrtShell->SelectObj( aCursorPos2 ); + m_pWrtShell->EnterSelFrameMode( &aCursorPos2 ); + } + m_pWrtShell->MakeSelVisible(); + m_sNewCursorPos.clear(); + } + else if(USHRT_MAX != m_nNewPage) + { + m_pWrtShell->GotoPage(m_nNewPage, true); + m_nNewPage = USHRT_MAX; + } + + SelectShell(); + + m_pWrtShell->StartAction(); + const SwViewOption* pVOpt = m_pWrtShell->GetViewOptions(); + if( pVOpt->GetZoom() != nZoomFactor || pVOpt->GetZoomType() != eZoom ) + SetZoom( eZoom, nZoomFactor); + + m_pWrtShell->LockView( true ); + m_pWrtShell->EndAction(); + m_pWrtShell->LockView( false ); + m_pWrtShell->EnableSmooth( true ); +} + +void SwView::ReadUserDataSequence ( const uno::Sequence < beans::PropertyValue >& rSequence ) +{ + if(GetDocShell()->IsPreview()||m_bIsPreviewDoubleClick) + return; + bool bIsOwnDocument = lcl_IsOwnDocument( *this ); + + CurrShell aCurr(m_pWrtShell.get()); + const SwRect& rRect = m_pWrtShell->GetCharRect(); + const tools::Rectangle &rVis = GetVisArea(); + const SwViewOption* pVOpt = m_pWrtShell->GetViewOptions(); + + sal_Int64 nX = rRect.Left(), nY = rRect.Top(), nLeft = rVis.Left(), nTop = rVis.Top(); + sal_Int64 nRight = nLeft; + sal_Int64 nBottom = LONG_MIN; + sal_Int16 nZoomType = static_cast< sal_Int16 >(pVOpt->GetZoomType()); + sal_Int16 nZoomFactor = static_cast < sal_Int16 > (pVOpt->GetZoom()); + bool bViewLayoutBookMode = pVOpt->IsViewLayoutBookMode(); + sal_Int16 nViewLayoutColumns = pVOpt->GetViewLayoutColumns(); + + bool bSelectedFrame = ( m_pWrtShell->GetSelFrameType() != FrameTypeFlags::NONE ), + bGotVisibleLeft = false, + bGotVisibleTop = false, bGotVisibleRight = false, + bGotVisibleBottom = false, bGotZoomType = false, + bGotZoomFactor = false, bGotIsSelectedFrame = false, + bGotViewLayoutColumns = false, bGotViewLayoutBookMode = false, + bBrowseMode = false, bGotBrowseMode = false; + bool bKeepRatio = pVOpt->IsKeepRatio(); + bool bGotKeepRatio = false; + + for (const beans::PropertyValue& rValue : rSequence) + { + if ( rValue.Name == "ViewLeft" ) + { + rValue.Value >>= nX; + nX = o3tl::toTwips(nX, o3tl::Length::mm100); + } + else if ( rValue.Name == "ViewTop" ) + { + rValue.Value >>= nY; + nY = o3tl::toTwips(nY, o3tl::Length::mm100); + } + else if ( rValue.Name == "VisibleLeft" ) + { + rValue.Value >>= nLeft; + nLeft = o3tl::toTwips(nLeft, o3tl::Length::mm100); + bGotVisibleLeft = true; + } + else if ( rValue.Name == "VisibleTop" ) + { + rValue.Value >>= nTop; + nTop = o3tl::toTwips(nTop, o3tl::Length::mm100); + bGotVisibleTop = true; + } + else if ( rValue.Name == "VisibleRight" ) + { + rValue.Value >>= nRight; + nRight = o3tl::toTwips(nRight, o3tl::Length::mm100); + bGotVisibleRight = true; + } + else if ( rValue.Name == "VisibleBottom" ) + { + rValue.Value >>= nBottom; + nBottom = o3tl::toTwips(nBottom, o3tl::Length::mm100); + bGotVisibleBottom = true; + } + else if ( rValue.Name == "ZoomType" ) + { + rValue.Value >>= nZoomType; + bGotZoomType = true; + } + else if ( rValue.Name == "ZoomFactor" ) + { + rValue.Value >>= nZoomFactor; + bGotZoomFactor = true; + } + else if ( rValue.Name == "ViewLayoutColumns" ) + { + rValue.Value >>= nViewLayoutColumns; + bGotViewLayoutColumns = true; + } + else if ( rValue.Name == "ViewLayoutBookMode" ) + { + bViewLayoutBookMode = *o3tl::doAccess<bool>(rValue.Value); + bGotViewLayoutBookMode = true; + } + else if ( rValue.Name == "IsSelectedFrame" ) + { + rValue.Value >>= bSelectedFrame; + bGotIsSelectedFrame = true; + } + else if (rValue.Name == "ShowOnlineLayout") + { + rValue.Value >>= bBrowseMode; + bGotBrowseMode = true; + } + else if (rValue.Name == "KeepRatio") + { + rValue.Value >>= bKeepRatio; + bGotKeepRatio = true; + } + // Fallback to common SdrModel processing + else + GetDocShell()->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel()->ReadUserDataSequenceValue(&rValue); + } + if (bGotBrowseMode) + { + // delegate further + GetViewImpl()->GetUNOObject_Impl()->getViewSettings()->setPropertyValue("ShowOnlineLayout", uno::Any(bBrowseMode)); + } + + SelectShell(); + + if (!bGotVisibleBottom) + return; + + Point aCursorPos( nX, nY ); + const tools::Long nAdd = m_pWrtShell->GetViewOptions()->getBrowseMode() ? DOCUMENTBORDER : DOCUMENTBORDER*2; + if (nBottom > (m_pWrtShell->GetDocSize().Height()+nAdd) ) + return; + + m_pWrtShell->EnableSmooth( false ); + const tools::Rectangle aVis( nLeft, nTop, nRight, nBottom ); + + SvxZoomType eZoom; + if ( !m_pWrtShell->GetViewOptions()->getBrowseMode() ) + eZoom = static_cast < SvxZoomType > ( nZoomType ); + else + { + eZoom = SvxZoomType::PERCENT; + } + if (bGotIsSelectedFrame) + { + bool bSelectObj = bSelectedFrame && m_pWrtShell->IsObjSelectable( aCursorPos ); + + // set flag value to avoid macro execution. + bool bSavedFlagValue = m_pWrtShell->IsMacroExecAllowed(); + m_pWrtShell->SetMacroExecAllowed( false ); +// os: changed: The user data has to be read if the view is switched back from page preview +// go to the last editing position when opening own files + m_pViewImpl->SetRestorePosition(aCursorPos, bSelectObj); + if(m_bOldShellWasPagePreview|| bIsOwnDocument) + { + m_pWrtShell->SwCursorShell::SetCursor( aCursorPos, !bSelectObj ); + + // Update the shell to toggle Header/Footer edit if needed + bool bInHeader = true; + if ( m_pWrtShell->IsInHeaderFooter( &bInHeader ) ) + { + if ( !bInHeader ) + { + m_pWrtShell->SetShowHeaderFooterSeparator( FrameControlType::Footer, true ); + m_pWrtShell->SetShowHeaderFooterSeparator( FrameControlType::Header, false ); + } + else + { + m_pWrtShell->SetShowHeaderFooterSeparator( FrameControlType::Header, true ); + m_pWrtShell->SetShowHeaderFooterSeparator( FrameControlType::Footer, false ); + } + + // Force repaint + m_pWrtShell->GetWin()->Invalidate(); + } + if ( m_pWrtShell->IsInHeaderFooter() != m_pWrtShell->IsHeaderFooterEdit() ) + m_pWrtShell->ToggleHeaderFooterEdit(); + + if( bSelectObj ) + { + m_pWrtShell->SelectObj( aCursorPos ); + m_pWrtShell->EnterSelFrameMode( &aCursorPos ); + } + } + + // reset flag value + m_pWrtShell->SetMacroExecAllowed( bSavedFlagValue ); + } + + if (bGotKeepRatio && bKeepRatio != pVOpt->IsKeepRatio()) + { + // Got a custom value, then it makes sense to trigger notifications. + SwViewOption aUsrPref(*pVOpt); + aUsrPref.SetKeepRatio(bKeepRatio); + SW_MOD()->ApplyUsrPref(aUsrPref, this); + } + + // Set ViewLayoutSettings + const bool bSetViewLayoutSettings = bGotViewLayoutColumns && bGotViewLayoutBookMode && + ( pVOpt->GetViewLayoutColumns() != nViewLayoutColumns || pVOpt->IsViewLayoutBookMode() != bViewLayoutBookMode ); + + const bool bSetViewSettings = bGotZoomType && bGotZoomFactor && + ( pVOpt->GetZoom() != nZoomFactor || pVOpt->GetZoomType() != eZoom ); + + // In case we have a 'fixed' view layout of 2 or more columns, + // we have to apply the view options *before* starting the action. + // Otherwise the SetZoom function cannot work correctly, because + // the view layout hasn't been calculated. + const bool bZoomNeedsViewLayout = bSetViewLayoutSettings && + 1 < nViewLayoutColumns && + bSetViewSettings && + eZoom != SvxZoomType::PERCENT; + + if ( !bZoomNeedsViewLayout ) + m_pWrtShell->StartAction(); + + if ( bSetViewLayoutSettings ) + SetViewLayout( nViewLayoutColumns, bViewLayoutBookMode, true ); + + if ( bZoomNeedsViewLayout ) + m_pWrtShell->StartAction(); + + if ( bSetViewSettings ) + SetZoom( eZoom, nZoomFactor, true ); + +// os: changed: The user data has to be read if the view is switched back from page preview +// go to the last editing position when opening own files + if(m_bOldShellWasPagePreview||bIsOwnDocument) + { + if ( bGotVisibleLeft && bGotVisibleTop ) + { + Point aTopLeft(aVis.TopLeft()); + // make sure the document is still centered + const SwTwips lBorder = IsDocumentBorder() ? DOCUMENTBORDER : 2 * DOCUMENTBORDER; + SwTwips nEditWidth = GetEditWin().GetOutDev()->GetOutputSize().Width(); + if(nEditWidth > (m_aDocSz.Width() + lBorder )) + aTopLeft.setX( ( m_aDocSz.Width() + lBorder - nEditWidth ) / 2 ); + else + { + //check if the values are possible + tools::Long nXMax = m_pHScrollbar->GetRangeMax() - m_pHScrollbar->GetVisibleSize(); + if( aTopLeft.X() > nXMax ) + aTopLeft.setX( nXMax < 0 ? 0 : nXMax ); + } + SetVisArea( aTopLeft ); + } + else if (bGotVisibleLeft && bGotVisibleTop && bGotVisibleRight && bGotVisibleBottom ) + SetVisArea( aVis ); + } + + m_pWrtShell->LockView( true ); + m_pWrtShell->EndAction(); + m_pWrtShell->LockView( false ); + m_pWrtShell->EnableSmooth( true ); + +} + +void SwView::WriteUserDataSequence ( uno::Sequence < beans::PropertyValue >& rSequence ) +{ + const SwRect& rRect = m_pWrtShell->GetCharRect(); + const tools::Rectangle& rVis = GetVisArea(); + + std::vector<beans::PropertyValue> aVector; + + sal_uInt16 nViewID( GetViewFrame()->GetCurViewId()); + aVector.push_back(comphelper::makePropertyValue("ViewId", "view" + OUString::number(nViewID))); + + aVector.push_back(comphelper::makePropertyValue("ViewLeft", convertTwipToMm100 ( rRect.Left() ))); + + aVector.push_back(comphelper::makePropertyValue("ViewTop", convertTwipToMm100 ( rRect.Top() ))); + + auto visibleLeft = convertTwipToMm100 ( rVis.Left() ); + aVector.push_back(comphelper::makePropertyValue("VisibleLeft", visibleLeft)); + + auto visibleTop = convertTwipToMm100 ( rVis.Top() ); + aVector.push_back(comphelper::makePropertyValue("VisibleTop", visibleTop)); + + auto visibleRight = rVis.IsWidthEmpty() ? visibleLeft : convertTwipToMm100 ( rVis.Right() ); + aVector.push_back(comphelper::makePropertyValue("VisibleRight", visibleRight)); + + auto visibleBottom = rVis.IsHeightEmpty() ? visibleTop : convertTwipToMm100 ( rVis.Bottom() ); + aVector.push_back(comphelper::makePropertyValue("VisibleBottom", visibleBottom)); + + const sal_Int16 nZoomType = static_cast< sal_Int16 >(m_pWrtShell->GetViewOptions()->GetZoomType()); + aVector.push_back(comphelper::makePropertyValue("ZoomType", nZoomType)); + + const sal_Int16 nViewLayoutColumns = static_cast< sal_Int16 >(m_pWrtShell->GetViewOptions()->GetViewLayoutColumns()); + aVector.push_back(comphelper::makePropertyValue("ViewLayoutColumns", nViewLayoutColumns)); + + aVector.push_back(comphelper::makePropertyValue("ViewLayoutBookMode", m_pWrtShell->GetViewOptions()->IsViewLayoutBookMode())); + + aVector.push_back(comphelper::makePropertyValue("ZoomFactor", static_cast < sal_Int16 > (m_pWrtShell->GetViewOptions()->GetZoom()))); + + aVector.push_back(comphelper::makePropertyValue("IsSelectedFrame", FrameTypeFlags::NONE != m_pWrtShell->GetSelFrameType())); + + aVector.push_back( + comphelper::makePropertyValue("KeepRatio", m_pWrtShell->GetViewOptions()->IsKeepRatio())); + + rSequence = comphelper::containerToSequence(aVector); + + // Common SdrModel processing + GetDocShell()->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel()->WriteUserDataSequence(rSequence); +} + +void SwView::ShowCursor( bool bOn ) +{ + //don't scroll the cursor into the visible area + bool bUnlockView = !m_pWrtShell->IsViewLocked(); + m_pWrtShell->LockView( true ); //lock visible section + + if( !bOn ) + m_pWrtShell->HideCursor(); + else if( !m_pWrtShell->IsFrameSelected() && !m_pWrtShell->IsObjSelected() ) + m_pWrtShell->ShowCursor(); + + if( bUnlockView ) + m_pWrtShell->LockView( false ); +} + +ErrCode SwView::DoVerb(sal_Int32 nVerb) +{ + if ( !GetViewFrame()->GetFrame().IsInPlace() ) + { + SwWrtShell &rSh = GetWrtShell(); + const SelectionType nSel = rSh.GetSelectionType(); + if ( nSel & SelectionType::Ole ) + rSh.LaunchOLEObj( nVerb ); + } + return ERRCODE_NONE; +} + +// only return true for a text selection + +bool SwView::HasSelection( bool bText ) const +{ + return bText ? GetWrtShell().SwCursorShell::HasSelection() + : GetWrtShell().HasSelection(); +} + +OUString SwView::GetSelectionText( bool bCompleteWrds, bool /*bOnlyASample*/ ) +{ + return GetSelectionTextParam( bCompleteWrds, true ); +} + +OUString SwView::GetSelectionTextParam( bool bCompleteWrds, bool bEraseTrail ) +{ + OUString sReturn; + if( bCompleteWrds && !GetWrtShell().HasSelection() ) + GetWrtShell().SelWrd(); + + GetWrtShell().GetSelectedText( sReturn ); + if( bEraseTrail ) + sReturn = comphelper::string::stripEnd(sReturn, ' '); + return sReturn; +} + +SwGlossaryHdl* SwView::GetGlosHdl() +{ + if(!m_pGlosHdl) + m_pGlosHdl.reset(new SwGlossaryHdl(GetViewFrame(), m_pWrtShell.get())); + return m_pGlosHdl.get(); +} + +void SwView::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) +{ + bool bCallBase = true; + if(auto pChangedHint = dynamic_cast<const FmDesignModeChangedHint*>(&rHint)) + { + bool bDesignMode = pChangedHint->GetDesignMode(); + if (!bDesignMode && GetDrawFuncPtr()) + { + GetDrawFuncPtr()->Deactivate(); + SetDrawFuncPtr(nullptr); + LeaveDrawCreate(); + AttrChangedNotify(nullptr); + } + } + else + { + SfxHintId nId = rHint.GetId(); + + switch ( nId ) + { + // sub shells will be destroyed by the + // dispatcher, if the view frame is dying. Thus, reset member <pShell>. + case SfxHintId::Dying: + { + if ( &rBC == GetViewFrame() ) + { + ResetSubShell(); + } + } + break; + case SfxHintId::ModeChanged: + { + // Modal mode change-over? + bool bModal = GetDocShell()->IsInModalMode(); + m_pHRuler->SetActive( !bModal ); + m_pVRuler->SetActive( !bModal ); + } + + [[fallthrough]]; + + case SfxHintId::TitleChanged: + if ( GetDocShell()->IsReadOnly() != GetWrtShell().GetViewOptions()->IsReadonly() ) + { + SwWrtShell &rSh = GetWrtShell(); + rSh.SetReadonlyOption( GetDocShell()->IsReadOnly() ); + + if ( rSh.GetViewOptions()->IsViewVRuler() ) + CreateVRuler(); + else + KillVRuler(); + if ( rSh.GetViewOptions()->IsViewHRuler() ) + CreateTab(); + else + KillTab(); + bool bReadonly = GetDocShell()->IsReadOnly(); + // if document is to be opened in alive-mode then this has to be + // regarded while switching from readonly-mode to edit-mode + if( !bReadonly ) + { + SwDrawModel * pDrawDoc = GetDocShell()->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel(); + if (pDrawDoc) + { + if( !pDrawDoc->GetOpenInDesignMode() ) + break;// don't touch the design mode + } + } + SfxBoolItem aItem( SID_FM_DESIGN_MODE, !bReadonly); + GetDispatcher().ExecuteList(SID_FM_DESIGN_MODE, + SfxCallMode::ASYNCHRON, { &aItem }); + } + break; + + case SfxHintId::SwDrawViewsCreated: + { + bCallBase = false; + if ( GetFormShell() ) + { + GetFormShell()->SetView(dynamic_cast<FmFormView*>(GetWrtShell().GetDrawView())); + SfxBoolItem aItem( SID_FM_DESIGN_MODE, !GetDocShell()->IsReadOnly()); + GetDispatcher().ExecuteList(SID_FM_DESIGN_MODE, + SfxCallMode::SYNCHRON, { &aItem }); + } + } + break; + case SfxHintId::RedlineChanged: + { + static sal_uInt16 const aSlotRedLine[] = { + FN_REDLINE_ACCEPT_DIRECT, + FN_REDLINE_REJECT_DIRECT, + FN_REDLINE_NEXT_CHANGE, + FN_REDLINE_PREV_CHANGE, + FN_REDLINE_ACCEPT_ALL, + FN_REDLINE_REJECT_ALL, + 0 + }; + GetViewFrame()->GetBindings().Invalidate(aSlotRedLine); + } + break; + default: break; + } + } + + if ( bCallBase ) + SfxViewShell::Notify(rBC, rHint); +} + +#if defined(_WIN32) || defined UNX + +void SwView::ScannerEventHdl() +{ + uno::Reference< XScannerManager2 > xScanMgr = SW_MOD()->GetScannerManager(); + if( xScanMgr.is() ) + { + const ScannerContext aContext( xScanMgr->getAvailableScanners().getConstArray()[ 0 ] ); + const ScanError eError = xScanMgr->getError( aContext ); + + if( ScanError_ScanErrorNone == eError ) + { + const uno::Reference< awt::XBitmap > xBitmap( xScanMgr->getBitmap( aContext ) ); + + if( xBitmap.is() ) + { + const BitmapEx aScanBmp( VCLUnoHelper::GetBitmap( xBitmap ) ); + + if( !aScanBmp.IsEmpty() ) + { + Graphic aGrf(aScanBmp); + m_pWrtShell->InsertGraphic( OUString(), OUString(), aGrf ); + } + } + } + } + SfxBindings& rBind = GetViewFrame()->GetBindings(); + rBind.Invalidate( SID_TWAIN_SELECT ); + rBind.Invalidate( SID_TWAIN_TRANSFER ); +} +#endif + +void SwView::StopShellTimer() +{ + if(m_aTimer.IsActive()) + { + m_aTimer.Stop(); + if ( m_bAttrChgNotifiedWithRegistrations ) + { + GetViewFrame()->GetBindings().LEAVEREGISTRATIONS(); + m_bAttrChgNotifiedWithRegistrations = false; + } + SelectShell(); + m_bAttrChgNotified = false; + } +} + +bool SwView::PrepareClose( bool bUI ) +{ + SfxViewFrame* pVFrame = GetViewFrame(); + pVFrame->SetChildWindow( SwInputChild::GetChildWindowId(), false ); + if( pVFrame->GetDispatcher()->IsLocked() ) + pVFrame->GetDispatcher()->Lock(false); + + if ( m_pFormShell && !m_pFormShell->PrepareClose( bUI ) ) + { + return false; + } + return SfxViewShell::PrepareClose( bUI ); +} + +// status methods for clipboard. +// Status changes now notified from the clipboard. +bool SwView::IsPasteAllowed() +{ + SotExchangeDest nPasteDestination = SwTransferable::GetSotDestination( *m_pWrtShell ); + if( m_nLastPasteDestination != nPasteDestination ) + { + TransferableDataHelper aDataHelper( + TransferableDataHelper::CreateFromSystemClipboard( + &GetEditWin()) ); + if( aDataHelper.GetXTransferable().is() ) + { + m_bPasteState = SwTransferable::IsPaste( *m_pWrtShell, aDataHelper ); + m_bPasteSpecialState = SwTransferable::IsPasteSpecial( + *m_pWrtShell, aDataHelper ); + } + else + m_bPasteState = m_bPasteSpecialState = false; + + if( static_cast<SotExchangeDest>(0xFFFF) == m_nLastPasteDestination ) // the init value + m_pViewImpl->AddClipboardListener(); + m_nLastPasteDestination = nPasteDestination; + } + return m_bPasteState; +} + +bool SwView::IsPasteSpecialAllowed() +{ + if ( m_pFormShell && m_pFormShell->IsActiveControl() ) + return false; + + SotExchangeDest nPasteDestination = SwTransferable::GetSotDestination( *m_pWrtShell ); + if( m_nLastPasteDestination != nPasteDestination ) + { + TransferableDataHelper aDataHelper( + TransferableDataHelper::CreateFromSystemClipboard( + &GetEditWin()) ); + if( aDataHelper.GetXTransferable().is() ) + { + m_bPasteState = SwTransferable::IsPaste( *m_pWrtShell, aDataHelper ); + m_bPasteSpecialState = SwTransferable::IsPasteSpecial( + *m_pWrtShell, aDataHelper ); + } + else + m_bPasteState = m_bPasteSpecialState = false; + + if( static_cast<SotExchangeDest>(0xFFFF) == m_nLastPasteDestination ) // the init value + m_pViewImpl->AddClipboardListener(); + } + return m_bPasteSpecialState; +} + +bool SwView::IsPasteSpreadsheet(bool bHasOwnTableCopied) +{ + TransferableDataHelper aDataHelper( + TransferableDataHelper::CreateFromSystemClipboard( + &GetEditWin()) ); + if( aDataHelper.GetXTransferable().is() ) + { + if (bHasOwnTableCopied && SwTransferable::IsPasteOwnFormat( aDataHelper )) + return true; + return aDataHelper.HasFormat( SotClipboardFormatId::SYLK ) || aDataHelper.HasFormat( SotClipboardFormatId::SYLK_BIGCAPS ); + } + return false; +} + +void SwView::NotifyDBChanged() +{ + GetViewImpl()->GetUNOObject_Impl()->NotifyDBChanged(); +} + +// Printing + +SfxObjectShellLock SwView::CreateTmpSelectionDoc() +{ + SwXTextView *const pTempImpl = GetViewImpl()->GetUNOObject_Impl(); + return pTempImpl->BuildTmpSelectionDoc(); +} + +void SwView::AddTransferable(SwTransferable& rTransferable) +{ + GetViewImpl()->AddTransferable(rTransferable); +} + +tools::Rectangle SwView::getLOKVisibleArea() const +{ + SwViewShell* pVwSh = GetWrtShellPtr(); + if (pVwSh) + return pVwSh->getLOKVisibleArea(); + else + return tools::Rectangle(); +} + +void SwView::flushPendingLOKInvalidateTiles() +{ + SwWrtShell* pSh = GetWrtShellPtr(); + assert(pSh); + pSh->FlushPendingLOKInvalidateTiles(); +} + +OString SwView::getLOKPayload(int nType, int nViewId, bool* ignore) const +{ + SwWrtShell* pSh = GetWrtShellPtr(); + assert(pSh); + return pSh->getLOKPayload(nType, nViewId, ignore); +} + +OUString SwView::GetDataSourceName() const +{ + uno::Reference<lang::XMultiServiceFactory> xFactory(GetDocShell()->GetModel(), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xSettings( + xFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY); + OUString sDataSourceName = ""; + xSettings->getPropertyValue("CurrentDatabaseDataSource") >>= sDataSourceName; + + return sDataSourceName; +} + +bool SwView::IsDataSourceAvailable(const OUString sDataSourceName) +{ + uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + Reference< XDatabaseContext> xDatabaseContext = DatabaseContext::create(xContext); + + return xDatabaseContext->hasByName(sDataSourceName); +} + +namespace sw { + +void InitPrintOptionsFromApplication(SwPrintData & o_rData, bool const bWeb) +{ + o_rData = *SW_MOD()->GetPrtOptions(bWeb); +} + +} // namespace sw + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/uiview/view0.cxx b/sw/source/uibase/uiview/view0.cxx new file mode 100644 index 000000000..fefada834 --- /dev/null +++ b/sw/source/uibase/uiview/view0.cxx @@ -0,0 +1,694 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <config_features.h> +#include <config_wasm_strip.h> + +#include <SwSpellDialogChildWindow.hxx> +#include <svl/eitem.hxx> +#include <unotools/configmgr.hxx> +#include <unotools/linguprops.hxx> +#include <unotools/lingucfg.hxx> +#include <viewopt.hxx> +#include <globals.h> +#include <sfx2/infobar.hxx> +#include <sfx2/request.hxx> +#include <svl/whiter.hxx> +#include <svx/srchdlg.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/sidebar/SidebarChildWindow.hxx> +#include <uivwimp.hxx> +#include <avmedia/mediaplayer.hxx> +#include <swmodule.hxx> +#include <com/sun/star/linguistic2/XLinguProperties.hpp> +#include <osl/diagnose.h> + +#include <sfx2/objface.hxx> +#include <wrtsh.hxx> +#include <edtwin.hxx> +#include <view.hxx> +#include <docsh.hxx> +#include <doc.hxx> +#include <globals.hrc> +#include <cmdid.h> +#include <globdoc.hxx> +#include <wview.hxx> + +#define ShellClass_SwView +#define ShellClass_Text +#define ShellClass_TextDrawText + +#include <sfx2/msg.hxx> +#include <swslots.hxx> +#include <PostItMgr.hxx> + +using namespace ::com::sun::star; + +#include <unotools/moduleoptions.hxx> +#include <sfx2/viewfac.hxx> + +#include <memory> +#include <swabstdlg.hxx> + +SFX_IMPL_NAMED_VIEWFACTORY(SwView, "Default") +{ + if (utl::ConfigManager::IsFuzzing() || SvtModuleOptions().IsWriter()) + { + SFX_VIEW_REGISTRATION(SwDocShell); + SFX_VIEW_REGISTRATION(SwGlobalDocShell); + } +} + +SFX_IMPL_INTERFACE(SwView, SfxViewShell) + +void SwView::InitInterface_Impl() +{ + GetStaticInterface()->RegisterChildWindow(SID_NAVIGATOR, true); + + GetStaticInterface()->RegisterChildWindow(::sfx2::sidebar::SidebarChildWindow::GetChildWindowId()); + + GetStaticInterface()->RegisterChildWindow(SfxInfoBarContainerChild::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(SvxSearchDialogWrapper::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(SwSpellDialogChildWindow::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(FN_REDLINE_ACCEPT); + GetStaticInterface()->RegisterChildWindow(SID_HYPERLINK_DIALOG); + GetStaticInterface()->RegisterChildWindow(FN_WORDCOUNT_DIALOG); +#if HAVE_FEATURE_AVMEDIA + GetStaticInterface()->RegisterChildWindow(::avmedia::MediaPlayer::GetChildWindowId()); +#endif + GetStaticInterface()->RegisterChildWindow(FN_INSERT_FIELD_DATA_ONLY); + + GetStaticInterface()->RegisterChildWindow(FN_SYNC_LABELS, false, SfxShellFeature::SwChildWindowLabel); + + GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_TOOLS, SfxVisibilityFlags::Standard|SfxVisibilityFlags::Server, + ToolbarId::Tools_Toolbox); +} + + +ShellMode SwView::GetShellMode() const +{ + return m_pViewImpl->GetShellMode(); +} + +view::XSelectionSupplier* SwView::GetUNOObject() +{ + return m_pViewImpl->GetUNOObject(); +} + +void SwView::ApplyAccessibilityOptions(SvtAccessibilityOptions const & rAccessibilityOptions) +{ +#if ENABLE_WASM_STRIP_ACCESSIBILITY + (void)rAccessibilityOptions; +#else + m_pWrtShell->ApplyAccessibilityOptions(rAccessibilityOptions); + //to enable the right state of the selection cursor in readonly documents + if(GetDocShell()->IsReadOnly()) + m_pWrtShell->ShowCursor(); +#endif +} + +void SwView::SetMailMergeConfigItem(std::shared_ptr<SwMailMergeConfigItem> const & rConfigItem) +{ + m_pViewImpl->SetMailMergeConfigItem(rConfigItem); + UIFeatureChanged(); +} + +std::shared_ptr<SwMailMergeConfigItem> const & SwView::GetMailMergeConfigItem() const +{ + return m_pViewImpl->GetMailMergeConfigItem(); +} + +static bool lcl_IsViewMarks( const SwViewOption& rVOpt ) +{ + return rVOpt.IsHardBlank() && + rVOpt.IsSoftHyph() && + SwViewOption::IsFieldShadings(); +} +static void lcl_SetViewMarks(SwViewOption& rVOpt, bool bOn ) +{ + rVOpt.SetHardBlank(bOn); + rVOpt.SetSoftHyph(bOn); + SwViewOption::SetAppearanceFlag( + ViewOptFlags::FieldShadings, bOn, true); +} + +static void lcl_SetViewMetaChars( SwViewOption& rVOpt, bool bOn) +{ + rVOpt.SetViewMetaChars( bOn ); + if(bOn && !(rVOpt.IsParagraph() || + rVOpt.IsTab() || + rVOpt.IsLineBreak() || + rVOpt.IsShowHiddenChar() || + rVOpt.IsShowBookmarks() || + rVOpt.IsBlank())) + { + rVOpt.SetParagraph(bOn); + rVOpt.SetTab(bOn); + rVOpt.SetLineBreak(bOn); + rVOpt.SetBlank(bOn); + rVOpt.SetShowHiddenChar(bOn); + rVOpt.SetShowBookmarks(bOn); + } +} + +void SwView::RecheckBrowseMode() +{ + // OS: pay attention to numerical order! + static sal_uInt16 const aInva[] = + { + //SID_NEWWINDOW,/*5620*/ + SID_BROWSER_MODE, /*6313*/ + SID_RULER_BORDERS, SID_RULER_PAGE_POS, + //SID_ATTR_LONG_LRSPACE, + SID_HTML_MODE, + SID_RULER_PROTECT, /* 10915 */ + //SID_AUTOSPELL_CHECK, + //SID_AUTOSPELL_MARKOFF, + SID_TOGGLE_RESOLVED_NOTES, /* 11672*/ + FN_RULER, /*20211*/ + FN_VIEW_GRAPHIC, /*20213*/ + FN_VIEW_BOUNDS, /**/ + FN_VIEW_FIELDS, /*20215*/ + FN_VLINEAL, /*20216*/ + FN_VSCROLLBAR, /*20217*/ + FN_HSCROLLBAR, /*20218*/ + FN_VIEW_META_CHARS, /**/ + FN_VIEW_MARKS, /**/ + //FN_VIEW_FIELDNAME, /**/ + FN_VIEW_TABLEGRID, /*20227*/ + FN_PRINT_LAYOUT, /*20237*/ + FN_QRY_MERGE, /*20364*/ + FN_SHADOWCURSOR, /**/ + 0 + }; + // the view must not exist! + GetViewFrame()->GetBindings().Invalidate(aInva); + CheckVisArea(); + + SvxZoomType eType; + if( GetWrtShell().GetViewOptions()->getBrowseMode() && SvxZoomType::PERCENT != (eType = + GetWrtShell().GetViewOptions()->GetZoomType()) ) + SetZoom( eType ); + InvalidateBorder(); +} + +// State of view options + +void SwView::StateViewOptions(SfxItemSet &rSet) +{ + SfxWhichIter aIter(rSet); + sal_uInt16 nWhich = aIter.FirstWhich(); + SfxBoolItem aBool; + const SwViewOption* pOpt = GetWrtShell().GetViewOptions(); + + while(nWhich) + { + bool bReadonly = GetDocShell()->IsReadOnly(); + if ( bReadonly && nWhich != FN_VIEW_GRAPHIC ) + { + rSet.DisableItem(nWhich); + nWhich = 0; + } + switch(nWhich) + { + case FN_RULER: + { + if(!pOpt->IsViewHRuler(true) && !pOpt->IsViewVRuler(true)) + { + rSet.DisableItem(nWhich); + nWhich = 0; + } + else + aBool.SetValue( pOpt->IsViewAnyRuler()); + } + break; + case SID_BROWSER_MODE: + case FN_PRINT_LAYOUT: + { + bool bState = pOpt->getBrowseMode(); + if(FN_PRINT_LAYOUT == nWhich) + bState = !bState; + aBool.SetValue( bState ); + } + break; + case FN_VIEW_BOUNDS: + aBool.SetValue( SwViewOption::IsDocBoundaries()); break; + case FN_VIEW_GRAPHIC: + aBool.SetValue( pOpt->IsGraphic() ); break; + case FN_VIEW_FIELDS: + aBool.SetValue( SwViewOption::IsFieldShadings() ); break; + case FN_VIEW_FIELDNAME: + aBool.SetValue( pOpt->IsFieldName() ); break; + case FN_VIEW_MARKS: + aBool.SetValue( lcl_IsViewMarks(*pOpt) ); break; + case FN_VIEW_META_CHARS: + aBool.SetValue( pOpt->IsViewMetaChars() ); break; + case FN_VIEW_TABLEGRID: + aBool.SetValue( SwViewOption::IsTableBoundaries() ); break; + case SID_TOGGLE_NOTES: + { + if (!GetPostItMgr()->HasNotes()) + { + rSet.DisableItem(nWhich); + nWhich = 0; + } + else + aBool.SetValue( pOpt->IsPostIts()); + break; + } + case SID_TOGGLE_RESOLVED_NOTES: + { + if (!GetPostItMgr()->HasNotes()) + { + rSet.DisableItem(nWhich); + nWhich = 0; + } + else + aBool.SetValue( pOpt->IsResolvedPostIts()); + break; + } + case FN_VIEW_HIDDEN_PARA: + aBool.SetValue( pOpt->IsShowHiddenPara()); break; + case FN_VIEW_HIDE_WHITESPACE: + { + if (pOpt->getBrowseMode() || !pOpt->CanHideWhitespace()) + { + rSet.DisableItem(nWhich); + nWhich = 0; + } + else + aBool.SetValue(pOpt->IsHideWhitespaceMode()); + break; + } + case FN_VIEW_SHOW_WHITESPACE: + { + aBool.SetValue(!pOpt->IsHideWhitespaceMode()); + break; + } + case SID_GRID_VISIBLE: + aBool.SetValue( pOpt->IsGridVisible() ); break; + case SID_GRID_USE: + aBool.SetValue( pOpt->IsSnap() ); break; + case SID_HELPLINES_MOVE: + aBool.SetValue( pOpt->IsCrossHair() ); break; + case FN_VIEW_SMOOTH_SCROLL: + aBool.SetValue( pOpt->IsSmoothScroll()); break; + case FN_VLINEAL: + aBool.SetValue( StatVRuler() ); break; + case FN_HSCROLLBAR: + if( pOpt->getBrowseMode() ) + { + rSet.DisableItem(nWhich); + nWhich = 0; + } + else + aBool.SetValue( IsHScrollbarVisible() ); + break; + case FN_VSCROLLBAR: + aBool.SetValue( IsVScrollbarVisible() ); break; + case SID_AUTOSPELL_CHECK: + aBool.SetValue( pOpt->IsOnlineSpell() ); + break; + case FN_SHADOWCURSOR: + if ( pOpt->getBrowseMode() ) + { + rSet.DisableItem( nWhich ); + nWhich = 0; + } + else + aBool.SetValue( pOpt->IsShadowCursor() ); + break; + case FN_SHOW_INLINETOOLTIPS: + aBool.SetValue( pOpt->IsShowInlineTooltips() ); + break; + case FN_USE_HEADERFOOTERMENU: + aBool.SetValue( pOpt->IsUseHeaderFooterMenu() ); + break; + case FN_SHOW_OUTLINECONTENTVISIBILITYBUTTON: + aBool.SetValue( pOpt->IsShowOutlineContentVisibilityButton() ); + break; + case FN_SHOW_CHANGES_IN_MARGIN: + aBool.SetValue( pOpt->IsShowChangesInMargin() ); + break; + } + + if( nWhich ) + { + aBool.SetWhich( nWhich ); + rSet.Put( aBool ); + } + nWhich = aIter.NextWhich(); + } +} + +// execute view options + +void SwView::ExecViewOptions(SfxRequest &rReq) +{ + std::optional<SwViewOption> pOpt( *GetWrtShell().GetViewOptions() ); + bool bModified = GetWrtShell().IsModified(); + + int eState = STATE_TOGGLE; + bool bSet = false; + bool bBrowseModeChanged = false; + + const SfxItemSet *pArgs = rReq.GetArgs(); + sal_uInt16 nSlot = rReq.GetSlot(); + const SfxPoolItem* pAttr=nullptr; + + if( pArgs && SfxItemState::SET == pArgs->GetItemState( nSlot , false, &pAttr )) + { + bSet = static_cast<const SfxBoolItem*>(pAttr)->GetValue(); + eState = bSet ? STATE_ON : STATE_OFF; + } + + bool bFlag = STATE_ON == eState; + uno::Reference< linguistic2::XLinguProperties > xLngProp( ::GetLinguPropertySet() ); + + switch ( nSlot ) + { + case FN_VIEW_GRAPHIC: + if( STATE_TOGGLE == eState ) + bFlag = !pOpt->IsGraphic(); + pOpt->SetGraphic( bFlag ); + break; + + case FN_VIEW_FIELDS: + if( STATE_TOGGLE == eState ) + bFlag = !SwViewOption::IsFieldShadings() ; + SwViewOption::SetAppearanceFlag(ViewOptFlags::FieldShadings, bFlag, true ); + break; + + case FN_VIEW_BOUNDS: + if( STATE_TOGGLE == eState ) + bFlag = !SwViewOption::IsDocBoundaries(); + SwViewOption::SetAppearanceFlag(ViewOptFlags::DocBoundaries, bFlag, true ); + break; + + case SID_GRID_VISIBLE: + if( STATE_TOGGLE == eState ) + bFlag = !pOpt->IsGridVisible(); + + pOpt->SetGridVisible( bFlag ); + break; + + case SID_GRID_USE: + if( STATE_TOGGLE == eState ) + bFlag = !pOpt->IsSnap(); + + pOpt->SetSnap( bFlag ); + break; + + case SID_HELPLINES_MOVE: + if( STATE_TOGGLE == eState ) + bFlag = !pOpt->IsCrossHair(); + + pOpt->SetCrossHair( bFlag ); + break; + + case SID_BROWSER_MODE: + bBrowseModeChanged = !pOpt->getBrowseMode(); + pOpt->setBrowseMode(true ); + break; + + case FN_PRINT_LAYOUT: + bBrowseModeChanged = pOpt->getBrowseMode(); + pOpt->setBrowseMode( false ); + break; + + case SID_TOGGLE_NOTES: + if ( STATE_TOGGLE == eState ) + bFlag = !pOpt->IsPostIts(); + + GetPostItMgr()->SetLayout(); + pOpt->SetPostIts( bFlag ); + if (pOpt->IsPostIts()) + GetPostItMgr()->CheckMetaText(); + break; + + case SID_TOGGLE_RESOLVED_NOTES: + if ( STATE_TOGGLE == eState ) + bFlag = pOpt->IsResolvedPostIts(); + + GetPostItMgr()->ShowHideResolvedNotes(!bFlag); + + GetPostItMgr()->SetLayout(); + pOpt->SetResolvedPostIts( !bFlag ); + + break; + + case FN_VIEW_HIDDEN_PARA: + if ( STATE_TOGGLE == eState ) + bFlag = !pOpt->IsShowHiddenPara(); + + pOpt->SetShowHiddenPara( bFlag ); + break; + + case FN_VIEW_HIDE_WHITESPACE: + if ( STATE_TOGGLE == eState ) + bFlag = !pOpt->IsHideWhitespaceMode(); + + pOpt->SetHideWhitespaceMode(bFlag); + break; + + case FN_VIEW_SHOW_WHITESPACE: + if ( STATE_TOGGLE == eState ) + bFlag = pOpt->IsHideWhitespaceMode(); + + pOpt->SetHideWhitespaceMode(!bFlag); + break; + + case FN_VIEW_SMOOTH_SCROLL: + + if ( STATE_TOGGLE == eState ) + bFlag = !pOpt->IsSmoothScroll(); + + pOpt->SetSmoothScroll( bFlag ); + break; + + case FN_VLINEAL: + if( STATE_TOGGLE == eState ) + bFlag = !pOpt->IsViewVRuler(); + + pOpt->SetViewVRuler( bFlag ); + break; + + case FN_VSCROLLBAR: + if( STATE_TOGGLE == eState ) + bFlag = !pOpt->IsViewVScrollBar(); + + pOpt->SetViewVScrollBar( bFlag ); + break; + + case FN_HSCROLLBAR: + if( STATE_TOGGLE == eState ) + bFlag = !pOpt->IsViewHScrollBar(); + + pOpt->SetViewHScrollBar( bFlag ); + break; + + case FN_RULER: + if( STATE_TOGGLE == eState ) + bFlag = !pOpt->IsViewAnyRuler(); + + pOpt->SetViewAnyRuler( bFlag ); + break; + + case FN_VIEW_TABLEGRID: + if( STATE_TOGGLE == eState ) + bFlag = !SwViewOption::IsTableBoundaries(); + SwViewOption::SetAppearanceFlag(ViewOptFlags::TableBoundaries, bFlag, true ); + break; + + case FN_VIEW_FIELDNAME: + if( STATE_TOGGLE == eState ) + bFlag = !pOpt->IsFieldName() ; + + pOpt->SetFieldName( bFlag ); + break; + + case FN_VIEW_MARKS: + if( STATE_TOGGLE == eState ) + bFlag = !lcl_IsViewMarks(*pOpt) ; + + lcl_SetViewMarks( *pOpt, bFlag ); + break; + + case FN_VIEW_META_CHARS: + if( STATE_TOGGLE == eState ) + bFlag = !pOpt->IsViewMetaChars(); + + lcl_SetViewMetaChars( *pOpt, bFlag ); + break; + + case SID_AUTOSPELL_CHECK: + const SfxPoolItem* pItem; + + if (pArgs && pArgs->HasItem(FN_PARAM_1, &pItem)) + bSet = static_cast<const SfxBoolItem*>(pItem)->GetValue(); + else if( STATE_TOGGLE == eState ) + { + bFlag = !pOpt->IsOnlineSpell(); + bSet = bFlag; + } + + pOpt->SetOnlineSpell(bSet); + { + SvtLinguConfig aCfg; + aCfg.SetProperty( UPN_IS_SPELL_AUTO, uno::Any( bSet ) ); + + if (xLngProp.is()) + xLngProp->setIsSpellAuto( bSet ); + + // for the time being we do not have a specific option for grammarchecking. + // thus we'll use the one for spell checking... + if (bSet) + { + SwDocShell *pDocSh = GetDocShell(); + SwDoc *pDoc = pDocSh? pDocSh->GetDoc() : nullptr; + + // right now we don't have view options for automatic grammar checking. Thus... + bool bIsAutoGrammar = false; + aCfg.GetProperty( UPN_IS_GRAMMAR_AUTO ) >>= bIsAutoGrammar; + + if (pDoc && bIsAutoGrammar) + pDoc->StartGrammarChecking(); + } + } + break; + + case FN_SHADOWCURSOR: + if( STATE_TOGGLE == eState ) + { + bFlag = !pOpt->IsShadowCursor(); + bSet = bFlag; + } + + pOpt->SetShadowCursor(bSet); + break; + + case FN_SHOW_INLINETOOLTIPS: + if( STATE_TOGGLE == eState ) + bFlag = !pOpt->IsShowInlineTooltips(); + + pOpt->SetShowInlineTooltips( bFlag ); + break; + + case FN_USE_HEADERFOOTERMENU: + if( STATE_TOGGLE == eState ) + bFlag = !pOpt->IsUseHeaderFooterMenu(); + + pOpt->SetUseHeaderFooterMenu( bFlag ); + break; + + case FN_SHOW_OUTLINECONTENTVISIBILITYBUTTON: + { + if( STATE_TOGGLE == eState ) + bFlag = !pOpt->IsShowOutlineContentVisibilityButton(); + + SwWrtShell &rSh = GetWrtShell(); + + if (!bFlag) // Outline folding is being turned ON! + rSh.MakeAllFoldedOutlineContentVisible(); + + pOpt->SetShowOutlineContentVisibilityButton(bFlag); + + // Apply option change here so if toggling the outline folding feature ON + // the invalidate function will see this. + rSh.StartAction(); + rSh.ApplyViewOptions(*pOpt); + rSh.EndAction(); + + if (bFlag) // Outline folding is being turned OFF! + rSh.MakeAllFoldedOutlineContentVisible(false); + + break; + } + + case FN_SHOW_CHANGES_IN_MARGIN: + if( STATE_TOGGLE == eState ) + bFlag = !pOpt->IsShowChangesInMargin(); + + pOpt->SetShowChangesInMargin( bFlag ); + break; + + default: + OSL_FAIL("wrong request method"); + return; + } + + // Set UserPrefs, mark request as modified + bool bWebView = dynamic_cast<const SwWebView*>(this) != nullptr; + SwWrtShell &rSh = GetWrtShell(); + rSh.StartAction(); + SwModule* pModule = SW_MOD(); + if( *rSh.GetViewOptions() != *pOpt ) + { + rSh.ApplyViewOptions( *pOpt ); + if( bBrowseModeChanged ) + { + GetDocShell()->ToggleLayoutMode(this); + } + + // The UsrPref must be marked as modified. + // call for initialization + pModule->GetUsrPref(bWebView); + SwModule::CheckSpellChanges( pOpt->IsOnlineSpell(), false, false, false ); + } + //OS: Set back modified again, because view/fields sets the Doc modified. + if( !bModified ) + rSh.ResetModified(); + + pModule->ApplyUsrPref( *pOpt, this, bWebView ? SvViewOpt::DestWeb : SvViewOpt::DestText ); + + // #i6193# let postits know about new spellcheck setting + if ( nSlot == SID_AUTOSPELL_CHECK ) + GetPostItMgr()->SetSpellChecking(); + + const bool bLockedView = rSh.IsViewLocked(); + rSh.LockView( true ); //lock visible section + GetWrtShell().EndAction(); + if( bBrowseModeChanged && !bFlag ) + CalcVisArea( GetEditWin().GetOutputSizePixel() ); + rSh.LockView( bLockedView ); + + pOpt.reset(); + Invalidate(rReq.GetSlot()); + if(!pArgs) + rReq.AppendItem(SfxBoolItem(nSlot, bFlag)); + rReq.Done(); +} + +void SwView::ExecFormatFootnote() +{ + SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create(); + ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateSwFootNoteOptionDlg(GetFrameWeld(), GetWrtShell())); + pDlg->Execute(); +} + +void SwView::ExecNumberingOutline(SfxItemPool & rPool) +{ + SfxItemSetFixed<FN_PARAM_1, FN_PARAM_1> aTmp(rPool); + SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create(); + ScopedVclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateOutlineTabDialog(GetFrameWeld(), &aTmp, GetWrtShell())); + pDlg->Execute(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/uiview/view1.cxx b/sw/source/uibase/uiview/view1.cxx new file mode 100644 index 000000000..979f5e0f5 --- /dev/null +++ b/sw/source/uibase/uiview/view1.cxx @@ -0,0 +1,216 @@ +/* -*- 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 <svl/eitem.hxx> +#include <svx/ruler.hxx> +#include <idxmrk.hxx> +#include <view.hxx> +#include <basesh.hxx> +#include <wrtsh.hxx> +#include <swmodule.hxx> +#include <docsh.hxx> +#include <fldwrap.hxx> +#include <redlndlg.hxx> +#include <edtwin.hxx> +#include <formatclipboard.hxx> +#include <cmdid.h> +#include <sfx2/dispatch.hxx> +#include <sfx2/request.hxx> +#include <sfx2/viewfrm.hxx> +#include <wordcountdialog.hxx> + +void SwView::Activate(bool bMDIActivate) +{ + // fdo#40438 Update the layout to make sure everything is correct before showing the content + m_pWrtShell->StartAction(); + m_pWrtShell->EndAction( true ); + + // Register the current View at the DocShell. + // The view remains active at the DocShell until it will + // be destroyed or by Activate a new one will be set. + SwDocShell* pDocSh = GetDocShell(); + if(pDocSh) + pDocSh->SetView(this); + SwModule* pSwMod = SW_MOD(); + pSwMod->SetView(this); + + // Document size has changed. + if(!bDocSzUpdated) + DocSzChgd(m_aDocSz); + + // make selection visible + if(m_bMakeSelectionVisible) + { + m_pWrtShell->MakeSelVisible(); + m_bMakeSelectionVisible = false; + } + m_pHRuler->SetActive(); + m_pVRuler->SetActive(); + + if ( bMDIActivate ) + { + if ( m_pShell ) + { + SfxDispatcher &rDispatcher = GetDispatcher(); + SfxShell *pTopShell = rDispatcher.GetShell( 0 ); + + // this SwView is the top-most shell on the stack + if ( pTopShell == this ) + { + for ( sal_uInt16 i = 1; true; ++i ) + { + SfxShell *pSfxShell = rDispatcher.GetShell( i ); + // does the stack contain any shells spawned by this SwView already? + if ( ( dynamic_cast< const SwBaseShell *>( pSfxShell ) != nullptr + || dynamic_cast< const FmFormShell *>( pSfxShell ) != nullptr ) + && ( pSfxShell->GetViewShell() == this ) ) + { + // it shouldn't b/c we haven't been activated yet + // so assert that 'cause it'll crash during dispose at the latest + assert( pSfxShell && "Corrupted shell stack: dependent shell positioned below its view"); + } + else + break; + } + } + } + + m_pWrtShell->ShellGetFocus(); // Selections visible + + if( !m_sSwViewData.isEmpty() ) + { + ReadUserData(m_sSwViewData); + m_sSwViewData.clear(); + } + + AttrChangedNotify(nullptr); + + // Initialize Fielddlg newly if necessary (e.g. for TYP_SETVAR) + sal_uInt16 nId = SwFieldDlgWrapper::GetChildWindowId(); + SfxViewFrame* pVFrame = GetViewFrame(); + SwFieldDlgWrapper *pWrp = static_cast<SwFieldDlgWrapper*>(pVFrame->GetChildWindow(nId)); + if (pWrp) + pWrp->ReInitDlg(GetDocShell()); + + // Initialize RedlineDlg newly if necessary + nId = SwRedlineAcceptChild::GetChildWindowId(); + SwRedlineAcceptChild *pRed = static_cast<SwRedlineAcceptChild*>(pVFrame->GetChildWindow(nId)); + if (pRed) + pRed->ReInitDlg(GetDocShell()); + + // reinit IdxMarkDlg + nId = SwInsertIdxMarkWrapper::GetChildWindowId(); + SwInsertIdxMarkWrapper *pIdxMrk = static_cast<SwInsertIdxMarkWrapper*>(pVFrame->GetChildWindow(nId)); + if (pIdxMrk) + pIdxMrk->ReInitDlg(*m_pWrtShell); + + // reinit AuthMarkDlg + nId = SwInsertAuthMarkWrapper::GetChildWindowId(); + SwInsertAuthMarkWrapper *pAuthMrk = static_cast<SwInsertAuthMarkWrapper*>(pVFrame-> + GetChildWindow(nId)); + if (pAuthMrk) + pAuthMrk->ReInitDlg(*m_pWrtShell); + } + else + // At least call the Notify (as a precaution because of the SlotFilter). + AttrChangedNotify(nullptr); + + SfxViewShell::Activate(bMDIActivate); +} + +void SwView::Deactivate(bool bMDIActivate) +{ + GetEditWin().FlushInBuffer(); // Flush characters still in the input buffer. + + if( bMDIActivate ) + { + m_pWrtShell->ShellLoseFocus(); // Selections invisible + + m_pHRuler->SetActive( false ); + m_pVRuler->SetActive( false ); + } + SfxViewShell::Deactivate(bMDIActivate); +} + +void SwView::MarginChanged() +{ + GetWrtShell().SetBrowseBorder( GetMargin() ); +} + +void SwView::ExecFormatPaintbrush(SfxRequest const & rReq) +{ + if(!m_pFormatClipboard) + return; + + if( m_pFormatClipboard->HasContent() ) + { + m_pFormatClipboard->Erase(); + + SwApplyTemplate aTemplate; + GetEditWin().SetApplyTemplate(aTemplate); + } + else + { + bool bPersistentCopy = false; + const SfxItemSet *pArgs = rReq.GetArgs(); + if( pArgs && pArgs->Count() >= 1 ) + { + bPersistentCopy = pArgs->Get(SID_FORMATPAINTBRUSH).GetValue(); + } + + m_pFormatClipboard->Copy( GetWrtShell(), GetPool(), bPersistentCopy ); + + SwApplyTemplate aTemplate; + aTemplate.m_pFormatClipboard = m_pFormatClipboard.get(); + GetEditWin().SetApplyTemplate(aTemplate); + } + GetViewFrame()->GetBindings().Invalidate(SID_FORMATPAINTBRUSH); +} + +void SwView::StateFormatPaintbrush(SfxItemSet &rSet) +{ + if(!m_pFormatClipboard) + return; + + const bool bHasContent = m_pFormatClipboard->HasContent(); + if( !bHasContent && + !SwFormatClipboard::CanCopyThisType( GetWrtShell().GetSelectionType()) + ) + { + rSet.DisableItem( SID_FORMATPAINTBRUSH ); + } + else + rSet.Put(SfxBoolItem(SID_FORMATPAINTBRUSH, bHasContent)); +} + +void SwView::UpdateWordCount(SfxShell* pShell, sal_uInt16 nSlot) +{ + SfxViewFrame* pVFrame = GetViewFrame(); + if (pVFrame != nullptr) + { + pVFrame->ToggleChildWindow(FN_WORDCOUNT_DIALOG); + pShell->Invalidate(nSlot); + + SwWordCountWrapper *pWrdCnt = static_cast<SwWordCountWrapper*>(pVFrame->GetChildWindow(SwWordCountWrapper::GetChildWindowId())); + if (pWrdCnt) + pWrdCnt->UpdateCounts(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/uiview/view2.cxx b/sw/source/uibase/uiview/view2.cxx new file mode 100644 index 000000000..e716c96b3 --- /dev/null +++ b/sw/source/uibase/uiview/view2.cxx @@ -0,0 +1,2890 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <config_features.h> +#include <config_fuzzers.h> + +#include <com/sun/star/util/SearchAlgorithms2.hpp> +#include <o3tl/any.hxx> +#include <vcl/graphicfilter.hxx> +#include <com/sun/star/sdb/DatabaseContext.hpp> +#include <com/sun/star/ui/dialogs/XFilePicker3.hpp> +#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp> +#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp> +#include <com/sun/star/ui/dialogs/ListboxControlActions.hpp> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <com/sun/star/linguistic2/XProofreadingIterator.hpp> +#include <com/sun/star/linguistic2/XDictionary.hpp> +#include <comphelper/propertyvalue.hxx> +#include <officecfg/Office/Common.hxx> +#include <SwCapObjType.hxx> +#include <SwStyleNameMapper.hxx> +#include <docary.hxx> +#include <hintids.hxx> +#include <SwRewriter.hxx> +#include <numrule.hxx> +#include <swundo.hxx> +#include <svl/PasswordHelper.hxx> +#include <svl/urihelper.hxx> +#include <sfx2/passwd.hxx> +#include <sfx2/sfxdlg.hxx> +#include <sfx2/filedlghelper.hxx> +#include <editeng/langitem.hxx> +#include <svx/viewlayoutitem.hxx> +#include <svx/zoomslideritem.hxx> +#include <svx/linkwarn.hxx> +#include <sfx2/htmlmode.hxx> +#include <vcl/svapp.hxx> +#include <sfx2/app.hxx> +#include <sfx2/request.hxx> +#include <sfx2/bindings.hxx> +#include <editeng/lrspitem.hxx> +#include <unotools/localedatawrapper.hxx> +#include <unotools/syslocale.hxx> +#include <editeng/unolingu.hxx> +#include <vcl/weld.hxx> +#include <editeng/tstpitem.hxx> +#include <sfx2/event.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/docfilt.hxx> +#include <sfx2/fcontnr.hxx> +#include <editeng/sizeitem.hxx> +#include <sfx2/dispatch.hxx> +#include <svl/whiter.hxx> +#include <svl/ptitem.hxx> +#include <sfx2/viewfrm.hxx> +#include <vcl/errinf.hxx> +#include <tools/urlobj.hxx> +#include <svx/svdview.hxx> +#include <swtypes.hxx> +#include <swwait.hxx> +#include <redlndlg.hxx> +#include <gotodlg.hxx> +#include <view.hxx> +#include <uivwimp.hxx> +#include <docsh.hxx> +#include <doc.hxx> +#include <printdata.hxx> +#include <IDocumentDeviceAccess.hxx> +#include <IDocumentRedlineAccess.hxx> +#include <DocumentRedlineManager.hxx> +#include <IDocumentUndoRedo.hxx> +#include <IDocumentSettingAccess.hxx> +#include <IDocumentDrawModelAccess.hxx> +#include <IDocumentStatistics.hxx> +#include <wrtsh.hxx> +#include <viewopt.hxx> +#include <basesh.hxx> +#include <swmodule.hxx> +#include <uitool.hxx> +#include <shellio.hxx> +#include <fmtinfmt.hxx> +#include <mdiexp.hxx> +#include <drawbase.hxx> +#include <frmatr.hxx> +#include <frmmgr.hxx> +#include <pagedesc.hxx> +#include <section.hxx> +#include <tox.hxx> +#include <edtwin.hxx> +#include <wview.hxx> +#include <cmdid.h> +#include <sfx2/strings.hrc> +#include <sfx2/sfxresid.hxx> +#include <strings.hrc> +#include <swerror.h> +#include <globals.hrc> +#include <fmtclds.hxx> +#include <sfx2/templatedlg.hxx> +#include <dbconfig.hxx> +#include <dbmgr.hxx> +#include <reffld.hxx> +#include <comphelper/lok.hxx> +#include <comphelper/string.hxx> +#include <comphelper/docpasswordhelper.hxx> + +#include <PostItMgr.hxx> + +#include <comphelper/processfactory.hxx> +#include <LibreOfficeKit/LibreOfficeKitEnums.h> + +#include <svx/svxdlg.hxx> +#include <swabstdlg.hxx> +#include <fmthdft.hxx> +#include <unotextrange.hxx> +#include <docstat.hxx> +#include <wordcountdialog.hxx> +#include <sfx2/sidebar/Sidebar.hxx> + +#include <vcl/GraphicNativeTransform.hxx> +#include <vcl/GraphicNativeMetadata.hxx> +#include <vcl/settings.hxx> +#include <i18nutil/searchopt.hxx> +#include <osl/diagnose.h> +#include <paratr.hxx> +#include <rootfrm.hxx> +#include <frameformats.hxx> + +#include <viewimp.hxx> +#include <pagefrm.hxx> + +#include <memory> +#include <string_view> +#include <svl/slstitm.hxx> + +#include <basegfx/utils/zoomtools.hxx> + +#include <ndtxt.hxx> + +#include <svx/srchdlg.hxx> +#include <o3tl/string_view.hxx> + +const char sStatusDelim[] = " : "; + +using namespace sfx2; +using namespace ::com::sun::star; +using namespace ::com::sun::star::i18n; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::scanner; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::ui::dialogs; + +static void lcl_SetAllTextToDefaultLanguage( SwWrtShell &rWrtSh, sal_uInt16 nWhichId ) +{ + if (!(nWhichId == RES_CHRATR_LANGUAGE || + nWhichId == RES_CHRATR_CJK_LANGUAGE || + nWhichId == RES_CHRATR_CTL_LANGUAGE)) + return; + + rWrtSh.StartAction(); + rWrtSh.LockView( true ); + rWrtSh.Push(); + + // prepare to apply new language to all text in document + rWrtSh.SelAll(); + rWrtSh.ExtendedSelectAll(); + + // set language attribute to default for all text + rWrtSh.ResetAttr({ nWhichId }); + + rWrtSh.Pop(SwCursorShell::PopMode::DeleteCurrent); + rWrtSh.LockView( false ); + rWrtSh.EndAction(); + +} + +/** + * Create string for showing the page number in the statusbar + * + * @param nPhyNum The physical page number + * @param nVirtNum The logical page number (user-assigned) + * @param rPgStr User-defined page name (will be shown if different from logical page number) + * + * @return OUString Formatted string: Page 1 of 10 (Page 1 of 8 to print OR Page nVirtNumv/rPgStr) + **/ +OUString SwView::GetPageStr(sal_uInt16 nPhyNum, sal_uInt16 nVirtNum, const OUString& rPgStr) +{ + // Show user-defined page number in brackets if any. + OUString extra; + if (!rPgStr.isEmpty() && std::u16string_view(OUString::number(nPhyNum)) != rPgStr) + extra = rPgStr; + else if (nPhyNum != nVirtNum) + extra = OUString::number(nVirtNum); + + sal_uInt16 nPageCount = GetWrtShell().GetPageCnt(); + sal_uInt16 nPrintedPhyNum = nPhyNum; + sal_uInt16 nPrintedPageCount = nPageCount; + if (!GetWrtShell().getIDocumentDeviceAccess().getPrintData().IsPrintEmptyPages()) + SwDoc::CalculateNonBlankPages(*m_pWrtShell->GetLayout(), nPrintedPageCount, nPrintedPhyNum); + // Show printed page numbers only, when they are different + OUString aStr( nPageCount != nPrintedPageCount + ? SwResId(STR_PAGE_COUNT_PRINTED) + : (extra.isEmpty() ? SwResId(STR_PAGE_COUNT) : SwResId(STR_PAGE_COUNT_CUSTOM))); + aStr = aStr.replaceFirst("%1", OUString::number(nPhyNum)); + aStr = aStr.replaceFirst("%2", OUString::number(nPageCount)); + if (nPageCount != nPrintedPageCount) + { + aStr = aStr.replaceFirst("%3", OUString::number(nPrintedPhyNum)); + aStr = aStr.replaceFirst("%4", OUString::number(nPrintedPageCount)); + } + else + aStr = aStr.replaceFirst("%3", extra); + + return aStr; +} + +ErrCode SwView::InsertGraphic( const OUString &rPath, const OUString &rFilter, + bool bLink, GraphicFilter *pFilter ) +{ + SwWait aWait( *GetDocShell(), true ); + + Graphic aGraphic; + ErrCode aResult = ERRCODE_NONE; + if( !pFilter ) + { + pFilter = &GraphicFilter::GetGraphicFilter(); + } + aResult = GraphicFilter::LoadGraphic( rPath, rFilter, aGraphic, pFilter ); + + if( ERRCODE_NONE == aResult ) + { + GraphicNativeMetadata aMetadata; + if ( aMetadata.read(aGraphic) ) + { + const Degree10 aRotation = aMetadata.getRotation(); + if (aRotation) + { + GraphicNativeTransform aTransform( aGraphic ); + aTransform.rotate( aRotation ); + } + } + + SwFlyFrameAttrMgr aFrameManager( true, GetWrtShellPtr(), Frmmgr_Type::GRF, nullptr ); + SwWrtShell& rShell = GetWrtShell(); + + // #i123922# determine if we really want to insert or replace the graphic at a selected object + const bool bReplaceMode(rShell.HasSelection() && SelectionType::Frame == rShell.GetSelectionType()); + + if(bReplaceMode) + { + // #i123922# Do same as in D&D, ReRead graphic and all is done + rShell.ReRead( + bLink ? rPath : OUString(), + bLink ? rFilter : OUString(), + &aGraphic); + } + else + { + rShell.StartAction(); + if( bLink ) + { + SwDocShell* pDocSh = GetDocShell(); + INetURLObject aTemp( + pDocSh->HasName() ? + pDocSh->GetMedium()->GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ) : + OUString()); + + OUString sURL = URIHelper::SmartRel2Abs( + aTemp, rPath, URIHelper::GetMaybeFileHdl() ); + aGraphic.setOriginURL(sURL); + rShell.InsertGraphic( sURL, rFilter, aGraphic, &aFrameManager ); + } + else + { + rShell.InsertGraphic( OUString(), OUString(), aGraphic, &aFrameManager ); + } + + // it is too late after "EndAction" because the Shell can already be destroyed. + rShell.EndAction(); + } + } + return aResult; +} + +bool SwView::InsertGraphicDlg( SfxRequest& rReq ) +{ + bool bReturn = false; + SwDocShell* pDocShell = GetDocShell(); + SwDoc* pDoc = pDocShell->GetDoc(); + + OUString sGraphicFormat = SwResId(STR_POOLFRM_GRAPHIC); + +// No file pickers in a non-desktop (mobile app) build. + +#if HAVE_FEATURE_DESKTOP + // when in HTML mode insert only as a link + const sal_uInt16 nHtmlMode = ::GetHtmlMode(pDocShell); + std::unique_ptr<FileDialogHelper> pFileDlg(new FileDialogHelper( + ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE, + FileDialogFlags::Graphic, GetFrameWeld())); + pFileDlg->SetTitle(SwResId(STR_INSERT_GRAPHIC )); + pFileDlg->SetContext( FileDialogHelper::WriterInsertImage ); + + uno::Reference < XFilePicker3 > xFP = pFileDlg->GetFilePicker(); + uno::Reference < XFilePickerControlAccess > xCtrlAcc(xFP, UNO_QUERY); + if(nHtmlMode & HTMLMODE_ON) + { + xCtrlAcc->setValue( ExtendedFilePickerElementIds::CHECKBOX_LINK, 0, Any(true)); + xCtrlAcc->enableControl( ExtendedFilePickerElementIds::CHECKBOX_LINK, false); + } + + std::vector<OUString> aFormats; + const size_t nArrLen = pDoc->GetFrameFormats()->size(); + for( size_t i = 0; i < nArrLen; ++i ) + { + const SwFrameFormat* pFormat = (*pDoc->GetFrameFormats())[ i ]; + if(pFormat->IsDefault() || pFormat->IsAuto()) + continue; + aFormats.push_back(pFormat->GetName()); + } + + // pool formats + + const std::vector<OUString>& rFramePoolArr( + SwStyleNameMapper::GetFrameFormatUINameArray()); + for(const auto & i : rFramePoolArr) + { + aFormats.push_back(i); + } + + std::sort(aFormats.begin(), aFormats.end()); + aFormats.erase(std::unique(aFormats.begin(), aFormats.end()), aFormats.end()); + + Sequence<OUString> aListBoxEntries(aFormats.size()); + OUString* pEntries = aListBoxEntries.getArray(); + sal_Int16 nSelect = 0; + for( size_t i = 0; i < aFormats.size(); ++i ) + { + pEntries[i] = aFormats[i]; + if(pEntries[i] == sGraphicFormat) + nSelect = i; + } + try + { + Any aTemplates(&aListBoxEntries, cppu::UnoType<decltype(aListBoxEntries)>::get()); + + xCtrlAcc->setValue( ExtendedFilePickerElementIds::LISTBOX_IMAGE_TEMPLATE, + ListboxControlActions::ADD_ITEMS , aTemplates ); + + Any aSelectPos(&nSelect, cppu::UnoType<decltype(nSelect)>::get()); + xCtrlAcc->setValue( ExtendedFilePickerElementIds::LISTBOX_IMAGE_TEMPLATE, + ListboxControlActions::SET_SELECT_ITEM, aSelectPos ); + } + catch (const Exception&) + { + OSL_FAIL("control access failed"); + } +#endif + + const SfxStringItem* pName = rReq.GetArg<SfxStringItem>(SID_INSERT_GRAPHIC); + bool bShowError = !pName; + if( pName +#if HAVE_FEATURE_DESKTOP + || (!Application::IsHeadlessModeEnabled() && ERRCODE_NONE == pFileDlg->Execute()) +#endif + ) + { + + OUString aFileName, aFilterName; + if ( pName ) + { + aFileName = pName->GetValue(); + const SfxStringItem* pFilter = rReq.GetArg<SfxStringItem>(FN_PARAM_FILTER); + if ( pFilter ) + aFilterName = pFilter->GetValue(); + } +#if HAVE_FEATURE_DESKTOP + else + { + aFileName = pFileDlg->GetPath(); + aFilterName = pFileDlg->GetCurrentFilter(); + rReq.AppendItem( SfxStringItem( SID_INSERT_GRAPHIC, aFileName ) ); + rReq.AppendItem( SfxStringItem( FN_PARAM_FILTER, aFilterName ) ); + + bool bAsLink = false; + if(nHtmlMode & HTMLMODE_ON) + bAsLink = true; + else + { + try + { + Any aVal = xCtrlAcc->getValue( ExtendedFilePickerElementIds::CHECKBOX_LINK, 0); + OSL_ENSURE(aVal.hasValue(), "Value CBX_INSERT_AS_LINK not found"); + bAsLink = !aVal.hasValue() || *o3tl::doAccess<bool>(aVal); + Any aTemplateValue = xCtrlAcc->getValue( + ExtendedFilePickerElementIds::LISTBOX_IMAGE_TEMPLATE, + ListboxControlActions::GET_SELECTED_ITEM ); + OUString sTmpl; + aTemplateValue >>= sTmpl; + rReq.AppendItem( SfxStringItem( FN_PARAM_2, sTmpl) ); + } + catch (const Exception&) + { + OSL_FAIL("control access failed"); + } + } + rReq.AppendItem( SfxBoolItem( FN_PARAM_1, bAsLink ) ); + } + const SfxBoolItem* pAsLink = rReq.GetArg<SfxBoolItem>(FN_PARAM_1); + const SfxStringItem* pStyle = rReq.GetArg<SfxStringItem>(FN_PARAM_2); +#endif + + bool bAsLink = false; + +#if HAVE_FEATURE_DESKTOP + if( nHtmlMode & HTMLMODE_ON ) + bAsLink = true; + else + { + if ( rReq.GetArgs() ) + { + if ( pAsLink ) + bAsLink = pAsLink->GetValue(); + if ( pStyle && !pStyle->GetValue().isEmpty() ) + sGraphicFormat = pStyle->GetValue(); + } + else + { + Any aVal = xCtrlAcc->getValue( ExtendedFilePickerElementIds::CHECKBOX_LINK, 0); + OSL_ENSURE(aVal.hasValue(), "Value CBX_INSERT_AS_LINK not found"); + bAsLink = !aVal.hasValue() || *o3tl::doAccess<bool>(aVal); + Any aTemplateValue = xCtrlAcc->getValue( + ExtendedFilePickerElementIds::LISTBOX_IMAGE_TEMPLATE, + ListboxControlActions::GET_SELECTED_ITEM ); + OUString sTmpl; + aTemplateValue >>= sTmpl; + if( !sTmpl.isEmpty() ) + sGraphicFormat = sTmpl; + rReq.AppendItem( SfxStringItem( FN_PARAM_2, sGraphicFormat ) ); + rReq.AppendItem( SfxBoolItem( FN_PARAM_1, bAsLink ) ); + } + + // really store as link only? + if( bAsLink && officecfg::Office::Common::Misc::ShowLinkWarningDialog::get() ) + { + SvxLinkWarningDialog aWarnDlg(GetFrameWeld(), pFileDlg->GetPath()); + if (aWarnDlg.run() != RET_OK) + bAsLink=false; // don't store as link + } + } +#endif + + SwWrtShell& rSh = GetWrtShell(); + rSh.LockPaint(); + rSh.StartAction(); + + SwRewriter aRewriter; + aRewriter.AddRule(UndoArg1, SwResId(STR_GRAPHIC_DEFNAME)); + + // #i123922# determine if we really want to insert or replace the graphic at a selected object + const bool bReplaceMode(rSh.HasSelection() && SelectionType::Frame == rSh.GetSelectionType()); + + rSh.StartUndo(SwUndoId::INSERT, &aRewriter); + + ErrCode nError = InsertGraphic( aFileName, aFilterName, bAsLink, &GraphicFilter::GetGraphicFilter() ); + + // format not equal to current filter (with autodetection) + if( nError == ERRCODE_GRFILTER_FORMATERROR ) + nError = InsertGraphic( aFileName, OUString(), bAsLink, &GraphicFilter::GetGraphicFilter() ); + + // #i123922# no new FrameFormat for replace mode, only when new object was created, + // else this would reset the current setting for the frame holding the graphic + if ( !bReplaceMode && rSh.IsFrameSelected() ) + { + SwFrameFormat* pFormat = pDoc->FindFrameFormatByName( sGraphicFormat ); + if(!pFormat) + pFormat = pDoc->MakeFrameFormat(sGraphicFormat, + pDocShell->GetDoc()->GetDfltFrameFormat(), + true, false); + rSh.SetFrameFormat( pFormat ); + } + + TranslateId pResId; + if( nError == ERRCODE_GRFILTER_OPENERROR ) + pResId = STR_GRFILTER_OPENERROR; + else if( nError == ERRCODE_GRFILTER_IOERROR ) + pResId = STR_GRFILTER_IOERROR; + else if( nError ==ERRCODE_GRFILTER_FORMATERROR ) + pResId = STR_GRFILTER_FORMATERROR; + else if( nError ==ERRCODE_GRFILTER_VERSIONERROR ) + pResId = STR_GRFILTER_VERSIONERROR; + else if( nError ==ERRCODE_GRFILTER_FILTERERROR ) + pResId = STR_GRFILTER_FILTERERROR; + else if( nError ==ERRCODE_GRFILTER_TOOBIG ) + pResId = STR_GRFILTER_TOOBIG; + + rSh.EndAction(); + rSh.UnlockPaint(); + if (pResId) + { + if( bShowError ) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SwResId(pResId))); + xInfoBox->run(); + } + rReq.Ignore(); + } + else + { + // set the specific graphic attributes to the graphic + bReturn = true; + AutoCaption( GRAPHIC_CAP ); + rReq.Done(); + } + + rSh.EndUndo(); // due to possible change of Shell + } + + return bReturn; +} + +void SwView::Execute(SfxRequest &rReq) +{ + const sal_uInt16 nSlot = rReq.GetSlot(); + const SfxItemSet* pArgs = rReq.GetArgs(); + const SfxPoolItem* pItem; + bool bIgnore = false; + switch( nSlot ) + { + case SID_CREATE_SW_DRAWVIEW: + m_pWrtShell->getIDocumentDrawModelAccess().GetOrCreateDrawModel(); + break; + + case FN_LINE_NUMBERING_DLG: + { + SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create(); + ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateVclSwViewDialog(*this)); + VclAbstractDialog::AsyncContext aContext; + aContext.maEndDialogFn = [](sal_Int32){}; + pDlg->StartExecuteAsync(aContext); + break; + } + case FN_EDIT_LINK_DLG: + EditLinkDlg(); + break; + case SID_REFRESH_VIEW: + GetEditWin().Invalidate(); + m_pWrtShell->Reformat(); + break; + case FN_PAGEUP: + case FN_PAGEUP_SEL: + case FN_PAGEDOWN: + case FN_PAGEDOWN_SEL: + { + tools::Rectangle aVis( GetVisArea() ); + SwEditWin& rTmpWin = GetEditWin(); + if ( FN_PAGEUP == nSlot || FN_PAGEUP_SEL == nSlot ) + PageUpCursor(FN_PAGEUP_SEL == nSlot); + else + PageDownCursor(FN_PAGEDOWN_SEL == nSlot); + + rReq.SetReturnValue(SfxBoolItem(nSlot, + aVis != GetVisArea())); + //#i42732# - notify the edit window that from now on we do not use the input language + rTmpWin.SetUseInputLanguage( false ); + } + break; + case SID_ZOOM_IN: + case SID_ZOOM_OUT: + { + tools::Long nFact = m_pWrtShell->GetViewOptions()->GetZoom(); + if (SID_ZOOM_IN == nSlot) + nFact = basegfx::zoomtools::zoomIn(nFact); + else + nFact = basegfx::zoomtools::zoomOut(nFact); + SetZoom(SvxZoomType::PERCENT, nFact); + } + break; + case FN_TO_PREV_PAGE: + case FN_TO_NEXT_PAGE: + { + sal_uInt16 nPage = 0; + if (m_pWrtShell->IsCursorVisible()) + nPage = m_pWrtShell->GetCursor()->GetPageNum(); + else + { + SwFrame* pPageFrame = m_pWrtShell->Imp()->GetFirstVisPage(m_pWrtShell->GetOut()); + if (pPageFrame) + nPage = pPageFrame->GetPhyPageNum(); + } + if (nPage != 0) + { + sal_uInt16 nOldPage(nPage); + if (FN_TO_PREV_PAGE == nSlot && nPage > 1) + nPage--; + else if (FN_TO_NEXT_PAGE == nSlot && nPage < m_pWrtShell->GetPageCount()) + nPage++; + if (nPage != nOldPage) + { + m_pWrtShell->LockPaint(); + if (IsDrawMode()) + LeaveDrawCreate(); + m_pWrtShell->EnterStdMode(); + m_pWrtShell->GotoPage(nPage, true); + // set visible area (borrowed from SwView::PhyPageUp/Down) + const Point aPt(m_aVisArea.Left(), m_pWrtShell->GetPagePos(nPage).Y()); + Point aAlPt(AlignToPixel(aPt)); + if(aPt.Y() != aAlPt.Y()) + aAlPt.AdjustY(3 * GetEditWin().PixelToLogic(Size(0, 1)).Height()); + SetVisArea(aAlPt); + m_pWrtShell->UnlockPaint(); + } + } + } + break; + case FN_SELECTION_CYCLE: + { + if (m_pWrtShell->IsSelFrameMode()) + break; + if (!m_pWrtShell->IsStdMode()) + m_pWrtShell->EnterStdMode(); + SwShellCursor *pCursor = m_pWrtShell->SwCursorShell::GetCursor_(); + Point CurrMarkPt = pCursor->GetMkPos(); + Point CurrPointPt = pCursor->GetPtPos(); + sal_uInt16 nStep = m_aSelectCycle.nStep; + if (nStep && (CurrMarkPt != m_aSelectCycle.m_MarkPt || CurrPointPt != m_aSelectCycle.m_PointPt)) + nStep = 0; + switch(nStep) + { + case 0: + m_aSelectCycle.m_pInitialCursor = CurrPointPt; + m_pWrtShell->SwCursorShell::ClearMark(); + m_pWrtShell->SelWrd(&CurrPointPt); + break; + case 1: + m_pWrtShell->SelSentence(&CurrPointPt); + break; + case 2: + m_pWrtShell->SelPara(&CurrPointPt); + break; + case 3: + m_pWrtShell->SwCursorShell::ClearMark(); + m_pWrtShell->SwCursorShell::SetCursor(m_aSelectCycle.m_pInitialCursor); + break; + } + nStep++; + nStep %= 4; + pCursor = m_pWrtShell->SwCursorShell::GetCursor_(); + m_aSelectCycle.m_MarkPt = pCursor->GetMkPos(); + m_aSelectCycle.m_PointPt = pCursor->GetPtPos(); + m_aSelectCycle.nStep = nStep; + } + break; + case FN_REDLINE_ON: + { + if( pArgs && + SfxItemState::SET == pArgs->GetItemState(nSlot, false, &pItem )) + { + IDocumentRedlineAccess& rIDRA = m_pWrtShell->getIDocumentRedlineAccess(); + Sequence <sal_Int8> aPasswd = rIDRA.GetRedlinePassword(); + if( aPasswd.hasElements() ) + { + OSL_ENSURE( !static_cast<const SfxBoolItem*>(pItem)->GetValue(), "SwView::Execute(): password set and redlining off doesn't match!" ); + + // xmlsec05: new password dialog + SfxPasswordDialog aPasswdDlg(GetFrameWeld()); + aPasswdDlg.SetMinLen(1); + //#i69751# the result of Execute() can be ignored + (void)aPasswdDlg.run(); + OUString sNewPasswd(aPasswdDlg.GetPassword()); + + // password verification + bool bPasswordOk = false; + if (aPasswd.getLength() == 1 && aPasswd[0] == 1) + { + // dummy RedlinePassword from OOXML import: get real password info + // from the grab-bag to verify the password + const css::uno::Sequence< css::beans::PropertyValue > aDocumentProtection = + static_cast<SfxObjectShell*>(GetDocShell())-> + GetDocumentProtectionFromGrabBag(); + + bPasswordOk = + // password is ok, if there is no DocumentProtection in the GrabBag, + // i.e. the dummy RedlinePassword imported from an OpenDocument file + !aDocumentProtection.hasElements() || + // verify password with the password info imported from OOXML + ::comphelper::DocPasswordHelper::IsModifyPasswordCorrect(sNewPasswd, + ::comphelper::DocPasswordHelper::ConvertPasswordInfo ( aDocumentProtection ) ); + } + else + { + // the simplified RedlinePassword + Sequence <sal_Int8> aNewPasswd = rIDRA.GetRedlinePassword(); + SvPasswordHelper::GetHashPassword( aNewPasswd, sNewPasswd ); + bPasswordOk = SvPasswordHelper::CompareHashPassword(aPasswd, sNewPasswd); + } + + if (bPasswordOk) + rIDRA.SetRedlinePassword(Sequence <sal_Int8> ()); + else + { // xmlsec05: message box for wrong password + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(nullptr, + VclMessageType::Info, VclButtonsType::Ok, + SfxResId(RID_SVXSTR_INCORRECT_PASSWORD))); + xInfoBox->run(); + break; + } + } + + SwDocShell* pDocShell = GetDocShell(); + pDocShell->SetChangeRecording( static_cast<const SfxBoolItem*>(pItem)->GetValue(), /*bLockAllViews=*/true ); + + // Notify all view shells of this document, as the track changes mode is document-global. + for (SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst(pDocShell); pViewFrame; pViewFrame = SfxViewFrame::GetNext(*pViewFrame, pDocShell)) + { + pViewFrame->GetBindings().Invalidate(FN_REDLINE_ON); + pViewFrame->GetBindings().Update(FN_REDLINE_ON); + } + } + } + break; + case FN_REDLINE_PROTECT : + { + IDocumentRedlineAccess& rIDRA = m_pWrtShell->getIDocumentRedlineAccess(); + Sequence <sal_Int8> aPasswd = rIDRA.GetRedlinePassword(); + if( pArgs && SfxItemState::SET == pArgs->GetItemState(nSlot, false, &pItem ) + && static_cast<const SfxBoolItem*>(pItem)->GetValue() == aPasswd.hasElements() ) + break; + + // xmlsec05: new password dialog + // message box for wrong password + SfxPasswordDialog aPasswdDlg(GetFrameWeld()); + aPasswdDlg.SetMinLen(1); + if (!aPasswd.hasElements()) + aPasswdDlg.ShowExtras(SfxShowExtras::CONFIRM); + if (aPasswdDlg.run()) + { + RedlineFlags nOn = RedlineFlags::On; + OUString sNewPasswd(aPasswdDlg.GetPassword()); + Sequence <sal_Int8> aNewPasswd = + rIDRA.GetRedlinePassword(); + SvPasswordHelper::GetHashPassword( aNewPasswd, sNewPasswd ); + if(!aPasswd.hasElements()) + { + rIDRA.SetRedlinePassword(aNewPasswd); + } + else if(SvPasswordHelper::CompareHashPassword(aPasswd, sNewPasswd)) + { + rIDRA.SetRedlinePassword(Sequence <sal_Int8> ()); + nOn = RedlineFlags::NONE; + } + const RedlineFlags nMode = rIDRA.GetRedlineFlags(); + m_pWrtShell->SetRedlineFlagsAndCheckInsMode( (nMode & ~RedlineFlags::On) | nOn); + rReq.AppendItem( SfxBoolItem( FN_REDLINE_PROTECT, !(nMode&RedlineFlags::On) ) ); + } + else + bIgnore = true; + } + break; + case FN_REDLINE_SHOW: + + if( pArgs && + SfxItemState::SET == pArgs->GetItemState(nSlot, false, &pItem)) + { + // tdf#125754 avoid recursive layout + // because all views share the layout, have to use AllAction + const bool bShow = static_cast<const SfxBoolItem*>(pItem)->GetValue(); + m_pWrtShell->StartAllAction(); + // always show redline insertions in Hide Changes mode + if ( m_pWrtShell->GetViewOptions()->IsShowChangesInMargin() && + m_pWrtShell->GetViewOptions()->IsShowChangesInMargin2() ) + { + GetDocShell()->GetDoc()->GetDocumentRedlineManager().HideAll(/*bDeletion=*/!bShow); + } + m_pWrtShell->GetLayout()->SetHideRedlines( !bShow ); + m_pWrtShell->EndAllAction(); + if (m_pWrtShell->IsRedlineOn()) + m_pWrtShell->SetInsMode(); + } + break; + case FN_MAILMERGE_SENDMAIL_CHILDWINDOW: + case FN_REDLINE_ACCEPT: + GetViewFrame()->ToggleChildWindow(nSlot); + break; + case FN_REDLINE_ACCEPT_DIRECT: + case FN_REDLINE_REJECT_DIRECT: + case FN_REDLINE_ACCEPT_TONEXT: + case FN_REDLINE_REJECT_TONEXT: + { + SwDoc *pDoc = m_pWrtShell->GetDoc(); + SwPaM *pCursor = m_pWrtShell->GetCursor(); + const SwRedlineTable& rRedlineTable = pDoc->getIDocumentRedlineAccess().GetRedlineTable(); + SwRedlineTable::size_type nRedline = SwRedlineTable::npos; + if (pArgs && pArgs->GetItemState(nSlot, false, &pItem) == SfxItemState::SET) + { + const sal_Int64 nChangeId = static_cast<const SfxUInt32Item*>(pItem)->GetValue(); + for (SwRedlineTable::size_type i = 0; i < rRedlineTable.size(); ++i) + { + if (nChangeId == rRedlineTable[i]->GetId()) + nRedline = i; + } + } + + if( pCursor->HasMark() && nRedline == SwRedlineTable::npos) + { + bool bAccept = FN_REDLINE_ACCEPT_DIRECT == nSlot || FN_REDLINE_ACCEPT_TONEXT == nSlot; + SwUndoId eUndoId = bAccept ? SwUndoId::ACCEPT_REDLINE : SwUndoId::REJECT_REDLINE; + SwWrtShell& rSh = GetWrtShell(); + SwRewriter aRewriter; + bool bTableSelection = rSh.IsTableMode(); + if ( bTableSelection ) + { + aRewriter.AddRule(UndoArg1, SwResId( STR_REDLINE_TABLECHG )); + rSh.StartUndo( eUndoId, &aRewriter); + } + if ( bAccept ) + m_pWrtShell->AcceptRedlinesInSelection(); + else + m_pWrtShell->RejectRedlinesInSelection(); + if ( bTableSelection ) + rSh.EndUndo( eUndoId, &aRewriter); + } + else + { + // We check for a redline at the start of the selection/cursor, not the point. + // This ensures we work properly with FN_REDLINE_NEXT_CHANGE, which leaves the + // point at the *end* of the redline and the mark at the start (so GetRedline + // would return NULL if called on the point) + const SwRangeRedline* pRedline = nullptr; + if (nRedline != SwRedlineTable::npos) + { + // A redline was explicitly requested by specifying an + // index, don't guess based on the cursor position. + + if (nRedline < rRedlineTable.size()) + pRedline = rRedlineTable[nRedline]; + } + else + pRedline = pDoc->getIDocumentRedlineAccess().GetRedline(*pCursor->Start(), &nRedline); + + // accept or reject table row deletion or insertion + bool bTableChange = false; + if ( !pRedline && m_pWrtShell->IsCursorInTable() ) + { + nRedline = 0; + auto pTabLine = pCursor->Start()->nNode.GetNode().GetTableBox()->GetUpper(); + + if ( RedlineType::None != pTabLine->GetRedlineType() ) + { + nRedline = pTabLine->UpdateTextChangesOnly(nRedline); + + if ( nRedline != SwRedlineTable::npos ) + { + bTableChange = true; + + SwWrtShell& rSh = GetWrtShell(); + SwRewriter aRewriter; + + aRewriter.AddRule(UndoArg1, SwResId( + rRedlineTable[nRedline]->GetType() == RedlineType::Delete + ? STR_REDLINE_TABLE_ROW_DELETE + : STR_REDLINE_TABLE_ROW_INSERT )); + + SwUndoId eUndoId = + (FN_REDLINE_ACCEPT_DIRECT == nSlot || FN_REDLINE_ACCEPT_TONEXT == nSlot) + ? SwUndoId::ACCEPT_REDLINE + : SwUndoId::REJECT_REDLINE; + + rSh.StartUndo( eUndoId, &aRewriter); + while ( nRedline != SwRedlineTable::npos && nRedline < rRedlineTable.size() ) + { + pRedline = rRedlineTable[nRedline]; + + // until next redline is not in the same row + SwTableBox* pTableBox = pRedline->Start()->nNode.GetNode().GetTableBox(); + if ( !pTableBox || pTableBox->GetUpper() != pTabLine ) + break; + + if (FN_REDLINE_ACCEPT_DIRECT == nSlot || FN_REDLINE_ACCEPT_TONEXT == nSlot) + m_pWrtShell->AcceptRedline(nRedline); + else + m_pWrtShell->RejectRedline(nRedline); + } + rSh.EndUndo( eUndoId, &aRewriter); + } + } + } + else + { + assert(pRedline != nullptr); + } + + if (pRedline && !bTableChange) + { + if (FN_REDLINE_ACCEPT_DIRECT == nSlot || FN_REDLINE_ACCEPT_TONEXT == nSlot) + m_pWrtShell->AcceptRedline(nRedline); + else + m_pWrtShell->RejectRedline(nRedline); + } + } + if (FN_REDLINE_ACCEPT_TONEXT == nSlot || FN_REDLINE_REJECT_TONEXT == nSlot) + { + // Go to next change after accepting or rejecting one (tdf#101977) + GetViewFrame()->GetDispatcher()->Execute(FN_REDLINE_NEXT_CHANGE, SfxCallMode::ASYNCHRON); + } + } + break; + + case FN_REDLINE_NEXT_CHANGE: + { + // If a parameter is provided, try going to the nth change, not to + // the next one. + SwDoc* pDoc = m_pWrtShell->GetDoc(); + const SwRedlineTable& rRedlineTable = pDoc->getIDocumentRedlineAccess().GetRedlineTable(); + SwRedlineTable::size_type nRedline = SwRedlineTable::npos; + if (pArgs && pArgs->GetItemState(nSlot, false, &pItem) == SfxItemState::SET) + { + const sal_uInt32 nChangeId = static_cast<const SfxUInt32Item*>(pItem)->GetValue(); + for (SwRedlineTable::size_type i = 0; i < rRedlineTable.size(); ++i) + { + if (nChangeId == rRedlineTable[i]->GetId()) + nRedline = i; + } + } + + const SwRangeRedline *pNext = nullptr; + if (nRedline < rRedlineTable.size()) + pNext = m_pWrtShell->GotoRedline(nRedline, true); + else + pNext = m_pWrtShell->SelNextRedline(); + + if (pNext) + { + if (comphelper::LibreOfficeKit::isActive()) + { + OString aPayload(".uno:CurrentTrackedChangeId="); + sal_uInt32 nRedlineId = pNext->GetId(); + aPayload += OString::number(nRedlineId); + libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED, aPayload.getStr()); + } + + m_pWrtShell->SetInSelect(); + } + + } + break; + + case FN_REDLINE_PREV_CHANGE: + { + const SwRangeRedline *pPrev = m_pWrtShell->SelPrevRedline(); + + if (pPrev) + { + if (comphelper::LibreOfficeKit::isActive()) + { + OString aPayload(".uno:CurrentTrackedChangeId="); + sal_uInt32 nRedlineId = pPrev->GetId(); + aPayload += OString::number(nRedlineId); + libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED, aPayload.getStr()); + } + + m_pWrtShell->SetInSelect(); + } + } + break; + + case SID_DOCUMENT_COMPARE: + case SID_DOCUMENT_MERGE: + { + OUString sFileName, sFilterName; + sal_Int16 nVersion = 0; + bool bHasFileName = false; + m_pViewImpl->SetParam( 0 ); + bool bNoAcceptDialog = false; + + if( pArgs ) + { + if( const SfxStringItem* pFileItem = pArgs->GetItemIfSet( SID_FILE_NAME, false )) + sFileName = pFileItem->GetValue(); + bHasFileName = !sFileName.isEmpty(); + + if( const SfxStringItem* pFilterNameItem = pArgs->GetItemIfSet( SID_FILTER_NAME, false )) + sFilterName = pFilterNameItem->GetValue(); + + if( const SfxInt16Item* pVersionItem = pArgs->GetItemIfSet( SID_VERSION, false )) + { + nVersion = pVersionItem->GetValue(); + m_pViewImpl->SetParam( nVersion ); + } + if( const SfxBoolItem* pDialogItem = pArgs->GetItemIfSet( SID_NO_ACCEPT_DIALOG, false )) + { + bNoAcceptDialog = pDialogItem->GetValue(); + } + } + + m_pViewImpl->InitRequest( rReq ); + tools::Long nFound = InsertDoc( nSlot, sFileName, sFilterName, nVersion ); + + if ( bHasFileName ) + { + rReq.SetReturnValue( SfxInt32Item( nSlot, nFound )); + + if (nFound > 0 && !bNoAcceptDialog) // show Redline browser + { + SfxViewFrame* pVFrame = GetViewFrame(); + pVFrame->ShowChildWindow(FN_REDLINE_ACCEPT); + + // re-initialize the Redline dialog + const sal_uInt16 nId = SwRedlineAcceptChild::GetChildWindowId(); + SwRedlineAcceptChild *pRed = static_cast<SwRedlineAcceptChild*>( + pVFrame->GetChildWindow(nId)); + if (pRed) + pRed->ReInitDlg(GetDocShell()); + } + } + else + bIgnore = true; + } + break; + case FN_SYNC_LABELS: + GetViewFrame()->ShowChildWindow(nSlot); + break; + case FN_ESCAPE: + { + if ( m_pWrtShell->HasDrawViewDrag() ) + { + m_pWrtShell->BreakDrag(); + m_pWrtShell->EnterSelFrameMode(); + } + else if ( m_pWrtShell->IsDrawCreate() ) + { + GetDrawFuncPtr()->BreakCreate(); + AttrChangedNotify(nullptr); // shell change if needed + } + else if ( m_pWrtShell->HasSelection() || IsDrawMode() ) + { + SdrView *pSdrView = m_pWrtShell->HasDrawView() ? m_pWrtShell->GetDrawView() : nullptr; + if(pSdrView && pSdrView->AreObjectsMarked() && + pSdrView->GetHdlList().GetFocusHdl()) + { + const_cast<SdrHdlList&>(pSdrView->GetHdlList()).ResetFocusHdl(); + } + else + { + if(pSdrView) + { + LeaveDrawCreate(); + Point aPt(LONG_MIN, LONG_MIN); + //go out of the frame + m_pWrtShell->SelectObj(aPt, SW_LEAVE_FRAME); + SfxBindings& rBind = GetViewFrame()->GetBindings(); + rBind.Invalidate( SID_ATTR_SIZE ); + } + m_pWrtShell->EnterStdMode(); + AttrChangedNotify(nullptr); // shell change if necessary + } + } + else if ( GetEditWin().GetApplyTemplate() ) + { + GetEditWin().SetApplyTemplate(SwApplyTemplate()); + } + else if( static_cast<SfxObjectShell*>(GetDocShell())->IsInPlaceActive() ) + { + Escape(); + } + else if ( GetEditWin().IsChainMode() ) + { + GetEditWin().SetChainMode( false ); + } + else if( m_pWrtShell->GetFlyFrameFormat() ) + { + const SwFrameFormat* pFormat = m_pWrtShell->GetFlyFrameFormat(); + if(m_pWrtShell->GotoFly( pFormat->GetName(), FLYCNTTYPE_FRM )) + { + m_pWrtShell->HideCursor(); + m_pWrtShell->EnterSelFrameMode(); + } + } + else + { + SfxBoolItem aItem( SID_WIN_FULLSCREEN, false ); + GetViewFrame()->GetDispatcher()->ExecuteList(SID_WIN_FULLSCREEN, + SfxCallMode::RECORD, { &aItem }); + bIgnore = true; + } + } + break; + case SID_ATTR_BORDER_INNER: + case SID_ATTR_BORDER_OUTER: + case SID_ATTR_BORDER_SHADOW: + if(pArgs) + m_pWrtShell->SetAttrSet(*pArgs); + break; + + case SID_ATTR_PAGE: + case SID_ATTR_PAGE_SIZE: + case SID_ATTR_PAGE_MAXSIZE: + case SID_ATTR_PAGE_PAPERBIN: + case SID_ATTR_PAGE_EXT1: + case FN_PARAM_FTN_INFO: + { + if(pArgs) + { + const size_t nCurIdx = m_pWrtShell->GetCurPageDesc(); + SwPageDesc aPageDesc( m_pWrtShell->GetPageDesc( nCurIdx ) ); + ::ItemSetToPageDesc( *pArgs, aPageDesc ); + // change the descriptor of the core + m_pWrtShell->ChgPageDesc( nCurIdx, aPageDesc ); + } + } + break; + case FN_GOTO_PAGE: + { + SwGotoPageDlg aDlg(GetViewFrame()->GetFrameWeld(), &GetViewFrame()->GetBindings()); + if (aDlg.run() == RET_OK) + GetWrtShell().GotoPage(aDlg.GetPageSelection(), true); + } + break; + case FN_EDIT_CURRENT_TOX: + { + GetViewFrame()->GetDispatcher()->Execute( + FN_INSERT_MULTI_TOX, SfxCallMode::ASYNCHRON); + } + break; + case FN_UPDATE_CUR_TOX: + { + const SwTOXBase* pBase = m_pWrtShell->GetCurTOX(); + if(pBase) + { + // tdf#106374: don't jump view on the update + const bool bWasLocked = m_pWrtShell->IsViewLocked(); + m_pWrtShell->LockView(true); + m_pWrtShell->StartAction(); + if(TOX_INDEX == pBase->GetType()) + m_pWrtShell->ApplyAutoMark(); + m_pWrtShell->UpdateTableOf( *pBase ); + m_pWrtShell->EndAction(); + if (!bWasLocked) + m_pWrtShell->LockView(false); + } + } + break; + case FN_UPDATE_TOX: + { + m_pWrtShell->StartAction(); + m_pWrtShell->EnterStdMode(); + bool bOldCursorInReadOnly = m_pWrtShell->IsReadOnlyAvailable(); + m_pWrtShell->SetReadOnlyAvailable( true ); + + for( int i = 0; i < 2; ++i ) + { + if( m_pWrtShell->GetTOXCount() == 1 ) + ++i; + + while( m_pWrtShell->GotoPrevTOXBase() ) + ; // jump to the first "table of ..." + + // if we are not in one, jump to next + const SwTOXBase* pBase = m_pWrtShell->GetCurTOX(); + if( !pBase ) + { + m_pWrtShell->GotoNextTOXBase(); + pBase = m_pWrtShell->GetCurTOX(); + } + + bool bAutoMarkApplied = false; + while( pBase ) + { + if(TOX_INDEX == pBase->GetType() && !bAutoMarkApplied) + { + m_pWrtShell->ApplyAutoMark(); + bAutoMarkApplied = true; + } + // pBase is needed only for the interface. Should be changed in future! (JP 1996) + m_pWrtShell->UpdateTableOf( *pBase ); + + if( m_pWrtShell->GotoNextTOXBase() ) + pBase = m_pWrtShell->GetCurTOX(); + else + pBase = nullptr; + } + } + m_pWrtShell->SetReadOnlyAvailable( bOldCursorInReadOnly ); + m_pWrtShell->EndAction(); + } + break; + case SID_ATTR_BRUSH: + { + if(pArgs && SfxItemState::SET == pArgs->GetItemState(RES_BACKGROUND, false, &pItem)) + { + const size_t nCurIdx = m_pWrtShell->GetCurPageDesc(); + SwPageDesc aDesc( m_pWrtShell->GetPageDesc( nCurIdx )); + SwFrameFormat& rMaster = aDesc.GetMaster(); + rMaster.SetFormatAttr(*pItem); + m_pWrtShell->ChgPageDesc( nCurIdx, aDesc); + } + } + break; + case SID_CLEARHISTORY: + { + m_pWrtShell->DelAllUndoObj(); + } + break; + case SID_UNDO: + { + m_pShell->ExecuteSlot(rReq); + } + break; +#if defined(_WIN32) || defined UNX + case SID_TWAIN_SELECT: + case SID_TWAIN_TRANSFER: + GetViewImpl()->ExecuteScan( rReq ); + break; +#endif + + case SID_ATTR_DEFTABSTOP: + { + const SfxUInt16Item* pTabStopItem = nullptr; + if(pArgs && (pTabStopItem = pArgs->GetItemIfSet(SID_ATTR_DEFTABSTOP, false))) + { + SvxTabStopItem aDefTabs( 0, 0, SvxTabAdjust::Default, RES_PARATR_TABSTOP ); + const sal_uInt16 nTab = pTabStopItem->GetValue(); + MakeDefTabs( nTab, aDefTabs ); + m_pWrtShell->SetDefault( aDefTabs ); + } + } + break; + case SID_ATTR_LANGUAGE : + { + const SvxLanguageItem* pLangItem; + if(pArgs && (pLangItem = pArgs->GetItemIfSet(SID_ATTR_LANGUAGE, false))) + { + SvxLanguageItem aLang(pLangItem->GetLanguage(), RES_CHRATR_LANGUAGE); + m_pWrtShell->SetDefault( aLang ); + lcl_SetAllTextToDefaultLanguage( *m_pWrtShell, RES_CHRATR_LANGUAGE ); + } + } + break; + case SID_ATTR_CHAR_CTL_LANGUAGE: + if(pArgs && SfxItemState::SET == pArgs->GetItemState(RES_CHRATR_CTL_LANGUAGE, false, &pItem)) + { + m_pWrtShell->SetDefault( *pItem ); + lcl_SetAllTextToDefaultLanguage( *m_pWrtShell, RES_CHRATR_CTL_LANGUAGE ); + } + break; + case SID_ATTR_CHAR_CJK_LANGUAGE: + if(pArgs && SfxItemState::SET == pArgs->GetItemState(RES_CHRATR_CJK_LANGUAGE, false, &pItem)) + { + m_pWrtShell->SetDefault( *pItem ); + lcl_SetAllTextToDefaultLanguage( *m_pWrtShell, RES_CHRATR_CJK_LANGUAGE ); + } + break; + case FN_TOGGLE_OUTLINE_CONTENT_VISIBILITY: + { + m_pWrtShell->EnterStdMode(); + size_t nPos(m_pWrtShell->GetOutlinePos()); + if (nPos != SwOutlineNodes::npos) + { + SwNode* pNode = m_pWrtShell->GetNodes().GetOutLineNds()[nPos]; + pNode->GetTextNode()->SetAttrOutlineContentVisible( + !m_pWrtShell->GetAttrOutlineContentVisible(nPos)); + m_pWrtShell->InvalidateOutlineContentVisibility(); + m_pWrtShell->GotoOutline(nPos); + } + } + break; + case FN_NAV_ELEMENT: + { + pArgs->GetItemState(GetPool().GetWhich(FN_NAV_ELEMENT), false, &pItem); + if(pItem) + { + SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::Empty); + sal_uInt32 nMoveType(static_cast<const SfxUInt32Item*>(pItem)->GetValue()); + SwView::SetMoveType(nMoveType); + } + } + break; + case FN_SCROLL_PREV: + case FN_SCROLL_NEXT: + { + bool *pbNext = new bool(true); + if (nSlot == FN_SCROLL_PREV) + *pbNext = false; + MoveNavigationHdl(pbNext); + } + break; + case SID_JUMPTOMARK: + if( pArgs && SfxItemState::SET == pArgs->GetItemState(SID_JUMPTOMARK, false, &pItem)) + JumpToSwMark( static_cast<const SfxStringItem*>(pItem)->GetValue() ); + break; + case SID_GALLERY : + // First make sure that the sidebar is visible + GetViewFrame()->ShowChildWindow(SID_SIDEBAR); + + ::sfx2::sidebar::Sidebar::ShowPanel( + u"GalleryPanel", + GetViewFrame()->GetFrame().GetFrameInterface()); + break; + case SID_AVMEDIA_PLAYER : + GetViewFrame()->ChildWindowExecute(rReq); + break; + case SID_VIEW_DATA_SOURCE_BROWSER: + { + SfxViewFrame* pVFrame = GetViewFrame(); + pVFrame->ChildWindowExecute(rReq); + if(pVFrame->HasChildWindow(SID_BROWSER)) + { + const SwDBData& rData = GetWrtShell().GetDBData(); + SwModule::ShowDBObj(*this, rData); + } + } + break; + case FN_INSERT_FIELD_DATA_ONLY: + { + bool bShow = false; + if( pArgs && + SfxItemState::SET == pArgs->GetItemState(nSlot, false, &pItem )) + bShow = static_cast<const SfxBoolItem*>(pItem)->GetValue(); + if((bShow && m_bInMailMerge) != GetViewFrame()->HasChildWindow(nSlot)) + GetViewFrame()->ToggleChildWindow(nSlot); + //if fields have been successfully inserted call the "real" + //mail merge dialog +#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS + SwWrtShell &rSh = GetWrtShell(); + if(m_bInMailMerge && rSh.IsAnyDatabaseFieldInDoc()) + { + SwDBManager* pDBManager = rSh.GetDBManager(); + if (pDBManager) + { + SwDBData aData = rSh.GetDBData(); + rSh.EnterStdMode(); // force change in text shell; necessary for mixing DB fields + AttrChangedNotify(nullptr); + + Sequence<PropertyValue> aProperties + { + comphelper::makePropertyValue("DataSourceName", aData.sDataSource), + comphelper::makePropertyValue("Command", aData.sCommand), + comphelper::makePropertyValue("CommandType", aData.nCommandType) + }; + pDBManager->ExecuteFormLetter(rSh, aProperties); + } + } +#endif + m_bInMailMerge &= bShow; + GetViewFrame()->GetBindings().Invalidate(FN_INSERT_FIELD); + } + break; + case FN_QRY_MERGE: + { + bool bUseCurrentDocument = true; + bool bQuery = !pArgs || SfxItemState::SET != pArgs->GetItemState(nSlot); + if(bQuery) + { + SfxViewFrame* pTmpFrame = GetViewFrame(); + SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create(); + ScopedVclPtr<AbstractMailMergeCreateFromDlg> pDlg(pFact->CreateMailMergeCreateFromDlg(pTmpFrame->GetFrameWeld())); + if (RET_OK == pDlg->Execute()) + bUseCurrentDocument = pDlg->IsThisDocument(); + else + break; + } + GenerateFormLetter(bUseCurrentDocument); + } + break; + case SID_RECHECK_DOCUMENT: + { + SwDocShell* pDocShell = GetDocShell(); + SwDoc* pDoc = pDocShell->GetDoc(); + uno::Reference< linguistic2::XProofreadingIterator > xGCIterator( pDoc->GetGCIterator() ); + if( xGCIterator.is() ) + { + xGCIterator->resetIgnoreRules(); + } + // reset ignore lists + pDoc->SpellItAgainSam( true, false, false ); + // clear ignore dictionary + uno::Reference< linguistic2::XDictionary > xDictionary = LinguMgr::GetIgnoreAllList(); + if( xDictionary.is() ) + xDictionary->clear(); + // put cursor to the start of the document + m_pWrtShell->StartOfSection(); + [[fallthrough]]; // call spell/grammar dialog + } + case FN_SPELL_GRAMMAR_DIALOG: + { + SfxViewFrame* pViewFrame = GetViewFrame(); + if (rReq.GetArgs() != nullptr) + pViewFrame->SetChildWindow (FN_SPELL_GRAMMAR_DIALOG, + static_cast<const SfxBoolItem&>( (rReq.GetArgs()-> + Get(FN_SPELL_GRAMMAR_DIALOG))).GetValue()); + else + pViewFrame->ToggleChildWindow(FN_SPELL_GRAMMAR_DIALOG); + + pViewFrame->GetBindings().Invalidate(FN_SPELL_GRAMMAR_DIALOG); + rReq.Ignore (); + } + break; + case SID_ALIGN_ANY_LEFT : + case SID_ALIGN_ANY_HCENTER : + case SID_ALIGN_ANY_RIGHT : + case SID_ALIGN_ANY_JUSTIFIED: + case SID_ALIGN_ANY_TOP : + case SID_ALIGN_ANY_VCENTER : + case SID_ALIGN_ANY_BOTTOM : + case SID_ALIGN_ANY_HDEFAULT : + case SID_ALIGN_ANY_VDEFAULT : + { + sal_uInt16 nAlias = 0; + if( m_nSelectionType & (SelectionType::DrawObjectEditMode|SelectionType::Text) ) + { + switch( nSlot ) + { + case SID_ALIGN_ANY_LEFT : nAlias = SID_ATTR_PARA_ADJUST_LEFT; break; + case SID_ALIGN_ANY_HCENTER : nAlias = SID_ATTR_PARA_ADJUST_CENTER; break; + case SID_ALIGN_ANY_RIGHT : nAlias = SID_ATTR_PARA_ADJUST_RIGHT; break; + case SID_ALIGN_ANY_JUSTIFIED: nAlias = SID_ATTR_PARA_ADJUST_BLOCK; break; + case SID_ALIGN_ANY_TOP : nAlias = SID_TABLE_VERT_NONE; break; + case SID_ALIGN_ANY_VCENTER : nAlias = SID_TABLE_VERT_CENTER; break; + case SID_ALIGN_ANY_BOTTOM : nAlias = SID_TABLE_VERT_BOTTOM; break; + } + } + else + { + switch( nSlot ) + { + case SID_ALIGN_ANY_LEFT : nAlias = SID_OBJECT_ALIGN_LEFT ; break; + case SID_ALIGN_ANY_HCENTER : nAlias = SID_OBJECT_ALIGN_CENTER ; break; + case SID_ALIGN_ANY_RIGHT : nAlias = SID_OBJECT_ALIGN_RIGHT ; break; + case SID_ALIGN_ANY_TOP : nAlias = SID_OBJECT_ALIGN_UP ; break; + case SID_ALIGN_ANY_VCENTER : nAlias = SID_OBJECT_ALIGN_MIDDLE ; break; + case SID_ALIGN_ANY_BOTTOM : nAlias = SID_OBJECT_ALIGN_DOWN ; break; + } + } + //these slots are either re-mapped to text or object alignment + if (nAlias) + GetViewFrame()->GetDispatcher()->Execute( + nAlias, SfxCallMode::ASYNCHRON); + } + break; + case SID_RESTORE_EDITING_VIEW: + { + //#i33307# restore editing position + Point aCursorPos; + bool bSelectObj; + if(m_pViewImpl->GetRestorePosition(aCursorPos, bSelectObj)) + { + m_pWrtShell->SwCursorShell::SetCursor( aCursorPos, !bSelectObj ); + if( bSelectObj ) + { + m_pWrtShell->SelectObj( aCursorPos ); + m_pWrtShell->EnterSelFrameMode( &aCursorPos ); + } + } + } + break; + case SID_INSERT_GRAPHIC: + { + rReq.SetReturnValue(SfxBoolItem(nSlot, InsertGraphicDlg( rReq ))); + } + break; + case SID_MOVE_SHAPE_HANDLE: + { + if (pArgs && pArgs->Count() >= 3) + { + SdrView *pSdrView = m_pWrtShell->HasDrawView() ? m_pWrtShell->GetDrawView() : nullptr; + if (pSdrView == nullptr) + break; + const SfxUInt32Item* handleNumItem = rReq.GetArg<SfxUInt32Item>(FN_PARAM_1); + const SfxUInt32Item* newPosXTwips = rReq.GetArg<SfxUInt32Item>(FN_PARAM_2); + const SfxUInt32Item* newPosYTwips = rReq.GetArg<SfxUInt32Item>(FN_PARAM_3); + const SfxInt32Item* OrdNum = rReq.GetArg<SfxInt32Item>(FN_PARAM_4); + + const sal_uLong handleNum = handleNumItem->GetValue(); + const sal_uLong newPosX = newPosXTwips->GetValue(); + const sal_uLong newPosY = newPosYTwips->GetValue(); + const Point mPoint(newPosX, newPosY); + const SdrHdl* handle = pSdrView->GetHdlList().GetHdl(handleNum); + if (!handle) + { + break; + } + + if (handle->GetKind() == SdrHdlKind::Anchor || handle->GetKind() == SdrHdlKind::Anchor_TR) + m_pWrtShell->FindAnchorPos(mPoint, /*bMoveIt=*/true); + else + pSdrView->MoveShapeHandle(handleNum, mPoint, OrdNum ? OrdNum->GetValue() : -1); + } + break; + } + + default: + OSL_ENSURE(false, "wrong dispatcher"); + return; + } + if(!bIgnore) + rReq.Done(); +} + +bool SwView::IsConditionalFastCall( const SfxRequest &rReq ) +{ + sal_uInt16 nId = rReq.GetSlot(); + bool bRet = false; + + if (nId == FN_REDLINE_ACCEPT_DIRECT || nId == FN_REDLINE_REJECT_DIRECT) + { + if (comphelper::LibreOfficeKit::isActive()) + bRet = true; + } + return bRet || SfxShell::IsConditionalFastCall(rReq); + +} + +/// invalidate page numbering field +void SwView::UpdatePageNums() +{ + SfxBindings &rBnd = GetViewFrame()->GetBindings(); + rBnd.Invalidate(FN_STAT_PAGE); +} + +void SwView::UpdateDocStats() +{ + SfxBindings &rBnd = GetViewFrame()->GetBindings(); + rBnd.Invalidate( FN_STAT_WORDCOUNT ); + rBnd.Update( FN_STAT_WORDCOUNT ); +} + +/// get status of the status line +void SwView::StateStatusLine(SfxItemSet &rSet) +{ + SwWrtShell& rShell = GetWrtShell(); + + SfxWhichIter aIter( rSet ); + sal_uInt16 nWhich = aIter.FirstWhich(); + OSL_ENSURE( nWhich, "empty set"); + + //get section change event + const SwSection* CurrSect = rShell.GetCurrSection(); + if( CurrSect ) + { + const OUString& sCurrentSectionName = CurrSect->GetSectionName(); + if(sCurrentSectionName != m_sOldSectionName) + { + SwCursorShell::FireSectionChangeEvent(2, 1); + } + m_sOldSectionName = sCurrentSectionName; + } + else if (!m_sOldSectionName.isEmpty()) + { + SwCursorShell::FireSectionChangeEvent(2, 1); + m_sOldSectionName= OUString(); + } + //get column change event + if(rShell.bColumnChange()) + { + SwCursorShell::FireColumnChangeEvent(2, 1); + } + + while( nWhich ) + { + switch( nWhich ) + { + case FN_STAT_PAGE: { + // number of pages, log. page number + sal_uInt16 nPage, nLogPage; + OUString sDisplay; + rShell.GetPageNumber( -1, rShell.IsCursorVisible(), nPage, nLogPage, sDisplay ); + bool bExtendedTooltip(!sDisplay.isEmpty() && + std::u16string_view(OUString::number(nPage)) != sDisplay && + nPage != nLogPage); + OUString aTooltip = bExtendedTooltip ? SwResId(STR_BOOKCTRL_HINT_EXTENDED) + : SwResId(STR_BOOKCTRL_HINT); + std::vector<OUString> aStringList + { + GetPageStr(nPage, nLogPage, sDisplay), + aTooltip + }; + rSet.Put(SfxStringListItem(FN_STAT_PAGE, &aStringList)); + //if existing page number is not equal to old page number, send out this event. + if (m_nOldPageNum != nLogPage ) + { + if (m_nOldPageNum != 0) + SwCursorShell::FirePageChangeEvent(m_nOldPageNum, nLogPage); + m_nOldPageNum = nLogPage; + } + const sal_uInt16 nCnt = GetWrtShell().GetPageCnt(); + if (m_nPageCnt != nCnt) // notify Basic + { + m_nPageCnt = nCnt; + SfxGetpApp()->NotifyEvent(SfxEventHint(SfxEventHintId::SwEventPageCount, SwDocShell::GetEventName(STR_SW_EVENT_PAGE_COUNT), GetViewFrame()->GetObjectShell()), false); + } + } + break; + + case FN_STAT_WORDCOUNT: + { + SwDocStat selectionStats; + SwDocStat documentStats; + rShell.CountWords(selectionStats); + documentStats = rShell.GetDoc()->getIDocumentStatistics().GetUpdatedDocStat( true /* complete-async */, false /* don't update fields */ ); + + sal_uLong nWord = selectionStats.nWord ? selectionStats.nWord : documentStats.nWord; + sal_uLong nChar = selectionStats.nChar ? selectionStats.nChar : documentStats.nChar; + TranslateId pResId = selectionStats.nWord ? STR_WORDCOUNT : STR_WORDCOUNT_NO_SELECTION; + TranslateNId pWordResId = selectionStats.nWord ? STR_WORDCOUNT_WORDARG : STR_WORDCOUNT_WORDARG_NO_SELECTION; + TranslateNId pCharResId = selectionStats.nWord ? STR_WORDCOUNT_CHARARG : STR_WORDCOUNT_CHARARG_NO_SELECTION; + + const LocaleDataWrapper& rLocaleData = Application::GetSettings().GetUILocaleDataWrapper(); + OUString aWordArg = SwResId(pWordResId, nWord).replaceAll("$1", rLocaleData.getNum(nWord, 0)); + OUString aCharArg = SwResId(pCharResId, nChar).replaceAll("$1", rLocaleData.getNum(nChar, 0)); + OUString aWordCount(SwResId(pResId)); + aWordCount = aWordCount.replaceAll("$1", aWordArg); + aWordCount = aWordCount.replaceAll("$2", aCharArg); + + rSet.Put( SfxStringItem( FN_STAT_WORDCOUNT, aWordCount ) ); + + SwWordCountWrapper *pWrdCnt = static_cast<SwWordCountWrapper*>(GetViewFrame()->GetChildWindow(SwWordCountWrapper::GetChildWindowId())); + if (pWrdCnt) + pWrdCnt->SetCounts(selectionStats, documentStats); + } + break; + + case FN_STAT_TEMPLATE: + { + rSet.Put(SfxStringItem( FN_STAT_TEMPLATE, + rShell.GetCurPageStyle())); + + } + break; + case SID_ATTR_ZOOM: + { + if ( ( GetDocShell()->GetCreateMode() != SfxObjectCreateMode::EMBEDDED ) || !GetDocShell()->IsInPlaceActive() ) + { + const SwViewOption* pVOpt = rShell.GetViewOptions(); + SvxZoomType eZoom = pVOpt->GetZoomType(); + SvxZoomItem aZoom(eZoom, + pVOpt->GetZoom()); + if( pVOpt->getBrowseMode() ) + { + aZoom.SetValueSet( + SvxZoomEnableFlags::N50| + SvxZoomEnableFlags::N75| + SvxZoomEnableFlags::N100| + SvxZoomEnableFlags::N150| + SvxZoomEnableFlags::N200); + } + rSet.Put( aZoom ); + } + else + rSet.DisableItem( SID_ATTR_ZOOM ); + } + break; + case SID_ATTR_VIEWLAYOUT: + { + if ( ( GetDocShell()->GetCreateMode() != SfxObjectCreateMode::EMBEDDED ) || !GetDocShell()->IsInPlaceActive() ) + { + const SwViewOption* pVOpt = rShell.GetViewOptions(); + const sal_uInt16 nColumns = pVOpt->GetViewLayoutColumns(); + const bool bBookMode = pVOpt->IsViewLayoutBookMode(); + SvxViewLayoutItem aViewLayout(nColumns, bBookMode); + rSet.Put( aViewLayout ); + } + else + rSet.DisableItem( SID_ATTR_VIEWLAYOUT ); + } + break; + case SID_ATTR_ZOOMSLIDER: + { + if ( ( GetDocShell()->GetCreateMode() != SfxObjectCreateMode::EMBEDDED ) || !GetDocShell()->IsInPlaceActive() ) + { + const SwViewOption* pVOpt = rShell.GetViewOptions(); + const sal_uInt16 nCurrentZoom = pVOpt->GetZoom(); + SvxZoomSliderItem aZoomSliderItem( nCurrentZoom, MINZOOM, MAXZOOM ); + aZoomSliderItem.AddSnappingPoint( 100 ); + + if ( !m_pWrtShell->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE) ) + { + const sal_uInt16 nColumns = pVOpt->GetViewLayoutColumns(); + const bool bAutomaticViewLayout = 0 == nColumns; + const SwPostItMgr* pMgr = GetPostItMgr(); + + // snapping points: + // automatic mode: 1 Page, 2 Pages, 100% + // n Columns mode: n Pages, 100% + // n Columns book mode: nPages without gaps, 100% + const SwRect aPageRect( m_pWrtShell->GetAnyCurRect( CurRectType::PageCalc ) ); + const SwRect aRootRect( m_pWrtShell->GetAnyCurRect( CurRectType::PagesArea ) ); // width of columns + Size aPageSize( aPageRect.SSize() ); + aPageSize.AdjustWidth(pMgr->HasNotes() && pMgr->ShowNotes() ? + pMgr->GetSidebarWidth() + pMgr->GetSidebarBorderWidth() : + 0 ); + + Size aRootSize( aRootRect.SSize() ); + + const MapMode aTmpMap( MapUnit::MapTwip ); + const Size& rEditSize = GetEditWin().GetOutputSizePixel(); + const Size aWindowSize( GetEditWin().PixelToLogic( rEditSize, aTmpMap ) ); + + const tools::Long nOf = pVOpt->GetDocumentBorder() * 2; + tools::Long nTmpWidth = bAutomaticViewLayout ? aPageSize.Width() : aRootSize.Width(); + nTmpWidth += nOf; + aPageSize.AdjustHeight(nOf ); + tools::Long nFac = aWindowSize.Width() * 100 / nTmpWidth; + + tools::Long nVisPercent = aWindowSize.Height() * 100 / aPageSize.Height(); + nFac = std::min( nFac, nVisPercent ); + + if (nFac >= MINZOOM) + { + aZoomSliderItem.AddSnappingPoint( nFac ); + } + + if ( bAutomaticViewLayout ) + { + nTmpWidth += aPageSize.Width() + pVOpt->GetGapBetweenPages(); + nFac = aWindowSize.Width() * 100 / nTmpWidth; + nFac = std::min( nFac, nVisPercent ); + if (nFac >= MINZOOM) + { + aZoomSliderItem.AddSnappingPoint( nFac ); + } + } + } + + rSet.Put( aZoomSliderItem ); + } + else + rSet.DisableItem( SID_ATTR_ZOOMSLIDER ); + } + break; + case SID_ATTR_POSITION: + case SID_ATTR_SIZE: + { + if( !rShell.IsFrameSelected() && !rShell.IsObjSelected() ) + SwBaseShell::SetFrameMode_( FLY_DRAG_END ); + else + { + FlyMode eFrameMode = SwBaseShell::GetFrameMode(); + if ( eFrameMode == FLY_DRAG_START || eFrameMode == FLY_DRAG ) + { + if ( nWhich == SID_ATTR_POSITION ) + rSet.Put( SfxPointItem( SID_ATTR_POSITION, + rShell.GetAnchorObjDiff())); + else + rSet.Put( SvxSizeItem( SID_ATTR_SIZE, + rShell.GetObjSize())); + } + } + } + break; + case SID_TABLE_CELL: + + if( rShell.IsFrameSelected() || rShell.IsObjSelected() ) + { + // #i39171# Don't put a SvxSizeItem into a slot which is defined as SfxStringItem. + // SvxPosSizeStatusBarControl no longer resets to empty display if only one slot + // has no item, so SID_TABLE_CELL can remain empty (the SvxSizeItem is supplied + // in SID_ATTR_SIZE). + } + else + { + OUString sStr; + if( rShell.IsCursorInTable() ) + { + // table name + cell coordinate + sStr = rShell.GetTableFormat()->GetName() + ":"; + sStr += rShell.GetBoxNms(); + } + else + { + const SwSection* pCurrSect = rShell.GetCurrSection(); + if( pCurrSect ) + { + switch( pCurrSect->GetType() ) + { + case SectionType::ToxHeader: + case SectionType::ToxContent: + { + const SwTOXBase* pTOX = m_pWrtShell->GetCurTOX(); + if( pTOX ) + sStr = pTOX->GetTOXName(); + else + { + OSL_ENSURE( false, + "Unknown kind of section" ); + sStr = pCurrSect->GetSectionName(); + } + } + break; + default: + sStr = pCurrSect->GetSectionName(); + break; + } + } + } + + const SwNumRule* pNumRule = rShell.GetNumRuleAtCurrCursorPos(); + const bool bOutlineNum = pNumRule && pNumRule->IsOutlineRule(); + + if (pNumRule && !bOutlineNum ) // cursor in numbering + { + sal_uInt8 nNumLevel = rShell.GetNumLevel(); + if ( nNumLevel < MAXLEVEL ) + { + if(!pNumRule->IsAutoRule()) + { + SfxItemSetFixed<RES_PARATR_NUMRULE, RES_PARATR_NUMRULE> aSet(GetPool()); + rShell.GetCurAttr(aSet); + if(SfxItemState::DEFAULT <= + aSet.GetItemState(RES_PARATR_NUMRULE)) + { + const OUString& rNumStyle = + aSet.Get(RES_PARATR_NUMRULE).GetValue(); + if(!rNumStyle.isEmpty()) + { + if(!sStr.isEmpty()) + sStr += sStatusDelim; + sStr += rNumStyle; + } + } + } + if (!sStr.isEmpty()) + sStr += sStatusDelim; + sStr += SwResId(STR_NUM_LEVEL) + OUString::number( nNumLevel + 1 ); + + } + } + const int nOutlineLevel = rShell.GetCurrentParaOutlineLevel(); + if( nOutlineLevel != 0 ) + { + if (!sStr.isEmpty()) + sStr += " , "; + if( bOutlineNum ) + { + sStr += SwResId(STR_OUTLINE_NUMBERING) + + sStatusDelim + SwResId(STR_NUM_LEVEL); + } + else + sStr += SwResId(STR_NUM_OUTLINE); + sStr += OUString::number( nOutlineLevel); + } + + if( rShell.HasReadonlySel() ) + { + if (!sStr.isEmpty()) + sStr = sStatusDelim + sStr; + sStr = SwResId(SW_STR_READONLY) + sStr; + } + if (!sStr.isEmpty()) + rSet.Put( SfxStringItem( SID_TABLE_CELL, sStr )); + } + break; + case FN_STAT_SELMODE: + { + if(rShell.IsStdMode()) + rSet.Put(SfxUInt16Item(FN_STAT_SELMODE, 0)); + else if(rShell.IsAddMode()) + rSet.Put(SfxUInt16Item(FN_STAT_SELMODE, 2)); + else if(rShell.IsBlockMode()) + rSet.Put(SfxUInt16Item(FN_STAT_SELMODE, 3)); + else + rSet.Put(SfxUInt16Item(FN_STAT_SELMODE, 1)); + break; + } + case SID_ATTR_INSERT: + if( rShell.IsRedlineOn() ) + rSet.DisableItem( nWhich ); + else + { + rSet.Put(SfxBoolItem(SID_ATTR_INSERT,rShell.IsInsMode())); + } + break; + } + nWhich = aIter.NextWhich(); + } +} + +/** execute method for the status line + * + * @param rReq ??? + */ +void SwView::ExecuteStatusLine(SfxRequest &rReq) +{ + SwWrtShell &rSh = GetWrtShell(); + const SfxItemSet* pArgs = rReq.GetArgs(); + const SfxPoolItem* pItem=nullptr; + bool bUp = false; + sal_uInt16 nWhich = rReq.GetSlot(); + switch( nWhich ) + { + case FN_STAT_PAGE: + { + GetViewFrame()->GetDispatcher()->Execute( FN_GOTO_PAGE, + SfxCallMode::SYNCHRON|SfxCallMode::RECORD ); + } + break; + + case FN_STAT_WORDCOUNT: + { + GetViewFrame()->GetDispatcher()->Execute(FN_WORDCOUNT_DIALOG, + SfxCallMode::SYNCHRON|SfxCallMode::RECORD ); + } + break; + + case FN_STAT_BOOKMARK: + if ( pArgs ) + { + if (SfxItemState::SET == pArgs->GetItemState( nWhich, true, &pItem)) + { + const IDocumentMarkAccess* pMarkAccess = rSh.getIDocumentMarkAccess(); + const sal_Int32 nIdx = static_cast<const SfxUInt16Item*>(pItem)->GetValue(); + if(nIdx < pMarkAccess->getBookmarksCount()) + { + const IDocumentMarkAccess::const_iterator_t ppBookmark = rSh.getIDocumentMarkAccess()->getBookmarksBegin() + nIdx; + rSh.EnterStdMode(); + rSh.GotoMark( *ppBookmark ); + } + else + OSL_FAIL("SwView::ExecuteStatusLine(..)" + " - Ignoring out of range bookmark index"); + } + } + break; + + case FN_STAT_TEMPLATE: + { + GetViewFrame()->GetDispatcher()->Execute(FN_FORMAT_PAGE_DLG, + SfxCallMode::SYNCHRON|SfxCallMode::RECORD ); + } + break; + case SID_ATTR_ZOOM: + { + if ( ( GetDocShell()->GetCreateMode() != SfxObjectCreateMode::EMBEDDED ) || !GetDocShell()->IsInPlaceActive() ) + { + const SfxItemSet *pSet = nullptr; + ScopedVclPtr<AbstractSvxZoomDialog> pDlg; + if ( pArgs ) + pSet = pArgs; + else + { + const SwViewOption& rViewOptions = *rSh.GetViewOptions(); + SfxItemSetFixed<SID_ATTR_ZOOM, SID_ATTR_ZOOM, SID_ATTR_VIEWLAYOUT, SID_ATTR_VIEWLAYOUT> aCoreSet(m_pShell->GetPool()); + SvxZoomItem aZoom( rViewOptions.GetZoomType(), rViewOptions.GetZoom() ); + + const bool bBrowseMode = rSh.GetViewOptions()->getBrowseMode(); + if( bBrowseMode ) + { + aZoom.SetValueSet( + SvxZoomEnableFlags::N50| + SvxZoomEnableFlags::N75| + SvxZoomEnableFlags::N100| + SvxZoomEnableFlags::N150| + SvxZoomEnableFlags::N200); + } + aCoreSet.Put( aZoom ); + + if ( !bBrowseMode ) + { + const SvxViewLayoutItem aViewLayout( rViewOptions.GetViewLayoutColumns(), rViewOptions.IsViewLayoutBookMode() ); + aCoreSet.Put( aViewLayout ); + } + + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + pDlg.disposeAndReset(pFact->CreateSvxZoomDialog(GetViewFrame()->GetFrameWeld(), aCoreSet)); + pDlg->SetLimits( MINZOOM, MAXZOOM ); + if( pDlg->Execute() != RET_CANCEL ) + pSet = pDlg->GetOutputItemSet(); + } + + const SvxViewLayoutItem* pViewLayoutItem = nullptr; + if ( pSet && (pViewLayoutItem = pSet->GetItemIfSet(SID_ATTR_VIEWLAYOUT))) + { + const sal_uInt16 nColumns = pViewLayoutItem->GetValue(); + const bool bBookMode = pViewLayoutItem->IsBookMode(); + SetViewLayout( nColumns, bBookMode ); + } + + const SvxZoomItem* pZoomItem = nullptr; + if ( pSet && (pZoomItem = pSet->GetItemIfSet(SID_ATTR_ZOOM))) + { + SvxZoomType eType = pZoomItem->GetType(); + SetZoom( eType, pZoomItem->GetValue() ); + } + bUp = true; + if ( pZoomItem ) + rReq.AppendItem( *pZoomItem ); + rReq.Done(); + } + } + break; + + case SID_ATTR_VIEWLAYOUT: + { + if ( pArgs && !rSh.getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE) && + ( ( GetDocShell()->GetCreateMode() != SfxObjectCreateMode::EMBEDDED ) || !GetDocShell()->IsInPlaceActive() ) ) + { + if ( const SvxViewLayoutItem* pLayoutItem = pArgs->GetItemIfSet(SID_ATTR_VIEWLAYOUT )) + { + const sal_uInt16 nColumns = pLayoutItem->GetValue(); + const bool bBookMode = (0 != nColumns && 0 == (nColumns % 2)) && pLayoutItem->IsBookMode(); + + SetViewLayout( nColumns, bBookMode ); + } + + bUp = true; + rReq.Done(); + + InvalidateRulerPos(); + } + } + break; + + case SID_ATTR_ZOOMSLIDER: + { + if ( pArgs && ( ( GetDocShell()->GetCreateMode() != SfxObjectCreateMode::EMBEDDED ) || !GetDocShell()->IsInPlaceActive() ) ) + { + if ( const SvxZoomSliderItem* pZoomItem = pArgs->GetItemIfSet(SID_ATTR_ZOOMSLIDER) ) + { + const sal_uInt16 nCurrentZoom = pZoomItem->GetValue(); + SetZoom( SvxZoomType::PERCENT, nCurrentZoom ); + } + + bUp = true; + rReq.Done(); + } + } + break; + + case SID_ATTR_SIZE: + { + sal_uInt16 nId = 0; + if( rSh.IsCursorInTable() ) + nId = FN_FORMAT_TABLE_DLG; + else if( rSh.GetCurTOX() ) + nId = FN_INSERT_MULTI_TOX; + else if( rSh.GetCurrSection() ) + nId = FN_EDIT_REGION; + else + { + const SwNumRule* pNumRule = rSh.GetNumRuleAtCurrCursorPos(); + if( pNumRule ) // cursor in numbering + { + if( pNumRule->IsAutoRule() ) + nId = FN_NUMBER_BULLETS; + else + { + // start dialog of the painter + nId = 0; + } + } + else if( rSh.IsFrameSelected() ) + nId = FN_FORMAT_FRAME_DLG; + else if( rSh.IsObjSelected() ) + nId = SID_ATTR_TRANSFORM; + } + if( nId ) + GetViewFrame()->GetDispatcher()->Execute(nId, + SfxCallMode::SYNCHRON | SfxCallMode::RECORD ); + } + break; + + case FN_STAT_SELMODE: + { + if ( pArgs ) + { + if (SfxItemState::SET == pArgs->GetItemState( nWhich, true, &pItem)) + { + switch ( static_cast<const SfxUInt16Item *>(pItem)->GetValue() ) + { + case 0: rSh.EnterStdMode(); break; + case 1: rSh.EnterExtMode(); break; + case 2: rSh.EnterAddMode(); break; + case 3: rSh.EnterBlockMode(); break; + } + } + } + bUp = true; + break; + } + case FN_SET_ADD_MODE: + rSh.ToggleAddMode(); + nWhich = FN_STAT_SELMODE; + bUp = true; + break; + case FN_SET_BLOCK_MODE: + rSh.ToggleBlockMode(); + nWhich = FN_STAT_SELMODE; + bUp = true; + break; + case FN_SET_EXT_MODE: + rSh.ToggleExtMode(); + nWhich = FN_STAT_SELMODE; + bUp = true; + break; + case SID_ATTR_INSERT: + SwPostItMgr* pMgr = GetPostItMgr(); + if ( pMgr && pMgr->HasActiveSidebarWin() ) + { + pMgr->ToggleInsModeOnActiveSidebarWin(); + } + else + rSh.ToggleInsMode(); + bUp = true; + break; + + } + if ( bUp ) + { + SfxBindings &rBnd = GetViewFrame()->GetBindings(); + rBnd.Invalidate(nWhich); + rBnd.Update(nWhich); + } +} + +void SwView::InsFrameMode(sal_uInt16 nCols) +{ + if ( m_pWrtShell->HasWholeTabSelection() ) + { + SwFlyFrameAttrMgr aMgr( true, m_pWrtShell.get(), Frmmgr_Type::TEXT, nullptr ); + + const SwFrameFormat &rPageFormat = + m_pWrtShell->GetPageDesc(m_pWrtShell->GetCurPageDesc()).GetMaster(); + SwTwips lWidth = rPageFormat.GetFrameSize().GetWidth(); + const SvxLRSpaceItem &rLR = rPageFormat.GetLRSpace(); + lWidth -= rLR.GetLeft() + rLR.GetRight(); + aMgr.SetSize(Size(lWidth, aMgr.GetSize().Height())); + if(nCols > 1) + { + SwFormatCol aCol; + aCol.Init( nCols, aCol.GetGutterWidth(), aCol.GetWishWidth() ); + aMgr.SetCol( aCol ); + } + aMgr.InsertFlyFrame(); + } + else + GetEditWin().InsFrame(nCols); +} + +/// show "edit link" dialog +void SwView::EditLinkDlg() +{ + bool bWeb = dynamic_cast<SwWebView*>( this ) != nullptr; + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr<SfxAbstractLinksDialog> pDlg(pFact->CreateLinksDialog(GetViewFrame()->GetFrameWeld(), &GetWrtShell().GetLinkManager(), bWeb)); + pDlg->Execute(); +} + +namespace sw { + +auto PrepareJumpToTOXMark(SwDoc const& rDoc, OUString const& rName) + -> std::optional<std::pair<SwTOXMark, sal_Int32>> +{ + sal_Int32 const first(rName.indexOf(toxMarkSeparator)); + if (first == -1) + { + SAL_WARN("sw.ui", "JumpToTOXMark: missing separator"); + return std::optional<std::pair<SwTOXMark, sal_Int32>>(); + } + sal_Int32 const counter(o3tl::toInt32(rName.subView(0, first))); + if (counter <= 0) + { + SAL_WARN("sw.ui", "JumpToTOXMark: invalid counter"); + return std::optional<std::pair<SwTOXMark, sal_Int32>>(); + } + sal_Int32 const second(rName.indexOf(toxMarkSeparator, first + 1)); + if (second == -1) + { + SAL_WARN("sw.ui", "JumpToTOXMark: missing separator"); + return std::optional<std::pair<SwTOXMark, sal_Int32>>(); + } + OUString const entry(rName.copy(first + 1, second - (first + 1))); + if (rName.getLength() < second + 2) + { + SAL_WARN("sw.ui", "JumpToTOXMark: invalid tox"); + return std::optional<std::pair<SwTOXMark, sal_Int32>>(); + } + sal_uInt16 const indexType(rName[second + 1]); + std::u16string_view const indexName(rName.subView(second + 2)); + SwTOXType const* pType(nullptr); + switch (indexType) + { + case 'A': + pType = rDoc.GetTOXType(TOX_INDEX, 0); + assert(pType); + break; + case 'C': + pType = rDoc.GetTOXType(TOX_CONTENT, 0); + assert(pType); + break; + case 'U': + for (auto i = rDoc.GetTOXTypeCount(TOX_USER); 0 < i; ) + { + --i; + auto const pTmp(rDoc.GetTOXType(TOX_USER, i)); + if (pTmp->GetTypeName() == indexName) + { + pType = pTmp; + break; + } + } + break; + } + if (!pType) + { + SAL_WARN("sw.ui", "JumpToTOXMark: tox doesn't exist"); + return std::optional<std::pair<SwTOXMark, sal_Int32>>(); + } + // type and alt text are the search keys + SwTOXMark tmp(pType); + tmp.SetAlternativeText(entry); + return std::optional<std::pair<SwTOXMark, sal_Int32>>(std::pair<SwTOXMark, sal_Int32>(tmp, counter)); +} + +} // namespace sw + +static auto JumpToTOXMark(SwWrtShell & rSh, OUString const& rName) -> bool +{ + std::optional<std::pair<SwTOXMark, sal_Int32>> const tmp( + sw::PrepareJumpToTOXMark(*rSh.GetDoc(), rName)); + if (!tmp) + { + return false; + } + SwTOXMark const* pMark(&tmp->first); + // hack: check first if one exists + if (&tmp->first != &rSh.GetDoc()->GotoTOXMark(tmp->first, TOX_SAME_NXT, rSh.IsReadOnlyAvailable())) + { + for (sal_Int32 i = 0; i < tmp->second; ++i) + { + pMark = &rSh.GotoTOXMark(*pMark, TOX_SAME_NXT); + } + return true; + } + else + { + SAL_WARN("sw.ui", "JumpToTOXMark: tox mark doesn't exist"); + return false; + } +} + +bool SwView::JumpToSwMark( std::u16string_view rMark ) +{ + bool bRet = false; + if( !rMark.empty() ) + { + // place bookmark at top-center + bool bSaveCC = m_bCenterCursor; + bool bSaveCT = m_bTopCursor; + SetCursorAtTop( true ); + + // For scrolling the FrameSet, the corresponding shell needs to have the focus. + bool bHasShFocus = m_pWrtShell->HasShellFocus(); + if( !bHasShFocus ) + m_pWrtShell->ShellGetFocus(); + + const SwFormatINetFormat* pINet; + OUString sCmp; + OUString sMark( INetURLObject::decode( rMark, + INetURLObject::DecodeMechanism::WithCharset )); + + sal_Int32 nLastPos, nPos = sMark.indexOf( cMarkSeparator ); + if( -1 != nPos ) + while( -1 != ( nLastPos = sMark.indexOf( cMarkSeparator, nPos + 1 )) ) + nPos = nLastPos; + + IDocumentMarkAccess::const_iterator_t ppMark; + IDocumentMarkAccess* const pMarkAccess = m_pWrtShell->getIDocumentMarkAccess(); + if( -1 != nPos ) + sCmp = sMark.copy(nPos + 1).replaceAll(" ", ""); + + if( !sCmp.isEmpty() ) + { + OUString sName( sMark.copy( 0, nPos ) ); + sCmp = sCmp.toAsciiLowerCase(); + FlyCntType eFlyType = FLYCNTTYPE_ALL; + + if (sCmp == "drawingobject") + bRet = m_pWrtShell->GotoDrawingObject(sName); + else if( sCmp == "region" ) + { + m_pWrtShell->EnterStdMode(); + bRet = m_pWrtShell->GotoRegion( sName ); + } + else if( sCmp == "outline" ) + { + m_pWrtShell->EnterStdMode(); + bRet = m_pWrtShell->GotoOutline( sName ); + } + else if( sCmp == "frame" ) + eFlyType = FLYCNTTYPE_FRM; + else if( sCmp == "graphic" ) + eFlyType = FLYCNTTYPE_GRF; + else if( sCmp == "ole" ) + eFlyType = FLYCNTTYPE_OLE; + else if( sCmp == "table" ) + { + m_pWrtShell->EnterStdMode(); + bRet = m_pWrtShell->GotoTable( sName ); + } + else if( sCmp == "sequence" ) + { + m_pWrtShell->EnterStdMode(); + sal_Int32 nNoPos = sName.indexOf( cSequenceMarkSeparator ); + if ( nNoPos != -1 ) + { + sal_uInt16 nSeqNo = o3tl::toInt32(sName.subView( nNoPos + 1 )); + sName = sName.copy( 0, nNoPos ); + bRet = m_pWrtShell->GotoRefMark(sName, REF_SEQUENCEFLD, nSeqNo); + } + } + else if (sCmp == "toxmark") + { + bRet = JumpToTOXMark(*m_pWrtShell, sName); + } + else if( sCmp == "text" ) + { + // normal text search + m_pWrtShell->EnterStdMode(); + + i18nutil::SearchOptions2 aSearchOpt( + SearchAlgorithms_ABSOLUTE, 0, + sName, OUString(), + SvtSysLocale().GetLanguageTag().getLocale(), + 0,0,0, + TransliterationFlags::IGNORE_CASE, + SearchAlgorithms2::ABSOLUTE, + '\\' ); + + //todo/mba: assuming that notes shouldn't be searched + if( m_pWrtShell->SearchPattern( aSearchOpt, false/*bSearchInNotes*/, SwDocPositions::Start, SwDocPositions::End )) + { + m_pWrtShell->EnterStdMode(); // remove the selection + bRet = true; + } + } + else if( pMarkAccess->getAllMarksEnd() != (ppMark = pMarkAccess->findMark(sMark)) ) + { + bRet = m_pWrtShell->GotoMark( *ppMark, false ); + } + else if( nullptr != ( pINet = m_pWrtShell->FindINetAttr( sMark ) )) { + m_pWrtShell->addCurrentPosition(); + bRet = m_pWrtShell->GotoINetAttr( *pINet->GetTextINetFormat() ); + } + + // for all types of Flys + if( FLYCNTTYPE_ALL != eFlyType && m_pWrtShell->GotoFly( sName, eFlyType )) + { + bRet = true; + if( FLYCNTTYPE_FRM == eFlyType ) + { + // TextFrames: set Cursor in the frame + m_pWrtShell->UnSelectFrame(); + m_pWrtShell->LeaveSelFrameMode(); + } + else + { + m_pWrtShell->HideCursor(); + m_pWrtShell->EnterSelFrameMode(); + } + } + } + else if( pMarkAccess->getAllMarksEnd() != (ppMark = pMarkAccess->findMark(sMark))) + { + bRet = m_pWrtShell->GotoMark( *ppMark, false ); + } + else if( nullptr != ( pINet = m_pWrtShell->FindINetAttr( sMark ) )) + bRet = m_pWrtShell->GotoINetAttr( *pINet->GetTextINetFormat() ); + + // make selection visible later + if ( m_aVisArea.IsEmpty() ) + m_bMakeSelectionVisible = true; + + // reset ViewStatus + SetCursorAtTop( bSaveCT, bSaveCC ); + + if(!m_pWrtShell->IsFrameSelected() && !m_pWrtShell->IsObjSelected()) + m_pWrtShell->ShowCursor(); + + if( !bHasShFocus ) + m_pWrtShell->ShellLoseFocus(); + } + return bRet; +} + +// #i67305# Undo after insert from file: +// Undo "Insert form file" crashes with documents imported from binary filter (.sdw) => disabled +// Undo "Insert form file" crashes with (.odt) documents crashes if these documents contains +// page styles with active header/footer => disabled for those documents +static size_t lcl_PageDescWithHeader( const SwDoc& rDoc ) +{ + size_t nRet = 0; + size_t nCnt = rDoc.GetPageDescCnt(); + for( size_t i = 0; i < nCnt; ++i ) + { + const SwPageDesc& rPageDesc = rDoc.GetPageDesc( i ); + const SwFrameFormat& rMaster = rPageDesc.GetMaster(); + const SwFormatHeader* pHeaderItem = rMaster.GetAttrSet().GetItemIfSet( RES_HEADER, false ); + const SwFormatFooter* pFooterItem = rMaster.GetAttrSet().GetItemIfSet( RES_FOOTER, false ); + if( (pHeaderItem && pHeaderItem->IsActive()) || + (pFooterItem && pFooterItem->IsActive()) ) + ++nRet; + } + return nRet; // number of page styles with active header/footer +} + +void SwView::ExecuteInsertDoc( SfxRequest& rRequest, const SfxPoolItem* pItem ) +{ + m_pViewImpl->InitRequest( rRequest ); + m_pViewImpl->SetParam( pItem ? 1 : 0 ); + const sal_uInt16 nSlot = rRequest.GetSlot(); + + if ( !pItem ) + { + InsertDoc( nSlot, "", "" ); + } + else + { + OUString sFile, sFilter; + sFile = static_cast<const SfxStringItem *>( pItem )->GetValue(); + if ( SfxItemState::SET == rRequest.GetArgs()->GetItemState( FN_PARAM_1, true, &pItem ) ) + sFilter = static_cast<const SfxStringItem *>(pItem )->GetValue(); + + bool bHasFileName = !sFile.isEmpty(); + tools::Long nFound = InsertDoc( nSlot, sFile, sFilter ); + + if ( bHasFileName ) + { + rRequest.SetReturnValue( SfxBoolItem( nSlot, nFound != -1 ) ); + rRequest.Done(); + } + } +} + +tools::Long SwView::InsertDoc( sal_uInt16 nSlotId, const OUString& rFileName, const OUString& rFilterName, sal_Int16 nVersion ) +{ + std::unique_ptr<SfxMedium> pMed; + SwDocShell* pDocSh = GetDocShell(); + + if( !rFileName.isEmpty() ) + { + SfxObjectFactory& rFact = pDocSh->GetFactory(); + std::shared_ptr<const SfxFilter> pFilter = rFact.GetFilterContainer()->GetFilter4FilterName( rFilterName ); + if ( !pFilter ) + { + pMed.reset(new SfxMedium(rFileName, StreamMode::READ, nullptr, nullptr )); + SfxFilterMatcher aMatcher( rFact.GetFilterContainer()->GetName() ); + pMed->UseInteractionHandler( true ); + ErrCode nErr = aMatcher.GuessFilter(*pMed, pFilter, SfxFilterFlags::NONE); + if ( nErr ) + pMed.reset(); + else + pMed->SetFilter( pFilter ); + } + else + pMed.reset(new SfxMedium(rFileName, StreamMode::READ, pFilter, nullptr)); + } + else + { + m_pViewImpl->StartDocumentInserter( + // tdf#118578 allow inserting any Writer document except GlobalDoc + SwDocShell::Factory().GetFactoryName(), + LINK( this, SwView, DialogClosedHdl ), + nSlotId + ); + return -1; + } + + if( !pMed ) + return -1; + + return InsertMedium( nSlotId, std::move(pMed), nVersion ); +} + +tools::Long SwView::InsertMedium( sal_uInt16 nSlotId, std::unique_ptr<SfxMedium> pMedium, sal_Int16 nVersion ) +{ + bool bInsert = false, bCompare = false; + tools::Long nFound = 0; + SwDocShell* pDocSh = GetDocShell(); + + switch( nSlotId ) + { + case SID_DOCUMENT_MERGE: break; + case SID_DOCUMENT_COMPARE: bCompare = true; break; + case SID_INSERTDOC: bInsert = true; break; + + default: + OSL_ENSURE( false, "unknown SlotId!" ); + bInsert = true; + break; + } + + if( bInsert ) + { + uno::Reference< frame::XDispatchRecorder > xRecorder = + GetViewFrame()->GetBindings().GetRecorder(); + if ( xRecorder.is() ) + { + SfxRequest aRequest(GetViewFrame(), SID_INSERTDOC); + aRequest.AppendItem(SfxStringItem(SID_INSERTDOC, pMedium->GetOrigURL())); + if(pMedium->GetFilter()) + aRequest.AppendItem(SfxStringItem(FN_PARAM_1, pMedium->GetFilter()->GetName())); + aRequest.Done(); + } + + SfxObjectShellRef aRef( pDocSh ); + + ErrCode nError = SfxObjectShell::HandleFilter( pMedium.get(), pDocSh ); + // #i16722# aborted? + if(nError != ERRCODE_NONE) + { + return -1; + } + + pMedium->Download(); // start download if needed + if( aRef.is() && 1 < aRef->GetRefCount() ) // still a valid ref? + { + SwReaderPtr pRdr; + Reader *pRead = pDocSh->StartConvertFrom(*pMedium, pRdr, m_pWrtShell.get()); + if( pRead || + (pMedium->GetFilter()->GetFilterFlags() & SfxFilterFlags::STARONEFILTER) ) + { + size_t nUndoCheck = 0; + SwDoc *pDoc = pDocSh->GetDoc(); + if( pRead && pDocSh->GetDoc() ) + nUndoCheck = lcl_PageDescWithHeader( *pDoc ); + ErrCode nErrno; + { //Scope for SwWait-Object, to be able to execute slots + //outside this scope. + SwWait aWait( *GetDocShell(), true ); + m_pWrtShell->StartAllAction(); + if ( m_pWrtShell->HasSelection() ) + m_pWrtShell->DelRight(); // delete selections + if( pRead ) + { + nErrno = pRdr->Read( *pRead ); // and insert document + pRdr.reset(); + } + else + { + ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo()); + uno::Reference<text::XTextRange> const xInsertPosition( + SwXTextRange::CreateXTextRange(*pDoc, + *m_pWrtShell->GetCursor()->GetPoint(), nullptr)); + nErrno = pDocSh->ImportFrom(*pMedium, xInsertPosition) + ? ERRCODE_NONE : ERR_SWG_READ_ERROR; + } + + } + + // update all "table of ..." sections if needed + if( m_pWrtShell->IsUpdateTOX() ) + { + SfxRequest aReq( FN_UPDATE_TOX, SfxCallMode::SLOT, GetPool() ); + Execute( aReq ); + m_pWrtShell->SetUpdateTOX( false ); // reset + } + + if( pDoc ) + { // Disable Undo for .sdw or + // if the number of page styles with header/footer has changed + if( !pRead || nUndoCheck != lcl_PageDescWithHeader( *pDoc ) ) + { + pDoc->GetIDocumentUndoRedo().DelAllUndoObj(); + } + } + + m_pWrtShell->EndAllAction(); + if( nErrno ) + { + ErrorHandler::HandleError( nErrno ); + nFound = nErrno.IsError() ? -1 : 0; + } + else + nFound = 0; + } + } + } + else + { + SfxObjectShellRef xDocSh; + SfxObjectShellLock xLockRef; + + const int nRet = SwFindDocShell( xDocSh, xLockRef, pMedium->GetName(), OUString(), + OUString(), nVersion, pDocSh ); + if( nRet ) + { + SwWait aWait( *GetDocShell(), true ); + m_pWrtShell->StartAllAction(); + + m_pWrtShell->EnterStdMode(); // delete selections + + if( bCompare ) + nFound = m_pWrtShell->CompareDoc( *static_cast<SwDocShell*>( xDocSh.get() )->GetDoc() ); + else + nFound = m_pWrtShell->MergeDoc( *static_cast<SwDocShell*>( xDocSh.get() )->GetDoc() ); + + m_pWrtShell->EndAllAction(); + + if (!bCompare && !nFound) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetEditWin().GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SwResId(STR_NO_MERGE_ENTRY))); + xInfoBox->run(); + } + if( nRet==2 && xDocSh.is() ) + xDocSh->DoClose(); + } + } + + return nFound; +} + +void SwView::EnableMailMerge() +{ + m_bInMailMerge = true; + SfxBindings& rBind = GetViewFrame()->GetBindings(); + rBind.Invalidate(FN_INSERT_FIELD_DATA_ONLY); + rBind.Update(FN_INSERT_FIELD_DATA_ONLY); +} + +#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS + +namespace +{ + bool lcl_NeedAdditionalDataSource( const uno::Reference< XDatabaseContext >& _rDatasourceContext ) + { + Sequence < OUString > aNames = _rDatasourceContext->getElementNames(); + + return ( !aNames.hasElements() + || ( ( 1 == aNames.getLength() ) + && aNames.getConstArray()[0] == SW_MOD()->GetDBConfig()->GetBibliographySource().sDataSource + ) + ); + } +} + +#endif + +void SwView::GenerateFormLetter(bool bUseCurrentDocument) +{ +#if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS + (void) bUseCurrentDocument; +#else + if(bUseCurrentDocument) + { + if(!GetWrtShell().IsAnyDatabaseFieldInDoc()) + { + //check availability of data sources (except biblio source) + uno::Reference<XComponentContext> xContext( ::comphelper::getProcessComponentContext() ); + uno::Reference<XDatabaseContext> xDBContext = DatabaseContext::create(xContext); + bool bCallAddressPilot = false; + if ( lcl_NeedAdditionalDataSource( xDBContext ) ) + { + // no data sources are available - create a new one + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(GetFrameWeld(), "modules/swriter/ui/datasourcesunavailabledialog.ui")); + std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("DataSourcesUnavailableDialog")); + // no cancel allowed + if (RET_OK != xQuery->run()) + return; + bCallAddressPilot = true; + } + else + { + //take an existing data source or create a new one? + SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create(); + ScopedVclPtr<AbstractMailMergeFieldConnectionsDlg> pConnectionsDlg(pFact->CreateMailMergeFieldConnectionsDlg(GetFrameWeld())); + if(RET_OK == pConnectionsDlg->Execute()) + bCallAddressPilot = !pConnectionsDlg->IsUseExistingConnections(); + else + return; + + } + if(bCallAddressPilot) + { + GetViewFrame()->GetDispatcher()->Execute( + SID_ADDRESS_DATA_SOURCE, SfxCallMode::SYNCHRON); + if ( lcl_NeedAdditionalDataSource( xDBContext ) ) + // no additional data source has been created + // -> assume that the user has cancelled the pilot + return; + } + + //call insert fields with database field page available, only + SfxViewFrame* pVFrame = GetViewFrame(); + //at first hide the default field dialog if currently visible + pVFrame->SetChildWindow(FN_INSERT_FIELD, false); + //enable the status of the db field dialog - it is disabled in the status method + //to prevent creation of the dialog without mail merge active + EnableMailMerge(); + //then show the "Data base only" field dialog + SfxBoolItem aOn(FN_INSERT_FIELD_DATA_ONLY, true); + pVFrame->GetDispatcher()->ExecuteList(FN_INSERT_FIELD_DATA_ONLY, + SfxCallMode::SYNCHRON, { &aOn }); + return; + } + else + { + OUString sSource; + if(!GetWrtShell().IsFieldDataSourceAvailable(sSource)) + { + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(GetFrameWeld(), "modules/swriter/ui/warndatasourcedialog.ui")); + std::unique_ptr<weld::MessageDialog> xWarning(xBuilder->weld_message_dialog("WarnDataSourceDialog")); + OUString sTmp(xWarning->get_primary_text()); + xWarning->set_primary_text(sTmp.replaceFirst("%1", sSource)); + if (RET_OK == xWarning->run()) + { + SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create(); + ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateVclDialog( nullptr, SID_OPTIONS_DATABASES )); + pDlg->Execute(); + } + return ; + } + } + SwDBManager* pDBManager = GetWrtShell().GetDBManager(); + + SwDBData aData; + SwWrtShell &rSh = GetWrtShell(); + + std::vector<OUString> aDBNameList; + std::vector<OUString> aAllDBNames; + rSh.GetAllUsedDB( aDBNameList, &aAllDBNames ); + if(!aDBNameList.empty()) + { + OUString sDBName(aDBNameList[0]); + sal_Int32 nIdx {0}; + aData.sDataSource = sDBName.getToken(0, DB_DELIM, nIdx); + aData.sCommand = sDBName.getToken(0, DB_DELIM, nIdx); + aData.nCommandType = o3tl::toInt32(o3tl::getToken(sDBName, 0, DB_DELIM, nIdx)); + } + rSh.EnterStdMode(); // force change in text shell; necessary for mixing DB fields + AttrChangedNotify(nullptr); + + if (pDBManager) + { + Sequence<PropertyValue> aProperties + { + comphelper::makePropertyValue("DataSourceName", aData.sDataSource), + comphelper::makePropertyValue("Command", aData.sCommand), + comphelper::makePropertyValue("CommandType", aData.nCommandType), + }; + pDBManager->ExecuteFormLetter(GetWrtShell(), aProperties); + } + } + else + { + // call documents and template dialog + SfxApplication* pSfxApp = SfxGetpApp(); + weld::Window* pTopWin = pSfxApp->GetTopWindow(); + + SfxTemplateManagerDlg aDocTemplDlg(GetFrameWeld()); + int nRet = aDocTemplDlg.run(); + bool bNewWin = false; + if ( nRet == RET_OK ) + { + if ( pTopWin != pSfxApp->GetTopWindow() ) + { + // the dialogue opens a document -> a new TopWindow appears + pTopWin = pSfxApp->GetTopWindow(); + bNewWin = true; + } + } + + if (bNewWin) + { + // after the destruction of the dialogue its parent comes to top, + // but we want that the new document is on top + pTopWin->present(); + } + } +#endif +} + +IMPL_LINK( SwView, DialogClosedHdl, sfx2::FileDialogHelper*, _pFileDlg, void ) +{ + if ( ERRCODE_NONE != _pFileDlg->GetError() ) + return; + + std::unique_ptr<SfxMedium> pMed = m_pViewImpl->CreateMedium(); + if ( !pMed ) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetEditWin().GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SwResId(RID_SVXSTR_TXTFILTER_FILTERERROR))); + xInfoBox->run(); + return; + } + + const sal_uInt16 nSlot = m_pViewImpl->GetRequest()->GetSlot(); + tools::Long nFound = InsertMedium( nSlot, std::move(pMed), m_pViewImpl->GetParam() ); + + if ( SID_INSERTDOC == nSlot ) + { + if ( m_pViewImpl->GetParam() == 0 ) + { + m_pViewImpl->GetRequest()->SetReturnValue( SfxBoolItem( nSlot, nFound != -1 ) ); + m_pViewImpl->GetRequest()->Ignore(); + } + else + { + m_pViewImpl->GetRequest()->SetReturnValue( SfxBoolItem( nSlot, nFound != -1 ) ); + m_pViewImpl->GetRequest()->Done(); + } + } + else if ( SID_DOCUMENT_COMPARE == nSlot || SID_DOCUMENT_MERGE == nSlot ) + { + m_pViewImpl->GetRequest()->SetReturnValue( SfxInt32Item( nSlot, nFound ) ); + + if ( nFound > 0 ) // show Redline browser + { + SfxViewFrame* pVFrame = GetViewFrame(); + pVFrame->ShowChildWindow(FN_REDLINE_ACCEPT); + + // re-initialize Redline dialog + sal_uInt16 nId = SwRedlineAcceptChild::GetChildWindowId(); + SwRedlineAcceptChild* pRed = static_cast<SwRedlineAcceptChild*>(pVFrame->GetChildWindow( nId )); + if ( pRed ) + pRed->ReInitDlg( GetDocShell() ); + } + } +} + +void SwView::ExecuteScan( SfxRequest& rReq ) +{ + if (m_pViewImpl) + m_pViewImpl->ExecuteScan(rReq) ; +} + +const OUString& SwView::GetOldGrfCat() +{ + return GetCachedString(OldGrfCat); +} + +void SwView::SetOldGrfCat(const OUString& sStr) +{ + SetCachedString(OldGrfCat, sStr); +} + +const OUString& SwView::GetOldTabCat() +{ + return GetCachedString(OldTabCat); +} + +void SwView::SetOldTabCat(const OUString& sStr) +{ + SetCachedString(OldTabCat, sStr); +} + +const OUString& SwView::GetOldFrameCat() +{ + return GetCachedString(OldFrameCat); +} + +void SwView::SetOldFrameCat(const OUString& sStr) +{ + SetCachedString(OldFrameCat, sStr); +} + +const OUString& SwView::GetOldDrwCat() +{ + return GetCachedString(OldDrwCat); +} + +void SwView::SetOldDrwCat(const OUString& sStr) +{ + SwView::SetCachedString(OldDrwCat, sStr); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/uiview/viewcoll.cxx b/sw/source/uibase/uiview/viewcoll.cxx new file mode 100644 index 000000000..9ee42e1e2 --- /dev/null +++ b/sw/source/uibase/uiview/viewcoll.cxx @@ -0,0 +1,78 @@ +/* -*- 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 <cmdid.h> +#include <uiitems.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/request.hxx> +#include <svl/stritem.hxx> +#include <svl/style.hxx> +#include <osl/diagnose.h> + +#include <view.hxx> +#include <wrtsh.hxx> + +void SwView::ExecColl(SfxRequest const &rReq) +{ + const SfxItemSet* pArgs = rReq.GetArgs(); + const SfxPoolItem* pItem = nullptr; + sal_uInt16 nWhich = rReq.GetSlot(); + switch( nWhich ) + { + case FN_SET_PAGE: + { + OSL_ENSURE(false, "Not implemented"); + } + break; + case FN_SET_PAGE_STYLE: + { + if( pArgs ) + { + if (SfxItemState::SET == pArgs->GetItemState( nWhich , true, &pItem )) + { + if( static_cast<const SfxStringItem*>(pItem)->GetValue() != + GetWrtShell().GetCurPageStyle() ) + { + SfxStringItem aName(SID_STYLE_APPLY, + static_cast<const SfxStringItem*>(pItem)->GetValue()); + SfxUInt16Item aFamItem( SID_STYLE_FAMILY, + sal_uInt16(SfxStyleFamily::Page)); + SwPtrItem aShell(FN_PARAM_WRTSHELL, GetWrtShellPtr()); + SfxRequest aReq(SID_STYLE_APPLY, SfxCallMode::SLOT, GetPool()); + aReq.AppendItem(aName); + aReq.AppendItem(aFamItem); + aReq.AppendItem(aShell); + GetCurShell()->ExecuteSlot(aReq); + } + } + } + else + { + SfxRequest aReq(FN_FORMAT_PAGE_DLG, SfxCallMode::SLOT, GetPool()); + GetCurShell()->ExecuteSlot(aReq); + } + } + break; + default: + OSL_FAIL("wrong CommandProcessor for Dispatch"); + return; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/uiview/viewdlg.cxx b/sw/source/uibase/uiview/viewdlg.cxx new file mode 100644 index 000000000..041b13bf4 --- /dev/null +++ b/sw/source/uibase/uiview/viewdlg.cxx @@ -0,0 +1,66 @@ +/* -*- 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 <sfx2/request.hxx> +#include <osl/diagnose.h> + +#include <view.hxx> +#include <wrtsh.hxx> +#include <cmdid.h> + +void SwView::ExecDlg(SfxRequest const &rReq) +{ + // Thus, from the basic no dialogues for background views are called: + const SfxPoolItem* pItem = nullptr; + const SfxItemSet* pArgs = rReq.GetArgs(); + + sal_uInt16 nSlot = rReq.GetSlot(); + if(pArgs) + pArgs->GetItemState( GetPool().GetWhich(nSlot), false, &pItem ); + + switch ( nSlot ) + { + case FN_CHANGE_PAGENUM: + { + if ( pItem ) + { + sal_uInt16 nValue = static_cast<const SfxUInt16Item *>(pItem)->GetValue(); + sal_uInt16 nOldValue = m_pWrtShell->GetPageOffset(); + sal_uInt16 nPage, nLogPage; + m_pWrtShell->GetPageNum( nPage, nLogPage, + m_pWrtShell->IsCursorVisible(), false); + + if(nValue != nOldValue || nValue != nLogPage) + { + if(!nOldValue) + m_pWrtShell->SetNewPageOffset( nValue ); + else + m_pWrtShell->SetPageOffset( nValue ); + } + } + } + break; + + default: + OSL_ENSURE(false, "wrong dispatcher"); + return; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/uiview/viewdlg2.cxx b/sw/source/uibase/uiview/viewdlg2.cxx new file mode 100644 index 000000000..eed4eddcc --- /dev/null +++ b/sw/source/uibase/uiview/viewdlg2.cxx @@ -0,0 +1,300 @@ +/* -*- 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 <sfx2/request.hxx> +#include <sfx2/objface.hxx> +#include <svx/svdograf.hxx> +#include <svx/svdview.hxx> +#include <osl/diagnose.h> +#include <fldmgr.hxx> +#include <expfld.hxx> +#include <modcfg.hxx> + +#include <swmodule.hxx> +#include <view.hxx> +#include <wview.hxx> +#include <wrtsh.hxx> +#include <cmdid.h> +#include <caption.hxx> +#include <poolfmt.hxx> +#include <edtwin.hxx> +#include <SwStyleNameMapper.hxx> + +#include <swabstdlg.hxx> + +#include <strings.hrc> + +#include <memory> + +#include <svl/stritem.hxx> + +using namespace css; + +void SwView::ExecDlgExt(SfxRequest const &rReq) +{ + switch ( rReq.GetSlot() ) + { + case FN_INSERT_CAPTION: + { + SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create(); + ScopedVclPtr<VclAbstractDialog> pDialog(pFact->CreateSwCaptionDialog(GetFrameWeld(), *this )); + pDialog->Execute(); + break; + } + case SID_INSERT_SIGNATURELINE: + case SID_EDIT_SIGNATURELINE: + { + VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create(); + const uno::Reference<frame::XModel> xModel(GetCurrentDocument()); + ScopedVclPtr<AbstractSignatureLineDialog> pDialog(pFact->CreateSignatureLineDialog( + GetFrameWeld(), xModel, rReq.GetSlot() == SID_EDIT_SIGNATURELINE)); + pDialog->Execute(); + break; + } + case SID_INSERT_QRCODE: + case SID_EDIT_QRCODE: + { + VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create(); + const uno::Reference<frame::XModel> xModel(GetCurrentDocument()); + ScopedVclPtr<AbstractQrCodeGenDialog> pDialog(pFact->CreateQrCodeGenDialog( + GetFrameWeld(), xModel, rReq.GetSlot() == SID_EDIT_QRCODE)); + pDialog->Execute(); + break; + } + case SID_ADDITIONS_DIALOG: + { + OUString sAdditionsTag = ""; + + const SfxStringItem* pStringArg = rReq.GetArg<SfxStringItem>(FN_PARAM_ADDITIONS_TAG); + if (pStringArg) + sAdditionsTag = pStringArg->GetValue(); + + VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create(); + ScopedVclPtr<AbstractAdditionsDialog> pDialog( + pFact->CreateAdditionsDialog(GetFrameWeld(), sAdditionsTag)); + pDialog->Execute(); + break; + } + case SID_SIGN_SIGNATURELINE: + { + VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create(); + const uno::Reference<frame::XModel> xModel(GetCurrentDocument()); + ScopedVclPtr<AbstractSignSignatureLineDialog> pDialog( + pFact->CreateSignSignatureLineDialog(GetFrameWeld(), xModel)); + pDialog->Execute(); + break; + } + case FN_EDIT_FOOTNOTE: + { + SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create(); + ScopedVclPtr<AbstractInsFootNoteDlg> pDlg(pFact->CreateInsFootNoteDlg( + GetFrameWeld(), *m_pWrtShell, true)); + + pDlg->SetHelpId(GetStaticInterface()->GetSlot(FN_EDIT_FOOTNOTE)->GetCommand()); + pDlg->SetText( SwResId(STR_EDIT_FOOTNOTE) ); + pDlg->Execute(); + break; + } + } +} + +bool SwView::isSignatureLineSelected() const +{ + SwWrtShell& rSh = GetWrtShell(); + SdrView* pSdrView = rSh.GetDrawView(); + if (!pSdrView) + return false; + + if (pSdrView->GetMarkedObjectCount() != 1) + return false; + + SdrObject* pPickObj = pSdrView->GetMarkedObjectByIndex(0); + if (!pPickObj) + return false; + + SdrGrafObj* pGraphic = dynamic_cast<SdrGrafObj*>(pPickObj); + if (!pGraphic) + return false; + + return pGraphic->isSignatureLine(); +} + +bool SwView::isSignatureLineSigned() const +{ + SwWrtShell& rSh = GetWrtShell(); + SdrView* pSdrView = rSh.GetDrawView(); + if (!pSdrView) + return false; + + if (pSdrView->GetMarkedObjectCount() != 1) + return false; + + SdrObject* pPickObj = pSdrView->GetMarkedObjectByIndex(0); + if (!pPickObj) + return false; + + SdrGrafObj* pGraphic = dynamic_cast<SdrGrafObj*>(pPickObj); + if (!pGraphic) + return false; + + return pGraphic->isSignatureLineSigned(); +} + +bool SwView::isQRCodeSelected() const +{ + SwWrtShell& rSh = GetWrtShell(); + SdrView* pSdrView = rSh.GetDrawView(); + if (!pSdrView) + return false; + + if (pSdrView->GetMarkedObjectCount() != 1) + return false; + + SdrObject* pPickObj = pSdrView->GetMarkedObjectByIndex(0); + if (!pPickObj) + return false; + + SdrGrafObj* pGraphic = dynamic_cast<SdrGrafObj*>(pPickObj); + if (!pGraphic) + return false; + + return pGraphic->getQrCode() != nullptr; +} + +void SwView::AutoCaption(const sal_uInt16 nType, const SvGlobalName *pOleId) +{ + SwModuleOptions* pModOpt = SW_MOD()->GetModuleConfig(); + + bool bWeb = dynamic_cast<SwWebView*>( this ) != nullptr; + if (pModOpt->IsInsWithCaption(bWeb)) + { + const InsCaptionOpt *pOpt = pModOpt->GetCapOption(bWeb, static_cast<SwCapObjType>(nType), pOleId); + if (pOpt && pOpt->UseCaption()) + InsertCaption(pOpt); + } +} + +void SwView::InsertCaption(const InsCaptionOpt *pOpt) +{ + if (!pOpt) + return; + + const OUString &rName = pOpt->GetCategory(); + + // Is there a pool template with the same name? + SwWrtShell &rSh = GetWrtShell(); + if(!rName.isEmpty()) + { + sal_uInt16 nPoolId = SwStyleNameMapper::GetPoolIdFromUIName(rName, SwGetPoolIdFromName::TxtColl); + if( USHRT_MAX != nPoolId ) + rSh.GetTextCollFromPool(nPoolId); + // Pool template does not exist: Does it exist on the document? + else if( !rSh.GetParaStyle(rName) ) + { + // It also does not exist in the document: generate + SwTextFormatColl* pDerivedFrom = rSh.GetTextCollFromPool(RES_POOLCOLL_LABEL); + rSh.MakeTextFormatColl(rName, pDerivedFrom); + } + } + + SelectionType eType = rSh.GetSelectionType(); + if (eType & SelectionType::Ole) + eType = SelectionType::Graphic; + + const SwLabelType eT = (eType & SelectionType::Table) ? SwLabelType::Table : + (eType & SelectionType::Frame) ? SwLabelType::Fly : + (eType == SelectionType::Text) ? SwLabelType::Fly : + (eType & SelectionType::DrawObject) ? SwLabelType::Draw : + SwLabelType::Object; + + SwFieldMgr aMgr(&rSh); + SwSetExpFieldType* pFieldType = + static_cast<SwSetExpFieldType*>(aMgr.GetFieldType(SwFieldIds::SetExp, rName)); + if (!pFieldType && !rName.isEmpty() ) + { + // Create new field types + SwSetExpFieldType aSwSetExpFieldType(rSh.GetDoc(), rName, nsSwGetSetExpType::GSE_SEQ); + aMgr.InsertFieldType(aSwSetExpFieldType); + pFieldType = static_cast<SwSetExpFieldType*>(aMgr.GetFieldType(SwFieldIds::SetExp, rName)); + } + + if (!pOpt->IgnoreSeqOpts()) + { + if (pFieldType) + { + pFieldType->SetDelimiter(pOpt->GetSeparator()); + pFieldType->SetOutlineLvl( static_cast< sal_uInt8 >(pOpt->GetLevel()) ); + } + } + + sal_uInt16 nID = USHRT_MAX; + SwFieldType* pType = nullptr; + const size_t nCount = aMgr.GetFieldTypeCount(); + if( !rName.isEmpty() ) + { + for (size_t i = 0; i < nCount; ++i) + { + pType = aMgr.GetFieldType(SwFieldIds::Unknown, i); + OUString aTmpName( pType->GetName() ); + if (aTmpName == rName && pType->Which() == SwFieldIds::SetExp) + { + nID = i; + OSL_ENSURE(nID==i, "Downcasting to sal_uInt16 lost information!"); + break; + } + } + } + rSh.StartAllAction(); + + GetWrtShell().InsertLabel( eT, + pOpt->GetCaption(), + !pOpt->IgnoreSeqOpts() ? OUString() : pOpt->GetSeparator(), + pOpt->GetNumSeparator(), + !pOpt->GetPos(), + nID, + pOpt->GetCharacterStyle(), + pOpt->CopyAttributes() ); + // Set Number Format + if(pType) + static_cast<SwSetExpFieldType*>(pType)->SetSeqFormat(pOpt->GetNumType()); + + rSh.UpdateExpFields( true ); + + rSh.EndAllAction(); + + if ( rSh.IsFrameSelected() ) + { + GetEditWin().StopInsFrame(); + rSh.EnterSelFrameMode(); + } + + // remember category + if (eType & SelectionType::Graphic) + SetOldGrfCat(rName); + else if( eType & SelectionType::Table) + SetOldTabCat(rName); + else if( eType & SelectionType::Frame) + SetOldFrameCat(rName); + else if( eType == SelectionType::Text) + SetOldFrameCat(rName); + else if( eType & SelectionType::DrawObject) + SetOldDrwCat(rName); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/uiview/viewdraw.cxx b/sw/source/uibase/uiview/viewdraw.cxx new file mode 100644 index 000000000..c0214b893 --- /dev/null +++ b/sw/source/uibase/uiview/viewdraw.cxx @@ -0,0 +1,757 @@ +/* -*- 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 <hintids.hxx> +#include <svl/itempool.hxx> +#include <svl/stritem.hxx> +#include <svx/svdobj.hxx> +#include <svx/svdview.hxx> +#include <svx/svdpage.hxx> +#include <editeng/outliner.hxx> +#include <svx/fmview.hxx> +#include <svx/dataaccessdescriptor.hxx> +#include <sfx2/viewfrm.hxx> +#include <doc.hxx> +#include <IDocumentDeviceAccess.hxx> +#include <textboxhelper.hxx> +#include <editeng/langitem.hxx> +#include <svx/fontworkbar.hxx> +#include <svx/fontworkgallery.hxx> +#include <editeng/eeitem.hxx> +#include <svx/svdogrp.hxx> +#include <svx/svdetc.hxx> +#include <editeng/editstat.hxx> +#include <sfx2/request.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/dispatch.hxx> +#include <svx/svdoutl.hxx> +#include <vcl/ptrstyle.hxx> +#include <osl/diagnose.h> + +#include <view.hxx> +#include <wrtsh.hxx> +#include <viewopt.hxx> +#include <cmdid.h> +#include <drwbassh.hxx> +#include <beziersh.hxx> +#include <conrect.hxx> +#include <conpoly.hxx> +#include <conarc.hxx> +#include <conform.hxx> +#include <concustomshape.hxx> +#include <dselect.hxx> +#include <edtwin.hxx> + +#include <dcontact.hxx> + +#include <svx/svdpagv.hxx> +#include <svx/extrusionbar.hxx> +#include <comphelper/lok.hxx> +#include <sfx2/lokhelper.hxx> +#include <LibreOfficeKit/LibreOfficeKitEnums.h> + +using namespace ::com::sun::star; + +// Execute Drawing-Ids + +void SwView::ExecDraw(const SfxRequest& rReq) +{ + const SfxItemSet *pArgs = rReq.GetArgs(); + const SfxPoolItem* pItem; + const SfxStringItem* pStringItem = nullptr; + SdrView *pSdrView = m_pWrtShell->GetDrawView(); + bool bDeselect = false; + + sal_uInt16 nSlotId = rReq.GetSlot(); + if(pArgs && SfxItemState::SET == pArgs->GetItemState(GetPool().GetWhich(nSlotId), false, &pItem)) + pStringItem = dynamic_cast< const SfxStringItem*>(pItem); + + SdrObjKind eNewFormObjKind = SdrObjKind::NONE; + if (nSlotId == SID_FM_CREATE_CONTROL) + { + const SfxUInt16Item* pIdentifierItem = rReq.GetArg<SfxUInt16Item>(SID_FM_CONTROL_IDENTIFIER); + if (pIdentifierItem) + eNewFormObjKind = static_cast<SdrObjKind>(pIdentifierItem->GetValue()); + } + + if (nSlotId == SID_OBJECT_SELECT && m_nFormSfxId == nSlotId) + { + bDeselect = true; + } + else if (nSlotId == SID_FM_CREATE_CONTROL) + { + if (eNewFormObjKind == m_eFormObjKind || eNewFormObjKind == SdrObjKind::NONE) + { + bDeselect = true; + GetViewFrame()->GetDispatcher()->Execute(SID_FM_LEAVE_CREATE); // Button should popping out + } + } + else if (nSlotId == SID_FM_CREATE_FIELDCONTROL) + { + FmFormView* pFormView = dynamic_cast<FmFormView*>(pSdrView); + if (pFormView) + { + const SfxUnoAnyItem* pDescriptorItem = rReq.GetArg<SfxUnoAnyItem>(SID_FM_DATACCESS_DESCRIPTOR); + OSL_ENSURE( pDescriptorItem, "SwView::ExecDraw(SID_FM_CREATE_FIELDCONTROL): invalid request args!" ); + if( pDescriptorItem ) + { + svx::ODataAccessDescriptor aDescriptor( pDescriptorItem->GetValue() ); + SdrObjectUniquePtr pObj = pFormView->CreateFieldControl( aDescriptor ); + + if ( pObj ) + { + Size aDocSize(m_pWrtShell->GetDocSize()); + const SwRect& rVisArea = m_pWrtShell->VisArea(); + Point aStartPos = rVisArea.Center(); + if(rVisArea.Width() > aDocSize.Width()) + aStartPos.setX( aDocSize.Width() / 2 + rVisArea.Left() ); + if(rVisArea.Height() > aDocSize.Height()) + aStartPos.setY( aDocSize.Height() / 2 + rVisArea.Top() ); + + //determine the size of the object + if(pObj->IsGroupObject()) + { + const tools::Rectangle& rBoundRect = static_cast<SdrObjGroup*>(pObj.get())->GetCurrentBoundRect(); + aStartPos.AdjustX( -(rBoundRect.GetWidth()/2) ); + aStartPos.AdjustY( -(rBoundRect.GetHeight()/2) ); + } + + // TODO: unmark all other + m_pWrtShell->EnterStdMode(); + m_pWrtShell->SwFEShell::InsertDrawObj( *(pObj.release()), aStartPos ); + } + } + } + } + else if ( nSlotId == SID_FONTWORK_GALLERY_FLOATER ) + { + vcl::Window& rWin = m_pWrtShell->GetView().GetViewFrame()->GetWindow(); + + rWin.EnterWait(); + + if( !m_pWrtShell->HasDrawView() ) + m_pWrtShell->MakeDrawView(); + + pSdrView = m_pWrtShell->GetDrawView(); + if (pSdrView) + { + std::shared_ptr<svx::FontWorkGalleryDialog> pDlg = std::make_shared<svx::FontWorkGalleryDialog>(rWin.GetFrameWeld(), *pSdrView); + pDlg->SetSdrObjectRef( pSdrView->GetModel() ); + weld::DialogController::runAsync(pDlg, [this, pDlg](int) { + vcl::Window& rWin2 = m_pWrtShell->GetView().GetViewFrame()->GetWindow(); + + SdrObject* pObj = pDlg->GetSdrObjectRef(); + if ( pObj ) + { + Size aDocSize( m_pWrtShell->GetDocSize() ); + const SwRect& rVisArea = comphelper::LibreOfficeKit::isActive() ? + SwRect(m_pWrtShell->getLOKVisibleArea()) : m_pWrtShell->VisArea(); + Point aPos( rVisArea.Center() ); + tools::Rectangle aObjRect( pObj->GetLogicRect() ); + + if ( rVisArea.Width() > aDocSize.Width()) + aPos.setX( aDocSize.Width() / 2 + rVisArea.Left() ); + else if (aPos.getX() > aObjRect.GetWidth() / 2) + aPos.AdjustX( -(aObjRect.GetWidth() / 2) ); + + if (rVisArea.Height() > aDocSize.Height()) + aPos.setY( aDocSize.Height() / 2 + rVisArea.Top() ); + else if (aPos.getY() > aObjRect.GetHeight() / 2) + aPos.AdjustY( -(aObjRect.GetHeight() / 2) ); + + m_pWrtShell->EnterStdMode(); + m_pWrtShell->SwFEShell::InsertDrawObj( *pObj, aPos ); + } + + rWin2.LeaveWait(); + }); + } + else + rWin.LeaveWait(); + } + else if ( m_nFormSfxId != USHRT_MAX ) + GetViewFrame()->GetDispatcher()->Execute( SID_FM_LEAVE_CREATE ); + + if( nSlotId == SID_DRAW_CS_ID ) + { + //deselect if same custom shape is selected again + SwDrawBase* pFuncPtr = GetDrawFuncPtr(); + if( pFuncPtr && pFuncPtr->GetSlotId() == SID_DRAW_CS_ID ) + { + ConstCustomShape* pConstCustomShape = static_cast<ConstCustomShape*>(pFuncPtr); + OUString aNew = ConstCustomShape::GetShapeTypeFromRequest( rReq ); + const OUString& aOld = pConstCustomShape->GetShapeType(); + if( aNew == aOld ) + { + bDeselect = true; + } + } + } + + //deselect if same shape is selected again (but different custom shapes do have same slot id) + if ( bDeselect || (nSlotId == m_nDrawSfxId && + (!pStringItem || (pStringItem->GetValue() == m_sDrawCustom)) + && (nSlotId != SID_DRAW_CS_ID) ) ) + { + if (GetDrawFuncPtr()) + { + GetDrawFuncPtr()->Deactivate(); + SetDrawFuncPtr(nullptr); + } + + if (m_pWrtShell->IsObjSelected() && !m_pWrtShell->IsSelFrameMode()) + m_pWrtShell->EnterSelFrameMode(); + LeaveDrawCreate(); + + AttrChangedNotify(nullptr); + return; + } + + LeaveDrawCreate(); + + if (m_pWrtShell->IsFrameSelected()) + m_pWrtShell->EnterStdMode(); // because bug #45639 + + std::unique_ptr<SwDrawBase> pFuncPtr; + + // for LibreOfficeKit - choosing a shape should construct it directly + bool bCreateDirectly = false; + + switch (nSlotId) + { + case SID_OBJECT_SELECT: + case SID_DRAW_SELECT: + pFuncPtr.reset( new DrawSelection(m_pWrtShell.get(), m_pEditWin, this) ); + m_nDrawSfxId = m_nFormSfxId = SID_OBJECT_SELECT; + m_sDrawCustom.clear(); + break; + + case SID_LINE_ARROW_END: + case SID_LINE_ARROW_CIRCLE: + case SID_LINE_ARROW_SQUARE: + case SID_LINE_ARROW_START: + case SID_LINE_CIRCLE_ARROW: + case SID_LINE_SQUARE_ARROW: + case SID_LINE_ARROWS: + case SID_DRAW_LINE: + case SID_DRAW_XLINE: + case SID_DRAW_MEASURELINE: + case SID_DRAW_RECT: + case SID_DRAW_ELLIPSE: + case SID_DRAW_TEXT: + case SID_DRAW_TEXT_VERTICAL: + case SID_DRAW_TEXT_MARQUEE: + case SID_DRAW_CAPTION: + case SID_DRAW_CAPTION_VERTICAL: + pFuncPtr.reset( new ConstRectangle(m_pWrtShell.get(), m_pEditWin, this) ); + bCreateDirectly = comphelper::LibreOfficeKit::isActive(); + m_nDrawSfxId = nSlotId; + m_sDrawCustom.clear(); + break; + + case SID_DRAW_XPOLYGON_NOFILL: + case SID_DRAW_XPOLYGON: + case SID_DRAW_POLYGON_NOFILL: + case SID_DRAW_POLYGON: + case SID_DRAW_BEZIER_NOFILL: + case SID_DRAW_BEZIER_FILL: + case SID_DRAW_FREELINE_NOFILL: + case SID_DRAW_FREELINE: + pFuncPtr.reset( new ConstPolygon(m_pWrtShell.get(), m_pEditWin, this) ); + m_nDrawSfxId = nSlotId; + m_sDrawCustom.clear(); + break; + + case SID_DRAW_ARC: + case SID_DRAW_PIE: + case SID_DRAW_CIRCLECUT: + pFuncPtr.reset( new ConstArc(m_pWrtShell.get(), m_pEditWin, this) ); + m_nDrawSfxId = nSlotId; + m_sDrawCustom.clear(); + break; + + case SID_FM_CREATE_CONTROL: + { + pFuncPtr.reset(new ConstFormControl(m_pWrtShell.get(), m_pEditWin, this, eNewFormObjKind)); + m_nFormSfxId = nSlotId; + m_eFormObjKind = eNewFormObjKind; + } + break; + + case SID_DRAWTBX_CS_BASIC : + case SID_DRAWTBX_CS_SYMBOL : + case SID_DRAWTBX_CS_ARROW : + case SID_DRAWTBX_CS_FLOWCHART : + case SID_DRAWTBX_CS_CALLOUT : + case SID_DRAWTBX_CS_STAR : + case SID_DRAW_CS_ID : + { + pFuncPtr.reset( new ConstCustomShape(m_pWrtShell.get(), m_pEditWin, this, rReq ) ); + + bCreateDirectly = comphelper::LibreOfficeKit::isActive(); + + m_nDrawSfxId = nSlotId; + if ( nSlotId != SID_DRAW_CS_ID ) + { + if ( pStringItem ) + { + m_sDrawCustom = pStringItem->GetValue(); + SfxBindings& rBind = GetViewFrame()->GetBindings(); + rBind.Invalidate( nSlotId ); + rBind.Update( nSlotId ); + } + } + } + break; + + default: + break; + } + + GetViewFrame()->GetBindings().Invalidate(SID_ATTRIBUTES_AREA); + + bool bEndTextEdit = true; + if (pFuncPtr) + { + if (GetDrawFuncPtr()) + { + GetDrawFuncPtr()->Deactivate(); + } + + auto pTempFuncPtr = pFuncPtr.get(); + SetDrawFuncPtr(std::move(pFuncPtr)); + AttrChangedNotify(nullptr); + + pTempFuncPtr->Activate(nSlotId); + NoRotate(); + if(rReq.GetModifier() == KEY_MOD1 || bCreateDirectly) + { + if (bCreateDirectly) + GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON); + if(SID_OBJECT_SELECT == m_nDrawSfxId ) + { + m_pWrtShell->GotoObj(true); + } + else if (dynamic_cast<ConstCustomShape*>(pTempFuncPtr)) + { + pTempFuncPtr->CreateDefaultObject(); + } + else + { + pTempFuncPtr->CreateDefaultObject(); + pTempFuncPtr->Deactivate(); + SetDrawFuncPtr(nullptr); + LeaveDrawCreate(); + m_pWrtShell->EnterStdMode(); + SdrView *pTmpSdrView = m_pWrtShell->GetDrawView(); + const SdrMarkList& rMarkList = pTmpSdrView->GetMarkedObjectList(); + if(rMarkList.GetMarkCount() == 1 && + (SID_DRAW_TEXT == nSlotId || SID_DRAW_TEXT_VERTICAL == nSlotId || + SID_DRAW_TEXT_MARQUEE == nSlotId )) + { + SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj(); + BeginTextEdit(pObj); + bEndTextEdit = false; + } + } + } + } + else + { + if (m_pWrtShell->IsObjSelected() && !m_pWrtShell->IsSelFrameMode()) + m_pWrtShell->EnterSelFrameMode(); + } + + if(bEndTextEdit && pSdrView && pSdrView->IsTextEdit()) + pSdrView->SdrEndTextEdit( true ); + + AttrChangedNotify(nullptr); +} + +// End drawing + +void SwView::ExitDraw() +{ + NoRotate(); + + if(!m_pShell) + return; + + // the shell may be invalid at close/reload/SwitchToViewShell + SfxDispatcher* pDispatch = GetViewFrame()->GetDispatcher(); + sal_uInt16 nIdx = 0; + SfxShell* pTest = nullptr; + do + { + pTest = pDispatch->GetShell(nIdx++); + } + while( pTest && pTest != this && pTest != m_pShell); + if(!(pTest == m_pShell && + // don't call LeaveSelFrameMode() etc. for the below, + // because objects may still be selected: + dynamic_cast< const SwDrawBaseShell *>( m_pShell ) == nullptr && + dynamic_cast< const SwBezierShell *>( m_pShell ) == nullptr && + dynamic_cast< const svx::ExtrusionBar *>( m_pShell ) == nullptr && + dynamic_cast< const svx::FontworkBar *>( m_pShell ) == nullptr)) + return; + + SdrView *pSdrView = m_pWrtShell->GetDrawView(); + + if (pSdrView && pSdrView->IsGroupEntered()) + { + pSdrView->LeaveOneGroup(); + pSdrView->UnmarkAll(); + GetViewFrame()->GetBindings().Invalidate(SID_ENTER_GROUP); + } + + if (GetDrawFuncPtr()) + { + if (m_pWrtShell->IsSelFrameMode()) + m_pWrtShell->LeaveSelFrameMode(); + GetDrawFuncPtr()->Deactivate(); + + SetDrawFuncPtr(nullptr); + LeaveDrawCreate(); + + GetViewFrame()->GetBindings().Invalidate(SID_INSERT_DRAW); + } + GetEditWin().SetPointer(PointerStyle::Text); +} + +// Disable rotate mode + +void SwView::NoRotate() +{ + if (IsDrawRotate()) + { + m_pWrtShell->SetDragMode(SdrDragMode::Move); + FlipDrawRotate(); + + const SfxBoolItem aTmp( SID_OBJECT_ROTATE, false ); + GetViewFrame()->GetBindings().SetState( aTmp ); + } +} + +// Enable DrawTextEditMode + +static bool lcl_isTextBox(SdrObject const * pObject) +{ + if (SwDrawContact* pDrawContact = static_cast<SwDrawContact*>(pObject->GetUserCall())) + { + if (SwFrameFormat* pFormat = pDrawContact->GetFormat()) + return SwTextBoxHelper::isTextBox(pFormat, RES_DRAWFRMFMT); + } + return false; +} + +bool SwView::EnterDrawTextMode(const Point& aDocPos) +{ + SwWrtShell *pSh = &GetWrtShell(); + SdrView *pSdrView = pSh->GetDrawView(); + OSL_ENSURE( pSdrView, "EnterDrawTextMode without DrawView?" ); + + bool bReturn = false; + + sal_uInt16 nOld = pSdrView->GetHitTolerancePixel(); + pSdrView->SetHitTolerancePixel( 2 ); + + SdrObject* pObj = nullptr; + SdrPageView* pPV = nullptr; + if (pSdrView->IsMarkedHit(aDocPos) && !pSdrView->PickHandle(aDocPos) && IsTextTool()) + pObj = pSdrView->PickObj(aDocPos, pSdrView->getHitTolLog(), pPV, SdrSearchOptions::PICKTEXTEDIT); + + if (pObj) + { + // To allow SwDrawVirtObj text objects to be activated, allow their type, too. + auto pVirtObj = dynamic_cast<SwDrawVirtObj*>( pObj ); + if ( (pVirtObj && dynamic_cast< const SdrTextObj *>(&pVirtObj->GetReferencedObj() ) != nullptr && + m_pWrtShell->IsSelObjProtected(FlyProtectFlags::Content) == FlyProtectFlags::NONE) || + dynamic_cast< const SdrTextObj *>( pObj ) != nullptr ) + { + // Refuse to edit editeng text of the shape if it has textbox attached. + if (!lcl_isTextBox(pObj)) + bReturn = BeginTextEdit( pObj, pPV, m_pEditWin ); + } + } + + pSdrView->SetHitTolerancePixel( nOld ); + + return bReturn; +} + +bool SwView::EnterShapeDrawTextMode(SdrObject* pObject) +{ + SdrView* pSdrView = GetWrtShell().GetDrawView(); + SdrPageView* pPageView = pSdrView->GetSdrPageView(); + return BeginTextEdit(pObject, pPageView, m_pEditWin); +} + +// Enable DrawTextEditMode + +bool SwView::BeginTextEdit(SdrObject* pObj, SdrPageView* pPV, vcl::Window* pWin, + bool bIsNewObj, bool bSetSelectionToStart) +{ + SwWrtShell *pSh = &GetWrtShell(); + SdrView *pSdrView = pSh->GetDrawView(); + std::unique_ptr<SdrOutliner> pOutliner = ::SdrMakeOutliner(OutlinerMode::TextObject, *pSdrView->GetModel()); + uno::Reference< linguistic2::XSpellChecker1 > xSpell( ::GetSpellChecker() ); + if (pOutliner) + { + pOutliner->SetRefDevice(pSh->getIDocumentDeviceAccess().getReferenceDevice(false)); + pOutliner->SetSpeller(xSpell); + uno::Reference<linguistic2::XHyphenator> xHyphenator( ::GetHyphenator() ); + pOutliner->SetHyphenator( xHyphenator ); + pSh->SetCalcFieldValueHdl(pOutliner.get()); + + EEControlBits nCntrl = pOutliner->GetControlWord(); + nCntrl |= EEControlBits::ALLOWBIGOBJS; + + const SwViewOption *pOpt = pSh->GetViewOptions(); + + if (SwViewOption::IsFieldShadings()) + nCntrl |= EEControlBits::MARKFIELDS; + else + nCntrl &= ~EEControlBits::MARKFIELDS; + + if (pOpt->IsOnlineSpell()) + nCntrl |= EEControlBits::ONLINESPELLING; + else + nCntrl &= ~EEControlBits::ONLINESPELLING; + + pOutliner->SetControlWord(nCntrl); + const SfxPoolItem& rItem = pSh->GetDoc()->GetDefault(RES_CHRATR_LANGUAGE); + pOutliner->SetDefaultLanguage(static_cast<const SvxLanguageItem&>(rItem).GetLanguage()); + + if( bIsNewObj ) + pOutliner->SetVertical( SID_DRAW_TEXT_VERTICAL == m_nDrawSfxId || + SID_DRAW_CAPTION_VERTICAL == m_nDrawSfxId ); + + // set default horizontal text direction at outliner + EEHorizontalTextDirection aDefHoriTextDir = + pSh->IsShapeDefaultHoriTextDirR2L() ? EEHorizontalTextDirection::R2L : EEHorizontalTextDirection::L2R; + pOutliner->SetDefaultHorizontalTextDirection( aDefHoriTextDir ); + } + + // To allow editing the referenced object from a SwDrawVirtObj here + // the original needs to be fetched eventually. This ATM activates the + // text edit mode for the original object. + SdrObject* pToBeActivated = pObj; + + // Always the original object is edited. To allow the TextEdit to happen + // where the VirtObj is positioned, on demand an occurring offset is set at + // the TextEdit object. That offset is used for creating and managing the + // OutlinerView. + Point aNewTextEditOffset(0, 0); + + if (SwDrawVirtObj* pVirtObj = dynamic_cast<SwDrawVirtObj *>(pObj)) + { + pToBeActivated = &const_cast<SdrObject&>(pVirtObj->GetReferencedObj()); + aNewTextEditOffset = pVirtObj->GetOffset(); + } + + // set in each case, thus it will be correct for all objects + static_cast<SdrTextObj*>(pToBeActivated)->SetTextEditOffset(aNewTextEditOffset); + + bool bRet(pSdrView->SdrBeginTextEdit( pToBeActivated, pPV, pWin, true, pOutliner.release(), nullptr, false, false, false )); + + // #i7672# + // Since SdrBeginTextEdit actually creates the OutlinerView and thus also + // sets the background color, an own background color needs to be set + // after TextEditing was started. This is now done here. + if(bRet) + { + OutlinerView* pView = pSdrView->GetTextEditOutlinerView(); + + if(pView) + { + Color aBackground(pSh->GetShapeBackground()); + pView->SetBackgroundColor(aBackground); + } + + // editing should start at the end of text, spell checking at the beginning ... + ESelection aNewSelection(EE_PARA_NOT_FOUND, EE_INDEX_NOT_FOUND, EE_PARA_NOT_FOUND, EE_INDEX_NOT_FOUND); + if (bSetSelectionToStart) + aNewSelection = ESelection(); + if (pView) + { + pView->SetSelection(aNewSelection); + + if (comphelper::LibreOfficeKit::isActive()) + { + OString sRect = pView->GetOutputArea().toString(); + SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_VIEW_LOCK, "rectangle", sRect); + } + } + } + + return bRet; +} + +// Is a DrawTextObject selected? +bool SwView::IsTextTool() const +{ + SdrObjKind nId; + SdrInventor nInvent; + SdrView *pSdrView = GetWrtShell().GetDrawView(); + OSL_ENSURE( pSdrView, "IsTextTool without DrawView?" ); + + if (pSdrView->IsCreateMode()) + pSdrView->SetCreateMode(false); + + pSdrView->TakeCurrentObj(nId,nInvent); + return nInvent == SdrInventor::Default; +} + +SdrView* SwView::GetDrawView() const +{ + return GetWrtShell().GetDrawView(); +} + +bool SwView::IsBezierEditMode() const +{ + return (!IsDrawSelMode() && GetWrtShell().GetDrawView()->HasMarkablePoints()); +} + +bool SwView::IsFormMode() const +{ + if (GetDrawFuncPtr() && GetDrawFuncPtr()->IsCreateObj()) + { + return GetDrawFuncPtr()->IsInsertForm(); + } + + return AreOnlyFormsSelected(); +} + +void SwView::SetDrawFuncPtr(std::unique_ptr<SwDrawBase> pFuncPtr) +{ + m_pDrawActual = std::move(pFuncPtr); +} + +void SwView::SetSelDrawSlot() +{ + m_nDrawSfxId = SID_OBJECT_SELECT; + m_sDrawCustom.clear(); +} + +bool SwView::AreOnlyFormsSelected() const +{ + if ( GetWrtShell().IsFrameSelected() ) + return false; + + bool bForm = true; + + SdrView* pSdrView = GetWrtShell().GetDrawView(); + + const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList(); + const size_t nCount = rMarkList.GetMarkCount(); + + if (nCount) + { + for (size_t i = 0; i < nCount; ++i) + { + // Except controls, are still normal draw objects selected? + SdrObject *pSdrObj = rMarkList.GetMark(i)->GetMarkedSdrObj(); + if (!pSdrObj) + continue; + + if (!HasOnlyObj(pSdrObj, SdrInventor::FmForm)) + { + bForm = false; + break; + } + } + } + else + bForm = false; + + return bForm; +} + +bool SwView::HasOnlyObj(SdrObject const *pSdrObj, SdrInventor eObjInventor) const +{ + bool bRet = false; + + if (pSdrObj->IsGroupObject()) + { + SdrObjList* pList = pSdrObj->GetSubList(); + const size_t nCnt = pList->GetObjCount(); + + for (size_t i = 0; i < nCnt; ++i) + { + bRet = HasOnlyObj(pList->GetObj(i), eObjInventor); + if (!bRet) + break; + } + } + else if (eObjInventor == pSdrObj->GetObjInventor()) + return true; + + return bRet; +} + +//#i87414# mod +IMPL_LINK(SwView, OnlineSpellCallback, SpellCallbackInfo&, rInfo, void) +{ + if (rInfo.nCommand == SpellCallbackCommand::STARTSPELLDLG) + GetViewFrame()->GetDispatcher()->Execute( FN_SPELL_GRAMMAR_DIALOG, SfxCallMode::ASYNCHRON); + else if (rInfo.nCommand == SpellCallbackCommand::AUTOCORRECT_OPTIONS) + GetViewFrame()->GetDispatcher()->Execute( SID_AUTO_CORRECT_DLG, SfxCallMode::ASYNCHRON ); +} + +bool SwView::ExecDrwTextSpellPopup(const Point& rPt) +{ + bool bRet = false; + SdrView *pSdrView = m_pWrtShell->GetDrawView(); + OutlinerView* pOLV = pSdrView->GetTextEditOutlinerView(); + Point aPos( GetEditWin().LogicToPixel( rPt ) ); + + if (pOLV->IsWrongSpelledWordAtPos( aPos )) + { + bRet = true; + Link<SpellCallbackInfo&,void> aLink = LINK(this, SwView, OnlineSpellCallback); + pOLV->ExecuteSpellPopup(aPos, aLink); + } + return bRet; +} + +bool SwView::IsDrawTextHyphenate() +{ + SdrView *pSdrView = m_pWrtShell->GetDrawView(); + bool bHyphenate = false; + + SfxItemSetFixed<EE_PARA_HYPHENATE, EE_PARA_HYPHENATE> aNewAttr( pSdrView->GetModel()->GetItemPool() ); + pSdrView->GetAttributes( aNewAttr ); + if( aNewAttr.GetItemState( EE_PARA_HYPHENATE ) >= SfxItemState::DEFAULT ) + bHyphenate = aNewAttr.Get( EE_PARA_HYPHENATE ).GetValue(); + + return bHyphenate; +} + +void SwView::HyphenateDrawText() +{ + SdrView *pSdrView = m_pWrtShell->GetDrawView(); + bool bHyphenate = IsDrawTextHyphenate(); + + SfxItemSetFixed<EE_PARA_HYPHENATE, EE_PARA_HYPHENATE> aSet( GetPool() ); + aSet.Put( SfxBoolItem( EE_PARA_HYPHENATE, !bHyphenate ) ); + pSdrView->SetAttributes( aSet ); + GetViewFrame()->GetBindings().Invalidate(FN_HYPHENATE_OPT_DLG); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/uiview/viewfunc.hxx b/sw/source/uibase/uiview/viewfunc.hxx new file mode 100644 index 000000000..c9d300039 --- /dev/null +++ b/sw/source/uibase/uiview/viewfunc.hxx @@ -0,0 +1,55 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_SW_SOURCE_UIBASE_UIVIEW_VIEWFUNC_HXX +#define INCLUDED_SW_SOURCE_UIBASE_UIVIEW_VIEWFUNC_HXX + +#include <vcl/outdev.hxx> + +#include <IDocumentDeviceAccess.hxx> + +class ImageButton; +class Point; +class SfxItemSet; +class SfxPrinter; +class SfxTabPage; +class Size; +class SvxRuler; +class SwScrollbar; +class SwViewShell; +namespace vcl { class Window; } + +// The following functions are available in viewprt.cxx +void SetPrinter( IDocumentDeviceAccess*, SfxPrinter const *, bool bWeb ); +void SetAppPrintOptions( SwViewShell* pSh, bool bWeb ); + +// The following functions are available in viewport.cxx +void ViewResizePixel( const vcl::RenderContext &rRef, + const Point &rOfst, + const Size &rSize, + const Size &rEditSz, + SwScrollbar& rVScrollbar, + SwScrollbar& rHScrollbar, + vcl::Window& rScrollBarBox, + SvxRuler* pVRuler = nullptr, + SvxRuler* pHRuler = nullptr, + bool bVRulerRight = false ); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/uiview/viewling.cxx b/sw/source/uibase/uiview/viewling.cxx new file mode 100644 index 000000000..d7c6fa406 --- /dev/null +++ b/sw/source/uibase/uiview/viewling.cxx @@ -0,0 +1,855 @@ +/* -*- 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 <hintids.hxx> + +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/linguistic2/XThesaurus.hpp> +#include <com/sun/star/linguistic2/ProofreadingResult.hpp> +#include <com/sun/star/linguistic2/XLinguProperties.hpp> +#include <com/sun/star/i18n/TextConversionOption.hpp> +#include <comphelper/lok.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/propertyvalue.hxx> +#include <comphelper/propertysequence.hxx> +#include <comphelper/scopeguard.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/weld.hxx> +#include <svtools/ehdl.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/request.hxx> +#include <svx/dialmgr.hxx> +#include <svx/svxerr.hxx> +#include <svx/svxdlg.hxx> +#include <osl/diagnose.h> +#include <swwait.hxx> +#include <uitool.hxx> +#include <view.hxx> +#include <wrtsh.hxx> +#include <viewopt.hxx> +#include <swundo.hxx> +#include <hyp.hxx> +#include <olmenu.hxx> +#include <pam.hxx> +#include <edtwin.hxx> +#include <ndtxt.hxx> +#include <txtfrm.hxx> +#include <cmdid.h> +#include <strings.hrc> +#include <hhcwrp.hxx> + +#include <boost/property_tree/json_parser.hpp> + +#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> +#include <com/sun/star/ui/ContextMenuExecuteEvent.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/frame/XDispatch.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/frame/XPopupMenuController.hpp> +#include <com/sun/star/awt/PopupMenuDirection.hpp> +#include <com/sun/star/util/URL.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/util/URLTransformer.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> + +#include <vcl/svapp.hxx> +#include <rtl/ustring.hxx> + +#include <cppuhelper/bootstrap.hxx> +#include <svtools/langtab.hxx> + +#include <editeng/editerr.hxx> +#include <LibreOfficeKit/LibreOfficeKitEnums.h> + +#include <memory> + +using namespace sw::mark; +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::linguistic2; + +// Lingu-Dispatcher + +void SwView::ExecLingu(SfxRequest &rReq) +{ + switch(rReq.GetSlot()) + { + case SID_THESAURUS: + StartThesaurus(); + rReq.Ignore(); + break; + case SID_HANGUL_HANJA_CONVERSION: + StartTextConversion( LANGUAGE_KOREAN, LANGUAGE_KOREAN, nullptr, + i18n::TextConversionOption::CHARACTER_BY_CHARACTER, true ); + break; + case SID_CHINESE_CONVERSION: + { + //open ChineseTranslationDialog + Reference< XComponentContext > xContext( + ::cppu::defaultBootstrap_InitialComponentContext() ); //@todo get context from calc if that has one + if(xContext.is()) + { + Reference< lang::XMultiComponentFactory > xMCF( xContext->getServiceManager() ); + if(xMCF.is()) + { + Reference< ui::dialogs::XExecutableDialog > xDialog( + xMCF->createInstanceWithContext( + "com.sun.star.linguistic2.ChineseTranslationDialog", xContext), + UNO_QUERY); + Reference< lang::XInitialization > xInit( xDialog, UNO_QUERY ); + if( xInit.is() ) + { + Reference<awt::XWindow> xParentWindow; + if (weld::Window* pParentWindow = rReq.GetFrameWeld()) + xParentWindow = pParentWindow->GetXWindow(); + // initialize dialog + uno::Sequence<uno::Any> aSeq(comphelper::InitAnyPropertySequence( + { + {"ParentWindow", uno::Any(xParentWindow)} + })); + xInit->initialize( aSeq ); + + //execute dialog + sal_Int16 nDialogRet = xDialog->execute(); + if( RET_OK == nDialogRet ) + { + //get some parameters from the dialog + bool bToSimplified = true; + bool bUseVariants = true; + bool bCommonTerms = true; + Reference< beans::XPropertySet > xProp( xDialog, UNO_QUERY ); + if( xProp.is() ) + { + try + { + xProp->getPropertyValue( "IsDirectionToSimplified" ) >>= bToSimplified; + xProp->getPropertyValue( "IsUseCharacterVariants" ) >>= bUseVariants; + xProp->getPropertyValue( "IsTranslateCommonTerms" ) >>= bCommonTerms; + } + catch (const Exception&) + { + } + } + + //execute translation + LanguageType nSourceLang = bToSimplified ? LANGUAGE_CHINESE_TRADITIONAL : LANGUAGE_CHINESE_SIMPLIFIED; + LanguageType nTargetLang = bToSimplified ? LANGUAGE_CHINESE_SIMPLIFIED : LANGUAGE_CHINESE_TRADITIONAL; + sal_Int32 nOptions = bUseVariants ? i18n::TextConversionOption::USE_CHARACTER_VARIANTS : 0; + if( !bCommonTerms ) + nOptions = nOptions | i18n::TextConversionOption::CHARACTER_BY_CHARACTER; + + vcl::Font aTargetFont = OutputDevice::GetDefaultFont( DefaultFontType::CJK_TEXT, + nTargetLang, GetDefaultFontFlags::OnlyOne ); + + // disallow formatting, updating the view, ... while + // converting the document. (saves time) + // Also remember the current view and cursor position for later + m_pWrtShell->StartAction(); + + // remember cursor position data for later restoration of the cursor + const SwPosition *pPoint = m_pWrtShell->GetCursor()->GetPoint(); + bool bRestoreCursor = pPoint->nNode.GetNode().IsTextNode(); + const SwNodeIndex aPointNodeIndex( pPoint->nNode ); + sal_Int32 nPointIndex = pPoint->nContent.GetIndex(); + + // since this conversion is not interactive the whole converted + // document should be undone in a single undo step. + m_pWrtShell->StartUndo( SwUndoId::OVERWRITE ); + + StartTextConversion( nSourceLang, nTargetLang, &aTargetFont, nOptions, false ); + + m_pWrtShell->EndUndo( SwUndoId::OVERWRITE ); + + if (bRestoreCursor) + { + SwTextNode *pTextNode = aPointNodeIndex.GetNode().GetTextNode(); + // check for unexpected error case + OSL_ENSURE(pTextNode && pTextNode->GetText().getLength() >= nPointIndex, + "text missing: corrupted node?" ); + if (!pTextNode || pTextNode->GetText().getLength() < nPointIndex) + nPointIndex = 0; + // restore cursor to its original position + m_pWrtShell->GetCursor()->GetPoint()->nContent.Assign( pTextNode, nPointIndex ); + } + + // enable all, restore view and cursor position + m_pWrtShell->EndAction(); + } + } + Reference< lang::XComponent > xComponent( xDialog, UNO_QUERY ); + if( xComponent.is() ) + xComponent->dispose(); + } + } + break; + } + case FN_HYPHENATE_OPT_DLG: + HyphenateDocument(); + break; + default: + OSL_ENSURE(false, "wrong Dispatcher"); + return; + } +} + +// start language specific text conversion + +void SwView::StartTextConversion( + LanguageType nSourceLang, + LanguageType nTargetLang, + const vcl::Font *pTargetFont, + sal_Int32 nOptions, + bool bIsInteractive ) +{ + // do not do text conversion if it is active elsewhere + if (SwEditShell::HasConvIter()) + { + return; + } + + SpellContext(); + + const SwViewOption* pVOpt = m_pWrtShell->GetViewOptions(); + const bool bOldIdle = pVOpt->IsIdle(); + pVOpt->SetIdle( false ); + + bool bOldIns = m_pWrtShell->IsInsMode(); + m_pWrtShell->SetInsMode(); + + const bool bSelection = static_cast<SwCursorShell*>(m_pWrtShell.get())->HasSelection() || + m_pWrtShell->GetCursor() != m_pWrtShell->GetCursor()->GetNext(); + + const bool bStart = bSelection || m_pWrtShell->IsStartOfDoc(); + const bool bOther = !bSelection && !(m_pWrtShell->GetFrameType(nullptr,true) & FrameTypeFlags::BODY); + + { + const uno::Reference< uno::XComponentContext > xContext( + comphelper::getProcessComponentContext() ); + SwHHCWrapper aWrap( this, xContext, nSourceLang, nTargetLang, pTargetFont, + nOptions, bIsInteractive, + bStart, bOther, bSelection ); + aWrap.Convert(); + } + + m_pWrtShell->SetInsMode( bOldIns ); + pVOpt->SetIdle( bOldIdle ); + SpellContext(false); +} + +// spellcheck and text conversion related stuff + +void SwView::SpellStart( SvxSpellArea eWhich, + bool bStartDone, bool bEndDone, + SwConversionArgs *pConvArgs ) +{ + Reference< XLinguProperties > xProp = ::GetLinguPropertySet(); + bool bIsWrapReverse = !pConvArgs && xProp.is() && xProp->getIsWrapReverse(); + + SwDocPositions eStart = SwDocPositions::Start; + SwDocPositions eEnd = SwDocPositions::End; + SwDocPositions eCurr = SwDocPositions::Curr; + switch ( eWhich ) + { + case SvxSpellArea::Body: + if( bIsWrapReverse ) + eCurr = SwDocPositions::End; + else + eCurr = SwDocPositions::Start; + break; + case SvxSpellArea::BodyEnd: + if( bIsWrapReverse ) + { + if( bStartDone ) + eStart = SwDocPositions::Curr; + eCurr = SwDocPositions::End; + } + else if( bStartDone ) + eCurr = SwDocPositions::Start; + break; + case SvxSpellArea::BodyStart: + if( !bIsWrapReverse ) + { + if( bEndDone ) + eEnd = SwDocPositions::Curr; + eCurr = SwDocPositions::Start; + } + else if( bEndDone ) + eCurr = SwDocPositions::End; + break; + case SvxSpellArea::Other: + if( bIsWrapReverse ) + { + eStart = SwDocPositions::OtherStart; + eEnd = SwDocPositions::OtherEnd; + eCurr = SwDocPositions::OtherEnd; + } + else + { + eStart = SwDocPositions::OtherStart; + eEnd = SwDocPositions::OtherEnd; + eCurr = SwDocPositions::OtherStart; + } + break; + default: + OSL_ENSURE( false, "SpellStart with unknown Area" ); + } + m_pWrtShell->SpellStart( eStart, eEnd, eCurr, pConvArgs ); +} + +// Error message while Spelling + +// The passed pointer nlang is itself the value +void SwView::SpellError(LanguageType eLang) +{ + int nPend = 0; + + if ( m_pWrtShell->ActionPend() ) + { + m_pWrtShell->Push(); + m_pWrtShell->ClearMark(); + do + { + m_pWrtShell->EndAction(); + ++nPend; + } + while( m_pWrtShell->ActionPend() ); + } + OUString aErr(SvtLanguageTable::GetLanguageString( eLang ) ); + + SwEditWin &rEditWin = GetEditWin(); + int nWaitCnt = 0; + while( rEditWin.IsWait() ) + { + rEditWin.LeaveWait(); + ++nWaitCnt; + } + if ( LANGUAGE_NONE == eLang ) + ErrorHandler::HandleError( ERRCODE_SVX_LINGU_NOLANGUAGE ); + else + ErrorHandler::HandleError( *new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) ); + + while( nWaitCnt ) + { + rEditWin.EnterWait(); + --nWaitCnt; + } + + if ( nPend ) + { + while( nPend-- ) + m_pWrtShell->StartAction(); + m_pWrtShell->Combine(); + } +} + +// Finish spelling and restore cursor + +void SwView::SpellEnd( SwConversionArgs const *pConvArgs ) +{ + m_pWrtShell->SpellEnd( pConvArgs ); + if( m_pWrtShell->IsExtMode() ) + m_pWrtShell->SetMark(); +} + +void SwView::HyphStart( SvxSpellArea eWhich ) +{ + switch ( eWhich ) + { + case SvxSpellArea::Body: + m_pWrtShell->HyphStart( SwDocPositions::Start, SwDocPositions::End ); + break; + case SvxSpellArea::BodyEnd: + m_pWrtShell->HyphStart( SwDocPositions::Curr, SwDocPositions::End ); + break; + case SvxSpellArea::BodyStart: + m_pWrtShell->HyphStart( SwDocPositions::Start, SwDocPositions::Curr ); + break; + case SvxSpellArea::Other: + m_pWrtShell->HyphStart( SwDocPositions::OtherStart, SwDocPositions::OtherEnd ); + break; + default: + OSL_ENSURE( false, "HyphStart with unknown Area" ); + } +} + +// Interactive separation + +void SwView::HyphenateDocument() +{ + // do not hyphenate if interactive hyphenation is active elsewhere + if (SwEditShell::HasHyphIter()) + { + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetEditWin().GetFrameWeld(), + VclMessageType::Warning, VclButtonsType::Ok, SwResId(STR_MULT_INTERACT_HYPH_WARN))); + xBox->set_title(SwResId(STR_HYPH_TITLE)); + xBox->run(); + return; + } + + SfxErrorContext aContext( ERRCTX_SVX_LINGU_HYPHENATION, OUString(), m_pEditWin->GetFrameWeld(), + RID_SVXERRCTX, SvxResLocale() ); + + Reference< XHyphenator > xHyph( ::GetHyphenator() ); + if (!xHyph.is()) + { + ErrorHandler::HandleError( ERRCODE_SVX_LINGU_LINGUNOTEXISTS ); + return; + } + + if (m_pWrtShell->GetSelectionType() & (SelectionType::DrawObjectEditMode|SelectionType::DrawObject)) + { + // Hyphenation in a Draw object + HyphenateDrawText(); + } + else + { + SwViewOption* pVOpt = const_cast<SwViewOption*>(m_pWrtShell->GetViewOptions()); + bool bOldIdle = pVOpt->IsIdle(); + pVOpt->SetIdle( false ); + + Reference< XLinguProperties > xProp( ::GetLinguPropertySet() ); + + m_pWrtShell->StartUndo(SwUndoId::INSATTR); // valid later + + bool bHyphSpecial = xProp.is() && xProp->getIsHyphSpecial(); + bool bSelection = static_cast<SwCursorShell*>(m_pWrtShell.get())->HasSelection() || + m_pWrtShell->GetCursor() != m_pWrtShell->GetCursor()->GetNext(); + bool bOther = m_pWrtShell->HasOtherCnt() && bHyphSpecial && !bSelection; + bool bStart = bSelection || ( !bOther && m_pWrtShell->IsStartOfDoc() ); + bool bStop = false; + if( !bOther && !(m_pWrtShell->GetFrameType(nullptr,true) & FrameTypeFlags::BODY) && !bSelection ) + // turned on no special area + { + // I want also in special areas hyphenation + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetEditWin().GetFrameWeld(), + VclMessageType::Question, VclButtonsType::YesNo, + SwResId(STR_QUERY_SPECIAL_FORCED))); + if (xBox->run() == RET_YES) + { + bOther = true; + if (xProp.is()) + { + xProp->setIsHyphSpecial( true ); + } + } + else + bStop = true; // No hyphenation + } + + if( !bStop ) + { + SwHyphWrapper aWrap( this, xHyph, bStart, bOther, bSelection ); + aWrap.SpellDocument(); + m_pWrtShell->EndUndo(SwUndoId::INSATTR); + } + pVOpt->SetIdle( bOldIdle ); + } +} + +bool SwView::IsValidSelectionForThesaurus() const +{ + // must not be a multi-selection, and if it is a selection it needs + // to be within a single paragraph + + const bool bMultiSel = m_pWrtShell->GetCursor()->IsMultiSelection(); + const bool bSelection = static_cast<SwCursorShell*>(m_pWrtShell.get())->HasSelection(); + return !bMultiSel && (!bSelection || m_pWrtShell->IsSelOnePara() ); +} + +OUString SwView::GetThesaurusLookUpText( bool bSelection ) const +{ + return bSelection ? m_pWrtShell->GetSelText() : m_pWrtShell->GetCurWord(); +} + +void SwView::InsertThesaurusSynonym( const OUString &rSynonmText, const OUString &rLookUpText, bool bSelection ) +{ + bool bOldIns = m_pWrtShell->IsInsMode(); + m_pWrtShell->SetInsMode(); + + m_pWrtShell->StartAllAction(); + m_pWrtShell->StartUndo(SwUndoId::DELETE); + + if( !bSelection ) + { + if(m_pWrtShell->IsEndWrd()) + m_pWrtShell->Left(CRSR_SKIP_CELLS, false, 1, false ); + + m_pWrtShell->SelWrd(); + + // make sure the selection build later from the data below does not + // include "in word" character to the left and right in order to + // preserve those. Therefore count those "in words" in order to modify + // the selection accordingly. + const sal_Unicode* pChar = rLookUpText.getStr(); + sal_Int32 nLeft = 0; + while (*pChar++ == CH_TXTATR_INWORD) + ++nLeft; + pChar = rLookUpText.getLength() ? rLookUpText.getStr() + rLookUpText.getLength() - 1 : nullptr; + sal_Int32 nRight = 0; + while (pChar && *pChar-- == CH_TXTATR_INWORD) + ++nRight; + + // adjust existing selection + SwPaM *pCursor = m_pWrtShell->GetCursor(); + pCursor->GetPoint()->nContent -= nRight; + pCursor->GetMark()->nContent += nLeft; + } + + m_pWrtShell->Insert( rSynonmText ); + + m_pWrtShell->EndUndo(SwUndoId::DELETE); + m_pWrtShell->EndAllAction(); + + m_pWrtShell->SetInsMode( bOldIns ); +} + +// Start thesaurus + +void SwView::StartThesaurus() +{ + if (!IsValidSelectionForThesaurus()) + return; + + SfxErrorContext aContext( ERRCTX_SVX_LINGU_THESAURUS, OUString(), m_pEditWin->GetFrameWeld(), + RID_SVXERRCTX, SvxResLocale() ); + + // Determine language + LanguageType eLang = m_pWrtShell->GetCurLang(); + if( LANGUAGE_SYSTEM == eLang ) + eLang = GetAppLanguage(); + + if( eLang == LANGUAGE_DONTKNOW || eLang == LANGUAGE_NONE ) + { + SpellError( LANGUAGE_NONE ); + return; + } + + SwViewOption* pVOpt = const_cast<SwViewOption*>(m_pWrtShell->GetViewOptions()); + const bool bOldIdle = pVOpt->IsIdle(); + pVOpt->SetIdle( false ); + comphelper::ScopeGuard guard([&]() { pVOpt->SetIdle(bOldIdle); }); // restore when leaving scope + + // get initial LookUp text + const bool bSelection = static_cast<SwCursorShell*>(m_pWrtShell.get())->HasSelection(); + OUString aTmp = GetThesaurusLookUpText( bSelection ); + + Reference< XThesaurus > xThes( ::GetThesaurus() ); + + if ( !xThes.is() || !xThes->hasLocale( LanguageTag::convertToLocale( eLang ) ) ) + SpellError( eLang ); + else + { + VclPtr<AbstractThesaurusDialog> pDlg; + // create dialog + { //Scope for SwWait-Object + SwWait aWait( *GetDocShell(), true ); + // load library with dialog only on demand ... + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + pDlg.reset(pFact->CreateThesaurusDialog(GetEditWin().GetFrameWeld(), xThes, aTmp, eLang)); + } + + if (pDlg) + { + guard.dismiss(); // ignore, we'll call SetIdle() explicitly after the dialog ends + + pDlg->StartExecuteAsync([aTmp, bSelection, bOldIdle, pDlg, pVOpt, this](sal_Int32 nResult){ + if (nResult == RET_OK ) + InsertThesaurusSynonym(pDlg->GetWord(), aTmp, bSelection); + + pVOpt->SetIdle(bOldIdle); + pDlg->disposeOnce(); + }); + } + } +} + +// Offer online suggestions + +namespace { + +//!! Start of extra code for context menu modifying extensions +struct ExecuteInfo +{ + uno::Reference< frame::XDispatch > xDispatch; + util::URL aTargetURL; + uno::Sequence< PropertyValue > aArgs; +}; + +class AsyncExecute +{ +public: + DECL_STATIC_LINK( AsyncExecute, ExecuteHdl_Impl, void*, void ); +}; + +} + +IMPL_STATIC_LINK( AsyncExecute, ExecuteHdl_Impl, void*, p, void ) +{ + ExecuteInfo* pExecuteInfo = static_cast<ExecuteInfo*>(p); + SolarMutexReleaser aReleaser; + try + { + // Asynchronous execution as this can lead to our own destruction! + // Framework can recycle our current frame and the layout manager disposes all user interface + // elements if a component gets detached from its frame! + pExecuteInfo->xDispatch->dispatch( pExecuteInfo->aTargetURL, pExecuteInfo->aArgs ); + } + catch (const Exception&) + { + } + + delete pExecuteInfo; +} +//!! End of extra code for context menu modifying extensions + +bool SwView::ExecSpellPopup(const Point& rPt) +{ + bool bRet = false; + const SwViewOption* pVOpt = m_pWrtShell->GetViewOptions(); + if( pVOpt->IsOnlineSpell() && + !m_pWrtShell->IsSelection()) + { + if (m_pWrtShell->GetSelectionType() & SelectionType::DrawObjectEditMode) + bRet = ExecDrwTextSpellPopup(rPt); + else if (!m_pWrtShell->IsSelFrameMode()) + { + const bool bOldViewLock = m_pWrtShell->IsViewLocked(); + m_pWrtShell->LockView( true ); + m_pWrtShell->Push(); + SwRect aToFill; + + SwCursorShell *pCursorShell = m_pWrtShell.get(); + SwPaM *pCursor = pCursorShell->GetCursor(); + SwPosition aPoint(*pCursor->GetPoint()); + const SwTextNode *pNode = aPoint.nNode.GetNode().GetTextNode(); + + // Spell-check in case the idle jobs haven't had a chance to kick in. + // This makes it possible to suggest spelling corrections for + // wrong words independent of the spell-checking idle job. + if (pNode && pNode->IsWrongDirty() && + !pCursorShell->IsTableMode() && + !pCursor->HasMark() && !pCursor->IsMultiSelection()) + { + std::pair<Point, bool> const tmp(rPt, false); + SwContentFrame *const pContentFrame = pCursor->GetContentNode()->getLayoutFrame( + pCursorShell->GetLayout(), + &aPoint, &tmp); + if (pContentFrame) + { + SwRect aRepaint(static_cast<SwTextFrame*>(pContentFrame)->AutoSpell_( + *pCursor->GetContentNode()->GetTextNode(), 0)); + if (aRepaint.HasArea()) + m_pWrtShell->InvalidateWindows(aRepaint); + } + } + + // decide which variant of the context menu to use... + // if neither spell checking nor grammar checking provides suggestions use the + // default context menu. + bool bUseGrammarContext = false; + Reference< XSpellAlternatives > xAlt( m_pWrtShell->GetCorrection(&rPt, aToFill) ); + ProofreadingResult aGrammarCheckRes; + sal_Int32 nErrorInResult = -1; + uno::Sequence< OUString > aSuggestions; + bool bCorrectionRes = false; + if (!xAlt.is() || !xAlt->getAlternatives().hasElements()) + { + sal_Int32 nErrorPosInText = -1; + bCorrectionRes = m_pWrtShell->GetGrammarCorrection( aGrammarCheckRes, nErrorPosInText, nErrorInResult, aSuggestions, &rPt, aToFill ); + OUString aMessageText; + if (nErrorInResult >= 0) + aMessageText = aGrammarCheckRes.aErrors[ nErrorInResult ].aShortComment; + // we like to use the grammar checking context menu if we either get + // some suggestions or at least a comment about the error found... + bUseGrammarContext = bCorrectionRes && + (aSuggestions.hasElements() || !aMessageText.isEmpty()); + } + + // open respective context menu for spell check or grammar errors with correction suggestions... + if ((!bUseGrammarContext && xAlt.is()) || + (bUseGrammarContext && bCorrectionRes && aGrammarCheckRes.aErrors.hasElements())) + { + // get paragraph text + OUString aParaText; + if (pNode) + { + pCursorShell->Push(); + if (!pCursorShell->IsSttPara()) + { + pCursorShell->MovePara(GoCurrPara, fnParaStart); + } + pCursorShell->SetMark(); + if (!pCursorShell->IsEndPara()) + { + pCursorShell->MovePara(GoCurrPara, fnParaEnd); + } + aParaText = pCursorShell->GetSelText(); + pCursorShell->Pop(SwCursorShell::PopMode::DeleteCurrent); + } + else + { + OSL_FAIL("text node expected but not found" ); + } + + bRet = true; + m_pWrtShell->SttSelect(); + std::unique_ptr<SwSpellPopup> xPopup(bUseGrammarContext ? + new SwSpellPopup(m_pWrtShell.get(), aGrammarCheckRes, nErrorInResult, aSuggestions, aParaText) : + new SwSpellPopup(m_pWrtShell.get(), xAlt, aParaText)); + ui::ContextMenuExecuteEvent aEvent; + const Point aPixPos = GetEditWin().LogicToPixel( rPt ); + + aEvent.SourceWindow = VCLUnoHelper::GetInterface( m_pEditWin ); + aEvent.ExecutePosition.X = aPixPos.X(); + aEvent.ExecutePosition.Y = aPixPos.Y(); + css::uno::Reference<css::awt::XPopupMenu> xMenu; + + OUString sMenuName = bUseGrammarContext ? + OUString("private:resource/GrammarContextMenu") : OUString("private:resource/SpellContextMenu"); + auto xMenuInterface = xPopup->CreateMenuInterface(); + if (TryContextMenuInterception(xMenuInterface, sMenuName, xMenu, aEvent)) + { + //! happy hacking for context menu modifying extensions of this + //! 'custom made' menu... *sigh* (code copied from sfx2 and framework) + if (xMenu.is()) + { + css::uno::Reference<css::awt::XWindowPeer> xParent(aEvent.SourceWindow, css::uno::UNO_QUERY); + const sal_uInt16 nId = xMenu->execute(xParent, css::awt::Rectangle(aPixPos.X(), aPixPos.Y(), 1, 1), + css::awt::PopupMenuDirection::EXECUTE_DOWN); + OUString aCommand = xMenu->getCommand(nId); + if (aCommand.isEmpty() ) + { + if (!ExecuteMenuCommand(xMenu, *GetViewFrame(), nId)) + xPopup->Execute(nId); + } + else + { + SfxViewFrame *pSfxViewFrame = GetViewFrame(); + uno::Reference< frame::XFrame > xFrame; + if ( pSfxViewFrame ) + xFrame = pSfxViewFrame->GetFrame().GetFrameInterface(); + css::util::URL aURL; + uno::Reference< frame::XDispatchProvider > xDispatchProvider( xFrame, UNO_QUERY ); + + try + { + uno::Reference< frame::XDispatch > xDispatch; + uno::Reference< util::XURLTransformer > xURLTransformer = util::URLTransformer::create(comphelper::getProcessComponentContext()); + + aURL.Complete = aCommand; + xURLTransformer->parseStrict(aURL); + uno::Sequence< beans::PropertyValue > aArgs; + xDispatch = xDispatchProvider->queryDispatch( aURL, OUString(), 0 ); + + if (xDispatch.is()) + { + // Execute dispatch asynchronously + ExecuteInfo* pExecuteInfo = new ExecuteInfo; + pExecuteInfo->xDispatch = xDispatch; + pExecuteInfo->aTargetURL = aURL; + pExecuteInfo->aArgs = aArgs; + Application::PostUserEvent( LINK(nullptr, AsyncExecute , ExecuteHdl_Impl), pExecuteInfo ); + } + } + catch (const Exception&) + { + } + } + } + else + { + if (comphelper::LibreOfficeKit::isActive()) + { + if (SfxViewShell* pViewShell = SfxViewShell::Current()) + { + boost::property_tree::ptree aMenu = SfxDispatcher::fillPopupMenu(xMenuInterface); + boost::property_tree::ptree aRoot; + aRoot.add_child("menu", aMenu); + + std::stringstream aStream; + boost::property_tree::write_json(aStream, aRoot, true); + pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CONTEXT_MENU, aStream.str().c_str()); + } + } + else + { + xPopup->Execute(aToFill.SVRect(), m_pEditWin); + } + } + } + } + + if (!comphelper::LibreOfficeKit::isActive()) + m_pWrtShell->Pop(SwCursorShell::PopMode::DeleteCurrent); + m_pWrtShell->LockView( bOldViewLock ); + } + } + return bRet; +} + +/** Function: ExecSmartTagPopup + + This function shows the popup menu for smarttag + actions. +*/ +void SwView::ExecSmartTagPopup( const Point& rPt ) +{ + const bool bOldViewLock = m_pWrtShell->IsViewLocked(); + m_pWrtShell->LockView( true ); + m_pWrtShell->Push(); + + css::uno::Sequence< css::uno::Any > aArgs{ + css::uno::Any(comphelper::makePropertyValue( "Frame", GetDispatcher().GetFrame()->GetFrame().GetFrameInterface() )), + css::uno::Any(comphelper::makePropertyValue( "CommandURL", OUString( ".uno:OpenSmartTagMenuOnCursor" ) )) + }; + + css::uno::Reference< css::uno::XComponentContext > xContext = comphelper::getProcessComponentContext(); + css::uno::Reference< css::frame::XPopupMenuController > xPopupController( + xContext->getServiceManager()->createInstanceWithArgumentsAndContext( + "com.sun.star.comp.svx.SmartTagMenuController", aArgs, xContext ), css::uno::UNO_QUERY ); + + css::uno::Reference< css::awt::XPopupMenu > xPopupMenu( xContext->getServiceManager()->createInstanceWithContext( + "com.sun.star.awt.PopupMenu", xContext ), css::uno::UNO_QUERY ); + + if ( xPopupController.is() && xPopupMenu.is() ) + { + xPopupController->setPopupMenu( xPopupMenu ); + + SwRect aToFill; + m_pWrtShell->GetSmartTagRect( rPt, aToFill ); + m_pWrtShell->SttSelect(); + + if ( aToFill.HasArea() ) + xPopupMenu->execute( m_pEditWin->GetComponentInterface(), + VCLUnoHelper::ConvertToAWTRect( m_pEditWin->LogicToPixel( aToFill.SVRect() ) ), css::awt::PopupMenuDirection::EXECUTE_DOWN ); + + css::uno::Reference< css::lang::XComponent > xComponent( xPopupController, css::uno::UNO_QUERY ); + if ( xComponent.is() ) + xComponent->dispose(); + } + + m_pWrtShell->Pop(SwCursorShell::PopMode::DeleteCurrent); + m_pWrtShell->LockView( bOldViewLock ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/uiview/viewmdi.cxx b/sw/source/uibase/uiview/viewmdi.cxx new file mode 100644 index 000000000..abbc74387 --- /dev/null +++ b/sw/source/uibase/uiview/viewmdi.cxx @@ -0,0 +1,761 @@ +/* -*- 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 <sfx2/dispatch.hxx> +#include <sfx2/viewfrm.hxx> +#include <svx/ruler.hxx> +#include <editeng/lrspitem.hxx> +#include <o3tl/safeint.hxx> +#include <svl/srchitem.hxx> +#include <svl/stritem.hxx> +#include <sfx2/request.hxx> +#include <swmodule.hxx> +#include <view.hxx> +#include <wrtsh.hxx> +#include <viewopt.hxx> +#include <frmatr.hxx> +#include <edtwin.hxx> +#include <pagedesc.hxx> +#include <IMark.hxx> +#include <fldbas.hxx> +#include <workctrl.hxx> +#include <usrpref.hxx> +#include <scroll.hxx> +#include <wview.hxx> + +#include <cmdid.h> + +#include <PostItMgr.hxx> +#include <AnnotationWin.hxx> + +#include <svx/srchdlg.hxx> +#include <svx/svdview.hxx> + +#include <vcl/uitest/logger.hxx> +#include <vcl/uitest/eventdescription.hxx> + +sal_uInt16 SwView::s_nMoveType = NID_PGE; +sal_Int32 SwView::s_nActMark = 0; + +using namespace ::com::sun::star::uno; + +namespace { + +void collectUIInformation(const OUString& aFactor) +{ + EventDescription aDescription; + aDescription.aID = "writer_edit"; + aDescription.aParameters = {{"ZOOM", aFactor}}; + aDescription.aAction = "SET"; + aDescription.aKeyWord = "SwEditWinUIObject"; + aDescription.aParent = "MainWindow"; + UITestLogger::getInstance().logEvent(aDescription); +} + +} + +void SwView::SetZoom( SvxZoomType eZoomType, short nFactor, bool bViewOnly ) +{ + bool const bCursorIsVisible(m_pWrtShell->IsCursorVisible()); + SetZoom_( GetEditWin().GetOutputSizePixel(), eZoomType, nFactor, bViewOnly ); + // fdo#40465 force the cursor to stay in view whilst zooming + if (bCursorIsVisible) + m_pWrtShell->ShowCursor(); + + Invalidate(SID_ZOOM_IN); + Invalidate(SID_ZOOM_OUT); + + collectUIInformation(OUString::number(nFactor)); +} + +void SwView::SetZoom_( const Size &rEditSize, SvxZoomType eZoomType, + short nFactor, bool bViewOnly ) +{ + bool bUnLockView = !m_pWrtShell->IsViewLocked(); + m_pWrtShell->LockView( true ); + m_pWrtShell->LockPaint(); + + { // start of SwActContext scope + SwActContext aActContext(m_pWrtShell.get()); + + tools::Long nFac = nFactor; + + const bool bWeb = dynamic_cast< const SwWebView *>( this ) != nullptr; + SwMasterUsrPref *pUsrPref = const_cast<SwMasterUsrPref*>(SW_MOD()->GetUsrPref(bWeb)); + + const SwPageDesc &rDesc = m_pWrtShell->GetPageDesc( m_pWrtShell->GetCurPageDesc() ); + const SvxLRSpaceItem &rLRSpace = rDesc.GetMaster().GetLRSpace(); + const SwViewOption *pOpt = m_pWrtShell->GetViewOptions(); + tools::Long lLeftMargin = 0; + + if( eZoomType != SvxZoomType::PERCENT ) + { + const bool bAutomaticViewLayout = 0 == pOpt->GetViewLayoutColumns(); + + const SwRect aPageRect( m_pWrtShell->GetAnyCurRect( CurRectType::PageCalc ) ); + const SwRect aRootRect( m_pWrtShell->GetAnyCurRect( CurRectType::PagesArea ) ); + Size aPageSize( aPageRect.SSize() ); + Size aRootSize( aRootRect.SSize() ); + + //mod #i6193# added sidebar width + SwPostItMgr* pPostItMgr = GetPostItMgr(); + if (pPostItMgr->HasNotes() && pPostItMgr->ShowNotes()) + aPageSize.AdjustWidth(pPostItMgr->GetSidebarWidth() + pPostItMgr->GetSidebarBorderWidth() ); + + const MapMode aTmpMap( MapUnit::MapTwip ); + const Size aWindowSize( GetEditWin().PixelToLogic( rEditSize, aTmpMap ) ); + + if( UseOnPage::Mirror == rDesc.GetUseOn() ) // mirrored pages + { + const SvxLRSpaceItem &rLeftLRSpace = rDesc.GetLeft().GetLRSpace(); + aPageSize.AdjustWidth(std::abs( rLeftLRSpace.GetLeft() - rLRSpace.GetLeft() ) ); + } + + if( SvxZoomType::OPTIMAL == eZoomType ) + { + if (!pPostItMgr->HasNotes() || !pPostItMgr->ShowNotes()) + aPageSize.AdjustWidth( -( rLRSpace.GetLeft() + rLRSpace.GetRight() + nLeftOfst * 2 ) ); + lLeftMargin = rLRSpace.GetLeft() + DOCUMENTBORDER + nLeftOfst; + nFac = aWindowSize.Width() * 100 / aPageSize.Width(); + } + else if(SvxZoomType::WHOLEPAGE == eZoomType || SvxZoomType::PAGEWIDTH == eZoomType ) + { + const tools::Long nOf = DOCUMENTBORDER * 2; + tools::Long nTmpWidth = bAutomaticViewLayout ? aPageSize.Width() : aRootSize.Width(); + nTmpWidth += nOf; + aPageSize.AdjustHeight(nOf ); + nFac = aWindowSize.Width() * 100 / nTmpWidth; + + if ( SvxZoomType::WHOLEPAGE == eZoomType ) + { + tools::Long nVisPercent = aWindowSize.Height() * 100 / aPageSize.Height(); + nFac = std::min( nFac, nVisPercent ); + } + } + else + { + const tools::Long nTmpWidth = bAutomaticViewLayout ? aPageSize.Width() : aRootSize.Width(); + nFac = aWindowSize.Width() * 100 / nTmpWidth; + } + } + + nFac = std::max( tools::Long( MINZOOM ), nFac ); + const sal_uInt16 nZoomFac = o3tl::narrowing<sal_uInt16>(nFac); + + SwViewOption aOpt( *pOpt ); + if ( !GetViewFrame()->GetFrame().IsInPlace() ) + { + //Update MasterUsrPrefs and after that update the ViewOptions of the current View. + if ( !bViewOnly && + (nZoomFac != pUsrPref->GetZoom() || + eZoomType != pUsrPref->GetZoomType()) ) + { + pUsrPref->SetZoom(nZoomFac); + pUsrPref->SetZoomType(eZoomType); + SW_MOD()->ApplyUsrPref(*pUsrPref, nullptr); + pUsrPref->SetModified(); + } + if ( pOpt->GetZoom() != nZoomFac ) + { + aOpt.SetZoom(nZoomFac); + aOpt.SetReadonly(pOpt->IsReadonly()); + m_pWrtShell->ApplyViewOptions( aOpt ); + } + if ( eZoomType != SvxZoomType::PERCENT ) + { + Point aPos; + + if ( eZoomType == SvxZoomType::WHOLEPAGE ) + aPos.setY( m_pWrtShell->GetAnyCurRect(CurRectType::Page).Top() - DOCUMENTBORDER ); + else + { + // Make sure that the cursor is in the visible range, so that + // the scrolling will be performed only once. + aPos.setX( lLeftMargin ); + const SwRect &rCharRect = m_pWrtShell->GetCharRect(); + if ( rCharRect.Top() > GetVisArea().Bottom() || + rCharRect.Bottom() < aPos.Y() ) + aPos.setY( rCharRect.Top() - rCharRect.Height() ); + else + aPos.setY( GetVisArea().Top() ); + } + SetVisArea( aPos ); + } + // Compromise solution - Under certain circumstances SetZoom is called + // in CalcVisAreas again and thus be set wrong values. + const_cast<SwViewOption*>(m_pWrtShell->GetViewOptions())->SetZoomType( eZoomType ); + CalcVisArea( rEditSize ); // for the recalculation of the viewable area + } + else if ( nZoomFac != pOpt->GetZoom() ) + { + aOpt.SetZoom( nZoomFac ); + m_pWrtShell->ApplyViewOptions( aOpt ); + } + + const Fraction aFrac( nFac, 100 ); + m_pVRuler->SetZoom( aFrac ); + m_pVRuler->ForceUpdate(); + m_pHRuler->SetZoom( aFrac ); + m_pHRuler->ForceUpdate(); + const_cast<SwViewOption*>(m_pWrtShell->GetViewOptions())->SetZoomType( eZoomType ); + } // end of SwActContext scope + + m_pWrtShell->UnlockPaint(); + if( bUnLockView ) + m_pWrtShell->LockView( false ); +} + +void SwView::SetViewLayout( sal_uInt16 nColumns, bool bBookMode, bool bViewOnly ) +{ + const bool bUnLockView = !m_pWrtShell->IsViewLocked(); + m_pWrtShell->LockView( true ); + m_pWrtShell->LockPaint(); + + { + + SwActContext aActContext(m_pWrtShell.get()); + + if ( !GetViewFrame()->GetFrame().IsInPlace() && !bViewOnly ) + { + const bool bWeb = dynamic_cast< const SwWebView *>( this ) != nullptr; + SwMasterUsrPref *pUsrPref = const_cast<SwMasterUsrPref*>(SW_MOD()->GetUsrPref(bWeb)); + + // Update MasterUsrPrefs and after that update the ViewOptions of the current View. + if ( nColumns != pUsrPref->GetViewLayoutColumns() || + bBookMode != pUsrPref->IsViewLayoutBookMode() ) + { + pUsrPref->SetViewLayoutColumns(nColumns); + pUsrPref->SetViewLayoutBookMode(bBookMode); + SW_MOD()->ApplyUsrPref(*pUsrPref, nullptr); + pUsrPref->SetModified(); + } + } + + const SwViewOption *pOpt = m_pWrtShell->GetViewOptions(); + + if ( nColumns != pOpt->GetViewLayoutColumns() || + bBookMode != pOpt->IsViewLayoutBookMode() ) + { + SwViewOption aOpt( *pOpt ); + aOpt.SetViewLayoutColumns( nColumns ); + aOpt.SetViewLayoutBookMode( bBookMode ); + m_pWrtShell->ApplyViewOptions( aOpt ); + } + + m_pVRuler->ForceUpdate(); + m_pHRuler->ForceUpdate(); + + } + + m_pWrtShell->UnlockPaint(); + if( bUnLockView ) + m_pWrtShell->LockView( false ); + + SfxBindings& rBnd = GetViewFrame()->GetBindings(); + rBnd.Invalidate( SID_ATTR_VIEWLAYOUT ); + rBnd.Invalidate( SID_ATTR_ZOOMSLIDER); +} + +// Scrollbar - Handler + +IMPL_LINK( SwView, WindowChildEventListener, VclWindowEvent&, rEvent, void ) +{ + OSL_ENSURE( rEvent.GetWindow(), "Window???" ); + vcl::Window* pChildWin = static_cast< vcl::Window* >( rEvent.GetData() ); + + switch ( rEvent.GetId() ) + { + case VclEventId::WindowHide: + if( pChildWin == m_pHScrollbar ) + ShowHScrollbar( false ); + else if( pChildWin == m_pVScrollbar ) + ShowVScrollbar( false ); + break; + case VclEventId::WindowShow: + if( pChildWin == m_pHScrollbar ) + ShowHScrollbar( true ); + else if( pChildWin == m_pVScrollbar ) + ShowVScrollbar( true ); + break; + default: break; + } +} + +void SwView::CreateScrollbar( bool bHori ) +{ + vcl::Window *pMDI = &GetViewFrame()->GetWindow(); + VclPtr<SwScrollbar>& ppScrollbar = bHori ? m_pHScrollbar : m_pVScrollbar; + + assert(!ppScrollbar); //check beforehand! + + ppScrollbar = VclPtr<SwScrollbar>::Create( pMDI, bHori ); + UpdateScrollbars(); + if(bHori) + ppScrollbar->SetScrollHdl( LINK( this, SwView, EndScrollHdl )); + else + ppScrollbar->SetScrollHdl( LINK( this, SwView, ScrollHdl )); + ppScrollbar->SetEndScrollHdl( LINK( this, SwView, EndScrollHdl )); + + ppScrollbar->EnableDrag(); + + if(GetWindow()) + InvalidateBorder(); + + if (!m_bShowAtResize) + ppScrollbar->ExtendedShow(); +} + +IMPL_LINK( SwView, MoveNavigationHdl, void*, p, void ) +{ + bool* pbNext = static_cast<bool*>(p); + if ( !pbNext ) + return; + const bool bNext = *pbNext; + SwWrtShell& rSh = GetWrtShell(); + if ( NID_SRCH_REP != s_nMoveType) + { + if ( rSh.GetDrawView()->IsTextEdit() ) + rSh.EndTextEdit(); + if ( IsDrawMode() ) + LeaveDrawCreate(); + } + if ( NID_POSTIT != s_nMoveType && m_pPostItMgr ) + { + sw::annotation::SwAnnotationWin* pActiveSidebarWin = m_pPostItMgr->GetActiveSidebarWin(); + if (pActiveSidebarWin) + pActiveSidebarWin->SwitchToFieldPos(); + } + if (NID_RECENCY != s_nMoveType && NID_PGE != s_nMoveType && NID_SRCH_REP != s_nMoveType) + rSh.addCurrentPosition(); + switch( s_nMoveType ) + { + case NID_PGE: + { + if (USHRT_MAX == rSh.GetNextPrevPageNum(bNext)) + { + const Point aPt(GetVisArea().Left(), + rSh.GetPagePos(bNext ? 1 : rSh.GetPageCnt()).Y()); + Point aAlPt(AlignToPixel(aPt) ); + // If there is a difference, has been truncated --> then add one pixel, + // so that no residue of the previous page is visible. + if(aPt.Y() != aAlPt.Y()) + aAlPt.AdjustY(3 * GetEditWin().PixelToLogic(Size(0, 1)).Height()); + SetVisArea(aAlPt); + SvxSearchDialogWrapper::SetSearchLabel(bNext ? SearchLabel::EndWrapped : + SearchLabel::StartWrapped); + } + else + { + bNext ? PhyPageDown() : PhyPageUp(); + SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::Empty); + } + } + break; + case NID_TBL : + rSh.EnterStdMode(); + if(bNext) + rSh.MoveTable(GotoNextTable, fnTableStart); + else + rSh.MoveTable(GotoPrevTable, fnTableStart); + break; + case NID_FRM : + case NID_GRF: + case NID_OLE: + { + GotoObjFlags eType = GotoObjFlags::FlyFrame; + if(s_nMoveType == NID_GRF) + eType = GotoObjFlags::FlyGrf; + else if(s_nMoveType == NID_OLE) + eType = GotoObjFlags::FlyOLE; + bool bSuccess = bNext ? + rSh.GotoNextFly(eType) : + rSh.GotoPrevFly(eType); + if(bSuccess) + { + rSh.HideCursor(); + rSh.EnterSelFrameMode(); + } + } + break; + case NID_CTRL: + if (!rSh.GetView().IsDesignMode()) + rSh.GetView().GetFormShell()->SetDesignMode(true); + [[fallthrough]]; + case NID_DRW: + { + bool bSuccess = rSh.GotoObj(bNext, + s_nMoveType == NID_DRW ? + GotoObjFlags::DrawSimple : + GotoObjFlags::DrawControl); + if(bSuccess) + { + rSh.HideCursor(); + rSh.EnterSelFrameMode(); + } + } + break; + case NID_REG : + rSh.EnterStdMode(); + if(bNext) + rSh.MoveRegion(GotoNextRegion, fnRegionStart); + else + rSh.MoveRegion(GotoPrevRegion, fnRegionStart); + + break; + case NID_BKM : + rSh.EnterStdMode(); + GetViewFrame()->GetDispatcher()->Execute(bNext ? + FN_NEXT_BOOKMARK : + FN_PREV_BOOKMARK); + break; + case NID_FIELD: + rSh.EnterStdMode(); + rSh.MoveFieldType(nullptr, bNext, SwFieldIds::Unknown); + break; + case NID_FIELD_BYTYPE: + { + // see: SwFieldMgr::GoNextPrev + SwField* pCurField = rSh.GetCurField(true); + if (!pCurField) + break; + rSh.EnterStdMode(); + SwFieldType* pTyp = nullptr; + const SwFieldTypesEnum nTypeId = pCurField->GetTypeId(); + if (SwFieldTypesEnum::SetInput == nTypeId || SwFieldTypesEnum::UserInput == nTypeId) + pTyp = rSh.GetFieldType(0, SwFieldIds::Input); + else + pTyp = pCurField->GetTyp(); + if (pTyp) + { + if (pTyp->Which() == SwFieldIds::Database) + rSh.MoveFieldType(nullptr, bNext, SwFieldIds::Database); + else + rSh.MoveFieldType(pTyp, bNext); + } + } + break; + case NID_OUTL: + rSh.EnterStdMode(); + bNext ? rSh.GotoNextOutline() : rSh.GotoPrevOutline(); + break; + case NID_SEL : + rSh.GoNextPrevCursorSetSearchLabel(bNext); + break; + case NID_FTN: + { + bool bFrameTypeFootnote(rSh.GetFrameType(nullptr, false) & FrameTypeFlags::FOOTNOTE); + + if (bFrameTypeFootnote) + { + rSh.LockView(true); + rSh.GotoFootnoteAnchor(); + } + + rSh.EnterStdMode(); + bNext ? + rSh.GotoNextFootnoteAnchor() : + rSh.GotoPrevFootnoteAnchor(); + + if (bFrameTypeFootnote) + { + rSh.LockView(false); + rSh.GotoFootnoteText(); + } + } + break; + case NID_MARK: + { + // unselect + rSh.MoveCursor(); + rSh.EnterStdMode(); + + // collect and sort navigator reminder names + IDocumentMarkAccess* const pMarkAccess = rSh.getIDocumentMarkAccess(); + std::vector< OUString > vNavMarkNames; + for(IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getAllMarksBegin(); + ppMark != pMarkAccess->getAllMarksEnd(); + ++ppMark) + { + if( IDocumentMarkAccess::GetType(**ppMark) == IDocumentMarkAccess::MarkType::NAVIGATOR_REMINDER ) + vNavMarkNames.push_back((*ppMark)->GetName()); + } + std::sort(vNavMarkNames.begin(), vNavMarkNames.end()); + + // move + if(!vNavMarkNames.empty()) + { + SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::Empty ); + + if(bNext) + { + s_nActMark++; + if (s_nActMark >= MAX_MARKS || s_nActMark >= static_cast<sal_Int32>(vNavMarkNames.size())) + { + s_nActMark = 0; + SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::ReminderEndWrapped ); + } + } + else + { + s_nActMark--; + if (s_nActMark < 0 || o3tl::make_unsigned(s_nActMark) >= vNavMarkNames.size()) + { + s_nActMark = vNavMarkNames.size()-1; + SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::ReminderStartWrapped ); + } + } + rSh.GotoMark(vNavMarkNames[s_nActMark]); + } + else + SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound ); + } + break; + + case NID_POSTIT: + { + if (m_pPostItMgr->HasNotes()) + { + rSh.EnterStdMode(); + m_pPostItMgr->AssureStdModeAtShell(); + m_pPostItMgr->SetActiveSidebarWin(nullptr); + GetEditWin().GrabFocus(); + SwShellCursor* pCursor = rSh.GetCursor_(); + SwCursorSaveState aSaveState(*pCursor); + SwFieldType* pFieldType = rSh.GetFieldType(0, SwFieldIds::Postit); + bool bWrapped = false; + bool bFound = false; + rSh.StartAction(); + while (!bFound) + { + if (!rSh.MoveFieldType(pFieldType, bNext)) + { + if (bWrapped) + break; + bWrapped = true; + rSh.SttEndDoc(bNext); + continue; + } + do + { + auto pAnnotationWin = m_pPostItMgr->GetAnnotationWin( + rSh.GetPostItFieldAtCursor()); + if (pAnnotationWin && pAnnotationWin->IsVisible()) + bFound = true; + } while (!bFound && rSh.MoveFieldType(pFieldType, bNext)); + } + if (!bFound) + { + pCursor->RestoreSavePos(); + SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NavElementNotFound); + } + rSh.EndAction(); + if (bFound) + { + GetViewFrame()->GetDispatcher()->Execute(FN_POSTIT); + if (bWrapped) + SvxSearchDialogWrapper::SetSearchLabel(bNext ? SearchLabel::EndWrapped : + SearchLabel::StartWrapped); + else + SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::Empty); + } + } + else + SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NavElementNotFound); + } + break; + + case NID_SRCH_REP: + if(s_pSrchItem) + { + bool bBackward = s_pSrchItem->GetBackward(); + if (rSh.HasSelection() && bNext != rSh.IsCursorPtAtEnd()) + rSh.SwapPam(); + s_pSrchItem->SetBackward(!bNext); + SfxRequest aReq(FN_REPEAT_SEARCH, SfxCallMode::SLOT, GetPool()); + ExecSearch(aReq); + s_pSrchItem->SetBackward(bBackward); + } + break; + case NID_INDEX_ENTRY: + rSh.GotoNxtPrvTOXMark(bNext); + break; + + case NID_TABLE_FORMULA: + rSh.GotoNxtPrvTableFormula( bNext ); + break; + + case NID_TABLE_FORMULA_ERROR: + rSh.GotoNxtPrvTableFormula( bNext, true ); + break; + + case NID_RECENCY : + rSh.EnterStdMode(); + bNext ? rSh.GetNavigationMgr().goForward() : rSh.GetNavigationMgr().goBack(); + break; + } + if (NID_POSTIT != s_nMoveType) + m_pEditWin->GrabFocus(); + delete pbNext; +} + +void SwView::CreateTab() +{ + m_pHRuler->SetActive(GetFrame() && IsActive()); + + m_pHRuler->Show(); + InvalidateBorder(); +} + +void SwView::KillTab() +{ + m_pHRuler->Hide(); + InvalidateBorder(); +} + +void SwView::ChangeTabMetric( FieldUnit eUnit ) +{ + if(m_pHRuler->GetUnit() != eUnit ) + { + m_pHRuler->SetUnit( eUnit ); + m_pHRuler->Invalidate(); + } +} + +void SwView::ChangeVRulerMetric( FieldUnit eUnit ) +{ + if(m_pVRuler->GetUnit() != eUnit) + { + m_pVRuler->SetUnit( eUnit ); + m_pVRuler->Invalidate(); + } +} + +void SwView::GetVRulerMetric(FieldUnit& eToFill) const +{ + eToFill = m_pVRuler->GetUnit(); +} + +void SwView::GetHRulerMetric(FieldUnit& eToFill) const +{ + eToFill = m_pHRuler->GetUnit(); +} + +void SwView::CreateVRuler() +{ + m_pHRuler->SetBorderPos( m_pVRuler->GetSizePixel().Width()-1 ); + + m_pVRuler->SetActive(GetFrame() && IsActive()); + m_pVRuler->Show(); + InvalidateBorder(); +} + +void SwView::KillVRuler() +{ + m_pVRuler->Hide(); + m_pHRuler->SetBorderPos(); + InvalidateBorder(); +} + +IMPL_LINK( SwView, ExecRulerClick, Ruler *, pRuler, void ) +{ + OUString sDefPage; + sal_uInt16 nDefDlg = SID_PARA_DLG; + switch( pRuler->GetClickType() ) + { + case RulerType::DontKnow: + case RulerType::Outside: + sDefPage="labelTP_BORDER"; + break; + case RulerType::Indent: + sDefPage="labelTP_PARA_STD"; + break; + case RulerType::Margin1: + case RulerType::Margin2: + nDefDlg= FN_FORMAT_PAGE_DLG; + sDefPage = "page"; + break; + default: + sDefPage = "labelTP_TABULATOR"; + + } + + SfxStringItem aDefPage(nDefDlg, sDefPage); + GetViewFrame()->GetDispatcher()->ExecuteList(nDefDlg, + SfxCallMode::SYNCHRON|SfxCallMode::RECORD, + { &aDefPage }); +} + +sal_uInt16 SwView::GetMoveType() +{ + return s_nMoveType; +} + +void SwView::SetMoveType(sal_uInt16 nSet) +{ + s_nMoveType = nSet; +} + +void SwView::SetActMark(sal_Int32 nSet) +{ + s_nActMark = nSet; +} + +void SwView::ShowHScrollbar(bool bShow) +{ + assert(m_pHScrollbar && "Scrollbar invalid"); + m_pHScrollbar->ExtendedShow(bShow); +} + +bool SwView::IsHScrollbarVisible()const +{ + assert(m_pHScrollbar && "Scrollbar invalid"); + return m_pHScrollbar->IsVisible( false ) || m_pHScrollbar->IsAuto(); +} + +void SwView::ShowVScrollbar(bool bShow) +{ + assert(m_pVScrollbar && "Scrollbar invalid"); + m_pVScrollbar->ExtendedShow(bShow); +} + +bool SwView::IsVScrollbarVisible()const +{ + assert(m_pVScrollbar && "Scrollbar invalid"); + return m_pVScrollbar->IsVisible( false ); +} + +void SwView::EnableHScrollbar(bool bEnable) +{ + if (m_bHScrollbarEnabled != bEnable) + { + m_bHScrollbarEnabled = bEnable; + InvalidateBorder(); + } +} + +void SwView::EnableVScrollbar(bool bEnable) +{ + if (m_bVScrollbarEnabled != bEnable) + { + m_bVScrollbarEnabled = bEnable; + InvalidateBorder(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/uiview/viewport.cxx b/sw/source/uibase/uiview/viewport.cxx new file mode 100644 index 000000000..af80d856d --- /dev/null +++ b/sw/source/uibase/uiview/viewport.cxx @@ -0,0 +1,1241 @@ +/* -*- 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 <vcl/commandevent.hxx> +#include <vcl/help.hxx> +#include <vcl/settings.hxx> +#include <vcl/syswin.hxx> + +#include <svx/ruler.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/viewfrm.hxx> +#include <view.hxx> +#include <wrtsh.hxx> +#include <viewopt.hxx> +#include <docsh.hxx> +#include <cmdid.h> +#include <edtwin.hxx> +#include <scroll.hxx> + +#include <PostItMgr.hxx> + +#include <basegfx/utils/zoomtools.hxx> +#include <comphelper/lok.hxx> +#include <vcl/weld.hxx> +#include <tools/svborder.hxx> +#include <osl/diagnose.h> + +#include "viewfunc.hxx" + +#include <FrameControlsManager.hxx> + +// The SetVisArea of the DocShell must not be called from InnerResizePixel. +// But our adjustments must take place. +static bool bProtectDocShellVisArea = false; + +static sal_uInt16 nPgNum = 0; + +bool SwView::IsDocumentBorder() +{ + if (GetDocShell()->GetCreateMode() == SfxObjectCreateMode::EMBEDDED) + return true; + + if (!m_pWrtShell) + return false; + + return m_pWrtShell->GetViewOptions()->getBrowseMode() || + SvxZoomType::PAGEWIDTH_NOBORDER == m_pWrtShell->GetViewOptions()->GetZoomType(); +} + +static tools::Long GetLeftMargin( SwView const &rView ) +{ + SvxZoomType eType = rView.GetWrtShell().GetViewOptions()->GetZoomType(); + tools::Long lRet = rView.GetWrtShell().GetAnyCurRect(CurRectType::PagePrt).Left(); + return eType == SvxZoomType::PERCENT ? lRet + DOCUMENTBORDER : + eType == SvxZoomType::PAGEWIDTH || eType == SvxZoomType::PAGEWIDTH_NOBORDER ? 0 : + lRet + DOCUMENTBORDER + nLeftOfst; +} + +static void lcl_GetPos(SwView const * pView, + Point& rPos, + SwScrollbar const * pScrollbar, + bool bBorder) +{ + SwWrtShell &rSh = pView->GetWrtShell(); + const Size aDocSz( rSh.GetDocSize() ); + + const tools::Long lBorder = bBorder ? DOCUMENTBORDER : DOCUMENTBORDER * 2; + const bool bHori = pScrollbar->IsHoriScroll(); + + const tools::Long lPos = pScrollbar->GetThumbPos() + (bBorder ? DOCUMENTBORDER : 0); + + tools::Long lDelta = lPos - (bHori ? rSh.VisArea().Pos().X() : rSh.VisArea().Pos().Y()); + + const tools::Long lSize = (bHori ? aDocSz.Width() : aDocSz.Height()) + lBorder; + // Should right or below are too much space, + // then they must be subtracted out of the VisArea! + tools::Long nTmp = pView->GetVisArea().Right()+lDelta; + if ( bHori && nTmp > lSize ) + lDelta -= nTmp - lSize; + nTmp = pView->GetVisArea().Bottom()+lDelta; + if ( !bHori && nTmp > lSize ) + lDelta -= nTmp - lSize; + + bHori ? rPos.AdjustX(lDelta) : rPos.AdjustY(lDelta); + if ( bBorder && (bHori ? rPos.X() : rPos.Y()) < DOCUMENTBORDER ) + bHori ? rPos.setX(DOCUMENTBORDER) : rPos.setY(DOCUMENTBORDER); +} + +// Set zero ruler + +void SwView::InvalidateRulerPos() +{ + static sal_uInt16 aInval[] = + { + SID_ATTR_PARA_LRSPACE, SID_RULER_BORDERS, SID_RULER_PAGE_POS, + SID_RULER_LR_MIN_MAX, SID_ATTR_LONG_ULSPACE, SID_ATTR_LONG_LRSPACE, + SID_RULER_BORDER_DISTANCE, + SID_ATTR_PARA_LRSPACE_VERTICAL, SID_RULER_BORDERS_VERTICAL, + SID_RULER_TEXT_RIGHT_TO_LEFT, + SID_RULER_ROWS, SID_RULER_ROWS_VERTICAL, FN_STAT_PAGE, + 0 + }; + + GetViewFrame()->GetBindings().Invalidate(aInval); + + assert(m_pHRuler && "Why is the ruler not there?"); + m_pHRuler->ForceUpdate(); + m_pVRuler->ForceUpdate(); +} + +// Limits the scrolling so far that only a quarter of the +// screen can be scrolled up before the end of the document. + +tools::Long SwView::SetHScrollMax( tools::Long lMax ) +{ + const tools::Long lBorder = IsDocumentBorder() ? DOCUMENTBORDER : DOCUMENTBORDER * 2; + const tools::Long lSize = GetDocSz().Width() + lBorder - m_aVisArea.GetWidth(); + + // At negative values the document is completely visible. + // In this case, no scrolling. + return std::clamp( lSize, tools::Long(0), lMax ); +} + +tools::Long SwView::SetVScrollMax( tools::Long lMax ) +{ + const tools::Long lBorder = IsDocumentBorder() ? DOCUMENTBORDER : DOCUMENTBORDER * 2; + tools::Long lSize = GetDocSz().Height() + lBorder - m_aVisArea.GetHeight(); + return std::clamp( lSize, tools::Long(0), lMax ); // see horizontal +} + +Point SwView::AlignToPixel(const Point &rPt) const +{ + return GetEditWin().PixelToLogic( GetEditWin().LogicToPixel( rPt ) ); +} + +// Document size has changed. + +void SwView::DocSzChgd(const Size &rSz) +{ + m_aDocSz = rSz; + + if( !m_pWrtShell || m_aVisArea.IsEmpty() ) // no shell -> no change + { + bDocSzUpdated = false; + return; + } + + //If text has been deleted, it may be that the VisArea points behind the visible range. + tools::Rectangle aNewVisArea( m_aVisArea ); + bool bModified = false; + SwTwips lGreenOffset = IsDocumentBorder() ? DOCUMENTBORDER : DOCUMENTBORDER * 2; + SwTwips lTmp = m_aDocSz.Width() + lGreenOffset; + + if ( aNewVisArea.Right() >= lTmp ) + { + lTmp = aNewVisArea.Right() - lTmp; + aNewVisArea.AdjustRight( -lTmp ); + aNewVisArea.AdjustLeft( -lTmp ); + bModified = true; + } + + lTmp = m_aDocSz.Height() + lGreenOffset; + if ( aNewVisArea.Bottom() >= lTmp ) + { + lTmp = aNewVisArea.Bottom() - lTmp; + aNewVisArea.AdjustBottom( -lTmp ); + aNewVisArea.AdjustTop( -lTmp ); + bModified = true; + } + + if ( bModified ) + SetVisArea( aNewVisArea, false ); + + if ( UpdateScrollbars() && !m_bInOuterResizePixel && !m_bInInnerResizePixel && + !GetViewFrame()->GetFrame().IsInPlace()) + OuterResizePixel( Point(), + GetViewFrame()->GetWindow().GetOutputSizePixel() ); +} + +// Set VisArea newly + +void SwView::SetVisArea( const tools::Rectangle &rRect, bool bUpdateScrollbar ) +{ + Size aOldSz( m_aVisArea.GetSize() ); + if (comphelper::LibreOfficeKit::isActive() && m_pWrtShell) + // If m_pWrtShell's visible area is the whole document, do the same here. + aOldSz = m_pWrtShell->VisArea().SSize(); + + if( rRect == m_aVisArea ) + return; + + const SwTwips lMin = IsDocumentBorder() ? DOCUMENTBORDER : 0; + + // No negative position, no negative size + tools::Rectangle aLR = rRect; + if( aLR.Top() < lMin ) + { + aLR.AdjustBottom(lMin - aLR.Top() ); + aLR.SetTop( lMin ); + } + if( aLR.Left() < lMin ) + { + aLR.AdjustRight(lMin - aLR.Left() ); + aLR.SetLeft( lMin ); + } + if( aLR.Right() < 0 ) + aLR.SetRight( 0 ); + if( aLR.Bottom() < 0 ) + aLR.SetBottom( 0 ); + + if( aLR == m_aVisArea ) + return; + + const Size aSize( aLR.GetSize() ); + if( aSize.IsEmpty() ) + return; + + // Before the data can be changed, call an update if necessary. This + // ensures that adjacent Paints in document coordinates are converted + // correctly. + // As a precaution, we do this only when an action is running in the + // shell, because then it is not really drawn but the rectangles will + // be only marked (in document coordinates). + if ( m_pWrtShell && m_pWrtShell->ActionPend() ) + m_pWrtShell->GetWin()->PaintImmediately(); + + m_aVisArea = aLR; + + const bool bOuterResize = bUpdateScrollbar && UpdateScrollbars(); + + if ( m_pWrtShell ) + { + m_pWrtShell->VisPortChgd( SwRect(m_aVisArea) ); + if ( aOldSz != m_pWrtShell->VisArea().SSize() && + ( std::abs(aOldSz.Width() - m_pWrtShell->VisArea().Width()) > 2 || + std::abs(aOldSz.Height() - m_pWrtShell->VisArea().Height()) > 2 ) ) + m_pWrtShell->InvalidateLayout( false ); + } + + if ( !bProtectDocShellVisArea ) + { + // If the size of VisArea is unchanged, we extend the size of the VisArea + // InternalObject on. By that the transport of errors shall be avoided. + tools::Rectangle aVis( m_aVisArea ); + if ( aVis.GetSize() == aOldSz ) + aVis.SetSize( GetDocShell()->SfxObjectShell::GetVisArea(ASPECT_CONTENT).GetSize() ); + // TODO/LATER: why casting?! + //GetDocShell()->SfxInPlaceObject::GetVisArea().GetSize() ); + + // With embedded always with modify... + // TODO/LATER: why casting?! + GetDocShell()->SfxObjectShell::SetVisArea( aVis ); + /* + if ( GetDocShell()->GetCreateMode() == SfxObjectCreateMode::EMBEDDED ) + GetDocShell()->SfxInPlaceObject::SetVisArea( aVis ); + else + GetDocShell()->SvEmbeddedObject::SetVisArea( aVis );*/ + } + + SfxViewShell::VisAreaChanged(); + + InvalidateRulerPos(); + + if ( bOuterResize && !m_bInOuterResizePixel && !m_bInInnerResizePixel) + OuterResizePixel( Point(), + GetViewFrame()->GetWindow().GetOutputSizePixel() ); +} + +// Set Pos VisArea + +void SwView::SetVisArea( const Point &rPt, bool bUpdateScrollbar ) +{ + // Align once, so brushes will be inserted correctly. + // This goes wrong in the BrowseView, because the entire document may + // not be visible. Since the content in frames is fitting exactly, + // align is not possible (better idea?!?!) + // (fix: Bild.de, 200%) It does not work completely without alignment + // Let's see how far we get with half BrushSize. + Point aPt = GetEditWin().LogicToPixel( rPt ); +#if HAVE_FEATURE_DESKTOP + const tools::Long nTmp = GetWrtShell().IsFrameView() ? 4 : 8; + aPt.AdjustX( -(aPt.X() % nTmp) ); + aPt.AdjustY( -(aPt.Y() % nTmp) ); +#endif + aPt = GetEditWin().PixelToLogic( aPt ); + + if ( aPt == m_aVisArea.TopLeft() ) + return; + + if (m_pWrtShell && m_pWrtShell->GetViewOptions()->IsShowOutlineContentVisibilityButton()) + GetEditWin().GetFrameControlsManager().HideControls(FrameControlType::Outline); + + const tools::Long lXDiff = m_aVisArea.Left() - aPt.X(); + const tools::Long lYDiff = m_aVisArea.Top() - aPt.Y(); + SetVisArea( tools::Rectangle( aPt, + Point( m_aVisArea.Right() - lXDiff, m_aVisArea.Bottom() - lYDiff ) ), + bUpdateScrollbar); +} + +void SwView::CheckVisArea() +{ + m_pHScrollbar->SetAuto( m_pWrtShell->GetViewOptions()->getBrowseMode() && + !GetViewFrame()->GetFrame().IsInPlace() ); + if ( IsDocumentBorder() ) + { + if ( m_aVisArea.Left() != DOCUMENTBORDER || + m_aVisArea.Top() != DOCUMENTBORDER ) + { + tools::Rectangle aNewVisArea( m_aVisArea ); + aNewVisArea.Move( DOCUMENTBORDER - m_aVisArea.Left(), + DOCUMENTBORDER - m_aVisArea.Top() ); + SetVisArea( aNewVisArea ); + } + } +} + +/// Calculate the visible range. + +// OUT Point *pPt: new position of the visible area + +// IN Rectangle &rRect: Rectangle, which should be located +// within the new visible area. +// sal_uInt16 nRange optional accurate indication of the +// range by which to scroll if necessary. + +void SwView::CalcPt( Point *pPt, const tools::Rectangle &rRect, + sal_uInt16 nRangeX, sal_uInt16 nRangeY) +{ + + const SwTwips lMin = IsDocumentBorder() ? DOCUMENTBORDER : 0; + + tools::Long nYScroll = GetYScroll(); + tools::Long nDesHeight = rRect.GetHeight(); + tools::Long nCurHeight = m_aVisArea.GetHeight(); + nYScroll = std::min(nYScroll, nCurHeight - nDesHeight); // If it is scarce, then scroll not too much. + if(nDesHeight > nCurHeight) // the height is not sufficient, then nYScroll is no longer of interest + { + pPt->setY( rRect.Top() ); + pPt->setY( std::max( lMin, SwTwips(pPt->Y()) ) ); + } + else if ( rRect.Top() < m_aVisArea.Top() ) // Upward shift + { + pPt->setY( rRect.Top() - (nRangeY != USHRT_MAX ? nRangeY : nYScroll) ); + pPt->setY( std::max( lMin, SwTwips(pPt->Y()) ) ); + } + else if( rRect.Bottom() > m_aVisArea.Bottom() ) // Downward shift + { + pPt->setY( rRect.Bottom() - + (m_aVisArea.GetHeight()) + ( nRangeY != USHRT_MAX ? + nRangeY : nYScroll ) ); + pPt->setY( SetVScrollMax( pPt->Y() ) ); + } + tools::Long nXScroll = GetXScroll(); + if ( rRect.Right() > m_aVisArea.Right() ) // Shift right + { + pPt->setX( rRect.Right() - + (m_aVisArea.GetWidth()) + + (nRangeX != USHRT_MAX ? nRangeX : nXScroll) ); + pPt->setX( SetHScrollMax( pPt->X() ) ); + } + else if ( rRect.Left() < m_aVisArea.Left() ) // Shift left + { + pPt->setX( rRect.Left() - (nRangeX != USHRT_MAX ? nRangeX : nXScroll) ); + pPt->setX( std::max( ::GetLeftMargin( *this ) + nLeftOfst, pPt->X() ) ); + pPt->setX( std::min( rRect.Left() - nScrollX, pPt->X() ) ); + pPt->setX( std::max( tools::Long(0), pPt->X() ) ); + } +} + +// Scrolling + +bool SwView::IsScroll( const tools::Rectangle &rRect ) const +{ + return m_bCenterCursor || m_bTopCursor || !m_aVisArea.Contains(rRect); +} + +void SwView::Scroll( const tools::Rectangle &rRect, sal_uInt16 nRangeX, sal_uInt16 nRangeY ) +{ + if ( m_aVisArea.IsEmpty() ) + return; + + tools::Rectangle aOldVisArea( m_aVisArea ); + tools::Long nDiffY = 0; + + weld::Window* pCareDialog = SwViewShell::GetCareDialog(GetWrtShell()); + if (pCareDialog) + { + int x, y, width, height; + tools::Rectangle aDlgRect; + if (pCareDialog->get_extents_relative_to(*GetEditWin().GetFrameWeld(), x, y, width, height)) + { + Point aTopLeft(GetEditWin().GetSystemWindow()->OutputToAbsoluteScreenPixel(Point(x, y))); + aTopLeft = GetEditWin().AbsoluteScreenToOutputPixel(aTopLeft); + aDlgRect = GetEditWin().PixelToLogic(tools::Rectangle(aTopLeft, Size(width, height))); + } + + // Only if the dialogue is not the VisArea right or left: + if ( aDlgRect.Left() < m_aVisArea.Right() && + aDlgRect.Right() > m_aVisArea.Left() ) + { + // If we are not supposed to be centered, lying in the VisArea + // and are not covered by the dialogue ... + if ( !m_bCenterCursor && aOldVisArea.Contains( rRect ) + && ( rRect.Left() > aDlgRect.Right() + || rRect.Right() < aDlgRect.Left() + || rRect.Top() > aDlgRect.Bottom() + || rRect.Bottom() < aDlgRect.Top() ) ) + return; + + // Is above or below the dialogue more space? + tools::Long nTopDiff = aDlgRect.Top() - m_aVisArea.Top(); + tools::Long nBottomDiff = m_aVisArea.Bottom() - aDlgRect.Bottom(); + if ( nTopDiff < nBottomDiff ) + { + if ( nBottomDiff > 0 ) // Is there room below at all? + { // then we move the upper edge and we remember this + nDiffY = aDlgRect.Bottom() - m_aVisArea.Top(); + m_aVisArea.AdjustTop(nDiffY ); + } + } + else + { + if ( nTopDiff > 0 ) // Is there room below at all? + m_aVisArea.SetBottom( aDlgRect.Top() ); // Modify the lower edge + } + } + } + + //s.o. !IsScroll() + if( !(m_bCenterCursor || m_bTopCursor) && m_aVisArea.Contains( rRect ) ) + { + m_aVisArea = aOldVisArea; + return; + } + // If the rectangle is larger than the visible area --> + // upper left corner + Size aSize( rRect.GetSize() ); + const Size aVisSize( m_aVisArea.GetSize() ); + if( !m_aVisArea.IsEmpty() && ( + aSize.Width() + GetXScroll() > aVisSize.Width() || + aSize.Height()+ GetYScroll() > aVisSize.Height() )) + { + Point aPt( m_aVisArea.TopLeft() ); + aSize.setWidth( std::min( aSize.Width(), aVisSize.Width() ) ); + aSize.setHeight( std::min( aSize.Height(),aVisSize.Height()) ); + + CalcPt( &aPt, tools::Rectangle( rRect.TopLeft(), aSize ), + static_cast< sal_uInt16 >((aVisSize.Width() - aSize.Width()) / 2), + static_cast< sal_uInt16 >((aVisSize.Height()- aSize.Height())/ 2) ); + + if( m_bTopCursor ) + { + const tools::Long nBorder = IsDocumentBorder() ? DOCUMENTBORDER : 0; + aPt.setY( std::min( std::max( nBorder, rRect.Top() ), + m_aDocSz.Height() + nBorder - + m_aVisArea.GetHeight() ) ); + } + aPt.AdjustY( -nDiffY ); + m_aVisArea = aOldVisArea; + SetVisArea( aPt ); + return; + } + if( !m_bCenterCursor ) + { + Point aPt( m_aVisArea.TopLeft() ); + CalcPt( &aPt, rRect, nRangeX, nRangeY ); + + if( m_bTopCursor ) + { + const tools::Long nBorder = IsDocumentBorder() ? DOCUMENTBORDER : 0; + aPt.setY( std::min( std::max( nBorder, rRect.Top() ), + m_aDocSz.Height() + nBorder - + m_aVisArea.GetHeight() ) ); + } + + aPt.AdjustY( -nDiffY ); + m_aVisArea = aOldVisArea; + SetVisArea( aPt ); + return; + } + + //Center cursor + Point aPnt( m_aVisArea.TopLeft() ); + // ... in Y-direction in any case + aPnt.AdjustY(( rRect.Top() + rRect.Bottom() + - m_aVisArea.Top() - m_aVisArea.Bottom() ) / 2 - nDiffY ); + // ... in X-direction, only if the rectangle protrudes over the right or left of the VisArea. + if ( rRect.Right() > m_aVisArea.Right() || rRect.Left() < m_aVisArea.Left() ) + { + aPnt.AdjustX(( rRect.Left() + rRect.Right() + - m_aVisArea.Left() - m_aVisArea.Right() ) / 2 ); + aPnt.setX( SetHScrollMax( aPnt.X() ) ); + const SwTwips lMin = IsDocumentBorder() ? DOCUMENTBORDER : 0; + aPnt.setX( std::max( (GetLeftMargin( *this ) - lMin) + nLeftOfst, aPnt.X() ) ); + } + m_aVisArea = aOldVisArea; + if (pCareDialog) + { + // If we want to avoid only a dialogue, we do + // not want to go beyond the end of the document. + aPnt.setY( SetVScrollMax( aPnt.Y() ) ); + } + SetVisArea( aPnt ); +} + +/// Scroll page by page +// Returns the value by which to be scrolled with PageUp / Down + +bool SwView::GetPageScrollUpOffset( SwTwips &rOff ) const +{ + // in the LOK case, force the value set by the API + if (comphelper::LibreOfficeKit::isActive() && m_nLOKPageUpDownOffset > 0) + { + rOff = -m_nLOKPageUpDownOffset; + return true; + } + + if ( !m_aVisArea.Top() || !m_aVisArea.GetHeight() ) + return false; + tools::Long nYScrl = GetYScroll() / 2; + rOff = -(m_aVisArea.GetHeight() - nYScrl); + // Do not scroll before the beginning of the document. + if( m_aVisArea.Top() - rOff < 0 ) + rOff = rOff - m_aVisArea.Top(); + else if( GetWrtShell().GetCharRect().Top() < (m_aVisArea.Top() + nYScrl)) + rOff += nYScrl; + + return true; +} + +bool SwView::GetPageScrollDownOffset( SwTwips &rOff ) const +{ + // in the LOK case, force the value set by the API + if (comphelper::LibreOfficeKit::isActive() && m_nLOKPageUpDownOffset > 0) + { + rOff = m_nLOKPageUpDownOffset; + return true; + } + + if ( !m_aVisArea.GetHeight() || + (m_aVisArea.GetHeight() > m_aDocSz.Height()) ) + return false; + tools::Long nYScrl = GetYScroll() / 2; + rOff = m_aVisArea.GetHeight() - nYScrl; + // Do not scroll past the end of the document. + if ( m_aVisArea.Top() + rOff > m_aDocSz.Height() ) + rOff = m_aDocSz.Height() - m_aVisArea.Bottom(); + else if( GetWrtShell().GetCharRect().Bottom() > + ( m_aVisArea.Bottom() - nYScrl )) + rOff -= nYScrl; + + return rOff > 0; +} + +// Scroll page by page +bool SwView::PageUp() +{ + if (!m_aVisArea.GetHeight()) + return false; + + Point aPos(m_aVisArea.TopLeft()); + aPos.AdjustY( -(m_aVisArea.GetHeight() - (GetYScroll() / 2)) ); + aPos.setY( std::max(tools::Long(0), aPos.Y()) ); + SetVisArea( aPos ); + return true; +} + +bool SwView::PageDown() +{ + if ( !m_aVisArea.GetHeight() ) + return false; + Point aPos( m_aVisArea.TopLeft() ); + aPos.AdjustY(m_aVisArea.GetHeight() - (GetYScroll() / 2) ); + aPos.setY( SetVScrollMax( aPos.Y() ) ); + SetVisArea( aPos ); + return true; +} + +void SwView::PhyPageUp() +{ + // Check for the currently visible page, do not format + sal_uInt16 nActPage = m_pWrtShell->GetNextPrevPageNum( false ); + + if( USHRT_MAX != nActPage ) + { + const Point aPt( m_aVisArea.Left(), + m_pWrtShell->GetPagePos( nActPage ).Y() ); + Point aAlPt( AlignToPixel( aPt ) ); + // If there is a difference, has been truncated --> then add one pixel, + // so that no residue of the previous page is visible. + if( aPt.Y() != aAlPt.Y() ) + aAlPt.AdjustY(3 * GetEditWin().PixelToLogic( Size( 0, 1 ) ).Height() ); + SetVisArea( aAlPt ); + } +} + +void SwView::PhyPageDown() +{ + // Check for the currently visible page, do not format + sal_uInt16 nActPage = m_pWrtShell->GetNextPrevPageNum(); + // If the last page of the document is visible, do nothing. + if( USHRT_MAX != nActPage ) + { + const Point aPt( m_aVisArea.Left(), + m_pWrtShell->GetPagePos( nActPage ).Y() ); + Point aAlPt( AlignToPixel( aPt ) ); + // If there is a difference, has been truncated --> then add one pixel, + // so that no residue of the previous page is visible. + if( aPt.Y() != aAlPt.Y() ) + aAlPt.AdjustY(3 * GetEditWin().PixelToLogic( Size( 0, 1 ) ).Height() ); + SetVisArea( aAlPt ); + } +} + +bool SwView::PageUpCursor( bool bSelect ) +{ + if ( !bSelect ) + { + const FrameTypeFlags eType = m_pWrtShell->GetFrameType(nullptr,true); + if ( eType & FrameTypeFlags::FOOTNOTE ) + { + m_pWrtShell->MoveCursor(); + m_pWrtShell->GotoFootnoteAnchor(); + m_pWrtShell->Right(CRSR_SKIP_CHARS, false, 1, false ); + return true; + } + } + + SwTwips lOff = 0; + if ( GetPageScrollUpOffset( lOff ) && + (m_pWrtShell->IsCursorReadonly() || + !m_pWrtShell->PageCursor( lOff, bSelect )) && + PageUp() ) + { + m_pWrtShell->ResetCursorStack(); + return true; + } + return false; +} + +bool SwView::PageDownCursor(bool bSelect) +{ + SwTwips lOff = 0; + if ( GetPageScrollDownOffset( lOff ) && + (m_pWrtShell->IsCursorReadonly() || + !m_pWrtShell->PageCursor( lOff, bSelect )) && + PageDown() ) + { + m_pWrtShell->ResetCursorStack(); + return true; + } + return false; +} + +// Handler of the scrollbars + +IMPL_LINK( SwView, ScrollHdl, ScrollBar *, p, void ) +{ + SwScrollbar* pScrollbar = static_cast<SwScrollbar*>(p); + if ( GetWrtShell().ActionPend() ) + return; + + if ( pScrollbar->GetType() == ScrollType::Drag ) + m_pWrtShell->EnableSmooth( false ); + + if(!m_pWrtShell->GetViewOptions()->getBrowseMode() && + pScrollbar->GetType() == ScrollType::Drag) + { + // Here comment out again if it is not desired to scroll together: + // The end scrollhandler invalidate the FN_STAT_PAGE, + // so we don't must do it again. + EndScrollHdl(pScrollbar); + + if ( !m_bWheelScrollInProgress && Help::IsQuickHelpEnabled() && + m_pWrtShell->GetViewOptions()->IsShowScrollBarTips()) + { + + Point aPos( m_aVisArea.TopLeft() ); + lcl_GetPos(this, aPos, pScrollbar, IsDocumentBorder()); + + sal_uInt16 nPhNum = 1; + sal_uInt16 nVirtNum = 1; + + OUString sDisplay; + if(m_pWrtShell->GetPageNumber( aPos.Y(), false, nPhNum, nVirtNum, sDisplay )) + { + // The end scrollhandler invalidate the FN_STAT_PAGE, + // so we don't must do it again. + // if(!GetViewFrame()->GetFrame().IsInPlace()) + // S F X_BINDINGS().Update(FN_STAT_PAGE); + + //QuickHelp: + if( m_pWrtShell->GetPageCnt() > 1 ) + { + tools::Rectangle aRect; + aRect.SetLeft( pScrollbar->GetParent()->OutputToScreenPixel( + pScrollbar->GetPosPixel() ).X() -8 ); + aRect.SetTop( pScrollbar->OutputToScreenPixel( + pScrollbar->GetPointerPosPixel() ).Y() ); + aRect.SetRight( aRect.Left() ); + aRect.SetBottom( aRect.Top() ); + + OUString sPageStr( GetPageStr( nPhNum, nVirtNum, sDisplay )); + SwContentAtPos aCnt( IsAttrAtPos::Outline ); + bool bSuccess = m_pWrtShell->GetContentAtPos(aPos, aCnt); + if (bSuccess && !aCnt.sStr.isEmpty()) + { + sPageStr += " - "; + sal_Int32 nChunkLen = std::min<sal_Int32>(aCnt.sStr.getLength(), 80); + std::u16string_view sChunk = aCnt.sStr.subView(0, nChunkLen); + sPageStr = sChunk + sPageStr; + sPageStr = sPageStr.replace('\t', ' '); + sPageStr = sPageStr.replace(0x0a, ' '); + } + nPgNum = nPhNum; + } + } + } + } + else + EndScrollHdl(pScrollbar); + + if ( pScrollbar->GetType() == ScrollType::Drag ) + m_pWrtShell->EnableSmooth( true ); +} + +// Handler of the scrollbars + +IMPL_LINK( SwView, EndScrollHdl, ScrollBar *, p, void ) +{ + SwScrollbar* pScrollbar = static_cast<SwScrollbar*>(p); + if ( GetWrtShell().ActionPend() ) + return; + + if(nPgNum) + { + nPgNum = 0; + Help::ShowQuickHelp(pScrollbar, tools::Rectangle(), OUString()); + } + Point aPos( m_aVisArea.TopLeft() ); + bool bBorder = IsDocumentBorder(); + lcl_GetPos(this, aPos, pScrollbar, bBorder); + if ( bBorder && aPos == m_aVisArea.TopLeft() ) + UpdateScrollbars(); + else + SetVisArea( aPos, false ); + + GetViewFrame()->GetBindings().Update(FN_STAT_PAGE); +} + +// Calculates the size of the m_aVisArea in dependency of the size of +// EditWin on the screen. + +void SwView::CalcVisArea( const Size &rOutPixel ) +{ + Point aTopLeft; + tools::Rectangle aRect( aTopLeft, rOutPixel ); + aTopLeft = GetEditWin().PixelToLogic( aTopLeft ); + Point aBottomRight( GetEditWin().PixelToLogic( aRect.BottomRight() ) ); + + aRect.SetLeft( aTopLeft.X() ); + aRect.SetTop( aTopLeft.Y() ); + aRect.SetRight( aBottomRight.X() ); + aRect.SetBottom( aBottomRight.Y() ); + + // The shifts to the right and/or below can now be incorrect + // (e.g. change zoom level, change view size). + const tools::Long lBorder = IsDocumentBorder() ? DOCUMENTBORDER : DOCUMENTBORDER*2; + if ( aRect.Left() ) + { + const tools::Long lWidth = GetWrtShell().GetDocSize().Width() + lBorder; + if ( aRect.Right() > lWidth ) + { + tools::Long lDelta = aRect.Right() - lWidth; + aRect.AdjustLeft( -lDelta ); + aRect.AdjustRight( -lDelta ); + } + } + if ( aRect.Top() ) + { + const tools::Long lHeight = GetWrtShell().GetDocSize().Height() + lBorder; + if ( aRect.Bottom() > lHeight ) + { + tools::Long lDelta = aRect.Bottom() - lHeight; + aRect.AdjustTop( -lDelta ); + aRect.AdjustBottom( -lDelta ); + } + } + SetVisArea( aRect ); + GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOM ); + GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER ); // for snapping points +} + +// Rearrange control elements + +void SwView::CalcAndSetBorderPixel( SvBorder &rToFill ) +{ + bool bRightVRuler = m_pWrtShell->GetViewOptions()->IsVRulerRight(); + if ( m_pVRuler->IsVisible() ) + { + tools::Long nWidth = m_pVRuler->GetSizePixel().Width(); + if(bRightVRuler) + rToFill.Right() = nWidth; + else + rToFill.Left() = nWidth; + } + + OSL_ENSURE(m_pHRuler, "Why is the ruler not present?"); + if ( m_pHRuler->IsVisible() ) + rToFill.Top() = m_pHRuler->GetSizePixel().Height(); + + const StyleSettings &rSet = GetEditWin().GetSettings().GetStyleSettings(); + const tools::Long nTmp = rSet.GetScrollBarSize(); + if( m_pVScrollbar->IsVisible(true) ) + { + if(bRightVRuler) + rToFill.Left() = nTmp; + else + rToFill.Right() = nTmp; + } + if ( m_pHScrollbar->IsVisible(true) ) + rToFill.Bottom() = nTmp; + + SetBorderPixel( rToFill ); +} + +void ViewResizePixel( const vcl::RenderContext &rRef, + const Point &rOfst, + const Size &rSize, + const Size &rEditSz, + SwScrollbar& rVScrollbar, + SwScrollbar& rHScrollbar, + vcl::Window& rScrollBarBox, + SvxRuler* pVRuler, + SvxRuler* pHRuler, + bool bVRulerRight ) +{ +// ViewResizePixel is also used by Preview!!! + + const bool bHRuler = pHRuler && pHRuler->IsVisible(); + const tools::Long nHLinSzHeight = bHRuler ? + pHRuler->GetSizePixel().Height() : 0; + const bool bVRuler = pVRuler && pVRuler->IsVisible(); + const tools::Long nVLinSzWidth = bVRuler ? + pVRuler->GetSizePixel().Width() : 0; + + const tools::Long nScrollBarSize = rRef.GetSettings().GetStyleSettings().GetScrollBarSize(); + const tools::Long nHBSzHeight = rHScrollbar.IsVisible(true) ? nScrollBarSize : 0; + const tools::Long nVBSzWidth = rVScrollbar.IsVisible(true) ? nScrollBarSize : 0; + + if(pVRuler) + { + WinBits nStyle = pVRuler->GetStyle()&~WB_RIGHT_ALIGNED; + Point aPos( rOfst.X(), rOfst.Y()+nHLinSzHeight ); + if(bVRulerRight) + { + aPos.AdjustX(rSize.Width() - nVLinSzWidth ); + nStyle |= WB_RIGHT_ALIGNED; + } + Size aSize( nVLinSzWidth, rEditSz.Height() ); + if(!aSize.Width()) + aSize.setWidth( pVRuler->GetSizePixel().Width() ); + pVRuler->SetStyle(nStyle); + pVRuler->SetPosSizePixel( aPos, aSize ); + if(!pVRuler->IsVisible()) + pVRuler->Resize(); + } + // Ruler needs a resize, otherwise it will not work in the invisible condition + if(pHRuler) + { + Size aSize( rSize.Width(), nHLinSzHeight ); + if ( nVBSzWidth && !bVRulerRight) + aSize.AdjustWidth( -nVBSzWidth ); + if(!aSize.Height()) + aSize.setHeight( pHRuler->GetSizePixel().Height() ); + pHRuler->SetPosSizePixel( rOfst, aSize ); + // VCL calls no resize on invisible windows + // but that is not a good idea for the ruler + if(!pHRuler->IsVisible()) + pHRuler->Resize(); + } + + // Arrange scrollbars and SizeBox + Point aScrollFillPos; + { + Point aPos( rOfst.X(), + rOfst.Y()+rSize.Height()-nHBSzHeight ); + if(bVRulerRight) + { + aPos.AdjustX(nVBSzWidth ); + } + + Size aSize( rSize.Width(), nHBSzHeight ); + if ( nVBSzWidth ) + aSize.AdjustWidth( -nVBSzWidth ); + rHScrollbar.SetPosSizePixel( aPos, aSize ); + aScrollFillPos.setY( aPos.Y() ); + } + { + Point aPos( rOfst.X()+rSize.Width()-nVBSzWidth, + rOfst.Y() ); + Size aSize( nVBSzWidth, rSize.Height() ); + if(bVRulerRight) + { + aPos.setX( rOfst.X() ); + if(bHRuler) + { + aPos.AdjustY(nHLinSzHeight ); + aSize.AdjustHeight( -nHLinSzHeight ); + } + } + + if ( nHBSzHeight ) + aSize.AdjustHeight( -nHBSzHeight ); + rVScrollbar.SetPosSizePixel( aPos, aSize ); + + aPos.AdjustY(aSize.Height() ); + + aScrollFillPos.setX( aPos.X() ); + } + + rScrollBarBox.SetPosSizePixel(aScrollFillPos, Size(nVBSzWidth, nHBSzHeight)); +} + +void SwView::ShowAtResize() +{ + m_bShowAtResize = false; + if ( m_pWrtShell->GetViewOptions()->IsViewHRuler() ) + m_pHRuler->Show(); +} + +void SwView::InnerResizePixel( const Point &rOfst, const Size &rSize, bool ) +{ + Size aObjSize = GetObjectShell()->GetVisArea().GetSize(); + if ( !aObjSize.IsEmpty() ) + { + SvBorder aBorder( GetBorderPixel() ); + Size aSize( rSize ); + aSize.AdjustWidth( -(aBorder.Left() + aBorder.Right()) ); + aSize.AdjustHeight( -(aBorder.Top() + aBorder.Bottom()) ); + Size aObjSizePixel = GetWindow()->LogicToPixel(aObjSize, MapMode(MapUnit::MapTwip)); + SfxViewShell::SetZoomFactor( Fraction( aSize.Width(), aObjSizePixel.Width() ), + Fraction( aSize.Height(), aObjSizePixel.Height() ) ); + } + + m_bInInnerResizePixel = true; + const bool bHScrollVisible = m_pHScrollbar->IsVisible(true); + const bool bVScrollVisible = m_pVScrollbar->IsVisible(true); + bool bRepeat = false; + do + { + Size aSz( rSize ); + SvBorder aBorder; + CalcAndSetBorderPixel( aBorder ); + if ( GetViewFrame()->GetFrame().IsInPlace() ) + { + Size aViewSize( aSz ); + Point aViewPos( rOfst ); + aViewSize.AdjustHeight( -(aBorder.Top() + aBorder.Bottom()) ); + aViewSize.AdjustWidth( -(aBorder.Left() + aBorder.Right()) ); + aViewPos.AdjustX(aBorder.Left() ); + aViewPos.AdjustY(aBorder.Top() ); + GetEditWin().SetPosSizePixel( aViewPos, aViewSize ); + } + else + { + aSz.AdjustHeight(aBorder.Top() + aBorder.Bottom() ); + aSz.AdjustWidth(aBorder.Left() + aBorder.Right() ); + } + + Size aEditSz( GetEditWin().GetOutputSizePixel() ); + ViewResizePixel( *GetEditWin().GetOutDev(), rOfst, aSz, aEditSz, *m_pVScrollbar, + *m_pHScrollbar, *m_pScrollFill, m_pVRuler, m_pHRuler, + m_pWrtShell->GetViewOptions()->IsVRulerRight()); + if ( m_bShowAtResize ) + ShowAtResize(); + + if( m_pHRuler->IsVisible() || m_pVRuler->IsVisible() ) + { + const Fraction& rFrac = GetEditWin().GetMapMode().GetScaleX(); + tools::Long nZoom = 100; + if (rFrac.IsValid()) + nZoom = tools::Long(rFrac * 100); + + const Fraction aFrac( nZoom, 100 ); + m_pVRuler->SetZoom( aFrac ); + m_pHRuler->SetZoom( aFrac ); + InvalidateRulerPos(); // Invalidate content. + } + // Reset the cursor stack because the cursor positions for PageUp/Down + // no longer fit the currently visible area. + m_pWrtShell->ResetCursorStack(); + + // EditWin never set! + + // Set VisArea, but do not call the SetVisArea of the Docshell there! + bProtectDocShellVisArea = true; + CalcVisArea( aEditSz ); + // Visibility changes of the automatic horizontal scrollbar + // require to repeat the ViewResizePixel() call - but only once! + if(bRepeat) + bRepeat = false; + else if(bHScrollVisible != m_pHScrollbar->IsVisible(true) || + bVScrollVisible != m_pVScrollbar->IsVisible(true)) + bRepeat = true; + }while( bRepeat ); + bProtectDocShellVisArea = false; + m_bInInnerResizePixel = false; +} + +void SwView::OuterResizePixel( const Point &rOfst, const Size &rSize ) +{ + // #i16909# return, if no size (caused by minimize window). + if ( m_bInOuterResizePixel || ( !rSize.Width() && !rSize.Height() ) ) + return; + m_bInOuterResizePixel = true; + + // Determine whether scroll bars may be displayed. + bool bShowH = true, + bShowV = true, + bAuto = true, + bHAuto = true; + + const SwViewOption *pVOpt = m_pWrtShell->GetViewOptions(); + if ( !pVOpt->IsReadonly() || pVOpt->IsStarOneSetting() ) + { + bShowH = pVOpt->IsViewHScrollBar(); + bShowV = pVOpt->IsViewVScrollBar(); + } + + if (!m_bHScrollbarEnabled) + { + bHAuto = bShowH = false; + } + if (!m_bVScrollbarEnabled) + { + bAuto = bShowV = false; + } + + SwDocShell* pDocSh = GetDocShell(); + bool bIsPreview = pDocSh->IsPreview(); + if( bIsPreview ) + { + bShowH = bShowV = bHAuto = bAuto = false; + } + if(m_pHScrollbar->IsVisible(false) != bShowH && !bHAuto) + ShowHScrollbar(bShowH); + m_pHScrollbar->SetAuto( bHAuto ); + if(m_pVScrollbar->IsVisible(false) != bShowV && !bAuto) + ShowVScrollbar(bShowV); + m_pVScrollbar->SetAuto(bAuto); + + CurrShell aCurr( m_pWrtShell.get() ); + bool bRepeat = false; + tools::Long nCnt = 0; + + bool bUnLockView = !m_pWrtShell->IsViewLocked(); + m_pWrtShell->LockView( true ); + m_pWrtShell->LockPaint(); + + do { + ++nCnt; + const bool bScroll1 = m_pVScrollbar->IsVisible(true); + const bool bScroll2 = m_pHScrollbar->IsVisible(true); + SvBorder aBorder; + CalcAndSetBorderPixel( aBorder ); + const Size aEditSz( GetEditWin().GetOutputSizePixel() ); + ViewResizePixel( *GetEditWin().GetOutDev(), rOfst, rSize, aEditSz, *m_pVScrollbar, + *m_pHScrollbar, *m_pScrollFill, m_pVRuler, m_pHRuler, + m_pWrtShell->GetViewOptions()->IsVRulerRight() ); + if ( m_bShowAtResize ) + ShowAtResize(); + + if( m_pHRuler->IsVisible() || m_pVRuler->IsVisible() ) + InvalidateRulerPos(); // Invalidate content. + + // Reset the cursor stack because the cursor positions for PageUp/Down + // no longer fit the currently visible area. + m_pWrtShell->ResetCursorStack(); + + OSL_ENSURE( !GetEditWin().IsVisible() || + !aEditSz.IsEmpty() || !m_aVisArea.IsEmpty(), "Small world, isn't it?" ); + + // Never set EditWin! + + // Of course the VisArea must also be set. + // Now is the right time to re-calculate the zoom if it is not a simple factor. + m_pWrtShell->StartAction(); + CalcVisArea( aEditSz ); + + //Thus also in the outplace editing the page width will be adjusted immediately. + //TODO/LATER: is that still necessary?! + /* + if ( pDocSh->GetCreateMode() == SfxObjectCreateMode::EMBEDDED ) + pDocSh->SetVisArea( + pDocSh->SfxInPlaceObject::GetVisArea() );*/ + if ( m_pWrtShell->GetViewOptions()->GetZoomType() != SvxZoomType::PERCENT && + !m_pWrtShell->GetViewOptions()->getBrowseMode() ) + SetZoom_( aEditSz, m_pWrtShell->GetViewOptions()->GetZoomType(), 100, true ); + m_pWrtShell->EndAction(); + + bRepeat = bScroll1 != m_pVScrollbar->IsVisible(true); + if ( !bRepeat ) + bRepeat = bScroll2 != m_pHScrollbar->IsVisible(true); + + // Do no infinite loops. + // If possible stop when the (auto-) scroll bars are visible. + if ( bRepeat && + ( nCnt > 10 || ( nCnt > 3 && bHAuto && bAuto ) ) + ) + { + bRepeat = false; + } + + } while ( bRepeat ); + + m_pWrtShell->UnlockPaint(); + if( bUnLockView ) + m_pWrtShell->LockView( false ); + + m_bInOuterResizePixel = false; + + if ( m_pPostItMgr ) + { + m_pPostItMgr->CalcRects(); + m_pPostItMgr->LayoutPostIts(); + } +} + +void SwView::SetZoomFactor( const Fraction &rX, const Fraction &rY ) +{ + const Fraction &rFrac = rX < rY ? rX : rY; + SetZoom( SvxZoomType::PERCENT, static_cast<short>(tools::Long(rFrac * Fraction( 100, 1 ))) ); + + // To minimize rounding errors we also adjust the odd values + // of the base class if necessary. + SfxViewShell::SetZoomFactor( rX, rY ); +} + +bool SwView::UpdateScrollbars() +{ + bool bRet = false; + if ( !m_aVisArea.IsEmpty() ) + { + const bool bBorder = IsDocumentBorder(); + tools::Rectangle aTmpRect( m_aVisArea ); + if ( bBorder ) + { + Point aPt( DOCUMENTBORDER, DOCUMENTBORDER ); + aPt = AlignToPixel( aPt ); + aTmpRect.Move( -aPt.X(), -aPt.Y() ); + } + + Size aTmpSz( m_aDocSz ); + const tools::Long lOfst = bBorder ? 0 : DOCUMENTBORDER * 2; + aTmpSz.AdjustWidth(lOfst ); aTmpSz.AdjustHeight(lOfst ); + + { + const bool bVScrollVisible = m_pVScrollbar->IsVisible(true); + m_pVScrollbar->DocSzChgd( aTmpSz ); + m_pVScrollbar->ViewPortChgd( aTmpRect ); + if ( bVScrollVisible != m_pVScrollbar->IsVisible(true) ) + bRet = true; + } + { + const bool bHScrollVisible = m_pHScrollbar->IsVisible(true); + m_pHScrollbar->DocSzChgd( aTmpSz ); + m_pHScrollbar->ViewPortChgd( aTmpRect ); + if ( bHScrollVisible != m_pHScrollbar->IsVisible(true) ) + bRet = true; + m_pScrollFill->Show(m_pHScrollbar->IsVisible(true) && m_pVScrollbar->IsVisible(true) ); + } + } + return bRet; +} + +void SwView::Move() +{ + if ( GetWrtShell().IsInSelect() ) + GetWrtShell().EndSelect(); + SfxViewShell::Move(); +} + +bool SwView::HandleWheelCommands( const CommandEvent& rCEvt ) +{ + bool bOk = false; + const CommandWheelData* pWData = rCEvt.GetWheelData(); + if (pWData && CommandWheelMode::ZOOM == pWData->GetMode()) + { + tools::Long nFact = m_pWrtShell->GetViewOptions()->GetZoom(); + if( 0L > pWData->GetDelta() ) + nFact = std::max( tools::Long(20), basegfx::zoomtools::zoomOut( nFact )); + else + nFact = std::min( tools::Long(600), basegfx::zoomtools::zoomIn( nFact )); + + SetZoom( SvxZoomType::PERCENT, nFact ); + bOk = true; + } + else + { + if (pWData && pWData->GetMode()==CommandWheelMode::SCROLL) + { + // This influences whether quick help is shown + m_bWheelScrollInProgress=true; + } + + if (pWData && (CommandWheelMode::SCROLL==pWData->GetMode()) && + (COMMAND_WHEEL_PAGESCROLL == pWData->GetScrollLines())) + { + if (pWData->GetDelta()<0) + PhyPageDown(); + else + PhyPageUp(); + bOk = true; + } + else + bOk = m_pEditWin->HandleScrollCommand(rCEvt, m_pHScrollbar, m_pVScrollbar); + + // Restore default state for case when scroll command comes from dragging scrollbar handle + m_bWheelScrollInProgress=false; + } + return bOk; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/uiview/viewprt.cxx b/sw/source/uibase/uiview/viewprt.cxx new file mode 100644 index 000000000..162d0469b --- /dev/null +++ b/sw/source/uibase/uiview/viewprt.cxx @@ -0,0 +1,349 @@ +/* -*- 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 <libxml/xmlwriter.h> +#include <cmdid.h> +#include <officecfg/Office/Common.hxx> +#include <sfx2/request.hxx> +#include <sfx2/viewfrm.hxx> +#include <vcl/svapp.hxx> +#include <vcl/stdtext.hxx> +#include <vcl/weld.hxx> +#include <sfx2/printer.hxx> +#include <editeng/paperinf.hxx> +#include <sfx2/dispatch.hxx> +#include <svx/dialmgr.hxx> +#include <svx/strings.hrc> +#include <svl/eitem.hxx> +#include <svl/stritem.hxx> +#include <svl/intitem.hxx> +#include <svl/flagitem.hxx> +#include <sfx2/linkmgr.hxx> +#include <osl/diagnose.h> + +#include <modcfg.hxx> +#include <edtwin.hxx> +#include <view.hxx> +#include <wrtsh.hxx> +#include <viewopt.hxx> +#include <prtopt.hxx> +#include <cfgitems.hxx> +#include "viewfunc.hxx" +#include <swmodule.hxx> +#include <wview.hxx> +#include <IDocumentDeviceAccess.hxx> + +#include <globals.hrc> +#include <strings.hrc> +#include <swabstdlg.hxx> + +#include <uivwimp.hxx> + +using namespace ::com::sun::star; + +// Hand over the printer to Sfx + +SfxPrinter* SwView::GetPrinter( bool bCreate ) +{ + const IDocumentDeviceAccess& rIDDA = GetWrtShell().getIDocumentDeviceAccess(); + SfxPrinter *pOld = rIDDA.getPrinter( false ); + SfxPrinter *pPrt = rIDDA.getPrinter( bCreate ); + if ( pOld != pPrt ) + { + bool bWeb = dynamic_cast<SwWebView*>(this) != nullptr; + ::SetAppPrintOptions( &GetWrtShell(), bWeb ); + } + return pPrt; +} + +// Propagate printer change + +void SetPrinter( IDocumentDeviceAccess* pIDDA, SfxPrinter const * pNew, bool bWeb ) +{ + SwPrintOptions* pOpt = SW_MOD()->GetPrtOptions(bWeb); + if( !pOpt) + return; + + // Reading Application own printing options from SfxPrinter + const SfxItemSet& rSet = pNew->GetOptions(); + + const SwAddPrinterItem* pAddPrinterAttr = + rSet.GetItemIfSet( FN_PARAM_ADDPRINTER, false ); + if( pAddPrinterAttr ) + { + if( pIDDA ) + pIDDA->setPrintData( *pAddPrinterAttr ); + if( !pAddPrinterAttr->GetFaxName().isEmpty() ) + pOpt->SetFaxName(pAddPrinterAttr->GetFaxName()); + } +} + +sal_uInt16 SwView::SetPrinter(SfxPrinter* pNew, SfxPrinterChangeFlags nDiffFlags ) +{ + SwWrtShell &rSh = GetWrtShell(); + SfxPrinter* pOld = rSh.getIDocumentDeviceAccess().getPrinter( false ); + if ( pOld && pOld->IsPrinting() ) + return SFX_PRINTERROR_BUSY; + + if ( (SfxPrinterChangeFlags::JOBSETUP | SfxPrinterChangeFlags::PRINTER) & nDiffFlags ) + { + rSh.getIDocumentDeviceAccess().setPrinter( pNew, true, true ); + if ( nDiffFlags & SfxPrinterChangeFlags::PRINTER ) + rSh.SetModified(); + } + bool bWeb = dynamic_cast< const SwWebView *>( this ) != nullptr; + if ( nDiffFlags & SfxPrinterChangeFlags::OPTIONS ) + ::SetPrinter( &rSh.getIDocumentDeviceAccess(), pNew, bWeb ); + + const bool bChgOri = bool(nDiffFlags & SfxPrinterChangeFlags::CHG_ORIENTATION); + const bool bChgSize = bool(nDiffFlags & SfxPrinterChangeFlags::CHG_SIZE); + if ( bChgOri || bChgSize ) + { + rSh.StartAllAction(); + if ( bChgOri ) + rSh.ChgAllPageOrientation( pNew->GetOrientation() ); + if ( bChgSize ) + { + Size aSz( SvxPaperInfo::GetPaperSize( pNew ) ); + rSh.ChgAllPageSize( aSz ); + } + rSh.SetModified(); + rSh.EndAllAction(); + InvalidateRulerPos(); + } + return 0; +} + +bool SwView::HasPrintOptionsPage() const +{ + return true; +} + +namespace +{ + class SvxPrtQryBox + { + private: + std::unique_ptr<weld::MessageDialog> m_xQueryBox; + public: + SvxPrtQryBox(weld::Window* pParent) + : m_xQueryBox(Application::CreateMessageDialog(pParent, VclMessageType::Question, VclButtonsType::NONE, SvxResId(RID_SVXSTR_QRY_PRINT_MSG))) + { + m_xQueryBox->set_title(SvxResId(RID_SVXSTR_QRY_PRINT_TITLE)); + + m_xQueryBox->add_button(SvxResId(RID_SVXSTR_QRY_PRINT_SELECTION), RET_OK); + m_xQueryBox->add_button(SvxResId(RID_SVXSTR_QRY_PRINT_ALL), 2); + m_xQueryBox->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL); + m_xQueryBox->set_default_response(RET_OK); + } + short run() { return m_xQueryBox->run(); } + }; +} + +// TabPage for application-specific print options + +std::unique_ptr<SfxTabPage> SwView::CreatePrintOptionsPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rSet) +{ + return ::CreatePrintOptionsPage(pPage, pController, rSet, false); +} + +// Print dispatcher + +void SwView::ExecutePrint(SfxRequest& rReq) +{ + bool bWeb = dynamic_cast<SwWebView*>( this ) != nullptr; + ::SetAppPrintOptions( &GetWrtShell(), bWeb ); + switch (rReq.GetSlot()) + { + case FN_FAX: + { + SwPrintOptions* pPrintOptions = SW_MOD()->GetPrtOptions(bWeb); + const OUString& sFaxName(pPrintOptions->GetFaxName()); + if (!sFaxName.isEmpty()) + { + SfxStringItem aPrinterName(SID_PRINTER_NAME, sFaxName); + SfxBoolItem aSilent( SID_SILENT, true ); + GetViewFrame()->GetDispatcher()->ExecuteList(SID_PRINTDOC, + SfxCallMode::SYNCHRON|SfxCallMode::RECORD, + { &aPrinterName, &aSilent }); + } + else + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetEditWin().GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SwResId(STR_ERR_NO_FAX))); + TranslateId pResId = bWeb ? STR_WEBOPTIONS : STR_TEXTOPTIONS; + xInfoBox->set_primary_text(xInfoBox->get_primary_text().replaceFirst("%1", SwResId(pResId))); + xInfoBox->run(); + SfxUInt16Item aDefPage(SID_SW_EDITOPTIONS, TP_OPTPRINT_PAGE); + GetViewFrame()->GetDispatcher()->ExecuteList(SID_SW_EDITOPTIONS, + SfxCallMode::SYNCHRON|SfxCallMode::RECORD, + { &aDefPage }); + } + } + break; + case SID_PRINTDOC: + case SID_PRINTDOCDIRECT: + { + SwWrtShell* pSh = &GetWrtShell(); + const SfxBoolItem* pSilentItem = rReq.GetArg<SfxBoolItem>(SID_SILENT); + bool bSilent = pSilentItem && pSilentItem->GetValue(); + const SfxBoolItem* pPrintFromMergeItem = rReq.GetArg<SfxBoolItem>(FN_QRY_MERGE); + if(pPrintFromMergeItem) + rReq.RemoveItem(FN_QRY_MERGE); + bool bFromMerge = pPrintFromMergeItem && pPrintFromMergeItem->GetValue(); + bool bPrintSelection = false; + if(!bSilent && !bFromMerge && + SW_MOD()->GetModuleConfig()->IsAskForMailMerge() && pSh->IsAnyDatabaseFieldInDoc()) + { + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(GetEditWin().GetFrameWeld(), "modules/swriter/ui/printmergedialog.ui")); + std::unique_ptr<weld::MessageDialog> xBox(xBuilder->weld_message_dialog("PrintMergeDialog")); + short nRet = xBox->run(); + if(RET_NO != nRet) + { + if(RET_YES == nRet) + { + SfxBoolItem aBool(FN_QRY_MERGE, true); + GetViewFrame()->GetDispatcher()->ExecuteList( + FN_QRY_MERGE, SfxCallMode::ASYNCHRON, + { &aBool }); + rReq.Ignore(); + } + return; + } + } + else if( rReq.GetSlot() == SID_PRINTDOCDIRECT && ! bSilent ) + { + if( pSh->IsSelection() || pSh->IsFrameSelected() || pSh->IsObjSelected() ) + { + SvxPrtQryBox aBox(GetEditWin().GetFrameWeld()); + short nBtn = aBox.run(); + if( RET_CANCEL == nBtn ) + return; + + if( RET_OK == nBtn ) + bPrintSelection = true; + } + } + + //#i61455# if master documents are printed silently without loaded links then update the links now + if( bSilent && pSh->IsGlobalDoc() && !pSh->IsGlblDocSaveLinks() ) + { + pSh->GetLinkManager().UpdateAllLinks( false, false, nullptr ); + } + SfxRequest aReq( rReq ); + SfxBoolItem aBool(SID_SELECTION, bPrintSelection); + aReq.AppendItem( aBool ); + SfxViewShell::ExecuteSlot( aReq, SfxViewShell::GetInterface() ); + return; + } + default: + OSL_ENSURE(false, "wrong dispatcher"); + return; + } +} + +int SwView::getPart() const +{ + return 0; +} + +void SwView::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwView")); + SfxViewShell::dumpAsXml(pWriter); + if (m_pWrtShell) + m_pWrtShell->dumpAsXml(pWriter); + (void)xmlTextWriterEndElement(pWriter); +} + +void SwView::SetRedlineAuthor(const OUString& rAuthor) +{ + m_pViewImpl->m_sRedlineAuthor = rAuthor; +} + +const OUString& SwView::GetRedlineAuthor() const +{ + return m_pViewImpl->m_sRedlineAuthor; +} + +void SwView::NotifyCursor(SfxViewShell* pViewShell) const +{ + m_pWrtShell->NotifyCursor(pViewShell); +} + +// Create page printer/additions for SwView and SwPagePreview + +std::unique_ptr<SfxTabPage> CreatePrintOptionsPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet &rOptions, + bool bPreview) +{ + SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create(); + + ::CreateTabPage fnCreatePage = pFact->GetTabPageCreatorFunc(TP_OPTPRINT_PAGE); + OSL_ENSURE(pFact, "No Page Creator"); + if (!fnCreatePage) + return nullptr; + + std::unique_ptr<SfxTabPage> xSfxPage = fnCreatePage(pPage, pController, &rOptions); + OSL_ENSURE(xSfxPage, "No page"); + if (!xSfxPage) + return nullptr; + + SfxAllItemSet aSet(*(rOptions.GetPool())); + aSet.Put(SfxBoolItem(SID_PREVIEWFLAG_TYPE, bPreview)); + aSet.Put(SfxBoolItem(SID_FAX_LIST, true)); + xSfxPage->PageCreated(aSet); + return xSfxPage; +} + +void SetAppPrintOptions( SwViewShell* pSh, bool bWeb ) +{ + const IDocumentDeviceAccess& rIDDA = pSh->getIDocumentDeviceAccess(); + const SwPrintData& aPrtData = rIDDA.getPrintData(); + + if( !rIDDA.getPrinter( false ) ) + return; + + // Close application own printing options in SfxPrinter. + SwAddPrinterItem aAddPrinterItem(aPrtData); + SfxItemSetFixed< + SID_PRINTER_NOTFOUND_WARN, SID_PRINTER_NOTFOUND_WARN, + SID_PRINTER_CHANGESTODOC, SID_PRINTER_CHANGESTODOC, + SID_HTML_MODE, SID_HTML_MODE, + FN_PARAM_ADDPRINTER, FN_PARAM_ADDPRINTER> aSet( pSh->GetAttrPool() ); + + if(bWeb) + aSet.Put(SfxUInt16Item(SID_HTML_MODE, + ::GetHtmlMode(static_cast<SwWrtShell*>(pSh)->GetView().GetDocShell()))); + aSet.Put(SfxBoolItem(SID_PRINTER_NOTFOUND_WARN, + officecfg::Office::Common::Print::Warning::NotFound::get() )); + aSet.Put(aAddPrinterItem); + aSet.Put( SfxFlagItem( SID_PRINTER_CHANGESTODOC, + static_cast<int>(officecfg::Office::Common::Print::Warning::PaperSize::get() + ? SfxPrinterChangeFlags::CHG_SIZE : SfxPrinterChangeFlags::NONE) | + static_cast<int>(officecfg::Office::Common::Print::Warning::PaperOrientation::get() + ? SfxPrinterChangeFlags::CHG_ORIENTATION : SfxPrinterChangeFlags::NONE ))); + + rIDDA.getPrinter( true )->SetOptions( aSet ); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/uiview/viewsrch.cxx b/sw/source/uibase/uiview/viewsrch.cxx new file mode 100644 index 000000000..118116423 --- /dev/null +++ b/sw/source/uibase/uiview/viewsrch.cxx @@ -0,0 +1,885 @@ +/* -*- 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 <string> + +#include <memory> +#include <boost/property_tree/json_parser.hpp> + +#include <hintids.hxx> + +#include <sal/log.hxx> +#include <svl/cjkoptions.hxx> +#include <svl/ctloptions.hxx> +#include <svx/pageitem.hxx> +#include <svl/whiter.hxx> +#include <sfx2/viewfrm.hxx> +#include <svl/eitem.hxx> +#include <svl/srchitem.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/request.hxx> +#include <sfx2/lokhelper.hxx> +#include <svx/srchdlg.hxx> +#include <swmodule.hxx> +#include <swwait.hxx> +#include <workctrl.hxx> +#include <view.hxx> +#include <wrtsh.hxx> +#include <swundo.hxx> +#include <uitool.hxx> +#include <cmdid.h> +#include <docsh.hxx> +#include <LibreOfficeKit/LibreOfficeKitEnums.h> +#include <comphelper/lok.hxx> +#include <comphelper/string.hxx> + +#include <strings.hrc> +#include <SwRewriter.hxx> + +#include <PostItMgr.hxx> + +using namespace com::sun::star; +using namespace ::com::sun::star::i18n; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; + +//Search Parameter + +struct SwSearchOptions +{ + SwDocPositions eStart, eEnd; + bool bDontWrap; + + SwSearchOptions( SwWrtShell const * pSh, bool bBackward ); +}; + +/// Adds rMatches using rKey as a key to the rTree tree. +static void lcl_addContainerToJson(boost::property_tree::ptree& rTree, const OString& rKey, const std::vector<OString>& rMatches) +{ + boost::property_tree::ptree aChildren; + + for (const OString& rMatch : rMatches) + { + boost::property_tree::ptree aChild; + aChild.put("part", "0"); + aChild.put("rectangles", rMatch.getStr()); + aChildren.push_back(std::make_pair("", aChild)); + } + + rTree.add_child(rKey.getStr(), aChildren); +} + +/// Emits LOK callbacks (count, selection) for search results. +static void lcl_emitSearchResultCallbacks(SvxSearchItem const * pSearchItem, SwWrtShell const * pWrtShell, bool bHighlightAll) +{ + // Emit a callback also about the selection rectangles, grouped by matches. + SwPaM* pPaM = pWrtShell->GetCursor(); + if (!pPaM) + return; + + std::vector<OString> aMatches; + for (SwPaM& rPaM : pPaM->GetRingContainer()) + { + if (SwShellCursor* pShellCursor = dynamic_cast<SwShellCursor*>(&rPaM)) + { + std::vector<OString> aSelectionRectangles; + pShellCursor->SwSelPaintRects::Show(&aSelectionRectangles); + std::vector<OString> aRect; + for (const OString & rSelectionRectangle : aSelectionRectangles) + { + if (rSelectionRectangle.isEmpty()) + continue; + aRect.push_back(rSelectionRectangle); + } + OString sRect = comphelper::string::join("; ", aRect); + aMatches.push_back(sRect); + } + } + boost::property_tree::ptree aTree; + aTree.put("searchString", pSearchItem->GetSearchString().toUtf8().getStr()); + aTree.put("highlightAll", bHighlightAll); + lcl_addContainerToJson(aTree, "searchResultSelection", aMatches); + + std::stringstream aStream; + boost::property_tree::write_json(aStream, aTree); + OString aPayload = aStream.str().c_str(); + + pWrtShell->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_RESULT_SELECTION, aPayload.getStr()); + + if(bHighlightAll) + { // FindAll disables this during find, do it once when done. + SfxLokHelper::notifyUpdate(pWrtShell->GetSfxViewShell(),LOK_CALLBACK_TEXT_SELECTION); + SfxLokHelper::notifyOtherViewsUpdatePerViewId(pWrtShell->GetSfxViewShell(), LOK_CALLBACK_TEXT_VIEW_SELECTION); + } +} + +void SwView::ExecSearch(SfxRequest& rReq) +{ + GetWrtShell().addCurrentPosition(); + + const SfxItemSet* pArgs = rReq.GetArgs(); + const SfxPoolItem* pItem = nullptr; + bool bQuiet = false; + if(pArgs && SfxItemState::SET == pArgs->GetItemState(SID_SEARCH_QUIET, false, &pItem)) + bQuiet = static_cast<const SfxBoolItem*>( pItem)->GetValue(); + + sal_uInt16 nSlot = rReq.GetSlot(); + if (nSlot == FN_REPEAT_SEARCH && !s_pSrchItem) + { + if(bQuiet) + { + rReq.SetReturnValue(SfxBoolItem(nSlot, false)); + nSlot = 0; + } + } + if( m_pWrtShell->IsBlockMode() ) + m_pWrtShell->LeaveBlockMode(); + switch (nSlot) + { + // for now do nothing + case SID_SEARCH_ITEM: + { + delete s_pSrchItem; + s_pSrchItem = pArgs->Get(SID_SEARCH_ITEM).Clone(); + } + break; + + case FID_SEARCH_ON: + s_bJustOpened = true; + GetViewFrame()->GetBindings().Invalidate(SID_SEARCH_ITEM); + break; + + case FID_SEARCH_OFF: + if(pArgs) + { + // Unregister dialog + delete s_pSrchItem; + s_pSrchItem = pArgs->Get(SID_SEARCH_ITEM).Clone(); + + s_xSearchList.reset(); + s_xReplaceList.reset(); + + SvxSearchDialog *const pSrchDlg(GetSearchDialog()); + if (pSrchDlg) + { + // We will remember the search-/replace items. + const SearchAttrItemList* pList = pSrchDlg->GetSearchItemList(); + if( nullptr != pList && pList->Count() ) + s_xSearchList.reset(new SearchAttrItemList( *pList )); + + pList = pSrchDlg->GetReplaceItemList(); + if (nullptr != pList && pList->Count()) + s_xReplaceList.reset(new SearchAttrItemList( *pList )); + } + } + break; + + case FN_REPEAT_SEARCH: + case FID_SEARCH_NOW: + { + sal_uInt16 nMoveType = SwView::GetMoveType(); + { + if(FID_SEARCH_NOW == nSlot && !rReq.IsAPI()) + SwView::SetMoveType(NID_SRCH_REP); + } + + SvxSearchDialog * pSrchDlg(GetSearchDialog()); + if (pSrchDlg) + { + s_xSearchList.reset(); + s_xReplaceList.reset(); + + const SearchAttrItemList* pList = pSrchDlg->GetSearchItemList(); + if( nullptr != pList && pList->Count() ) + s_xSearchList.reset(new SearchAttrItemList( *pList )); + + pList = pSrchDlg->GetReplaceItemList(); + if (nullptr != pList && pList->Count()) + s_xReplaceList.reset(new SearchAttrItemList( *pList )); + } + + if (nSlot == FN_REPEAT_SEARCH) + { + OSL_ENSURE(s_pSrchItem, "SearchItem missing"); + if( !s_pSrchItem ) + s_pSrchItem = new SvxSearchItem(SID_SEARCH_ITEM); + } + else + { + // Get SearchItem from request + OSL_ENSURE(pArgs, "Args missing"); + if ( pArgs ) + { + delete s_pSrchItem; + s_pSrchItem = pArgs->Get(SID_SEARCH_ITEM).Clone(); + } + } + SvxSearchCmd eCommand = s_pSrchItem->GetCommand(); + switch (eCommand) + { + case SvxSearchCmd::FIND: + { + bool bRet = SearchAndWrap(bQuiet); + if( bRet ) + { + Scroll(m_pWrtShell->GetCharRect().SVRect()); + if (comphelper::LibreOfficeKit::isActive()) + lcl_emitSearchResultCallbacks(s_pSrchItem, m_pWrtShell.get(), /* bHighlightAll = */ false); + } + rReq.SetReturnValue(SfxBoolItem(nSlot, bRet)); + + GetDocShell()->Broadcast(SfxHint(SfxHintId::SwNavigatorUpdateTracking)); + } + break; + case SvxSearchCmd::FIND_ALL: + { + // Disable LOK selection notifications during search. + m_pWrtShell->GetSfxViewShell()->setTiledSearching(true); + bool bRet = SearchAll(); + m_pWrtShell->GetSfxViewShell()->setTiledSearching(false); + + GetDocShell()->Broadcast( + SfxHint(SfxHintId::SwNavigatorUpdateTracking)); + GetDocShell()->Broadcast( + SfxHint(SfxHintId::SwNavigatorSelectOutlinesWithSelections)); + + if( !bRet ) + { +#if HAVE_FEATURE_DESKTOP + if( !bQuiet ) + { + m_pWrtShell->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_NOT_FOUND, s_pSrchItem->GetSearchString().toUtf8().getStr()); + SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound); + } +#endif + s_bFound = false; + } + else if (comphelper::LibreOfficeKit::isActive()) + lcl_emitSearchResultCallbacks(s_pSrchItem, m_pWrtShell.get(), /* bHighlightAll = */ true); + rReq.SetReturnValue(SfxBoolItem(nSlot, bRet)); + } + break; + case SvxSearchCmd::REPLACE: + { + + // 1) Replace selection (Not if only attributes should be replaced) +//JP 27.04.95: Why? +// what if you only want to assign attributes to the found?? + + SvxSearchCmd nCmd = SvxSearchCmd::FIND; + if( !s_pSrchItem->GetReplaceString().isEmpty() || + !s_xReplaceList ) + { + // Prevent, that the replaced string will be found again + // if the replacement string is containing the search string. + bool bBack = s_pSrchItem->GetBackward(); + if (bBack) + m_pWrtShell->Push(); + OUString aReplace( s_pSrchItem->GetReplaceString() ); + i18nutil::SearchOptions2 aTmp( s_pSrchItem->GetSearchOptions() ); + std::optional<OUString> xBackRef = sw::ReplaceBackReferences(aTmp, + m_pWrtShell->GetCursor(), m_pWrtShell->GetLayout()); + if( xBackRef ) + s_pSrchItem->SetReplaceString( *xBackRef ); + Replace(); + if( xBackRef ) + { + s_pSrchItem->SetReplaceString( aReplace ); + } + if (bBack) + { + m_pWrtShell->Pop(); + m_pWrtShell->SwapPam(); + } + } + else if( s_xReplaceList ) + nCmd = SvxSearchCmd::REPLACE; + + // 2) Search further (without replacing!) + + SvxSearchCmd nOldCmd = s_pSrchItem->GetCommand(); + s_pSrchItem->SetCommand( nCmd ); + bool bRet = SearchAndWrap(bQuiet); + if( bRet ) + Scroll( m_pWrtShell->GetCharRect().SVRect()); + s_pSrchItem->SetCommand( nOldCmd ); + rReq.SetReturnValue(SfxBoolItem(nSlot, bRet)); + } + break; + + case SvxSearchCmd::REPLACE_ALL: + { + SwSearchOptions aOpts( m_pWrtShell.get(), s_pSrchItem->GetBackward() ); + s_bExtra = false; + sal_uLong nFound; + + { //Scope for SwWait-Object + SwWait aWait( *GetDocShell(), true ); + m_pWrtShell->StartAllAction(); + + // i#8288 "replace all" should not change cursor + // position, so save current cursor + m_pWrtShell->Push(); + + if (!s_pSrchItem->GetSelection()) + { + // if we don't want to search in the selection... + m_pWrtShell->KillSelection(nullptr, false); + if (SwDocPositions::Start == aOpts.eEnd) + { + m_pWrtShell->EndOfSection(); + } + else + { + m_pWrtShell->StartOfSection(); + } + } + nFound = FUNC_Search( aOpts ); + // create it just to overwrite it with stack cursor + m_pWrtShell->CreateCursor(); + // i#8288 restore the original cursor position + m_pWrtShell->Pop(SwCursorShell::PopMode::DeleteCurrent); + m_pWrtShell->EndAllAction(); + } + + rReq.SetReturnValue(SfxBoolItem(nSlot, nFound != 0 && ULONG_MAX != nFound)); + if( !nFound ) + { +#if HAVE_FEATURE_DESKTOP + if( !bQuiet ) + { + m_pWrtShell->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_NOT_FOUND, s_pSrchItem->GetSearchString().toUtf8().getStr()); + SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound); + } +#endif + s_bFound = false; + SwView::SetMoveType(nMoveType); + return; + } + + if( !bQuiet && ULONG_MAX != nFound) + { + OUString sText( SwResId( STR_NB_REPLACED ) ); + sText = sText.replaceFirst("XX", OUString::number( nFound )); + SvxSearchDialogWrapper::SetSearchLabel(sText); + } + } + break; + } + + uno::Reference< frame::XDispatchRecorder > xRecorder = + GetViewFrame()->GetBindings().GetRecorder(); + //prevent additional dialogs in recorded macros + if ( xRecorder.is() ) + rReq.AppendItem(SfxBoolItem(SID_SEARCH_QUIET, true)); + + rReq.Done(); + m_eLastSearchCommand = s_pSrchItem->GetCommand(); + SwView::SetMoveType(nMoveType); + } + break; + case FID_SEARCH_SEARCHSET: + case FID_SEARCH_REPLACESET: + { + static const WhichRangesContainer aNormalAttr(svl::Items< +/* 0 */ RES_CHRATR_CASEMAP, RES_CHRATR_CASEMAP, +/* 2 */ RES_CHRATR_COLOR, RES_CHRATR_POSTURE, +/* 4 */ RES_CHRATR_SHADOWED, RES_CHRATR_WORDLINEMODE, +/* 6 */ RES_CHRATR_BLINK, RES_CHRATR_BLINK, +/* 8 */ RES_CHRATR_BACKGROUND, RES_CHRATR_BACKGROUND, +/*10 */ RES_CHRATR_ROTATE, RES_CHRATR_ROTATE, +/*12 */ RES_CHRATR_SCALEW, RES_CHRATR_RELIEF, +/*14 */ RES_CHRATR_OVERLINE, RES_CHRATR_OVERLINE, +/*16 */ RES_PARATR_LINESPACING, RES_PARATR_HYPHENZONE, +/*18 */ RES_PARATR_REGISTER, RES_PARATR_REGISTER, +/*20 */ RES_PARATR_VERTALIGN, RES_PARATR_VERTALIGN, +/*22 */ RES_LR_SPACE, RES_UL_SPACE, +/*24 */ SID_ATTR_PARA_MODEL, SID_ATTR_PARA_KEEP + >); + + SfxItemSet aSet(m_pWrtShell->GetAttrPool(), aNormalAttr); + + if( SW_MOD()->GetCTLOptions().IsCTLFontEnabled() ) + { + aSet.MergeRange(RES_CHRATR_CTL_FONT, RES_CHRATR_CTL_WEIGHT); + } + if( SvtCJKOptions::IsAnyEnabled() ) + { + aSet.MergeRange(RES_CHRATR_CJK_FONT, RES_CHRATR_CJK_WEIGHT); + aSet.MergeRange(RES_CHRATR_EMPHASIS_MARK, RES_CHRATR_TWO_LINES); + aSet.MergeRange(RES_PARATR_SCRIPTSPACE, RES_PARATR_FORBIDDEN_RULES); + } + + TypedWhichId<SvxSetItem> nWhich = SID_SEARCH_SEARCHSET; + + if ( FID_SEARCH_REPLACESET == nSlot ) + { + nWhich = SID_SEARCH_REPLACESET; + + if ( s_xReplaceList ) + { + s_xReplaceList->Get( aSet ); + s_xReplaceList.reset(); + } + } + else if ( s_xSearchList ) + { + s_xSearchList->Get( aSet ); + s_xSearchList.reset(); + } + rReq.SetReturnValue( SvxSetItem( nWhich, aSet ) ); + } + break; + default: + SAL_WARN_IF( nSlot, "sw", "nSlot: " << nSlot << " wrong Dispatcher (viewsrch.cxx)" ); + return; + } +} + +bool SwView::SearchAndWrap(bool bApi) +{ + SwSearchOptions aOpts( m_pWrtShell.get(), s_pSrchItem->GetBackward() ); + + // Remember starting position of the search for wraparound + // Start- / EndAction perhaps because existing selections of 'search all' + m_pWrtShell->StartAllAction(); + m_pWrtShell->Push(); + + // After a search all action we place the cursor at the beginning of + // the document so that the single search selects the first matching + // occurrence in the document instead of the second. + if( m_eLastSearchCommand == SvxSearchCmd::FIND_ALL ) + { + if( SwDocPositions::Start == aOpts.eEnd ) + m_pWrtShell->EndOfSection(); + else + m_pWrtShell->StartOfSection(); + } + + // fdo#65014 : Ensure that the point of the cursor is at the extremity of the + // selection closest to the end being searched to as to exclude the selected + // region from the search. (This doesn't work in the case of multiple + // selected regions as the cursor doesn't mark the selection in that case.) + m_pWrtShell->GetCursor()->Normalize( s_pSrchItem->GetBackward() ); + + if (!m_pWrtShell->HasSelection() && (s_pSrchItem->HasStartPoint())) + { + // No selection -> but we have a start point (top left corner of the + // current view), start searching from there, not from the current + // cursor position. + SwEditShell& rShell = GetWrtShell(); + Point aPosition(s_pSrchItem->GetStartPointX(), s_pSrchItem->GetStartPointY()); + rShell.SetCursor(aPosition); + } + + // If you want to search in selected areas, they must not be unselected. + if (!s_pSrchItem->GetSelection()) + m_pWrtShell->KillSelection(nullptr, false); + + std::unique_ptr<SwWait> pWait(new SwWait( *GetDocShell(), true )); + if( FUNC_Search( aOpts ) ) + { + s_bFound = true; + if(m_pWrtShell->IsSelFrameMode()) + { + m_pWrtShell->UnSelectFrame(); + m_pWrtShell->LeaveSelFrameMode(); + } + m_pWrtShell->Pop(); + m_pWrtShell->EndAllAction(); + return true; + } + pWait.reset(); + + // Search in the specialized areas when no search is present in selections. + // When searching selections will already searched in these special areas. + bool bHasSrchInOther = s_bExtra; + if (!s_pSrchItem->GetSelection() && !s_bExtra ) + { + s_bExtra = true; + if( FUNC_Search( aOpts ) ) + { + s_bFound = true; + m_pWrtShell->Pop(); + m_pWrtShell->EndAllAction(); + return true; + } + s_bExtra = false; + } + else + s_bExtra = !s_bExtra; + + // If starting position is at the end or beginning of the document. + if (aOpts.bDontWrap) + { + m_pWrtShell->EndAllAction(); + if( !bApi ) + { +#if HAVE_FEATURE_DESKTOP + m_pWrtShell->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_NOT_FOUND, s_pSrchItem->GetSearchString().toUtf8().getStr()); + SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound); +#endif + } + s_bFound = false; + m_pWrtShell->Pop(); + return false; + } + m_pWrtShell->EndAllAction(); + // Try again with WrapAround? + + m_pWrtShell->StartAllAction(); + m_pWrtShell->Pop(SwCursorShell::PopMode::DeleteCurrent); + pWait.reset(new SwWait( *GetDocShell(), true )); + + bool bSrchBkwrd = SwDocPositions::Start == aOpts.eEnd; + + aOpts.eEnd = bSrchBkwrd ? SwDocPositions::Start : SwDocPositions::End; + aOpts.eStart = bSrchBkwrd ? SwDocPositions::End : SwDocPositions::Start; + + if (bHasSrchInOther) + { + m_pWrtShell->ClearMark(); + // Select the start or the end of the entire document + if (bSrchBkwrd) + m_pWrtShell->SttEndDoc(false); + else + m_pWrtShell->SttEndDoc(true); + } + + s_bFound = bool(FUNC_Search( aOpts )); + + // If WrapAround found no matches in the body text, search in the special + // sections, too. + if (!s_bFound && !s_pSrchItem->GetSelection() && !s_bExtra) + { + s_bExtra = true; + if (FUNC_Search(aOpts)) + s_bFound = true; + else + s_bExtra = false; + } + + m_pWrtShell->EndAllAction(); + pWait.reset(); +#if HAVE_FEATURE_DESKTOP + if (s_bFound) + { + if (!bSrchBkwrd) + SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::End); + else + SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::Start); + } + else if(!bApi) + { + m_pWrtShell->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_NOT_FOUND, s_pSrchItem->GetSearchString().toUtf8().getStr()); + SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound); + } +#endif + return s_bFound; +} + +bool SwView::SearchAll() +{ + SwWait aWait( *GetDocShell(), true ); + m_pWrtShell->StartAllAction(); + + SwSearchOptions aOpts( m_pWrtShell.get(), s_pSrchItem->GetBackward() ); + + if (!s_pSrchItem->GetSelection()) + { + // Cancel existing selections, if should not be sought in selected areas. + m_pWrtShell->KillSelection(nullptr, false); + + if( SwDocPositions::Start == aOpts.eEnd ) + m_pWrtShell->EndOfSection(); + else + m_pWrtShell->StartOfSection(); + } + s_bExtra = false; + sal_uInt16 nFound = o3tl::narrowing<sal_uInt16>(FUNC_Search( aOpts )); + s_bFound = 0 != nFound; + + m_pWrtShell->EndAllAction(); + return s_bFound; +} + +void SwView::Replace() +{ + SwWait aWait( *GetDocShell(), true ); + + m_pWrtShell->StartAllAction(); + + if( s_pSrchItem->GetPattern() ) // Templates? + { + SwRewriter aRewriter; + aRewriter.AddRule(UndoArg1, s_pSrchItem->GetSearchString()); + aRewriter.AddRule(UndoArg2, SwResId(STR_YIELDS)); + aRewriter.AddRule(UndoArg3, s_pSrchItem->GetReplaceString()); + + m_pWrtShell->StartUndo(SwUndoId::UI_REPLACE_STYLE, &aRewriter); + + m_pWrtShell->SetTextFormatColl( m_pWrtShell->GetParaStyle( + s_pSrchItem->GetReplaceString(), + SwWrtShell::GETSTYLE_CREATESOME )); + + m_pWrtShell->EndUndo(); + } + else + { + if (GetPostItMgr()->HasActiveSidebarWin()) + GetPostItMgr()->Replace(s_pSrchItem); + + bool bReqReplace = true; + + if(m_pWrtShell->HasSelection()) + { + /* check that the selection match the search string*/ + //save state + SwPosition aStartPos = * m_pWrtShell->GetCursor()->Start(); + SwPosition aEndPos = * m_pWrtShell->GetCursor()->End(); + bool bHasSelection = s_pSrchItem->GetSelection(); + SvxSearchCmd nOldCmd = s_pSrchItem->GetCommand(); + + //set state for checking if current selection has a match + s_pSrchItem->SetCommand( SvxSearchCmd::FIND ); + s_pSrchItem->SetSelection(true); + + //check if it matches + SwSearchOptions aOpts( m_pWrtShell.get(), s_pSrchItem->GetBackward() ); + if( ! FUNC_Search(aOpts) ) + { + + //no matching therefore should not replace selection + // => remove selection + + if(! s_pSrchItem->GetBackward() ) + { + (* m_pWrtShell->GetCursor()->Start()) = aStartPos; + (* m_pWrtShell->GetCursor()->End()) = aEndPos; + } + else + { + (* m_pWrtShell->GetCursor()->Start()) = aEndPos; + (* m_pWrtShell->GetCursor()->End()) = aStartPos; + } + bReqReplace = false; + } + + //set back old search state + s_pSrchItem->SetCommand( nOldCmd ); + s_pSrchItem->SetSelection(bHasSelection); + } + /* + * remove current selection + * otherwise it is always replaced + * no matter if the search string exists or not in the selection + * Now the selection is removed and the next matching string is selected + */ + + if( bReqReplace ) + { + + bool bReplaced = m_pWrtShell->SwEditShell::Replace( s_pSrchItem->GetReplaceString(), + s_pSrchItem->GetRegExp()); + if( bReplaced && s_xReplaceList && s_xReplaceList->Count() && m_pWrtShell->HasSelection() ) + { + SfxItemSet aReplSet( m_pWrtShell->GetAttrPool(), + aTextFormatCollSetRange ); + if( s_xReplaceList->Get( aReplSet ).Count() ) + { + ::SfxToSwPageDescAttr( *m_pWrtShell, aReplSet ); + m_pWrtShell->SwEditShell::SetAttrSet( aReplSet ); + } + } + } + } + + m_pWrtShell->EndAllAction(); +} + +SwSearchOptions::SwSearchOptions( SwWrtShell const * pSh, bool bBackward ) + : eStart(SwDocPositions::Curr) +{ + if( bBackward ) + { + eEnd = SwDocPositions::Start; + bDontWrap = pSh->IsEndOfDoc(); + } + else + { + eEnd = SwDocPositions::End; + bDontWrap = pSh->IsStartOfDoc(); + } +} + +sal_uLong SwView::FUNC_Search( const SwSearchOptions& rOptions ) +{ +#if HAVE_FEATURE_DESKTOP + SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::Empty); +#endif + bool bDoReplace = s_pSrchItem->GetCommand() == SvxSearchCmd::REPLACE || + s_pSrchItem->GetCommand() == SvxSearchCmd::REPLACE_ALL; + + FindRanges eRanges = s_pSrchItem->GetSelection() + ? FindRanges::InSel + : s_bExtra + ? FindRanges::InOther : FindRanges::InBody; + if (s_pSrchItem->GetCommand() == SvxSearchCmd::FIND_ALL || + s_pSrchItem->GetCommand() == SvxSearchCmd::REPLACE_ALL) + eRanges |= FindRanges::InSelAll; + + m_pWrtShell->SttSelect(); + + static const WhichRangesContainer aSearchAttrRange(svl::Items< + RES_CHRATR_BEGIN, RES_CHRATR_END-1, + RES_PARATR_BEGIN, RES_PARATR_END-1, + RES_FRMATR_BEGIN, RES_FRMATR_END-1, + SID_ATTR_PARA_MODEL, SID_ATTR_PARA_KEEP + >); + + SfxItemSet aSrchSet( m_pWrtShell->GetAttrPool(), aSearchAttrRange); + if( s_xSearchList && s_xSearchList->Count() ) + { + s_xSearchList->Get( aSrchSet ); + + // -- Page break with page template + ::SfxToSwPageDescAttr( *m_pWrtShell, aSrchSet ); + } + + std::optional<SfxItemSet> xReplSet; + if( bDoReplace && s_xReplaceList && s_xReplaceList->Count() ) + { + xReplSet.emplace( m_pWrtShell->GetAttrPool(), aSearchAttrRange ); + s_xReplaceList->Get( *xReplSet ); + + // -- Page break with page template + ::SfxToSwPageDescAttr( *m_pWrtShell, *xReplSet ); + + if( !xReplSet->Count() ) // too bad, we don't know + xReplSet.reset(); // the attributes + } + + // build SearchOptions to be used + + i18nutil::SearchOptions2 aSearchOpt( s_pSrchItem->GetSearchOptions() ); + aSearchOpt.Locale = GetAppLanguageTag().getLocale(); + if( !bDoReplace ) + aSearchOpt.replaceString.clear(); + + sal_uLong nFound; + if( aSrchSet.Count() || ( xReplSet && xReplSet->Count() )) + { + nFound = m_pWrtShell->SearchAttr( + aSrchSet, + !s_pSrchItem->GetPattern(), + rOptions.eStart, + rOptions.eEnd, + eRanges, + !s_pSrchItem->GetSearchString().isEmpty() ? &aSearchOpt : nullptr, + xReplSet ? &*xReplSet : nullptr ); + } + else if( s_pSrchItem->GetPattern() ) + { + // Searching (and replacing) templates + const OUString& sRplStr( s_pSrchItem->GetReplaceString() ); + nFound = m_pWrtShell->SearchTempl( s_pSrchItem->GetSearchString(), + rOptions.eStart, + rOptions.eEnd, + eRanges, + bDoReplace ? &sRplStr : nullptr ); + } + else + { + // Normal search + nFound = m_pWrtShell->SearchPattern(aSearchOpt, s_pSrchItem->GetNotes(), + rOptions.eStart, + rOptions.eEnd, + eRanges, + bDoReplace ); + } + m_pWrtShell->EndSelect(); + return nFound; +} + +SvxSearchDialog* SwView::GetSearchDialog() +{ +#if HAVE_FEATURE_DESKTOP + const sal_uInt16 nId = SvxSearchDialogWrapper::GetChildWindowId(); + SfxViewFrame* pFrame = SfxViewFrame::Current(); + if (!pFrame) + return nullptr; + SvxSearchDialogWrapper *pWrp = static_cast<SvxSearchDialogWrapper*>(pFrame->GetChildWindow(nId)); + if (!pWrp) + return nullptr; + return pWrp->getDialog(); +#else + return nullptr; +#endif +} + +void SwView::StateSearch(SfxItemSet &rSet) +{ + SfxWhichIter aIter(rSet); + sal_uInt16 nWhich = aIter.FirstWhich(); + + while(nWhich) + { + switch(nWhich) + { + case SID_SEARCH_OPTIONS: + { + SearchOptionFlags nOpt = SearchOptionFlags::ALL; + if( GetDocShell()->IsReadOnly() ) + nOpt &= ~SearchOptionFlags( SearchOptionFlags::REPLACE | + SearchOptionFlags::REPLACE_ALL ); + rSet.Put( SfxUInt16Item( SID_SEARCH_OPTIONS, static_cast<sal_uInt16>(nOpt) )); + } + break; + case SID_SEARCH_ITEM: + { + if ( !s_pSrchItem ) + { + s_pSrchItem = new SvxSearchItem( SID_SEARCH_ITEM ); + s_pSrchItem->SetFamily(SfxStyleFamily::Para); + s_pSrchItem->SetSearchString( m_pWrtShell->GetSelText() ); + } + + if( s_bJustOpened && m_pWrtShell->IsSelection() ) + { + OUString aText; + if( 1 == m_pWrtShell->GetCursorCnt() && + !( aText = m_pWrtShell->SwCursorShell::GetSelText() ).isEmpty() ) + { + s_pSrchItem->SetSearchString( aText ); + s_pSrchItem->SetSelection( false ); + } + else + s_pSrchItem->SetSelection( true ); + } + + s_bJustOpened = false; + rSet.Put( *s_pSrchItem ); + } + break; + } + nWhich = aIter.NextWhich(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/uiview/viewstat.cxx b/sw/source/uibase/uiview/viewstat.cxx new file mode 100644 index 000000000..cc26c1613 --- /dev/null +++ b/sw/source/uibase/uiview/viewstat.cxx @@ -0,0 +1,691 @@ +/* -*- 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 <memory> + +#include <hintids.hxx> +#include <com/sun/star/linguistic2/XThesaurus.hpp> +#include <svl/whiter.hxx> +#include <svl/cjkoptions.hxx> +#include <sfx2/viewfrm.hxx> +#include <svl/imageitm.hxx> +#include <sfx2/linkmgr.hxx> +#include <editeng/langitem.hxx> +#include <editeng/brushitem.hxx> +#include <editeng/tstpitem.hxx> +#include <sfx2/htmlmode.hxx> +#include <swmodule.hxx> +#include <tox.hxx> +#include <sfx2/dispatch.hxx> +#include <view.hxx> +#include <wrtsh.hxx> +#include <uitool.hxx> +#include <viewopt.hxx> +#include <pagedesc.hxx> +#include <wview.hxx> +#include <globdoc.hxx> +#include <svl/stritem.hxx> +#include <unotools/moduleoptions.hxx> +#include <comphelper/lok.hxx> +#include <LibreOfficeKit/LibreOfficeKitEnums.h> +#include <svl/visitem.hxx> +#include <redline.hxx> +#include <rootfrm.hxx> +#include <docary.hxx> +#include <sfx2/infobar.hxx> +#include <docsh.hxx> +#include <strings.hrc> + +#include <cmdid.h> +#include <IDocumentRedlineAccess.hxx> + +#include <doc.hxx> +#include <workctrl.hxx> + +using namespace ::com::sun::star; + +void SwView::GetState(SfxItemSet &rSet) +{ + SfxWhichIter aIter(rSet); + sal_uInt16 nWhich = aIter.FirstWhich(); + FrameTypeFlags eFrameType = FrameTypeFlags::NONE; + bool bGetFrameType = false; + bool bWeb = dynamic_cast<SwWebView*>( this ) != nullptr; + + while(nWhich) + { + switch(nWhich) + { + case SID_ZOOM_IN: + case SID_ZOOM_OUT: + { + tools::Long nFact = m_pWrtShell->GetViewOptions()->GetZoom(); + if ((SID_ZOOM_IN == nWhich && nFact >= tools::Long(600)) || + (SID_ZOOM_OUT == nWhich && nFact <= tools::Long(20))) + { + rSet.DisableItem(nWhich); + } + } + break; + case FN_TOGGLE_OUTLINE_CONTENT_VISIBILITY: + { + bool bDisable(true); + if (m_pWrtShell->GetViewOptions()->IsShowOutlineContentVisibilityButton()) + { + SwOutlineNodes::size_type nPos = m_pWrtShell->GetOutlinePos(); + if (nPos != SwOutlineNodes::npos) + bDisable = false; + } + if (bDisable) + rSet.DisableItem(nWhich); + } + break; + case FN_NAV_ELEMENT: + // used to update all instances of this control + rSet.InvalidateItem( nWhich ); + break; + case FN_SCROLL_PREV: + case FN_SCROLL_NEXT: + { + if (s_nMoveType == NID_RECENCY) + { + if (!m_pWrtShell->GetNavigationMgr().forwardEnabled()) + rSet.DisableItem(FN_SCROLL_NEXT); + if (!m_pWrtShell->GetNavigationMgr().backEnabled()) + rSet.DisableItem(FN_SCROLL_PREV); + } + } + break; + case FN_EDIT_LINK_DLG: + if( m_pWrtShell->GetLinkManager().GetLinks().empty() ) + rSet.DisableItem(nWhich); + else if( m_pWrtShell->IsSelFrameMode() && + m_pWrtShell->IsSelObjProtected(FlyProtectFlags::Content) != FlyProtectFlags::NONE) + { + rSet.DisableItem(nWhich); + } + break; + + case SID_DRAWTBX_LINES: + if ( bWeb ) + rSet.DisableItem(nWhich); + break; + + case SID_INSERT_GRAPHIC: + if( m_pWrtShell->CursorInsideInputField() ) + { + rSet.DisableItem(nWhich); + } + break; + case SID_INSERT_SIGNATURELINE: + if( !( m_nSelectionType & SelectionType::Text || + m_nSelectionType & SelectionType::NumberList ) ) + { + rSet.DisableItem(nWhich); + } + break; + case SID_EDIT_SIGNATURELINE: + case SID_SIGN_SIGNATURELINE: + if (!isSignatureLineSelected() || isSignatureLineSigned()) + rSet.DisableItem(nWhich); + break; + case SID_INSERT_QRCODE: + if( !( m_nSelectionType & SelectionType::Text || + m_nSelectionType & SelectionType::NumberList ) ) + { + rSet.DisableItem(nWhich); + } + break; + case SID_EDIT_QRCODE: + if (!isQRCodeSelected()) + rSet.DisableItem(nWhich); + break; + case FN_INSERT_CAPTION: + { + // There are captions for graphics, OLE objects, frames and tables + if( !bGetFrameType ) + { + eFrameType = m_pWrtShell->GetFrameType(nullptr, true); + bGetFrameType = true; + } + if (! ( ((eFrameType & FrameTypeFlags::FLY_ANY) && m_nSelectionType != SelectionType::DrawObjectEditMode)|| + m_nSelectionType & SelectionType::Table || + m_nSelectionType & SelectionType::DrawObject) ) + { + rSet.DisableItem(nWhich); + } + else if((m_pWrtShell->IsObjSelected() || m_pWrtShell->IsFrameSelected()) && + (m_pWrtShell->IsSelObjProtected( FlyProtectFlags::Parent) != FlyProtectFlags::NONE || + m_pWrtShell->IsSelObjProtected( FlyProtectFlags::Content ) != FlyProtectFlags::NONE)) + { + rSet.DisableItem(nWhich); + } + else if( m_pWrtShell->IsTableMode() + || isSignatureLineSelected() + || m_pWrtShell->CursorInsideInputField() ) + { + rSet.DisableItem(nWhich); + } + } + break; + + case FN_EDIT_FOOTNOTE: + { + if( !m_pWrtShell->GetCurFootnote() ) + rSet.DisableItem(nWhich); + } + break; + + case FN_CHANGE_PAGENUM: + { + FrameTypeFlags nType = m_pWrtShell->GetFrameType(nullptr,true); + if( ( FrameTypeFlags::FLY_ANY | FrameTypeFlags::HEADER | FrameTypeFlags::FOOTER | + FrameTypeFlags::FOOTNOTE | FrameTypeFlags::DRAWOBJ ) & nType ) + rSet.DisableItem(nWhich); + else + rSet.Put(SfxUInt16Item(nWhich, m_pWrtShell->GetPageOffset())); + } + break; + case SID_PRINTDOC: + case SID_PRINTDOCDIRECT: + GetSlotState( nWhich, SfxViewShell::GetInterface(), &rSet ); + break; + case SID_ATTR_PAGE_ORIENTATION: + case SID_ATTR_PAGE: + case SID_ATTR_PAGE_SIZE: + case SID_ATTR_PAGE_PAPERBIN: + case RES_PAPER_BIN: + case FN_PARAM_FTN_INFO: + { + const size_t nCurIdx = m_pWrtShell->GetCurPageDesc(); + const SwPageDesc& rDesc = m_pWrtShell->GetPageDesc( nCurIdx ); + + // set correct parent to get the XFILL_NONE FillStyle as needed + if(!rSet.GetParent()) + { + const SwFrameFormat& rMaster = rDesc.GetMaster(); + + rSet.SetParent(&rMaster.GetDoc()->GetDfltFrameFormat()->GetAttrSet()); + } + + ::PageDescToItemSet( rDesc, rSet); + + if (nWhich == SID_ATTR_PAGE_ORIENTATION && comphelper::LibreOfficeKit::isActive()) + { + OString aPayload = ".uno:Orientation="; + if (rDesc.GetLandscape()) + { + aPayload += "IsLandscape"; + } + else + { + aPayload += "IsPortrait"; + } + libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED, aPayload.getStr()); + } + } + break; + case RES_BACKGROUND: + case SID_ATTR_BRUSH: + { + const size_t nCurIdx = m_pWrtShell->GetCurPageDesc(); + const SwPageDesc& rDesc = m_pWrtShell->GetPageDesc( nCurIdx ); + const SwFrameFormat& rMaster = rDesc.GetMaster(); + const SvxBrushItem& rBrush = rMaster.GetFormatAttr(RES_BACKGROUND); + rSet.Put(rBrush); + } + break; + case SID_CLEARHISTORY: + { + rSet.Put(SfxBoolItem(nWhich, m_pWrtShell->GetLastUndoInfo(nullptr, nullptr))); + } + break; + case SID_UNDO: + { + // which must not be present, so let them create: + if( !m_pShell ) + SelectShell(); + + const SfxPoolItem* pState = m_pShell->GetSlotState(SID_UNDO); + if(pState) + rSet.Put(*pState); + else + rSet.DisableItem(nWhich); + } + break; + case FN_INSERT_OBJ_CTRL: + if( bWeb + || m_pWrtShell->CursorInsideInputField() ) + { + rSet.DisableItem(nWhich); + } + break; + + case FN_UPDATE_TOX: + if(!m_pWrtShell->GetTOXCount()) + rSet.DisableItem(nWhich); + break; + case FN_EDIT_CURRENT_TOX: + case FN_UPDATE_CUR_TOX: + { + const SwTOXBase* pBase = nullptr; + if(nullptr == (pBase = m_pWrtShell->GetCurTOX()) || + (FN_EDIT_CURRENT_TOX == nWhich && pBase->IsTOXBaseInReadonly())) + rSet.DisableItem(nWhich); + } + break; + case SID_TWAIN_SELECT: + case SID_TWAIN_TRANSFER: +#if defined(_WIN32) || defined UNX + { + if(!SW_MOD()->GetScannerManager().is()) + rSet.DisableItem(nWhich); + } +#endif + break; + case RES_PARATR_TABSTOP: + case SID_ATTR_DEFTABSTOP: + { + const SvxTabStopItem& rDefTabs = m_pWrtShell->GetDefault(RES_PARATR_TABSTOP); + rSet.Put( SfxUInt16Item( nWhich, + o3tl::narrowing<sal_uInt16>(::GetTabDist(rDefTabs)))); + } + break; + case SID_ATTR_LANGUAGE: + { + rSet.Put(m_pWrtShell->GetDefault(RES_CHRATR_LANGUAGE).CloneSetWhich(SID_ATTR_LANGUAGE)); + } + break; + case RES_CHRATR_CJK_LANGUAGE: + { + rSet.Put(m_pWrtShell->GetDefault(RES_CHRATR_CJK_LANGUAGE) + .CloneSetWhich(RES_CHRATR_CJK_LANGUAGE)); + } + break; + case RES_CHRATR_CTL_LANGUAGE: + { + rSet.Put(m_pWrtShell->GetDefault(RES_CHRATR_CTL_LANGUAGE) + .CloneSetWhich(RES_CHRATR_CTL_LANGUAGE)); + } + break; + case FN_REDLINE_ON: + rSet.Put( SfxBoolItem( nWhich, GetDocShell()->IsChangeRecording() ) ); + // When the view is new (e.g. on load), show the Hidden Track Changes infobar + // if Show Changes is disabled, but recording of changes is enabled + // or hidden tracked changes are there already in the document. + // Note: the infobar won't be shown, if the Track Changes toolbar is already + // enabled, see in sfx2. + if ( m_bForceChangesToolbar && m_pWrtShell->GetLayout()->IsHideRedlines() ) + { + bool isRecording = GetDocShell()->IsChangeRecording(); + bool hasRecorded = + m_pWrtShell->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable().size(); + if ( isRecording || hasRecorded ) + { + GetDocShell()->AppendInfoBarWhenReady( + "hiddentrackchanges", SwResId(STR_HIDDEN_CHANGES), + SwResId( (isRecording && hasRecorded) + ? STR_HIDDEN_CHANGES_DETAIL + : isRecording + ? STR_HIDDEN_CHANGES_DETAIL2 + : STR_HIDDEN_CHANGES_DETAIL3 ), + InfobarType::INFO); + } + } + m_bForceChangesToolbar = false; + break; + case FN_REDLINE_PROTECT : + rSet.Put( SfxBoolItem( nWhich, GetDocShell()->HasChangeRecordProtection() ) ); + break; + case FN_REDLINE_SHOW: + { + rSet.Put(SfxBoolItem(nWhich, !m_pWrtShell->GetLayout()->IsHideRedlines())); + } + break; + case SID_AVMEDIA_PLAYER : + case FN_REDLINE_ACCEPT : + { + SfxViewFrame* pVFrame = GetViewFrame(); + if (pVFrame->KnowsChildWindow(nWhich)) + rSet.Put(SfxBoolItem( nWhich, pVFrame->HasChildWindow(nWhich))); + else + rSet.DisableItem(nWhich); + } + break; + case FN_REDLINE_ACCEPT_DIRECT: + case FN_REDLINE_REJECT_DIRECT: + case FN_REDLINE_ACCEPT_TONEXT: + case FN_REDLINE_REJECT_TONEXT: + { + SwDoc *pDoc = m_pWrtShell->GetDoc(); + SwPaM *pCursor = m_pWrtShell->GetCursor(); + bool bDisable = false; + if (GetDocShell()->HasChangeRecordProtection()) + bDisable = true; + else if (pCursor->HasMark()) + { + // If the selection does not contain redlines, disable accepting/rejecting changes. + SwRedlineTable::size_type index = 0; + const SwRedlineTable& table = pDoc->getIDocumentRedlineAccess().GetRedlineTable(); + const SwRangeRedline* redline = table.FindAtPosition( *pCursor->Start(), index ); + if( redline != nullptr && *redline->Start() == *pCursor->End()) + redline = nullptr; + if( redline == nullptr ) + { + // for table selections, GetCursor() gives only PaM of the first cell, + // so extend the redline limit to end of last cell of the selection + // TODO: adjust this for column selections, where the selected columns + // don't contain any redlines and any tracked row changes, but the + // adjacent not selected columns do to avoid false Enable + std::unique_ptr<SwPosition> pSelectionEnd; + if ( m_pWrtShell->IsTableMode() && + m_pWrtShell->GetTableCursor()->GetSelectedBoxesCount() ) + { + const SwSelBoxes& rBoxes = m_pWrtShell->GetTableCursor()->GetSelectedBoxes(); + const SwStartNode *pSttNd = rBoxes.back()->GetSttNd(); + const SwNode* pEndNode = pSttNd->GetNodes()[pSttNd->EndOfSectionIndex()]; + pSelectionEnd.reset(new SwPosition(*pEndNode)); + } + else + pSelectionEnd.reset( + new SwPosition(pCursor->End()->nNode, pCursor->End()->nContent)); + + for(; index < table.size(); ++index ) + { + const SwRangeRedline* tmp = table[ index ]; + if( *tmp->Start() >= *pSelectionEnd ) + break; + if( tmp->HasMark() && tmp->IsVisible()) + { + redline = tmp; + break; + } + } + } + if( redline == nullptr ) + bDisable = true; + } + else + { + // If the cursor position isn't on a redline, disable + // accepting/rejecting changes. + SwTableBox* pTableBox; + if (nullptr == pDoc->getIDocumentRedlineAccess().GetRedline(*pCursor->Start(), nullptr) && + // except in the case of an inserted or deleted table row + ( !m_pWrtShell->IsCursorInTable() || + (pTableBox = pCursor->Start()->nNode.GetNode().GetTableBox() ) == nullptr || + RedlineType::None == pTableBox->GetUpper()->GetRedlineType() ) ) + { + bDisable = true; + } + } + + // LibreOfficeKit wants to handle changes by index, so always allow here. + if (bDisable) + rSet.DisableItem(nWhich); + if (comphelper::LibreOfficeKit::isActive()) + { + OString aPayload(".uno:TrackedChangeIndex="); + SwRedlineTable::size_type nRedline = 0; + if (pDoc->getIDocumentRedlineAccess().GetRedline(*pCursor->Start(), &nRedline)) + aPayload += OString::number(nRedline); + libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED, aPayload.getStr()); + } + } + break; + + case FN_REDLINE_NEXT_CHANGE: + case FN_REDLINE_PREV_CHANGE: + { + // Enable change navigation if we have any redlines. Ideally we should disable + // "Next Change" if we're at or past the last change, and similarly for + // "Previous Change" + if (0 == m_pWrtShell->GetRedlineCount()) + rSet.DisableItem(nWhich); + } + break; + + case SID_THESAURUS: + { + SwWrtShell &rSh = GetWrtShell(); + if (2 <= rSh.GetCursorCnt()) // multi selection? + rSet.DisableItem(nWhich); + else + { + LanguageType nLang = rSh.GetCurLang(); + + // disable "Thesaurus" (menu entry and key shortcut) if the + // language is not supported (by default it is enabled) + uno::Reference< linguistic2::XThesaurus > xThes( ::GetThesaurus() ); + if (!xThes.is() || nLang == LANGUAGE_NONE || + !xThes->hasLocale( LanguageTag::convertToLocale( nLang ) )) + rSet.DisableItem(nWhich); + } + } + break; + case SID_HANGUL_HANJA_CONVERSION: + case SID_CHINESE_CONVERSION: + { + if (!SvtCJKOptions::IsAnyEnabled()) + { + GetViewFrame()->GetBindings().SetVisibleState( nWhich, false ); + rSet.DisableItem(nWhich); + } + else + GetViewFrame()->GetBindings().SetVisibleState( nWhich, true ); + } + break; + case SID_MAIL_SCROLLBODY_PAGEDOWN: + { + const tools::Long nBottom = m_pWrtShell->GetDocSize().Height() + DOCUMENTBORDER; + const tools::Long nAct = GetVisArea().Bottom(); + rSet.Put(SfxBoolItem(SID_MAIL_SCROLLBODY_PAGEDOWN, nAct < nBottom )); + } + break; + + case SID_DOCUMENT_COMPARE: + case SID_DOCUMENT_MERGE: + if( dynamic_cast<const SwGlobalDocShell* >(GetDocShell()) != nullptr|| + (SID_DOCUMENT_MERGE == nWhich && m_pWrtShell->getIDocumentRedlineAccess().GetRedlinePassword().hasElements())) + rSet.DisableItem(nWhich); + break; + case SID_VIEW_DATA_SOURCE_BROWSER: + if ( !SvtModuleOptions().IsModuleInstalled( SvtModuleOptions::EModule::DATABASE ) ) + rSet.Put( SfxVisibilityItem( nWhich, false ) ); + else + rSet.Put( SfxBoolItem( nWhich, GetViewFrame()->HasChildWindow( SID_BROWSER ) ) ); + break; + case SID_READONLY_MODE: + rSet.Put(SfxBoolItem(nWhich, + m_pWrtShell->HasReadonlySel()||GetDocShell()->IsReadOnly())); + break; + case SID_IMAGE_ORIENTATION: + { + SfxImageItem aImageItem(nWhich); + if(m_pWrtShell->IsInVerticalText()) + aImageItem.SetRotation( 2700_deg10 ); + if(m_pWrtShell->IsInRightToLeftText()) + aImageItem.SetMirrored( true ); + rSet.Put(aImageItem); + } + break; + case FN_INSERT_FIELD_DATA_ONLY : + if(!m_bInMailMerge && !GetViewFrame()->HasChildWindow(nWhich)) + rSet.DisableItem(nWhich); + break; + case FN_MAILMERGE_SENDMAIL_CHILDWINDOW: + break; + case SID_ALIGN_ANY_LEFT : + case SID_ALIGN_ANY_HCENTER : + case SID_ALIGN_ANY_RIGHT : + case SID_ALIGN_ANY_JUSTIFIED: + case SID_ALIGN_ANY_TOP : + case SID_ALIGN_ANY_VCENTER : + case SID_ALIGN_ANY_BOTTOM : + case SID_ALIGN_ANY_HDEFAULT : + case SID_ALIGN_ANY_VDEFAULT : + { + if( !m_pShell ) + SelectShell(); + sal_uInt16 nAlias = 0; + if( m_nSelectionType & (SelectionType::DrawObjectEditMode|SelectionType::Text) ) + { + switch( nWhich ) + { + case SID_ALIGN_ANY_LEFT : nAlias = SID_ATTR_PARA_ADJUST_LEFT; break; + case SID_ALIGN_ANY_HCENTER : nAlias = SID_ATTR_PARA_ADJUST_CENTER; break; + case SID_ALIGN_ANY_RIGHT : nAlias = SID_ATTR_PARA_ADJUST_RIGHT; break; + case SID_ALIGN_ANY_JUSTIFIED: nAlias = SID_ATTR_PARA_ADJUST_BLOCK; break; + case SID_ALIGN_ANY_TOP : nAlias = SID_TABLE_VERT_NONE; break; + case SID_ALIGN_ANY_VCENTER : nAlias = SID_TABLE_VERT_CENTER; break; + case SID_ALIGN_ANY_BOTTOM : nAlias = SID_TABLE_VERT_BOTTOM; break; + } + } + else + { + switch( nWhich ) + { + case SID_ALIGN_ANY_LEFT : nAlias = SID_OBJECT_ALIGN_LEFT ; break; + case SID_ALIGN_ANY_HCENTER : nAlias = SID_OBJECT_ALIGN_CENTER ; break; + case SID_ALIGN_ANY_RIGHT : nAlias = SID_OBJECT_ALIGN_RIGHT ; break; + case SID_ALIGN_ANY_TOP : nAlias = SID_OBJECT_ALIGN_UP ; break; + case SID_ALIGN_ANY_VCENTER : nAlias = SID_OBJECT_ALIGN_MIDDLE ; break; + case SID_ALIGN_ANY_BOTTOM : nAlias = SID_OBJECT_ALIGN_DOWN ; break; + } + } + //these slots are either re-mapped to text or object alignment + const SfxPoolItem* pState = nullptr; + if(nAlias) + GetViewFrame()->GetDispatcher()->QueryState( nAlias, pState ); + if(pState) + { + if (!(m_nSelectionType & SelectionType::DrawObject)) + { + rSet.Put(pState->CloneSetWhich(nWhich)); + } + } + else + rSet.DisableItem(nWhich); + } + break; + } + nWhich = aIter.NextWhich(); + } +} + +void SwView::GetDrawState(SfxItemSet &rSet) +{ + SfxWhichIter aIter(rSet); + bool bWeb = dynamic_cast<SwWebView*>( this ) != nullptr; + + for( sal_uInt16 nWhich = aIter.FirstWhich(); nWhich; + nWhich = aIter.NextWhich() ) + switch(nWhich) + { + case SID_DRAW_LINE: + case SID_DRAW_XLINE: + case SID_LINE_ARROW_END: + case SID_LINE_ARROW_CIRCLE: + case SID_LINE_ARROW_SQUARE: + case SID_LINE_ARROW_START: + case SID_LINE_CIRCLE_ARROW: + case SID_LINE_SQUARE_ARROW: + case SID_LINE_ARROWS: + case SID_DRAW_MEASURELINE: + case SID_DRAW_RECT: + case SID_DRAW_ELLIPSE: + case SID_DRAW_XPOLYGON_NOFILL: + case SID_DRAW_XPOLYGON: + case SID_DRAW_POLYGON_NOFILL: + case SID_DRAW_POLYGON: + case SID_DRAW_BEZIER_NOFILL: + case SID_DRAW_BEZIER_FILL: + case SID_DRAW_FREELINE_NOFILL: + case SID_DRAW_FREELINE: + case SID_DRAW_ARC: + case SID_DRAW_PIE: + case SID_DRAW_CIRCLECUT: + case SID_DRAW_TEXT: + case SID_DRAW_CAPTION: + if ( bWeb ) + rSet.DisableItem( nWhich ); + else + if (nWhich != SID_DRAW_TEXT) //tdf#113171 + rSet.Put( SfxBoolItem( nWhich, m_nDrawSfxId == nWhich ) ); + break; + + case SID_DRAW_TEXT_VERTICAL: + case SID_DRAW_CAPTION_VERTICAL: + if ( bWeb || !SvtCJKOptions::IsVerticalTextEnabled() ) + rSet.DisableItem( nWhich ); + else + if (nWhich != SID_DRAW_TEXT_VERTICAL) //tdf#113171 + rSet.Put( SfxBoolItem( nWhich, m_nDrawSfxId == nWhich ) ); + break; + + case SID_DRAW_TEXT_MARQUEE: + if (::GetHtmlMode(GetDocShell()) & HTMLMODE_SOME_STYLES) + rSet.Put( SfxBoolItem(nWhich, m_nDrawSfxId == nWhich)); + else + rSet.DisableItem(nWhich); + break; + case SID_OBJECT_SELECT: + rSet.Put( SfxBoolItem(nWhich, m_nDrawSfxId == nWhich || + m_nFormSfxId == nWhich)); + break; + + case SID_INSERT_DRAW: + case SID_FONTWORK_GALLERY_FLOATER : + case SID_DRAWTBX_ARROWS: + { + if ( bWeb ) + rSet.DisableItem( nWhich ); + } + break; + + case SID_DRAWTBX_CS_BASIC : + case SID_DRAWTBX_CS_SYMBOL : + case SID_DRAWTBX_CS_ARROW : + case SID_DRAWTBX_CS_FLOWCHART : + case SID_DRAWTBX_CS_CALLOUT : + case SID_DRAWTBX_CS_STAR : + { + if ( bWeb ) + rSet.DisableItem( nWhich ); + else + rSet.Put( SfxStringItem( nWhich, m_nDrawSfxId == nWhich ? m_sDrawCustom : OUString() ) ); + } + break; + + } +} + +bool SwView::HasUIFeature(SfxShellFeature nFeature) const +{ + assert((nFeature & ~SfxShellFeature::SwMask) == SfxShellFeature::NONE); + switch(nFeature) + { + case SfxShellFeature::SwChildWindowLabel: + return m_pWrtShell->IsLabelDoc(); + default: + return false; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/uiview/viewtab.cxx b/sw/source/uibase/uiview/viewtab.cxx new file mode 100644 index 000000000..3f33b3f40 --- /dev/null +++ b/sw/source/uibase/uiview/viewtab.cxx @@ -0,0 +1,2537 @@ +/* -*- 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 <hintids.hxx> +#include <uitool.hxx> +#include <svx/rulritem.hxx> +#include <svx/xflclit.hxx> +#include <svx/xflgrit.hxx> +#include <svx/xflhtit.hxx> +#include <svx/xbtmpit.hxx> +#include <svx/xfillit0.hxx> +#include <tools/UnitConversion.hxx> +#include <editeng/tstpitem.hxx> +#include <sfx2/request.hxx> +#include <sfx2/viewfrm.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <svl/eitem.hxx> +#include <svl/whiter.hxx> +#include <svx/ruler.hxx> +#include <editeng/protitem.hxx> +#include <svl/rectitem.hxx> +#include <sfx2/bindings.hxx> +#include <fmtfsize.hxx> +#include <fmthdft.hxx> +#include <fmtclds.hxx> +#include <fmtornt.hxx> +#include <frmatr.hxx> +#include <view.hxx> +#include <wrtsh.hxx> +#include <cmdid.h> +#include <viewopt.hxx> +#include <tabcol.hxx> +#include <frmfmt.hxx> +#include <pagedesc.hxx> +#include <wview.hxx> +#include <fmtcol.hxx> +#include <section.hxx> +#include <ndtxt.hxx> +#include <pam.hxx> +#include <comphelper/lok.hxx> +#include <LibreOfficeKit/LibreOfficeKitEnums.h> +#include <boost/property_tree/json_parser.hpp> +#include <osl/diagnose.h> + +#include <IDocumentSettingAccess.hxx> + +using namespace ::com::sun::star; + +// Pack columns +static void lcl_FillSvxColumn(const SwFormatCol& rCol, + tools::Long nTotalWidth, + SvxColumnItem& rColItem, + tools::Long nDistance) +{ + const SwColumns& rCols = rCol.GetColumns(); + + bool bOrtho = rCol.IsOrtho() && !rCols.empty(); + tools::Long nInnerWidth = 0; + if( bOrtho ) + { + nInnerWidth = nTotalWidth; + for (const auto & i : rCols) + { + nInnerWidth -= i.GetLeft() + i.GetRight(); + } + if( nInnerWidth < 0 ) + nInnerWidth = 0; + else + nInnerWidth /= rCols.size(); + } + + tools::Long nWidth = 0; + for ( size_t i = 0; i < rCols.size(); ++i ) + { + const SwColumn* pCol = &rCols[i]; + const tools::Long nStart = pCol->GetLeft() + nWidth + nDistance; + if( bOrtho ) + nWidth += nInnerWidth + pCol->GetLeft() + pCol->GetRight(); + else + nWidth += rCol.CalcColWidth(i, static_cast< sal_uInt16 >(nTotalWidth)); + const tools::Long nEnd = nWidth - pCol->GetRight() + nDistance; + + SvxColumnDescription aColDesc(nStart, nEnd, true); + rColItem.Append(aColDesc); + } +} + +// Transfer ColumnItem in ColumnInfo +static void lcl_ConvertToCols(const SvxColumnItem& rColItem, + tools::Long nTotalWidth, + SwFormatCol& rCols) +{ + OSL_ENSURE( rCols.GetNumCols() == rColItem.Count(), "Column count mismatch" ); + // ruler executes that change the columns shortly after the selection has changed + // can result in a crash + if(rCols.GetNumCols() != rColItem.Count()) + return; + + sal_uInt16 nLeft = 0; + SwTwips nSumAll= 0; // Sum up all columns and margins + + SwColumns& rArr = rCols.GetColumns(); + + // Tabcols sequentially + for( sal_uInt16 i=0; i < rColItem.Count()-1; ++i ) + { + OSL_ENSURE(rColItem[i+1].nStart >= rColItem[i].nEnd,"overlapping columns" ); + const tools::Long nStart = std::max(rColItem[i+1].nStart, rColItem[i].nEnd); + const sal_uInt16 nRight = o3tl::narrowing<sal_uInt16>((nStart - rColItem[i].nEnd) / 2); + + const tools::Long nWidth = rColItem[i].nEnd - rColItem[i].nStart + nLeft + nRight; + + SwColumn* pCol = &rArr[i]; + pCol->SetWishWidth( sal_uInt16(tools::Long(rCols.GetWishWidth()) * nWidth / nTotalWidth )); + pCol->SetLeft( nLeft ); + pCol->SetRight( nRight ); + nSumAll += pCol->GetWishWidth(); + + nLeft = nRight; + } + rArr[rColItem.Count()-1].SetLeft( nLeft ); + + // The difference between the total sum of the desired width and the so far + // calculated columns and margins should result in the width of the last column. + rArr[rColItem.Count()-1].SetWishWidth( rCols.GetWishWidth() - o3tl::narrowing<sal_uInt16>(nSumAll) ); + + rCols.SetOrtho(false, 0, 0 ); +} + +// Delete tabs +static void lcl_EraseDefTabs(SvxTabStopItem& rTabStops) +{ + // Delete DefTabs + for ( sal_uInt16 i = 0; i < rTabStops.Count(); ) + { + // Here also throw out the DefTab to zero + if ( SvxTabAdjust::Default == rTabStops[i].GetAdjustment() || + rTabStops[i].GetTabPos() == 0 ) + { + rTabStops.Remove(i); + continue; + } + ++i; + } +} + +// Flip page margin +void SwView::SwapPageMargin(const SwPageDesc& rDesc, SvxLRSpaceItem& rLRSpace) +{ + sal_uInt16 nPhyPage, nVirPage; + GetWrtShell().GetPageNum( nPhyPage, nVirPage ); + + if ( rDesc.GetUseOn() == UseOnPage::Mirror && (nPhyPage % 2) == 0 ) + { + tools::Long nTmp = rLRSpace.GetRight(); + rLRSpace.SetRight( rLRSpace.GetLeft() ); + rLRSpace.SetLeft( nTmp ); + } +} + +// If the frame border is moved, the column separator +// should stay in the same absolute position. +static void lcl_Scale(tools::Long& nVal, tools::Long nScale) +{ + nVal *= nScale; + nVal >>= 8; +} + +static void ResizeFrameCols(SwFormatCol& rCol, + tools::Long nOldWidth, + tools::Long nNewWidth, + tools::Long nLeftDelta ) +{ + SwColumns& rArr = rCol.GetColumns(); + tools::Long nWishSum = static_cast<tools::Long>(rCol.GetWishWidth()); + tools::Long nWishDiff = (nWishSum * 100/nOldWidth * nNewWidth) / 100 - nWishSum; + tools::Long nNewWishWidth = nWishSum + nWishDiff; + if(nNewWishWidth > 0xffffl) + { + // If the desired width is getting too large, then all values + // must be scaled appropriately. + tools::Long nScale = (0xffffl << 8)/ nNewWishWidth; + for(SwColumn & i : rArr) + { + SwColumn* pCol = &i; + tools::Long nVal = pCol->GetWishWidth(); + lcl_Scale(nVal, nScale); + pCol->SetWishWidth(o3tl::narrowing<sal_uInt16>(nVal)); + nVal = pCol->GetLeft(); + lcl_Scale(nVal, nScale); + pCol->SetLeft(o3tl::narrowing<sal_uInt16>(nVal)); + nVal = pCol->GetRight(); + lcl_Scale(nVal, nScale); + pCol->SetRight(o3tl::narrowing<sal_uInt16>(nVal)); + } + lcl_Scale(nNewWishWidth, nScale); + lcl_Scale(nWishDiff, nScale); + } + rCol.SetWishWidth( o3tl::narrowing<sal_uInt16>(nNewWishWidth) ); + + if( nLeftDelta >= 2 || nLeftDelta <= -2) + rArr.front().SetWishWidth(rArr.front().GetWishWidth() + o3tl::narrowing<sal_uInt16>(nWishDiff)); + else + rArr.back().SetWishWidth(rArr.back().GetWishWidth() + o3tl::narrowing<sal_uInt16>(nWishDiff)); + // Reset auto width + rCol.SetOrtho(false, 0, 0 ); +} + +// Here all changes to the tab bar will be shot again into the model. +void SwView::ExecTabWin( SfxRequest const & rReq ) +{ + SwWrtShell &rSh = GetWrtShell(); + const FrameTypeFlags nFrameType = rSh.IsObjSelected() ? + FrameTypeFlags::DRAWOBJ : + rSh.GetFrameType(nullptr,true); + const bool bFrameSelection = rSh.IsFrameSelected(); + const bool bBrowse = rSh.GetViewOptions()->getBrowseMode(); + + const sal_uInt16 nSlot = rReq.GetSlot(); + const SfxItemSet* pReqArgs = rReq.GetArgs(); + const size_t nDescId = rSh.GetCurPageDesc(); + const SwPageDesc& rDesc = rSh.GetPageDesc( nDescId ); + + const bool bVerticalWriting = rSh.IsInVerticalText(); + const SwFormatHeader& rHeaderFormat = rDesc.GetMaster().GetHeader(); + SwFrameFormat *pHeaderFormat = const_cast<SwFrameFormat*>(rHeaderFormat.GetHeaderFormat()); + + const SwFormatFooter& rFooterFormat = rDesc.GetMaster().GetFooter(); + SwFrameFormat *pFooterFormat = const_cast<SwFrameFormat*>(rFooterFormat.GetFooterFormat()); + + const SwFormatFrameSize &rFrameSize = rDesc.GetMaster().GetFrameSize(); + + const SwRect& rPageRect = rSh.GetAnyCurRect(CurRectType::Page); + const tools::Long nPageWidth = bBrowse ? rPageRect.Width() : rFrameSize.GetWidth(); + const tools::Long nPageHeight = bBrowse ? rPageRect.Height() : rFrameSize.GetHeight(); + + bool bUnlockView = false; + rSh.StartAllAction(); + bool bSect = bool(nFrameType & FrameTypeFlags::COLSECT); + + switch (nSlot) + { + case SID_ATTR_LONG_LRSPACE: + if ( pReqArgs ) + { + SvxLongLRSpaceItem aLongLR( pReqArgs->Get( SID_ATTR_LONG_LRSPACE ) ); + SvxLRSpaceItem aLR(RES_LR_SPACE); + if ( !bSect && (bFrameSelection || nFrameType & FrameTypeFlags::FLY_ANY) ) + { + SwFrameFormat* pFormat = rSh.GetFlyFrameFormat(); + const SwRect &rRect = rSh.GetAnyCurRect(CurRectType::FlyEmbedded); + + bool bVerticalFrame(false); + { + bool bRTL; + bool bVertL2R; + bVerticalFrame = ( bFrameSelection && + rSh.IsFrameVertical(true, bRTL, bVertL2R) ) || + ( !bFrameSelection && bVerticalWriting); + } + tools::Long nDeltaX = bVerticalFrame ? + rRect.Right() - rPageRect.Right() + aLongLR.GetRight() : + rPageRect.Left() + aLongLR.GetLeft() - rRect.Left(); + + SfxItemSetFixed<RES_FRM_SIZE, RES_FRM_SIZE, + RES_VERT_ORIENT, RES_HORI_ORIENT, + RES_COL, RES_COL> aSet( GetPool() ); + + if(bVerticalFrame) + { + SwFormatVertOrient aVertOrient(pFormat->GetVertOrient()); + aVertOrient.SetVertOrient(text::VertOrientation::NONE); + aVertOrient.SetPos(aVertOrient.GetPos() + nDeltaX ); + aSet.Put( aVertOrient ); + } + else + { + SwFormatHoriOrient aHoriOrient( pFormat->GetHoriOrient() ); + aHoriOrient.SetHoriOrient( text::HoriOrientation::NONE ); + aHoriOrient.SetPos( aHoriOrient.GetPos() + nDeltaX ); + aSet.Put( aHoriOrient ); + } + + SwFormatFrameSize aSize( pFormat->GetFrameSize() ); + tools::Long nOldWidth = aSize.GetWidth(); + + if(aSize.GetWidthPercent()) + { + SwRect aRect; + rSh.CalcBoundRect(aRect, RndStdIds::FLY_AS_CHAR); + tools::Long nPrtWidth = aRect.Width(); + aSize.SetWidthPercent(sal_uInt8((nPageWidth - aLongLR.GetLeft() - aLongLR.GetRight()) * 100 /nPrtWidth)); + } + else + aSize.SetWidth( nPageWidth - + (aLongLR.GetLeft() + aLongLR.GetRight())); + + if( nFrameType & FrameTypeFlags::COLUMN ) + { + SwFormatCol aCol(pFormat->GetCol()); + + ::ResizeFrameCols(aCol, nOldWidth, aSize.GetWidth(), nDeltaX ); + aSet.Put(aCol); + } + + aSet.Put( aSize ); + + rSh.StartAction(); + rSh.Push(); + rSh.SetFlyFrameAttr( aSet ); + // Cancel the frame selection + if(!bFrameSelection && rSh.IsFrameSelected()) + { + rSh.UnSelectFrame(); + rSh.LeaveSelFrameMode(); + } + rSh.Pop(); + rSh.EndAction(); + } + else if ( nFrameType & ( FrameTypeFlags::HEADER | FrameTypeFlags::FOOTER )) + { + // Subtract out page margins + tools::Long nOld = rDesc.GetMaster().GetLRSpace().GetLeft(); + aLongLR.SetLeft( nOld > aLongLR.GetLeft() ? 0 : aLongLR.GetLeft() - nOld ); + + nOld = rDesc.GetMaster().GetLRSpace().GetRight(); + aLongLR.SetRight( nOld > aLongLR.GetRight() ? 0 : aLongLR.GetRight() - nOld ); + aLR.SetLeft(aLongLR.GetLeft()); + aLR.SetRight(aLongLR.GetRight()); + + if ( nFrameType & FrameTypeFlags::HEADER && pHeaderFormat ) + pHeaderFormat->SetFormatAttr( aLR ); + else if( nFrameType & FrameTypeFlags::FOOTER && pFooterFormat ) + pFooterFormat->SetFormatAttr( aLR ); + } + else if( nFrameType == FrameTypeFlags::DRAWOBJ) + { + SwRect aRect( rSh.GetObjRect() ); + aRect.Left( aLongLR.GetLeft() + rPageRect.Left() ); + aRect.Right( rPageRect.Right() - aLongLR.GetRight()); + rSh.SetObjRect( aRect ); + } + else if(bSect || rSh.IsDirectlyInSection()) + { + //change the section indents and the columns if available + //at first determine the changes + SwRect aSectRect = rSh.GetAnyCurRect(CurRectType::SectionPrt); + const SwRect aTmpRect = rSh.GetAnyCurRect(CurRectType::Section); + aSectRect.Pos() += aTmpRect.Pos(); + tools::Long nLeftDiff = aLongLR.GetLeft() - static_cast<tools::Long>(aSectRect.Left() - rPageRect.Left() ); + tools::Long nRightDiff = aLongLR.GetRight() - static_cast<tools::Long>( rPageRect.Right() - aSectRect.Right()); + //change the LRSpaceItem of the section accordingly + const SwSection* pCurrSect = rSh.GetCurrSection(); + const SwSectionFormat* pSectFormat = pCurrSect->GetFormat(); + SvxLRSpaceItem aLRTmp = pSectFormat->GetLRSpace(); + aLRTmp.SetLeft(aLRTmp.GetLeft() + nLeftDiff); + aLRTmp.SetRight(aLRTmp.GetRight() + nRightDiff); + SfxItemSetFixed<RES_LR_SPACE, RES_LR_SPACE, RES_COL, RES_COL> aSet(rSh.GetAttrPool()); + aSet.Put(aLRTmp); + //change the first/last column + if(bSect) + { + SwFormatCol aCols( pSectFormat->GetCol() ); + tools::Long nDiffWidth = nLeftDiff + nRightDiff; + ::ResizeFrameCols(aCols, aSectRect.Width(), aSectRect.Width() - nDiffWidth, nLeftDiff ); + aSet.Put( aCols ); + } + SwSectionData aData(*pCurrSect); + rSh.UpdateSection(rSh.GetSectionFormatPos(*pSectFormat), aData, &aSet); + } + else + { // Adjust page margins + aLR.SetLeft(aLongLR.GetLeft()); + aLR.SetRight(aLongLR.GetRight()); + SwapPageMargin( rDesc, aLR ); + SwPageDesc aDesc( rDesc ); + aDesc.GetMaster().SetFormatAttr( aLR ); + rSh.ChgPageDesc( nDescId, aDesc ); + } + } + break; + + // apply new left and right margins to current page style + case SID_ATTR_PAGE_LRSPACE: + if ( pReqArgs ) + { + const SvxLongLRSpaceItem& aLongLR( pReqArgs->Get( SID_ATTR_PAGE_LRSPACE ) ); + + SwPageDesc aDesc( rDesc ); + { + SvxLRSpaceItem aLR( RES_LR_SPACE ); + aLR.SetLeft(aLongLR.GetLeft()); + aLR.SetRight(aLongLR.GetRight()); + SwapPageMargin( rDesc, aLR ); + aDesc.GetMaster().SetFormatAttr( aLR ); + } + rSh.ChgPageDesc( nDescId, aDesc ); + } + break; + + case SID_ATTR_LONG_ULSPACE: + if ( pReqArgs ) + { + SvxLongULSpaceItem aLongULSpace( pReqArgs->Get( SID_ATTR_LONG_ULSPACE ) ); + + if( bFrameSelection || nFrameType & FrameTypeFlags::FLY_ANY ) + { + SwFrameFormat* pFormat = rSh.GetFlyFrameFormat(); + const SwRect &rRect = rSh.GetAnyCurRect(CurRectType::FlyEmbedded); + const tools::Long nDeltaY = rPageRect.Top() + aLongULSpace.GetUpper() - rRect.Top(); + const tools::Long nHeight = nPageHeight - (aLongULSpace.GetUpper() + aLongULSpace.GetLower()); + + SfxItemSetFixed<RES_FRM_SIZE, RES_FRM_SIZE, + RES_VERT_ORIENT, RES_HORI_ORIENT> aSet( GetPool() ); + //which of the orientation attributes is to be put depends on the frame's environment + bool bRTL; + bool bVertL2R; + if ( ( bFrameSelection && + rSh.IsFrameVertical(true, bRTL, bVertL2R ) ) || + ( !bFrameSelection && bVerticalWriting ) ) + { + SwFormatHoriOrient aHoriOrient(pFormat->GetHoriOrient()); + aHoriOrient.SetHoriOrient(text::HoriOrientation::NONE); + aHoriOrient.SetPos(aHoriOrient.GetPos() + nDeltaY ); + aSet.Put( aHoriOrient ); + } + else + { + SwFormatVertOrient aVertOrient(pFormat->GetVertOrient()); + aVertOrient.SetVertOrient(text::VertOrientation::NONE); + aVertOrient.SetPos(aVertOrient.GetPos() + nDeltaY ); + aSet.Put( aVertOrient ); + } + SwFormatFrameSize aSize(pFormat->GetFrameSize()); + if(aSize.GetHeightPercent()) + { + SwRect aRect; + rSh.CalcBoundRect(aRect, RndStdIds::FLY_AS_CHAR); + tools::Long nPrtHeight = aRect.Height(); + aSize.SetHeightPercent(sal_uInt8(nHeight * 100 /nPrtHeight)); + } + else + aSize.SetHeight(nHeight ); + + aSet.Put( aSize ); + rSh.SetFlyFrameAttr( aSet ); + } + else if( nFrameType == FrameTypeFlags::DRAWOBJ ) + { + SwRect aRect( rSh.GetObjRect() ); + aRect.Top( aLongULSpace.GetUpper() + rPageRect.Top() ); + aRect.Bottom( rPageRect.Bottom() - aLongULSpace.GetLower() ); + rSh.SetObjRect( aRect ) ; + } + else if(bVerticalWriting && (bSect || rSh.IsDirectlyInSection())) + { + //change the section indents and the columns if available + //at first determine the changes + SwRect aSectRect = rSh.GetAnyCurRect(CurRectType::SectionPrt); + const SwRect aTmpRect = rSh.GetAnyCurRect(CurRectType::Section); + aSectRect.Pos() += aTmpRect.Pos(); + const tools::Long nLeftDiff = aLongULSpace.GetUpper() - static_cast<tools::Long>(aSectRect.Top() - rPageRect.Top()); + const tools::Long nRightDiff = aLongULSpace.GetLower() - static_cast<tools::Long>(nPageHeight - aSectRect.Bottom() + rPageRect.Top()); + //change the LRSpaceItem of the section accordingly + const SwSection* pCurrSect = rSh.GetCurrSection(); + const SwSectionFormat* pSectFormat = pCurrSect->GetFormat(); + SvxLRSpaceItem aLR = pSectFormat->GetLRSpace(); + aLR.SetLeft(aLR.GetLeft() + nLeftDiff); + aLR.SetRight(aLR.GetRight() + nRightDiff); + SfxItemSetFixed<RES_LR_SPACE, RES_LR_SPACE, RES_COL, RES_COL> aSet(rSh.GetAttrPool()); + aSet.Put(aLR); + //change the first/last column + if(bSect) + { + SwFormatCol aCols( pSectFormat->GetCol() ); + tools::Long nDiffWidth = nLeftDiff + nRightDiff; + ::ResizeFrameCols(aCols, aSectRect.Height(), aSectRect.Height() - nDiffWidth, nLeftDiff ); + aSet.Put( aCols ); + } + SwSectionData aData(*pCurrSect); + rSh.UpdateSection(rSh.GetSectionFormatPos(*pSectFormat), aData, &aSet); + } + else + { SwPageDesc aDesc( rDesc ); + + if ( nFrameType & ( FrameTypeFlags::HEADER | FrameTypeFlags::FOOTER )) + { + + const bool bHead = bool(nFrameType & FrameTypeFlags::HEADER); + SvxULSpaceItem aUL( rDesc.GetMaster().GetULSpace() ); + if ( bHead ) + aUL.SetUpper( o3tl::narrowing<sal_uInt16>(aLongULSpace.GetUpper()) ); + else + aUL.SetLower( o3tl::narrowing<sal_uInt16>(aLongULSpace.GetLower()) ); + aDesc.GetMaster().SetFormatAttr( aUL ); + + if( (bHead && pHeaderFormat) || (!bHead && pFooterFormat) ) + { + SwFormatFrameSize aSz( bHead ? pHeaderFormat->GetFrameSize() : + pFooterFormat->GetFrameSize() ); + aSz.SetHeightSizeType( SwFrameSize::Fixed ); + aSz.SetHeight(nPageHeight - aLongULSpace.GetLower() - + aLongULSpace.GetUpper() ); + if ( bHead ) + pHeaderFormat->SetFormatAttr( aSz ); + else + pFooterFormat->SetFormatAttr( aSz ); + } + } + else + { + SvxULSpaceItem aUL(RES_UL_SPACE); + aUL.SetUpper(o3tl::narrowing<sal_uInt16>(aLongULSpace.GetUpper())); + aUL.SetLower(o3tl::narrowing<sal_uInt16>(aLongULSpace.GetLower())); + aDesc.GetMaster().SetFormatAttr(aUL); + } + + rSh.ChgPageDesc( nDescId, aDesc ); + } + } + break; + + // apply new top and bottom margins to current page style + case SID_ATTR_PAGE_ULSPACE: + if ( pReqArgs ) + { + const SvxLongULSpaceItem& aLongULSpace( pReqArgs->Get( SID_ATTR_PAGE_ULSPACE ) ); + + SwPageDesc aDesc( rDesc ); + { + SvxULSpaceItem aUL(RES_UL_SPACE); + aUL.SetUpper(o3tl::narrowing<sal_uInt16>(aLongULSpace.GetUpper())); + aUL.SetLower(o3tl::narrowing<sal_uInt16>(aLongULSpace.GetLower())); + aDesc.GetMaster().SetFormatAttr(aUL); + } + rSh.ChgPageDesc( nDescId, aDesc ); + } + break; + + case SID_ATTR_PAGE_COLUMN: + if ( pReqArgs ) + { + const SfxInt16Item aColumnItem( static_cast<const SfxInt16Item&>(pReqArgs->Get(nSlot)) ); + const sal_uInt16 nPageColumnType = aColumnItem.GetValue(); + + // nPageColumnType = + // 1 - single-columned page + // 2 - two-columned page + // 3 - three-columned page + // 4 - two-columned page with left column width of 2/3 of page width + // 5 - two-columned page with right column width of 2/3 of page width + + sal_uInt16 nCount = 2; + if ( nPageColumnType == 1 ) + { + nCount = 0; + } + else if ( nPageColumnType == 3 ) + { + nCount = 3; + } + + const sal_uInt16 nGutterWidth = 0; + + const SvxLRSpaceItem aLR( rDesc.GetMaster().GetLRSpace() ); + const tools::Long nLeft = aLR.GetLeft(); + const tools::Long nRight = aLR.GetRight(); + const tools::Long nWidth = nPageWidth - nLeft - nRight; + + SwFormatCol aCols( rDesc.GetMaster().GetCol() ); + aCols.Init( nCount, nGutterWidth, nWidth ); + aCols.SetWishWidth( nWidth ); + aCols.SetGutterWidth( nGutterWidth, nWidth ); + aCols.SetOrtho( false, nGutterWidth, nWidth ); + + tools::Long nColumnLeft = 0; + tools::Long nColumnRight = 0; + if ( nPageColumnType == 4 ) + { + nColumnRight = static_cast<tools::Long>(nWidth/3); + nColumnLeft = nWidth - nColumnRight; + aCols.GetColumns()[0].SetWishWidth( nColumnLeft ); + aCols.GetColumns()[1].SetWishWidth( nColumnRight ); + } + else if ( nPageColumnType == 5 ) + { + nColumnLeft = static_cast<tools::Long>(nWidth/3); + nColumnRight = nWidth - nColumnLeft; + aCols.GetColumns()[0].SetWishWidth( nColumnLeft ); + aCols.GetColumns()[1].SetWishWidth( nColumnRight ); + } + + SwPageDesc aDesc( rDesc ); + aDesc.GetMaster().SetFormatAttr( aCols ); + rSh.ChgPageDesc( rSh.GetCurPageDesc(), aDesc ); + } + break; + + case SID_ATTR_TABSTOP_VERTICAL: + case SID_ATTR_TABSTOP: + if (pReqArgs) + { + const sal_uInt16 nWhich = GetPool().GetWhich(nSlot); + SvxTabStopItem aTabStops( static_cast<const SvxTabStopItem&>(pReqArgs-> + Get( nWhich ))); + aTabStops.SetWhich(RES_PARATR_TABSTOP); + const SvxTabStopItem& rDefTabs = rSh.GetDefault(RES_PARATR_TABSTOP); + + // Default tab at pos 0 + SfxItemSetFixed<RES_LR_SPACE, RES_LR_SPACE> aSet( GetPool() ); + rSh.GetCurAttr( aSet ); + const SvxLRSpaceItem& rLR = aSet.Get(RES_LR_SPACE); + + if ( rLR.GetTextFirstLineOffset() < 0 ) + { + SvxTabStop aSwTabStop( 0, SvxTabAdjust::Default ); + aTabStops.Insert( aSwTabStop ); + } + + // Populate with default tabs. + ::MakeDefTabs( ::GetTabDist( rDefTabs ), aTabStops ); + + SwTextFormatColl* pColl = rSh.GetCurTextFormatColl(); + if( pColl && pColl->IsAutoUpdateFormat() ) + { + SfxItemSetFixed<RES_PARATR_TABSTOP, RES_PARATR_TABSTOP> aTmp(GetPool()); + aTmp.Put(aTabStops); + rSh.AutoUpdatePara( pColl, aTmp ); + } + else + rSh.SetAttrItem( aTabStops ); + } + break; + case SID_TABSTOP_ADD_OR_CHANGE: + if (pReqArgs) + { + const auto aIndexItem = static_cast<const SfxInt32Item&>(pReqArgs->Get(SID_TABSTOP_ATTR_INDEX)); + const auto aPositionItem = static_cast<const SfxInt32Item&>(pReqArgs->Get(SID_TABSTOP_ATTR_POSITION)); + const auto aRemoveItem = static_cast<const SfxBoolItem&>(pReqArgs->Get(SID_TABSTOP_ATTR_REMOVE)); + const sal_Int32 nIndex = aIndexItem.GetValue(); + const sal_Int32 nPosition = aPositionItem.GetValue(); + const bool bRemove = aRemoveItem.GetValue(); + + + + SfxItemSetFixed<RES_PARATR_TABSTOP, RES_PARATR_TABSTOP> aItemSet(GetPool()); + rSh.GetCurAttr(aItemSet); + SvxTabStopItem aTabStopItem(aItemSet.Get(RES_PARATR_TABSTOP)); + lcl_EraseDefTabs(aTabStopItem); + + if (nIndex < aTabStopItem.Count()) + { + if (nIndex == -1) + { + SvxTabStop aSwTabStop(0, SvxTabAdjust::Default); + aTabStopItem.Insert(aSwTabStop); + + const SvxTabStopItem& rDefaultTabs = rSh.GetDefault(RES_PARATR_TABSTOP); + MakeDefTabs(GetTabDist(rDefaultTabs), aTabStopItem); + + SvxTabStop aTabStop(nPosition); + aTabStopItem.Insert(aTabStop); + } + else + { + SvxTabStop aTabStop = aTabStopItem.At(nIndex); + aTabStopItem.Remove(nIndex); + if (!bRemove) + { + aTabStop.GetTabPos() = nPosition; + aTabStopItem.Insert(aTabStop); + + SvxTabStop aSwTabStop(0, SvxTabAdjust::Default); + aTabStopItem.Insert(aSwTabStop); + } + const SvxTabStopItem& rDefaultTabs = rSh.GetDefault(RES_PARATR_TABSTOP); + MakeDefTabs(GetTabDist(rDefaultTabs), aTabStopItem); + } + rSh.SetAttrItem(aTabStopItem); + } + } + break; + case SID_PARAGRAPH_CHANGE_STATE: + { + if (pReqArgs) + { + SfxItemSetFixed<RES_LR_SPACE, RES_LR_SPACE> aLRSpaceSet( GetPool() ); + rSh.GetCurAttr( aLRSpaceSet ); + SvxLRSpaceItem aParaMargin( aLRSpaceSet.Get( RES_LR_SPACE ) ); + + if (const SfxStringItem *fLineIndent = pReqArgs->GetItemIfSet(SID_PARAGRAPH_FIRST_LINE_INDENT)) + { + const OUString ratio = fLineIndent->GetValue(); + aParaMargin.SetTextFirstLineOffset(nPageWidth * ratio.toFloat()); + } + else if (const SfxStringItem *pLeftIndent = pReqArgs->GetItemIfSet(SID_PARAGRAPH_LEFT_INDENT)) + { + const OUString ratio = pLeftIndent->GetValue(); + aParaMargin.SetLeft(nPageWidth * ratio.toFloat()); + } + else if (const SfxStringItem *pRightIndent = pReqArgs->GetItemIfSet(SID_PARAGRAPH_RIGHT_INDENT)) + { + const OUString ratio = pRightIndent->GetValue(); + aParaMargin.SetRight(nPageWidth * ratio.toFloat()); + } + rSh.SetAttrItem(aParaMargin); + } + break; + } + case SID_HANGING_INDENT: + { + SfxItemSetFixed<RES_LR_SPACE, RES_LR_SPACE> aLRSpaceSet( GetPool() ); + rSh.GetCurAttr( aLRSpaceSet ); + SvxLRSpaceItem aParaMargin( aLRSpaceSet.Get( RES_LR_SPACE ) ); + + SvxLRSpaceItem aNewMargin( RES_LR_SPACE ); + aNewMargin.SetTextLeft( aParaMargin.GetTextLeft() + aParaMargin.GetTextFirstLineOffset() ); + aNewMargin.SetRight( aParaMargin.GetRight() ); + aNewMargin.SetTextFirstLineOffset( (aParaMargin.GetTextFirstLineOffset()) * -1 ); + + rSh.SetAttrItem( aNewMargin ); + break; + } + + case SID_ATTR_PARA_LRSPACE_VERTICAL: + case SID_ATTR_PARA_LRSPACE: + if ( pReqArgs ) + { + SvxLRSpaceItem aParaMargin(static_cast<const SvxLRSpaceItem&>(pReqArgs->Get(nSlot))); + + aParaMargin.SetRight( aParaMargin.GetRight() - m_nRightBorderDistance ); + aParaMargin.SetTextLeft(aParaMargin.GetTextLeft() - m_nLeftBorderDistance ); + + aParaMargin.SetWhich( RES_LR_SPACE ); + SwTextFormatColl* pColl = rSh.GetCurTextFormatColl(); + + // #i23726# + if (m_pNumRuleNodeFromDoc) + { + // --> #i42922# Mouse move of numbering label + // has to consider the left indent of the paragraph + SfxItemSetFixed<RES_LR_SPACE, RES_LR_SPACE> aSet( GetPool() ); + rSh.GetCurAttr( aSet ); + const SvxLRSpaceItem& rLR = aSet.Get(RES_LR_SPACE); + + SwPosition aPos(*m_pNumRuleNodeFromDoc); + // #i90078# + rSh.SetIndent( static_cast< short >(aParaMargin.GetTextLeft() - rLR.GetTextLeft()), aPos); + // #i42921# invalidate state of indent in order to get a ruler update. + aParaMargin.SetWhich( nSlot ); + GetViewFrame()->GetBindings().SetState( aParaMargin ); + } + else if( pColl && pColl->IsAutoUpdateFormat() ) + { + SfxItemSetFixed<RES_LR_SPACE, RES_LR_SPACE> aSet(GetPool()); + aSet.Put(aParaMargin); + rSh.AutoUpdatePara( pColl, aSet); + } + else + rSh.SetAttrItem( aParaMargin ); + + if ( aParaMargin.GetTextFirstLineOffset() < 0 ) + { + SfxItemSetFixed<RES_PARATR_TABSTOP, RES_PARATR_TABSTOP> aSet( GetPool() ); + + rSh.GetCurAttr( aSet ); + const SvxTabStopItem& rTabStops = aSet.Get(RES_PARATR_TABSTOP); + + // Do we have a tab at position zero? + sal_uInt16 i; + + for ( i = 0; i < rTabStops.Count(); ++i ) + if ( rTabStops[i].GetTabPos() == 0 ) + break; + + if ( i >= rTabStops.Count() ) + { + // No DefTab + std::unique_ptr<SvxTabStopItem> aTabStops(rTabStops.Clone()); + + ::lcl_EraseDefTabs(*aTabStops); + + SvxTabStop aSwTabStop( 0, SvxTabAdjust::Default ); + aTabStops->Insert(aSwTabStop); + + const SvxTabStopItem& rDefTabs = rSh.GetDefault(RES_PARATR_TABSTOP); + ::MakeDefTabs( ::GetTabDist(rDefTabs), *aTabStops ); + + if( pColl && pColl->IsAutoUpdateFormat()) + { + SfxItemSetFixed<RES_PARATR_TABSTOP, RES_PARATR_TABSTOP> aSetTmp(GetPool()); + aSetTmp.Put(std::move(aTabStops)); + rSh.AutoUpdatePara( pColl, aSetTmp ); + } + else + rSh.SetAttrItem( *aTabStops ); + } + } + } + break; + + case SID_ATTR_PARA_ULSPACE: + if ( pReqArgs ) + { + SvxULSpaceItem aParaMargin(static_cast<const SvxULSpaceItem&>(pReqArgs->Get(nSlot))); + + aParaMargin.SetUpper( aParaMargin.GetUpper() ); + aParaMargin.SetLower(aParaMargin.GetLower()); + + aParaMargin.SetWhich( RES_UL_SPACE ); + SwTextFormatColl* pColl = rSh.GetCurTextFormatColl(); + if( pColl && pColl->IsAutoUpdateFormat() ) + { + SfxItemSetFixed<RES_UL_SPACE, RES_UL_SPACE> aSet(GetPool()); + aSet.Put(aParaMargin); + rSh.AutoUpdatePara( pColl, aSet); + } + else + rSh.SetAttrItem( aParaMargin ); + } + break; + case SID_PARASPACE_INCREASE: + case SID_PARASPACE_DECREASE: + { + SfxItemSetFixed<RES_UL_SPACE, RES_UL_SPACE> aULSpaceSet( GetPool() ); + rSh.GetCurAttr( aULSpaceSet ); + SvxULSpaceItem aULSpace( aULSpaceSet.Get( RES_UL_SPACE ) ); + sal_uInt16 nUpper = aULSpace.GetUpper(); + sal_uInt16 nLower = aULSpace.GetLower(); + + if ( nSlot == SID_PARASPACE_INCREASE ) + { + nUpper = std::min< sal_uInt16 >( nUpper + 57, 5670 ); + nLower = std::min< sal_uInt16 >( nLower + 57, 5670 ); + } + else + { + nUpper = std::max< sal_Int16 >( nUpper - 57, 0 ); + nLower = std::max< sal_Int16 >( nLower - 57, 0 ); + } + + aULSpace.SetUpper( nUpper ); + aULSpace.SetLower( nLower ); + + SwTextFormatColl* pColl = rSh.GetCurTextFormatColl(); + if( pColl && pColl->IsAutoUpdateFormat() ) + { + aULSpaceSet.Put( aULSpace ); + rSh.AutoUpdatePara( pColl, aULSpaceSet ); + } + else + rSh.SetAttrItem( aULSpace, SetAttrMode::DEFAULT, true ); + } + break; + + case SID_RULER_CHANGE_STATE: + if (pReqArgs) + { + if ( const SfxStringItem *pMargin1 = pReqArgs->GetItemIfSet(SID_RULER_MARGIN1) ) + { + const OUString ratio = pMargin1->GetValue(); + GetHRuler().SetValues(RulerChangeType::MARGIN1, GetHRuler().GetPageWidth() * ratio.toFloat()); + } + else if ( const SfxStringItem *pMargin2 = pReqArgs->GetItemIfSet(SID_RULER_MARGIN2) ) + { + const OUString ratio = pMargin2->GetValue(); + GetHRuler().SetValues(RulerChangeType::MARGIN2, GetHRuler().GetPageWidth() * ratio.toFloat()); + } + } + break; + case SID_RULER_BORDERS_VERTICAL: + case SID_RULER_BORDERS: + if ( pReqArgs ) + { + SvxColumnItem aColItem(static_cast<const SvxColumnItem&>(pReqArgs->Get(nSlot))); + + if( m_bSetTabColFromDoc || (!bSect && rSh.GetTableFormat()) ) + { + OSL_ENSURE(aColItem.Count(), "ColDesc is empty!!"); + + const bool bSingleLine = rReq. + GetArgs()->Get(SID_RULER_ACT_LINE_ONLY).GetValue(); + + SwTabCols aTabCols; + if ( m_bSetTabColFromDoc ) + rSh.GetMouseTabCols( aTabCols, m_aTabColFromDocPos ); + else + rSh.GetTabCols(aTabCols); + + // left table border + tools::Long nBorder = static_cast<tools::Long>(aColItem.GetLeft() - aTabCols.GetLeftMin()); + aTabCols.SetLeft( nBorder ); + + nBorder = (bVerticalWriting ? nPageHeight : nPageWidth) - aTabCols.GetLeftMin() - aColItem.GetRight(); + + if ( aColItem.GetRight() > 0 ) + aTabCols.SetRight( nBorder ); + + // Tabcols sequentially + // The last column is defined by the edge. + // Columns in right-to-left tables need to be mirrored + bool bIsTableRTL = + IsTabColFromDoc() ? + rSh.IsMouseTableRightToLeft(m_aTabColFromDocPos) + : rSh.IsTableRightToLeft(); + const size_t nColCount = aColItem.Count() - 1; + if(bIsTableRTL) + { + for ( size_t i = 0; i < nColCount && i < aTabCols.Count(); ++i ) + { + const SvxColumnDescription& rCol = aColItem[nColCount - i]; + aTabCols[i] = aTabCols.GetRight() - rCol.nStart; + aTabCols.SetHidden( i, !rCol.bVisible ); + } + } + else + { + for ( size_t i = 0; i < nColCount && i < aTabCols.Count(); ++i ) + { + const SvxColumnDescription& rCol = aColItem[i]; + aTabCols[i] = rCol.nEnd + aTabCols.GetLeft(); + aTabCols.SetHidden( i, !rCol.bVisible ); + } + } + + if ( m_bSetTabColFromDoc ) + { + if( !rSh.IsViewLocked() ) + { + bUnlockView = true; + rSh.LockView( true ); + } + rSh.SetMouseTabCols( aTabCols, bSingleLine, + m_aTabColFromDocPos ); + } + else + rSh.SetTabCols(aTabCols, bSingleLine); + + } + else + { + if ( bFrameSelection || nFrameType & FrameTypeFlags::FLY_ANY || bSect) + { + SwSectionFormat *pSectFormat = nullptr; + SfxItemSetFixed<RES_COL, RES_COL> aSet( GetPool() ); + if(bSect) + { + SwSection *pSect = rSh.GetAnySection(); + OSL_ENSURE( pSect, "Which section?"); + pSectFormat = pSect->GetFormat(); + } + else + { + rSh.GetFlyFrameAttr( aSet ); + } + SwFormatCol aCols( + bSect ? + pSectFormat->GetCol() : + aSet.Get( RES_COL, false )); + SwRect aCurRect = rSh.GetAnyCurRect(bSect ? CurRectType::SectionPrt : CurRectType::FlyEmbeddedPrt); + const tools::Long lWidth = bVerticalWriting ? aCurRect.Height() : aCurRect.Width(); + ::lcl_ConvertToCols( aColItem, lWidth, aCols ); + aSet.Put( aCols ); + if(bSect) + rSh.SetSectionAttr( aSet, pSectFormat ); + else + { + rSh.StartAction(); + rSh.Push(); + rSh.SetFlyFrameAttr( aSet ); + // Cancel the frame selection again + if(!bFrameSelection && rSh.IsFrameSelected()) + { + rSh.UnSelectFrame(); + rSh.LeaveSelFrameMode(); + } + rSh.Pop(); + rSh.EndAction(); + } + } + else + { + SwFormatCol aCols( rDesc.GetMaster().GetCol() ); + const SwRect aPrtRect = rSh.GetAnyCurRect(CurRectType::PagePrt); + ::lcl_ConvertToCols( aColItem, + bVerticalWriting ? aPrtRect.Height() : aPrtRect.Width(), + aCols ); + SwPageDesc aDesc( rDesc ); + aDesc.GetMaster().SetFormatAttr( aCols ); + rSh.ChgPageDesc( rSh.GetCurPageDesc(), aDesc ); + } + } + } + break; + + case SID_RULER_ROWS : + case SID_RULER_ROWS_VERTICAL: + if (pReqArgs) + { + SvxColumnItem aColItem(static_cast<const SvxColumnItem&>(pReqArgs->Get(nSlot))); + + if( m_bSetTabColFromDoc || (!bSect && rSh.GetTableFormat()) ) + { + OSL_ENSURE(aColItem.Count(), "ColDesc is empty!!"); + + SwTabCols aTabCols; + if ( m_bSetTabRowFromDoc ) + rSh.GetMouseTabRows( aTabCols, m_aTabColFromDocPos ); + else + rSh.GetTabRows(aTabCols); + + if ( bVerticalWriting ) + { + aTabCols.SetRight(nPageWidth - aColItem.GetRight() - aColItem.GetLeft()); + aTabCols.SetLeftMin(aColItem.GetLeft()); + } + else + { + tools::Long nBorder = nPageHeight - aTabCols.GetLeftMin() - aColItem.GetRight(); + aTabCols.SetRight( nBorder ); + } + + const size_t nColItems = aColItem.Count() - 1; + if(bVerticalWriting) + { + for ( size_t i = nColItems; i; --i ) + { + const SvxColumnDescription& rCol = aColItem[i - 1]; + tools::Long nColumnPos = aTabCols.GetRight() - rCol.nEnd ; + aTabCols[i - 1] = nColumnPos; + aTabCols.SetHidden( i - 1, !rCol.bVisible ); + } + } + else + { + for ( size_t i = 0; i < nColItems; ++i ) + { + const SvxColumnDescription& rCol = aColItem[i]; + aTabCols[i] = rCol.nEnd + aTabCols.GetLeft(); + aTabCols.SetHidden( i, !rCol.bVisible ); + } + } + bool bSingleLine = false; + if( const SfxBoolItem* pSingleLine = rReq.GetArgs()->GetItemIfSet(SID_RULER_ACT_LINE_ONLY, false) ) + bSingleLine = pSingleLine->GetValue(); + if ( m_bSetTabRowFromDoc ) + { + if( !rSh.IsViewLocked() ) + { + bUnlockView = true; + rSh.LockView( true ); + } + rSh.SetMouseTabRows( aTabCols, bSingleLine, m_aTabColFromDocPos ); + } + else + rSh.SetTabRows(aTabCols, bSingleLine); + } + } + break; + case SID_TABLE_CHANGE_CURRENT_BORDER_POSITION: + { + if (pReqArgs) + { + const SfxStringItem *pBorderType = pReqArgs->GetItemIfSet(SID_TABLE_BORDER_TYPE); + const SfxUInt16Item *pIndex = pReqArgs->GetItemIfSet(SID_TABLE_BORDER_INDEX); + const SfxInt32Item *pOffset = pReqArgs->GetItemIfSet(SID_TABLE_BORDER_OFFSET); + constexpr tools::Long constDistanceOffset = 40; + + if (pBorderType && pIndex && pOffset) + { + const OUString sType = pBorderType->GetValue(); + const sal_uInt16 nIndex = pIndex->GetValue(); + const sal_Int32 nOffset = pOffset->GetValue(); + + if (sType.startsWith("column")) + { + SwTabCols aTabCols; + rSh.GetTabCols(aTabCols); + + if (sType == "column-left") + { + tools::Long nNewPosition = aTabCols.GetLeft() + nOffset; + if(aTabCols.Count() > 0) + { + auto & rEntry = aTabCols.GetEntry(0); + nNewPosition = std::min(nNewPosition, rEntry.nPos - constDistanceOffset); + } + aTabCols.SetLeft(nNewPosition); + } + else if (sType == "column-right") + { + tools::Long nNewPosition = aTabCols.GetRight() + nOffset; + if(aTabCols.Count() > 0) + { + auto & rEntry = aTabCols.GetEntry(aTabCols.Count() - 1); + nNewPosition = std::max(nNewPosition, rEntry.nPos + constDistanceOffset); + } + aTabCols.SetRight(nNewPosition); + } + else if (sType == "column-middle" && nIndex < aTabCols.Count()) + { + auto & rEntry = aTabCols.GetEntry(nIndex); + tools::Long nNewPosition = rEntry.nPos + nOffset; + nNewPosition = std::clamp(nNewPosition, rEntry.nMin, rEntry.nMax - constDistanceOffset); + rEntry.nPos = nNewPosition; + } + + rSh.SetTabCols(aTabCols, false); + } + else if (sType.startsWith("row")) + { + SwTabCols aTabRows; + rSh.GetTabRows(aTabRows); + + if (sType == "row-left") + { + auto & rEntry = aTabRows.GetEntry(0); + tools::Long nNewPosition = aTabRows.GetLeft() + nOffset; + nNewPosition = std::min(nNewPosition, rEntry.nPos - constDistanceOffset); + aTabRows.SetLeft(nNewPosition); + } + else if (sType == "row-right") + { + tools::Long nNewPosition = aTabRows.GetRight() + nOffset; + if(aTabRows.Count() > 0) + { + auto & rEntry = aTabRows.GetEntry(aTabRows.Count() - 1); + nNewPosition = std::max(nNewPosition, rEntry.nPos + constDistanceOffset); + } + aTabRows.SetRight(nNewPosition); + } + else if (sType == "row-middle" && nIndex < aTabRows.Count()) + { + auto & rEntry = aTabRows.GetEntry(nIndex); + tools::Long nNewPosition = rEntry.nPos + nOffset; + nNewPosition = std::clamp(nNewPosition, rEntry.nMin, rEntry.nMax - constDistanceOffset); + rEntry.nPos = nNewPosition; + } + + rSh.SetTabRows(aTabRows, false); + } + } + } + } + break; + case SID_ATTR_PAGE_HEADER: + { + if ( pReqArgs ) + { + const bool bHeaderOn = static_cast<const SfxBoolItem&>(pReqArgs->Get(SID_ATTR_PAGE_HEADER)).GetValue(); + SwPageDesc aDesc(rDesc); + SwFrameFormat &rMaster = aDesc.GetMaster(); + rMaster.SetFormatAttr( SwFormatHeader( bHeaderOn )); + rSh.ChgPageDesc(rSh.GetCurPageDesc(), aDesc); + } + } + break; + case SID_ATTR_PAGE_HEADER_LRMARGIN: + { + if ( pReqArgs && rDesc.GetMaster().GetHeader().IsActive() ) + { + const SvxLongLRSpaceItem& aLongLR = pReqArgs->Get(SID_ATTR_PAGE_HEADER_LRMARGIN); + SvxLRSpaceItem aLR(RES_LR_SPACE); + SwPageDesc aDesc(rDesc); + aLR.SetLeft(aLongLR.GetLeft()); + aLR.SetRight(aLongLR.GetRight()); + SwFrameFormat* pFormat = const_cast<SwFrameFormat*>(aDesc.GetMaster().GetHeader().GetHeaderFormat()); + pFormat->SetFormatAttr( aLR ); + rSh.ChgPageDesc(rSh.GetCurPageDesc(), aDesc); + } + } + break; + case SID_ATTR_PAGE_HEADER_SPACING: + { + if ( pReqArgs && rDesc.GetMaster().GetHeader().IsActive()) + { + const SvxLongULSpaceItem& aLongUL = pReqArgs->Get(SID_ATTR_PAGE_HEADER_SPACING); + SwPageDesc aDesc(rDesc); + SvxULSpaceItem aUL(0, aLongUL.GetLower(), RES_UL_SPACE ); + SwFrameFormat* pFormat = const_cast<SwFrameFormat*>(aDesc.GetMaster().GetHeader().GetHeaderFormat()); + pFormat->SetFormatAttr( aUL ); + rSh.ChgPageDesc(rSh.GetCurPageDesc(), aDesc); + } + } + break; + case SID_ATTR_PAGE_HEADER_LAYOUT: + { + if ( pReqArgs && rDesc.GetMaster().GetHeader().IsActive()) + { + const SfxInt16Item& aLayoutItem = static_cast<const SfxInt16Item&>(pReqArgs->Get(SID_ATTR_PAGE_HEADER_LAYOUT)); + sal_uInt16 nLayout = aLayoutItem.GetValue(); + SwPageDesc aDesc(rDesc); + aDesc.ChgHeaderShare((nLayout>>1) == 0); + aDesc.ChgFirstShare((nLayout % 2) == 0); // FIXME control changes for both header footer - tdf#100287 + rSh.ChgPageDesc(rSh.GetCurPageDesc(), aDesc); + } + } + break; + case SID_ATTR_PAGE_FOOTER: + { + if ( pReqArgs ) + { + const bool bFooterOn = static_cast<const SfxBoolItem&>(pReqArgs->Get(SID_ATTR_PAGE_FOOTER)).GetValue(); + SwPageDesc aDesc(rDesc); + SwFrameFormat &rMaster = aDesc.GetMaster(); + rMaster.SetFormatAttr( SwFormatFooter( bFooterOn )); + rSh.ChgPageDesc(rSh.GetCurPageDesc(), aDesc); + } + } + break; + case SID_ATTR_PAGE_FOOTER_LRMARGIN: + { + if ( pReqArgs && rDesc.GetMaster().GetFooter().IsActive() ) + { + const SvxLongLRSpaceItem& aLongLR = pReqArgs->Get(SID_ATTR_PAGE_FOOTER_LRMARGIN); + SvxLRSpaceItem aLR(RES_LR_SPACE); + SwPageDesc aDesc(rDesc); + aLR.SetLeft(aLongLR.GetLeft()); + aLR.SetRight(aLongLR.GetRight()); + SwFrameFormat* pFormat = const_cast<SwFrameFormat*>(aDesc.GetMaster().GetFooter().GetFooterFormat()); + pFormat->SetFormatAttr( aLR ); + rSh.ChgPageDesc(rSh.GetCurPageDesc(), aDesc); + } + } + break; + case SID_ATTR_PAGE_FOOTER_SPACING: + { + if ( pReqArgs && rDesc.GetMaster().GetFooter().IsActive()) + { + const SvxLongULSpaceItem& aLongUL = pReqArgs->Get(SID_ATTR_PAGE_FOOTER_SPACING); + SwPageDesc aDesc(rDesc); + SvxULSpaceItem aUL(aLongUL.GetUpper(), 0, RES_UL_SPACE ); + SwFrameFormat* pFormat = const_cast<SwFrameFormat*>(aDesc.GetMaster().GetFooter().GetFooterFormat()); + pFormat->SetFormatAttr( aUL ); + rSh.ChgPageDesc(rSh.GetCurPageDesc(), aDesc); + } + } + break; + case SID_ATTR_PAGE_FOOTER_LAYOUT: + { + if ( pReqArgs && rDesc.GetMaster().GetFooter().IsActive()) + { + const SfxInt16Item& aLayoutItem = static_cast<const SfxInt16Item&>(pReqArgs->Get(SID_ATTR_PAGE_FOOTER_LAYOUT)); + sal_uInt16 nLayout = aLayoutItem.GetValue(); + SwPageDesc aDesc(rDesc); + aDesc.ChgFooterShare((nLayout>>1) == 0); + aDesc.ChgFirstShare((nLayout % 2) == 0); // FIXME control changes for both header footer - tdf#100287 + rSh.ChgPageDesc(rSh.GetCurPageDesc(), aDesc); + } + } + break; + + case SID_ATTR_PAGE_COLOR: + case SID_ATTR_PAGE_FILLSTYLE: + case SID_ATTR_PAGE_GRADIENT: + case SID_ATTR_PAGE_HATCH: + case SID_ATTR_PAGE_BITMAP: + { + if(pReqArgs) + { + SwPageDesc aDesc(rDesc); + SwFrameFormat &rMaster = aDesc.GetMaster(); + switch (nSlot) + { + case SID_ATTR_PAGE_FILLSTYLE: + { + XFillStyleItem aFSItem( pReqArgs->Get( XATTR_FILLSTYLE ) ); + drawing::FillStyle eXFS = aFSItem.GetValue(); + + if ( eXFS == drawing::FillStyle_NONE ) + rMaster.SetFormatAttr( XFillStyleItem( eXFS ) ); + } + break; + + case SID_ATTR_PAGE_COLOR: + { + XFillColorItem aColorItem( pReqArgs->Get( XATTR_FILLCOLOR ) ); + rMaster.SetFormatAttr( XFillStyleItem( drawing::FillStyle_SOLID ) ); + rMaster.SetFormatAttr( aColorItem ); + } + break; + + case SID_ATTR_PAGE_GRADIENT: + { + XFillGradientItem aGradientItem( pReqArgs->Get( XATTR_FILLGRADIENT ) ); + rMaster.SetFormatAttr( XFillStyleItem( drawing::FillStyle_GRADIENT ) ); + rMaster.SetFormatAttr( aGradientItem ); + } + break; + + case SID_ATTR_PAGE_HATCH: + { + XFillHatchItem aHatchItem( pReqArgs->Get( XATTR_FILLHATCH ) ); + rMaster.SetFormatAttr( XFillStyleItem( drawing::FillStyle_HATCH ) ); + rMaster.SetFormatAttr( aHatchItem ); + } + break; + + case SID_ATTR_PAGE_BITMAP: + { + XFillBitmapItem aBitmapItem( pReqArgs->Get( XATTR_FILLBITMAP ) ); + rMaster.SetFormatAttr( XFillStyleItem( drawing::FillStyle_BITMAP ) ); + rMaster.SetFormatAttr( aBitmapItem ); + } + break; + + default: + break; + } + rSh.ChgPageDesc(rSh.GetCurPageDesc(), aDesc); + } + } + break; + + default: + OSL_ENSURE( false, "wrong SlotId"); + } + rSh.EndAllAction(); + + if( bUnlockView ) + rSh.LockView( false ); + + m_bSetTabColFromDoc = m_bSetTabRowFromDoc = m_bTabColFromDoc = m_bTabRowFromDoc = false; + SetNumRuleNodeFromDoc(nullptr); +} + +// Here the status of the tab bar will be determined. +// This means that all relevant attributes at the CursorPos +// will be submitted to the tab bar. +void SwView::StateTabWin(SfxItemSet& rSet) +{ + SwWrtShell &rSh = GetWrtShell(); + + const Point* pPt = IsTabColFromDoc() || IsTabRowFromDoc() ? &m_aTabColFromDocPos : nullptr; + const FrameTypeFlags nFrameType = rSh.IsObjSelected() + ? FrameTypeFlags::DRAWOBJ + : rSh.GetFrameType( pPt, true ); + + const bool bFrameSelection = rSh.IsFrameSelected(); + const bool bBrowse = rSh.GetViewOptions()->getBrowseMode(); + // PageOffset/limiter + const SwRect& rPageRect = rSh.GetAnyCurRect( CurRectType::Page, pPt ); + const SwRect& rPagePrtRect = rSh.GetAnyCurRect( CurRectType::PagePrt, pPt ); + const tools::Long nPageWidth = rPageRect.Width(); + const tools::Long nPageHeight = rPageRect.Height(); + + const SwPageDesc& rDesc = rSh.GetPageDesc( + IsTabColFromDoc() || m_bTabRowFromDoc ? + rSh.GetMousePageDesc(m_aTabColFromDocPos) : rSh.GetCurPageDesc() ); + + const SvxFrameDirectionItem& rFrameDir = rDesc.GetMaster().GetFrameDir(); + const bool bVerticalWriting = rSh.IsInVerticalText(); + + //enable tab stop display on the rulers depending on the writing direction + WinBits nRulerStyle = m_pHRuler->GetStyle() & ~WB_EXTRAFIELD; + m_pHRuler->SetStyle(bVerticalWriting||bBrowse ? nRulerStyle : nRulerStyle|WB_EXTRAFIELD); + nRulerStyle = m_pVRuler->GetStyle() & ~WB_EXTRAFIELD; + m_pVRuler->SetStyle(bVerticalWriting ? nRulerStyle|WB_EXTRAFIELD : nRulerStyle); + + //#i24363# tab stops relative to indent + bool bRelative = rSh.getIDocumentSettingAccess().get(DocumentSettingId::TABS_RELATIVE_TO_INDENT); + m_pHRuler->SetTabsRelativeToIndent( bRelative ); + m_pVRuler->SetTabsRelativeToIndent( bRelative ); + + SvxLRSpaceItem aPageLRSpace( rDesc.GetMaster().GetLRSpace() ); + SwapPageMargin( rDesc, aPageLRSpace ); + + SfxItemSetFixed<RES_PARATR_TABSTOP, RES_PARATR_TABSTOP, + RES_LR_SPACE, RES_UL_SPACE> aCoreSet( GetPool() ); + // get also the list level indent values merged as LR-SPACE item, if needed. + rSh.GetCurAttr( aCoreSet, true ); + const SelectionType nSelType = rSh.GetSelectionType(); + + SfxWhichIter aIter( rSet ); + sal_uInt16 nWhich = aIter.FirstWhich(); + + while ( nWhich ) + { + switch ( nWhich ) + { + + case SID_ATTR_PAGE_COLUMN: + { + sal_uInt16 nColumnType = 0; + + const SwFrameFormat& rMaster = rDesc.GetMaster(); + const SwFormatCol& aCol(rMaster.GetCol()); + const sal_uInt16 nCols = aCol.GetNumCols(); + if ( nCols == 0 ) + { + nColumnType = 1; + } + else if ( nCols == 2 ) + { + const sal_uInt16 nColLeft = aCol.CalcPrtColWidth(0, aCol.GetWishWidth()); + const sal_uInt16 nColRight = aCol.CalcPrtColWidth(1, aCol.GetWishWidth()); + + if ( abs(nColLeft - nColRight) <= 10 ) + { + nColumnType = 2; + } + else if( abs(nColLeft - nColRight*2) < 20 ) + { + nColumnType = 4; + } + else if( abs(nColLeft*2 - nColRight) < 20 ) + { + nColumnType = 5; + } + } + else if( nCols == 3 ) + { + nColumnType = 3; + } + else + nColumnType = nCols; + + rSet.Put( SfxInt16Item( SID_ATTR_PAGE_COLUMN, nColumnType ) ); + } + break; + + case SID_ATTR_LONG_LRSPACE: + { + SvxLongLRSpaceItem aLongLR( aPageLRSpace.GetLeft(), + aPageLRSpace.GetRight(), + SID_ATTR_LONG_LRSPACE); + if(bBrowse) + { + aLongLR.SetLeft(rPagePrtRect.Left()); + aLongLR.SetRight(nPageWidth - rPagePrtRect.Right()); + } + if ( ( nFrameType & FrameTypeFlags::HEADER || nFrameType & FrameTypeFlags::FOOTER ) && + !(nFrameType & FrameTypeFlags::COLSECT) ) + { + SwFrameFormat *pFormat = const_cast<SwFrameFormat*>((nFrameType & FrameTypeFlags::HEADER) ? + rDesc.GetMaster().GetHeader().GetHeaderFormat() : + rDesc.GetMaster().GetFooter().GetFooterFormat()); + if( pFormat )// #i80890# if rDesc is not the one belonging to the current page is might crash + { + SwRect aRect( rSh.GetAnyCurRect( CurRectType::HeaderFooter, pPt)); + aRect.Pos() -= rSh.GetAnyCurRect( CurRectType::Page, pPt ).Pos(); + const SvxLRSpaceItem& aLR = pFormat->GetLRSpace(); + aLongLR.SetLeft ( aLR.GetLeft() + aRect.Left() ); + aLongLR.SetRight( nPageWidth - aRect.Right() + aLR.GetRight() ); + } + } + else + { + SwRect aRect; + if( !bFrameSelection && ((nFrameType & FrameTypeFlags::COLSECT) || rSh.IsDirectlyInSection()) ) + { + aRect = rSh.GetAnyCurRect(CurRectType::SectionPrt, pPt); + const SwRect aTmpRect = rSh.GetAnyCurRect(CurRectType::Section, pPt); + aRect.Pos() += aTmpRect.Pos(); + } + + else if ( bFrameSelection || nFrameType & FrameTypeFlags::FLY_ANY ) + aRect = rSh.GetAnyCurRect(CurRectType::FlyEmbedded, pPt); + else if( nFrameType & FrameTypeFlags::DRAWOBJ) + aRect = rSh.GetObjRect(); + + if( aRect.Width() ) + { + // make relative to page position: + aLongLR.SetLeft(aRect.Left() - rPageRect.Left()); + aLongLR.SetRight(rPageRect.Right() - aRect.Right()); + } + } + rSet.Put( aLongLR ); + } + break; + + // provide left and right margins of current page style + case SID_ATTR_PAGE_LRSPACE: + { + const SvxLRSpaceItem aTmpPageLRSpace( rDesc.GetMaster().GetLRSpace() ); + const SvxLongLRSpaceItem aLongLR( + aTmpPageLRSpace.GetLeft(), + aTmpPageLRSpace.GetRight(), + SID_ATTR_PAGE_LRSPACE ); + rSet.Put( aLongLR ); + } + break; + + case SID_ATTR_LONG_ULSPACE: + { + // Page margin top bottom + SvxULSpaceItem aUL( rDesc.GetMaster().GetULSpace() ); + SvxLongULSpaceItem aLongUL( static_cast<tools::Long>(aUL.GetUpper()), + static_cast<tools::Long>(aUL.GetLower()), + SID_ATTR_LONG_ULSPACE); + + if ( bFrameSelection || nFrameType & FrameTypeFlags::FLY_ANY ) + { + // Convert document coordinates into page coordinates. + const SwRect &rRect = rSh.GetAnyCurRect(CurRectType::FlyEmbedded, pPt); + aLongUL.SetUpper(rRect.Top() - rPageRect.Top()); + aLongUL.SetLower(rPageRect.Bottom() - rRect.Bottom()); + } + else if ( nFrameType & FrameTypeFlags::HEADER || nFrameType & FrameTypeFlags::FOOTER ) + { + SwRect aRect( rSh.GetAnyCurRect( CurRectType::HeaderFooter, pPt)); + aRect.Pos() -= rSh.GetAnyCurRect( CurRectType::Page, pPt ).Pos(); + aLongUL.SetUpper( aRect.Top() ); + aLongUL.SetLower( nPageHeight - aRect.Bottom() ); + } + else if( nFrameType & FrameTypeFlags::DRAWOBJ) + { + const SwRect &rRect = rSh.GetObjRect(); + aLongUL.SetUpper(rRect.Top() - rPageRect.Top()); + aLongUL.SetLower(rPageRect.Bottom() - rRect.Bottom()); + } + else if(bBrowse) + { + aLongUL.SetUpper(rPagePrtRect.Top()); + aLongUL.SetLower(nPageHeight - rPagePrtRect.Bottom()); + } + rSet.Put( aLongUL ); + } + break; + + // provide top and bottom margins of current page style + case SID_ATTR_PAGE_ULSPACE: + { + const SvxULSpaceItem aUL( rDesc.GetMaster().GetULSpace() ); + SvxLongULSpaceItem aLongUL( + static_cast<tools::Long>(aUL.GetUpper()), + static_cast<tools::Long>(aUL.GetLower()), + SID_ATTR_PAGE_ULSPACE ); + + rSet.Put( aLongUL ); + } + break; + + case SID_ATTR_TABSTOP_VERTICAL : + case RES_PARATR_TABSTOP: + { + if ( dynamic_cast< const SwWebView *>( this ) != nullptr || + IsTabColFromDoc() || + IsTabRowFromDoc() || + ( nSelType & SelectionType::Graphic ) || + ( nSelType & SelectionType::Frame ) || + ( nSelType & SelectionType::Ole ) || + ( SfxItemState::DEFAULT > aCoreSet.GetItemState(RES_LR_SPACE) ) || + (!bVerticalWriting && (SID_ATTR_TABSTOP_VERTICAL == nWhich) ) || + ( bVerticalWriting && (RES_PARATR_TABSTOP == nWhich)) + ) + rSet.DisableItem( nWhich ); + else + { + SvxTabStopItem aTabStops(aCoreSet.Get( RES_PARATR_TABSTOP )); + + const SvxTabStopItem& rDefTabs = rSh.GetDefault(RES_PARATR_TABSTOP); + + OSL_ENSURE(m_pHRuler, "why is there no ruler?"); + const tools::Long nDefTabDist = ::GetTabDist(rDefTabs); + m_pHRuler->SetDefTabDist( nDefTabDist ); + m_pVRuler->SetDefTabDist( nDefTabDist ); + ::lcl_EraseDefTabs(aTabStops); + aTabStops.SetWhich(nWhich); + rSet.Put(aTabStops); + + if (comphelper::LibreOfficeKit::isActive() && nWhich == RES_PARATR_TABSTOP) + { + boost::property_tree::ptree aRootTree; + boost::property_tree::ptree aEntries; + + for (sal_uInt16 i = 0; i < aTabStops.Count(); ++i) + { + SvxTabStop const & rTabStop = aTabStops[i]; + boost::property_tree::ptree aEntry; + aEntry.put("position", convertTwipToMm100(rTabStop.GetTabPos())); + aEntry.put("type", sal_uInt16(rTabStop.GetAdjustment())); + aEntry.put("decimal", OUString(rTabStop.GetDecimal())); + aEntry.put("fill", OUString(rTabStop.GetFill())); + aEntries.push_back(std::make_pair("", aEntry)); + } + aRootTree.push_back(std::make_pair("tabstops", aEntries)); + + std::stringstream aStream; + boost::property_tree::write_json(aStream, aRootTree); + rSh.GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_TAB_STOP_LIST, aStream.str().c_str()); + } + } + break; + } + + case SID_HANGING_INDENT: + { + SfxItemState e = aCoreSet.GetItemState(RES_LR_SPACE); + if( e == SfxItemState::DISABLED ) + rSet.DisableItem(nWhich); + break; + } + + case SID_ATTR_PARA_LRSPACE_VERTICAL: + case SID_ATTR_PARA_LRSPACE: + case SID_ATTR_PARA_LEFTSPACE: + case SID_ATTR_PARA_RIGHTSPACE: + case SID_ATTR_PARA_FIRSTLINESPACE: + { + if ( nSelType & SelectionType::Graphic || + nSelType & SelectionType::Frame || + nSelType & SelectionType::Ole || + nFrameType == FrameTypeFlags::DRAWOBJ || + (!bVerticalWriting && (SID_ATTR_PARA_LRSPACE_VERTICAL == nWhich)) || + ( bVerticalWriting && (SID_ATTR_PARA_LRSPACE == nWhich)) + ) + { + rSet.DisableItem(nWhich); + } + else + { + std::shared_ptr<SvxLRSpaceItem> aLR(std::make_shared<SvxLRSpaceItem>(RES_LR_SPACE)); + if ( !IsTabColFromDoc() ) + { + aLR.reset(aCoreSet.Get(RES_LR_SPACE).Clone()); + + // #i23726# + if (m_pNumRuleNodeFromDoc) + { + short nOffset = static_cast< short >(aLR->GetTextLeft() + + // #i42922# Mouse move of numbering label + // has to consider the left indent of the paragraph + m_pNumRuleNodeFromDoc->GetLeftMarginWithNum( true ) ); + + short nFLOffset; + m_pNumRuleNodeFromDoc->GetFirstLineOfsWithNum( nFLOffset ); + + aLR->SetLeft( nOffset + nFLOffset ); + } + } + aLR->SetWhich(nWhich); + rSet.Put(*aLR); + } + break; + } + + case SID_ATTR_PARA_ULSPACE: + case SID_ATTR_PARA_ABOVESPACE: + case SID_ATTR_PARA_BELOWSPACE: + case SID_PARASPACE_INCREASE: + case SID_PARASPACE_DECREASE: + { + SvxULSpaceItem aUL = aCoreSet.Get(RES_UL_SPACE); + SfxItemState e = aCoreSet.GetItemState(RES_UL_SPACE); + if( e >= SfxItemState::DEFAULT ) + { + if ( !aUL.GetUpper() && !aUL.GetLower() ) + rSet.DisableItem( SID_PARASPACE_DECREASE ); + else if ( aUL.GetUpper() >= 5670 && aUL.GetLower() >= 5670 ) + rSet.DisableItem( SID_PARASPACE_INCREASE ); + if ( nWhich == SID_ATTR_PARA_ULSPACE + || nWhich == SID_ATTR_PARA_ABOVESPACE + || nWhich == SID_ATTR_PARA_BELOWSPACE + ) + { + aUL.SetWhich( nWhich ); + rSet.Put( aUL ); + } + } + else + { + rSet.DisableItem( SID_PARASPACE_INCREASE ); + rSet.DisableItem( SID_PARASPACE_DECREASE ); + rSet.InvalidateItem( SID_ATTR_PARA_ULSPACE ); + rSet.InvalidateItem( SID_ATTR_PARA_ABOVESPACE ); + rSet.InvalidateItem( SID_ATTR_PARA_BELOWSPACE ); + } + } + break; + + case SID_RULER_BORDER_DISTANCE: + { + m_nLeftBorderDistance = 0; + m_nRightBorderDistance = 0; + SfxItemSetFixed<RES_BOX, RES_BOX, + SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER> aCoreSet2(GetPool()); + if ( nSelType & SelectionType::Graphic || + nSelType & SelectionType::Frame || + nSelType & SelectionType::Ole || + nFrameType == FrameTypeFlags::DRAWOBJ ) + rSet.DisableItem(SID_RULER_BORDER_DISTANCE); + else + { + SvxLRSpaceItem aDistLR(SID_RULER_BORDER_DISTANCE); + if(nFrameType & FrameTypeFlags::FLY_ANY) + { + if( IsTabColFromDoc() ) + { + const SwRect& rFlyPrtRect = rSh.GetAnyCurRect( CurRectType::FlyEmbeddedPrt, pPt ); + aDistLR.SetLeft(rFlyPrtRect.Left()); + aDistLR.SetRight(rFlyPrtRect.Left()); + rSet.Put(aDistLR); + } + else + { + SvxBoxInfoItem aBoxInfo( SID_ATTR_BORDER_INNER ); + aCoreSet2.Put(aBoxInfo); + rSh.GetFlyFrameAttr(aCoreSet2); + const SvxBoxItem& rBox = aCoreSet2.Get(RES_BOX); + aDistLR.SetLeft(rBox.GetDistance(SvxBoxItemLine::LEFT)); + aDistLR.SetRight(rBox.GetDistance(SvxBoxItemLine::RIGHT)); + rSet.Put(aDistLR); + + //add the paragraph border distance + SfxItemSetFixed<RES_BOX, RES_BOX> aCoreSet1( GetPool() ); + rSh.GetCurAttr( aCoreSet1 ); + const SvxBoxItem& rParaBox = aCoreSet1.Get(RES_BOX); + aDistLR.SetLeft(aDistLR.GetLeft() + rParaBox.GetDistance(SvxBoxItemLine::LEFT)); + aDistLR.SetRight(aDistLR.GetRight() + rParaBox.GetDistance(SvxBoxItemLine::RIGHT)); + } + m_nLeftBorderDistance = static_cast< sal_uInt16 >(aDistLR.GetLeft()); + m_nRightBorderDistance = static_cast< sal_uInt16 >(aDistLR.GetRight()); + } + else if ( IsTabColFromDoc() || + ( rSh.GetTableFormat() && !bFrameSelection && + !(nFrameType & FrameTypeFlags::COLSECT ) ) ) + { + SvxBoxInfoItem aBoxInfo( SID_ATTR_BORDER_INNER ); + aBoxInfo.SetTable(false); + aBoxInfo.SetDist(true); + aCoreSet2.Put(aBoxInfo); + rSh.GetTabBorders( aCoreSet2 ); + const SvxBoxItem& rBox = aCoreSet2.Get(RES_BOX); + aDistLR.SetLeft(rBox.GetDistance(SvxBoxItemLine::LEFT)); + aDistLR.SetRight(rBox.GetDistance(SvxBoxItemLine::RIGHT)); + rSet.Put(aDistLR); + + //add the border distance of the paragraph + SfxItemSetFixed<RES_BOX, RES_BOX> aCoreSet1( GetPool() ); + rSh.GetCurAttr( aCoreSet1 ); + const SvxBoxItem& rParaBox = aCoreSet1.Get(RES_BOX); + aDistLR.SetLeft(aDistLR.GetLeft() + rParaBox.GetDistance(SvxBoxItemLine::LEFT)); + aDistLR.SetRight(aDistLR.GetRight() + rParaBox.GetDistance(SvxBoxItemLine::RIGHT)); + m_nLeftBorderDistance = static_cast< sal_uInt16 >(aDistLR.GetLeft()); + m_nRightBorderDistance = static_cast< sal_uInt16 >(aDistLR.GetRight()); + } + else if ( !rSh.IsDirectlyInSection() ) + { + //get the page/header/footer border distance + const SwFrameFormat& rMaster = rDesc.GetMaster(); + const SvxBoxItem& rBox = rMaster.GetAttrSet().Get(RES_BOX); + aDistLR.SetLeft(rBox.GetDistance(SvxBoxItemLine::LEFT)); + aDistLR.SetRight(rBox.GetDistance(SvxBoxItemLine::RIGHT)); + + const SvxBoxItem* pBox = nullptr; + if(nFrameType & FrameTypeFlags::HEADER) + { + rMaster.GetHeader(); + const SwFormatHeader& rHeaderFormat = rMaster.GetHeader(); + SwFrameFormat *pHeaderFormat = const_cast<SwFrameFormat*>(rHeaderFormat.GetHeaderFormat()); + if( pHeaderFormat )// #i80890# if rDesc is not the one belonging to the current page is might crash + pBox = & pHeaderFormat->GetBox(); + } + else if(nFrameType & FrameTypeFlags::FOOTER ) + { + const SwFormatFooter& rFooterFormat = rMaster.GetFooter(); + SwFrameFormat *pFooterFormat = const_cast<SwFrameFormat*>(rFooterFormat.GetFooterFormat()); + if( pFooterFormat )// #i80890# if rDesc is not the one belonging to the current page is might crash + pBox = & pFooterFormat->GetBox(); + } + if(pBox) + { + aDistLR.SetLeft(pBox->GetDistance(SvxBoxItemLine::LEFT)); + aDistLR.SetRight(pBox->GetDistance(SvxBoxItemLine::RIGHT)); + } + rSet.Put(aDistLR); + + //add the border distance of the paragraph + rSh.GetCurAttr(aCoreSet2); + const SvxBoxItem& rParaBox = aCoreSet2.Get(RES_BOX); + aDistLR.SetLeft(aDistLR.GetLeft() + rParaBox.GetDistance(SvxBoxItemLine::LEFT)); + aDistLR.SetRight(aDistLR.GetRight() + rParaBox.GetDistance(SvxBoxItemLine::RIGHT)); + m_nLeftBorderDistance = static_cast< sal_uInt16 >(aDistLR.GetLeft()); + m_nRightBorderDistance = static_cast< sal_uInt16 >(aDistLR.GetRight()); + } + } + } + break; + + case SID_RULER_TEXT_RIGHT_TO_LEFT: + { + if ( nSelType & SelectionType::Graphic || + nSelType & SelectionType::Frame || + nSelType & SelectionType::Ole || + nFrameType == FrameTypeFlags::DRAWOBJ) + rSet.DisableItem(nWhich); + else + { + bool bFlag = rSh.IsInRightToLeftText(); + rSet.Put(SfxBoolItem(nWhich, bFlag)); + } + } + break; + + case SID_RULER_BORDERS_VERTICAL: + case SID_RULER_BORDERS: + { + bool bFrameHasVerticalColumns(false); + { + bool bFrameRTL; + bool bFrameVertL2R; + bFrameHasVerticalColumns = rSh.IsFrameVertical(false, bFrameRTL, bFrameVertL2R) && + bFrameSelection; + } + bool bHasTable = ( IsTabColFromDoc() || + ( rSh.GetTableFormat() && !bFrameSelection && + !(nFrameType & FrameTypeFlags::COLSECT ) ) ); + + bool bTableVertical = bHasTable && rSh.IsTableVertical(); + + if(((SID_RULER_BORDERS_VERTICAL == nWhich) && + ((bHasTable && !bTableVertical) || + (!bVerticalWriting && !bFrameSelection && !bHasTable ) || + ( bFrameSelection && !bFrameHasVerticalColumns))) || + ((SID_RULER_BORDERS == nWhich) && + ((bHasTable && bTableVertical) || + (bVerticalWriting && !bFrameSelection&& !bHasTable) || bFrameHasVerticalColumns))) + rSet.DisableItem(nWhich); + else if ( bHasTable ) + { + SwTabCols aTabCols; + size_t nNum = 0; + m_bSetTabColFromDoc = IsTabColFromDoc(); + if ( m_bSetTabColFromDoc ) + { + rSh.GetMouseTabCols( aTabCols, m_aTabColFromDocPos ); + nNum = rSh.GetCurMouseTabColNum( m_aTabColFromDocPos ); + } + else + { + rSh.GetTabCols( aTabCols ); + nNum = rSh.GetCurTabColNum(); + if(rSh.IsTableRightToLeft()) + nNum = aTabCols.Count() - nNum; + } + + OSL_ENSURE(nNum <= aTabCols.Count(), "TabCol not found"); + const int nLft = aTabCols.GetLeftMin() + aTabCols.GetLeft(); + const int nRgt = (bTableVertical ? nPageHeight : nPageWidth) - + (aTabCols.GetLeftMin() + aTabCols.GetRight()); + + const sal_uInt16 nL = static_cast< sal_uInt16 >(std::max(nLft, 0)); + const sal_uInt16 nR = static_cast< sal_uInt16 >(std::max(nRgt, 0)); + + SvxColumnItem aColItem(nNum, nL, nR); + + tools::Long nStart = 0; + tools::Long nEnd = 0; + + //columns in right-to-left tables need to be mirrored + bool bIsTableRTL = + IsTabColFromDoc() ? + rSh.IsMouseTableRightToLeft(m_aTabColFromDocPos) + : rSh.IsTableRightToLeft(); + if(bIsTableRTL) + { + for ( size_t i = aTabCols.Count(); i; --i ) + { + const SwTabColsEntry& rEntry = aTabCols.GetEntry( i - 1 ); + nEnd = aTabCols.GetRight() - rEntry.nPos; + SvxColumnDescription aColDesc( nStart, nEnd, + aTabCols.GetRight() - rEntry.nMax, + aTabCols.GetRight() - rEntry.nMin, + !aTabCols.IsHidden(i - 1) ); + aColItem.Append(aColDesc); + nStart = nEnd; + } + SvxColumnDescription aColDesc(nStart, + aTabCols.GetRight() - aTabCols.GetLeft(), true); + aColItem.Append(aColDesc); + } + else + { + for ( size_t i = 0; i < aTabCols.Count(); ++i ) + { + const SwTabColsEntry& rEntry = aTabCols.GetEntry( i ); + nEnd = rEntry.nPos - aTabCols.GetLeft(); + SvxColumnDescription aColDesc( nStart, nEnd, + rEntry.nMin - aTabCols.GetLeft(), rEntry.nMax - aTabCols.GetLeft(), + !aTabCols.IsHidden(i) ); + aColItem.Append(aColDesc); + nStart = nEnd; + } + SvxColumnDescription aColDesc(nStart, aTabCols.GetRight() - aTabCols.GetLeft(), + 0, 0, true); + aColItem.Append(aColDesc); + } + aColItem.SetWhich(nWhich); + rSet.Put(aColItem); + } + else if ( bFrameSelection || nFrameType & ( FrameTypeFlags::COLUMN | FrameTypeFlags::COLSECT ) ) + { + // Out of frame or page? + sal_uInt16 nNum = 0; + if(bFrameSelection) + { + const SwFrameFormat* pFormat = rSh.GetFlyFrameFormat(); + if(pFormat) + nNum = pFormat->GetCol().GetNumCols(); + } + else + nNum = rSh.GetCurColNum(); + + if( + // For that matter FrameTypeFlags::COLSECT should not be included + // if the border is selected! + !bFrameSelection && + nFrameType & FrameTypeFlags::COLSECT ) + { + const SwSection *pSect = rSh.GetAnySection(false, pPt); + OSL_ENSURE( pSect, "Which section?"); + if( pSect ) + { + SwSectionFormat const *pFormat = pSect->GetFormat(); + const SwFormatCol& rCol = pFormat->GetCol(); + if (rSh.IsColRightToLeft()) + nNum = rCol.GetColumns().size() - nNum; + else + --nNum; + SvxColumnItem aColItem(nNum); + SwRect aRect = rSh.GetAnyCurRect(CurRectType::SectionPrt, pPt); + const SwRect aTmpRect = rSh.GetAnyCurRect(CurRectType::Section, pPt); + + ::lcl_FillSvxColumn(rCol, bVerticalWriting ? aRect.Height() : aRect.Width(), aColItem, 0); + + if(bVerticalWriting) + { + aRect.Pos() += Point(aTmpRect.Left(), aTmpRect.Top()); + aRect.Pos().AdjustY( -(rPageRect.Top()) ); + aColItem.SetLeft(aRect.Top()); + aColItem.SetRight(nPageHeight - aRect.Bottom()); + } + else + { + aRect.Pos() += aTmpRect.Pos(); + + // make relative to page position: + aColItem.SetLeft (o3tl::narrowing<sal_uInt16>( aRect.Left() - rPageRect.Left() )); + aColItem.SetRight(o3tl::narrowing<sal_uInt16>( rPageRect.Right() - aRect.Right())); + } + aColItem.SetOrtho(aColItem.CalcOrtho()); + + aColItem.SetWhich(nWhich); + rSet.Put(aColItem); + } + } + else if( bFrameSelection || nFrameType & FrameTypeFlags::FLY_ANY ) + { + // Columns in frame + if ( nNum ) + { + const SwFrameFormat* pFormat = rSh.GetFlyFrameFormat() ; + + const SwFormatCol& rCol = pFormat->GetCol(); + if (rSh.IsColRightToLeft()) + nNum = rCol.GetColumns().size() - nNum; + else + nNum--; + SvxColumnItem aColItem(nNum); + const SwRect &rSizeRect = rSh.GetAnyCurRect(CurRectType::FlyEmbeddedPrt, pPt); + + bool bUseVertical = bFrameHasVerticalColumns || (!bFrameSelection && bVerticalWriting); + const tools::Long lWidth = bUseVertical ? rSizeRect.Height() : rSizeRect.Width(); + const SwRect &rRect = rSh.GetAnyCurRect(CurRectType::FlyEmbedded, pPt); + tools::Long nDist2 = ((bUseVertical ? rRect.Height() : rRect.Width()) - lWidth) /2; + ::lcl_FillSvxColumn(rCol, lWidth, aColItem, nDist2); + + if(bUseVertical) + { + aColItem.SetLeft(rRect.Top()- rPageRect.Top()); + aColItem.SetRight(nPageHeight + rPageRect.Top() - rRect.Bottom()); + } + else + { + aColItem.SetLeft(rRect.Left() - rPageRect.Left()); + aColItem.SetRight(rPageRect.Right() - rRect.Right()); + } + + aColItem.SetOrtho(aColItem.CalcOrtho()); + + aColItem.SetWhich(nWhich); + rSet.Put(aColItem); + } + else + rSet.DisableItem(nWhich); + } + else + { // Columns on the page + const SwFrameFormat& rMaster = rDesc.GetMaster(); + SwFormatCol aCol(rMaster.GetCol()); + if(rFrameDir.GetValue() == SvxFrameDirection::Horizontal_RL_TB) + nNum = aCol.GetColumns().size() - nNum; + else + nNum--; + + SvxColumnItem aColItem(nNum); + const SwRect aPrtRect = rSh.GetAnyCurRect(CurRectType::PagePrt, pPt); + const SvxBoxItem& rBox = rMaster.GetFormatAttr(RES_BOX); + tools::Long nDist = rBox.GetSmallestDistance(); + + lcl_FillSvxColumn( + aCol, + bVerticalWriting ? aPrtRect.Height() : aPrtRect.Width(), + aColItem, nDist); + + if(bBrowse) + { + if (bVerticalWriting) + { + aColItem.SetLeft(o3tl::narrowing<sal_uInt16>(rPagePrtRect.Top())); + aColItem.SetRight(sal_uInt16(nPageHeight - rPagePrtRect.Bottom())); + } + else + { + aColItem.SetLeft(o3tl::narrowing<sal_uInt16>(rPagePrtRect.Left())); + aColItem.SetRight(sal_uInt16(nPageWidth - rPagePrtRect.Right())); + } + } + else + { + if (bVerticalWriting) + { + SvxULSpaceItem aUL( rDesc.GetMaster().GetULSpace() ); + aColItem.SetLeft (aUL.GetUpper()); + aColItem.SetRight(aUL.GetLower()); + } + else + { + aColItem.SetLeft (aPageLRSpace.GetLeft()); + aColItem.SetRight(aPageLRSpace.GetRight()); + } + } + aColItem.SetOrtho(aColItem.CalcOrtho()); + + aColItem.SetWhich(nWhich); + rSet.Put(aColItem); + } + } + else + rSet.DisableItem(nWhich); + break; + } + + case SID_RULER_ROWS : + case SID_RULER_ROWS_VERTICAL: + { + bool bFrameHasVerticalColumns(false); + { + bool bFrameRTL; + bool bFrameVertL2R; + bFrameHasVerticalColumns = rSh.IsFrameVertical(false, bFrameRTL, bFrameVertL2R) && + bFrameSelection; + } + + if(((SID_RULER_ROWS == nWhich) && + ((!bVerticalWriting && !bFrameSelection) || (bFrameSelection && !bFrameHasVerticalColumns))) || + ((SID_RULER_ROWS_VERTICAL == nWhich) && + ((bVerticalWriting && !bFrameSelection) || bFrameHasVerticalColumns))) + rSet.DisableItem(nWhich); + else if ( IsTabRowFromDoc() || + ( rSh.GetTableFormat() && !bFrameSelection && + !(nFrameType & FrameTypeFlags::COLSECT ) ) ) + { + SwTabCols aTabCols; + m_bSetTabRowFromDoc = IsTabRowFromDoc(); + if ( m_bSetTabRowFromDoc ) + { + rSh.GetMouseTabRows( aTabCols, m_aTabColFromDocPos ); + } + else + { + rSh.GetTabRows( aTabCols ); + } + + const int nLft = aTabCols.GetLeftMin(); + const int nRgt = (bVerticalWriting ? nPageWidth : nPageHeight) - + (aTabCols.GetLeftMin() + aTabCols.GetRight()); + + const sal_uInt16 nL = static_cast< sal_uInt16 >(std::max(nLft, 0)); + const sal_uInt16 nR = static_cast< sal_uInt16 >(std::max(nRgt, 0)); + + SvxColumnItem aColItem(0, nL, nR); + + tools::Long nStart = 0; + tools::Long nEnd = 0; + + for ( size_t i = 0; i < aTabCols.Count(); ++i ) + { + const SwTabColsEntry& rEntry = aTabCols.GetEntry( i ); + if(bVerticalWriting) + { + nEnd = aTabCols.GetRight() - rEntry.nPos; + SvxColumnDescription aColDesc( nStart, nEnd, + std::max(tools::Long(0), aTabCols.GetRight() - rEntry.nMax), + std::max(tools::Long(0), aTabCols.GetRight() - rEntry.nMin), + !aTabCols.IsHidden(i) ); + aColItem.Append(aColDesc); + } + else + { + nEnd = rEntry.nPos - aTabCols.GetLeft(); + SvxColumnDescription aColDesc( nStart, nEnd, + rEntry.nMin - aTabCols.GetLeft(), + rEntry.nMax - aTabCols.GetLeft(), + !aTabCols.IsHidden(i) ); + aColItem.Append(aColDesc); + } + nStart = nEnd; + } + if(bVerticalWriting) + nEnd = aTabCols.GetRight(); + else + nEnd = aTabCols.GetLeft(); + + SvxColumnDescription aColDesc( nStart, nEnd, + aTabCols.GetRight(), + aTabCols.GetRight(), + false ); + aColItem.Append(aColDesc); + + aColItem.SetWhich(nWhich); + rSet.Put(aColItem); + } + else + rSet.DisableItem(nWhich); + } + break; + + case SID_RULER_PAGE_POS: + { + SvxPagePosSizeItem aPagePosSize( + Point( rPageRect.Left(), rPageRect.Top()) , nPageWidth, nPageHeight); + + rSet.Put(aPagePosSize); + break; + } + + case SID_RULER_LR_MIN_MAX: + { + tools::Rectangle aRectangle; + if( ( nFrameType & FrameTypeFlags::COLSECT ) && !IsTabColFromDoc() && + ( nFrameType & ( FrameTypeFlags::TABLE|FrameTypeFlags::COLUMN ) ) ) + { + if( nFrameType & FrameTypeFlags::TABLE ) + { + const size_t nNum = rSh.GetCurTabColNum(); + SwTabCols aTabCols; + rSh.GetTabCols( aTabCols ); + + const int nLft = aTabCols.GetLeftMin() + aTabCols.GetLeft(); + const int nRgt = nPageWidth -(aTabCols.GetLeftMin() + aTabCols.GetRight()); + + const sal_uInt16 nL = static_cast< sal_uInt16 >(std::max(nLft, 0)); + const sal_uInt16 nR = static_cast< sal_uInt16 >(std::max(nRgt, 0)); + + aRectangle.SetLeft( nL ); + if(nNum > 1) + aRectangle.AdjustLeft(aTabCols[nNum - 2] ); + if(nNum) + aRectangle.AdjustLeft(MINLAY ); + if(aTabCols.Count() <= nNum + 1 ) + aRectangle.SetRight( nR ); + else + aRectangle.SetRight( nPageWidth - (nL + aTabCols[nNum + 1]) ); + + if(nNum < aTabCols.Count()) + aRectangle.AdjustRight(MINLAY ); + } + else + { + const SwFrameFormat* pFormat = rSh.GetFlyFrameFormat(); + const SwFormatCol* pCols = pFormat ? &pFormat->GetCol(): + &rDesc.GetMaster().GetCol(); + const SwColumns& rCols = pCols->GetColumns(); + sal_uInt16 nNum = rSh.GetCurOutColNum(); + const sal_uInt16 nCount = std::min(sal_uInt16(nNum + 1), sal_uInt16(rCols.size())); + const SwRect aRect( rSh.GetAnyCurRect( pFormat + ? CurRectType::FlyEmbeddedPrt + : CurRectType::PagePrt, pPt )); + const SwRect aAbsRect( rSh.GetAnyCurRect( pFormat + ? CurRectType::FlyEmbedded + : CurRectType::Page, pPt )); + + // The width of the frame or within the page margins. + const sal_uInt16 nTotalWidth = o3tl::narrowing<sal_uInt16>(aRect.Width()); + // The entire frame width - The difference is twice the distance to the edge. + const sal_uInt16 nOuterWidth = o3tl::narrowing<sal_uInt16>(aAbsRect.Width()); + int nWidth = 0, + nEnd = 0; + aRectangle.SetLeft( 0 ); + for ( sal_uInt16 i = 0; i < nCount; ++i ) + { + const SwColumn* pCol = &rCols[i]; + const int nStart = pCol->GetLeft() + nWidth; + if(i == nNum - 2) + aRectangle.SetLeft( nStart ); + nWidth += pCols->CalcColWidth( i, nTotalWidth ); + nEnd = nWidth - pCol->GetRight(); + } + aRectangle.SetRight( rPageRect.Right() - nEnd ); + aRectangle.AdjustLeft( -(rPageRect.Left()) ); + + if(nNum > 1) + { + aRectangle.AdjustLeft(MINLAY ); + aRectangle.AdjustLeft(aRect.Left() ); + } + if(pFormat) // Range in frame - here you may up to the edge + { + aRectangle.SetLeft(0); + aRectangle.SetRight(0); + } + else + { + // Move the rectangle to the correct absolute position. + aRectangle.AdjustLeft(aAbsRect.Left() ); + aRectangle.AdjustRight( -(aAbsRect.Left()) ); + // Include distance to the border. + aRectangle.AdjustRight( -((nOuterWidth - nTotalWidth) / 2) ); + } + + if(nNum < rCols.size()) + { + aRectangle.AdjustRight(MINLAY ); + } + else + // Right is only the margin now. + aRectangle.SetRight( 0 ); + + } + } + else if ( ((nFrameType & FrameTypeFlags::TABLE) || IsTabColFromDoc()) && + !bFrameSelection ) + { + bool bColumn; + if ( IsTabColFromDoc() ) + bColumn = rSh.GetCurMouseColNum( m_aTabColFromDocPos ) != 0; + else + bColumn = bool(nFrameType & (FrameTypeFlags::COLUMN|FrameTypeFlags::FLY_ANY|FrameTypeFlags::COLSECTOUTTAB)); + + if ( !bColumn ) + { + if( nFrameType & FrameTypeFlags::FLY_ANY && IsTabColFromDoc() ) + { + SwRect aRect( rSh.GetAnyCurRect( + CurRectType::FlyEmbeddedPrt, pPt ) ); + aRect.Pos() += rSh.GetAnyCurRect( CurRectType::FlyEmbedded, + pPt ).Pos(); + + aRectangle.SetLeft( aRect.Left() - rPageRect.Left() ); + aRectangle.SetRight( rPageRect.Right() - aRect.Right() ); + } + else if( bBrowse ) + { + aRectangle.SetLeft( rPagePrtRect.Left() ); + aRectangle.SetRight( nPageWidth - rPagePrtRect.Right() ); + } + else + { + aRectangle.SetLeft( aPageLRSpace.GetLeft() ); + aRectangle.SetRight( aPageLRSpace.GetRight() ); + } + } + else + { // Here only for table in multi-column pages and borders. + bool bSectOutTable = bool(nFrameType & FrameTypeFlags::TABLE); + bool bFrame = bool(nFrameType & FrameTypeFlags::FLY_ANY); + bool bColSct = bool(nFrameType & ( bSectOutTable + ? FrameTypeFlags::COLSECTOUTTAB + : FrameTypeFlags::COLSECT ) + ); + //So you can also drag with the mouse, without being in the table. + CurRectType eRecType = CurRectType::PagePrt; + size_t nNum = IsTabColFromDoc() ? + rSh.GetCurMouseColNum( m_aTabColFromDocPos ): + rSh.GetCurOutColNum(); + const SwFrameFormat* pFormat = nullptr; + if( bColSct ) + { + eRecType = bSectOutTable ? CurRectType::SectionOutsideTable + : CurRectType::Section; + const SwSection *pSect = rSh.GetAnySection( bSectOutTable, pPt ); + OSL_ENSURE( pSect, "Which section?"); + pFormat = pSect->GetFormat(); + } + else if( bFrame ) + { + pFormat = rSh.GetFlyFrameFormat(); + eRecType = CurRectType::FlyEmbeddedPrt; + } + + const SwFormatCol* pCols = pFormat ? &pFormat->GetCol(): + &rDesc.GetMaster().GetCol(); + const SwColumns& rCols = pCols->GetColumns(); + const sal_uInt16 nBorder = pFormat + ? pFormat->GetBox().GetSmallestDistance() + : rDesc.GetMaster().GetBox().GetSmallestDistance(); + + // RECT_FLY_PRT_EMBEDDED returns the relative position to RECT_FLY_EMBEDDED + // the absolute position must be added here + + SwRect aRect( rSh.GetAnyCurRect( eRecType, pPt ) ); + if(CurRectType::FlyEmbeddedPrt == eRecType) + aRect.Pos() += rSh.GetAnyCurRect( CurRectType::FlyEmbedded, + pPt ).Pos(); + + const sal_uInt16 nTotalWidth = o3tl::narrowing<sal_uInt16>(aRect.Width()); + // Initialize nStart and nEnd for nNum == 0 + int nWidth = 0, + nStart = 0, + nEnd = nTotalWidth; + + if( nNum > rCols.size() ) + { + OSL_ENSURE( false, "wrong FormatCol is being edited!" ); + nNum = rCols.size(); + } + + for( size_t i = 0; i < nNum; ++i ) + { + const SwColumn* pCol = &rCols[i]; + nStart = pCol->GetLeft() + nWidth; + nWidth += pCols->CalcColWidth( o3tl::narrowing<sal_uInt16>(i), nTotalWidth ); + nEnd = nWidth - pCol->GetRight(); + } + if( bFrame || bColSct ) + { + aRectangle.SetLeft( aRect.Left() - rPageRect.Left() + nStart ); + aRectangle.SetRight( nPageWidth - aRectangle.Left() - nEnd + nStart ); + } + else if(!bBrowse) + { + aRectangle.SetLeft( aPageLRSpace.GetLeft() + nStart ); + aRectangle.SetRight( nPageWidth - nEnd - aPageLRSpace.GetLeft() ); + } + else + { + tools::Long nLeft = rPagePrtRect.Left(); + aRectangle.SetLeft( nStart + nLeft ); + aRectangle.SetRight( nPageWidth - nEnd - nLeft ); + } + if(!bFrame) + { + aRectangle.AdjustLeft(nBorder ); + aRectangle.AdjustRight( -nBorder ); + } + } + } + else if ( nFrameType & ( FrameTypeFlags::HEADER | FrameTypeFlags::FOOTER )) + { + aRectangle.SetLeft( aPageLRSpace.GetLeft() ); + aRectangle.SetRight( aPageLRSpace.GetRight() ); + } + else + { + aRectangle.SetLeft(0); + aRectangle.SetRight(0); + } + + SfxRectangleItem aLR( SID_RULER_LR_MIN_MAX , aRectangle); + rSet.Put(aLR); + } + break; + + case SID_RULER_PROTECT: + { + if(bFrameSelection) + { + FlyProtectFlags nProtect = m_pWrtShell->IsSelObjProtected( FlyProtectFlags::Size|FlyProtectFlags::Pos|FlyProtectFlags::Content ); + + SvxProtectItem aProt(SID_RULER_PROTECT); + aProt.SetContentProtect(bool(nProtect & FlyProtectFlags::Content)); + aProt.SetSizeProtect (bool(nProtect & FlyProtectFlags::Size)); + aProt.SetPosProtect (bool(nProtect & FlyProtectFlags::Pos)); + rSet.Put(aProt); + } + else + { + SvxProtectItem aProtect(SID_RULER_PROTECT); + if(bBrowse && !(nFrameType & (FrameTypeFlags::DRAWOBJ|FrameTypeFlags::COLUMN)) && !rSh.GetTableFormat()) + { + aProtect.SetSizeProtect(true); + aProtect.SetPosProtect(true); + } + rSet.Put(aProtect); + } + } + break; + + case SID_ATTR_PAGE_HEADER: + case SID_ATTR_PAGE_HEADER_LRMARGIN: + case SID_ATTR_PAGE_HEADER_SPACING: + case SID_ATTR_PAGE_HEADER_LAYOUT: + { + const SwFormatHeader& rHeader = rDesc.GetMaster().GetHeader(); + bool bHeaderOn = rHeader.IsActive(); + rSet.Put( SfxBoolItem(SID_ATTR_PAGE_HEADER, bHeaderOn ) ); + if(bHeaderOn) + { + const SvxLRSpaceItem* pLR = static_cast<const SvxLRSpaceItem*>( + rHeader.GetHeaderFormat()->GetAttrSet().GetItem(SID_ATTR_LRSPACE)); + const SvxULSpaceItem* pUL = static_cast<const SvxULSpaceItem*>( + rHeader.GetHeaderFormat()->GetAttrSet().GetItem(SID_ATTR_ULSPACE)); + if (pLR && pUL) + { + SvxLongLRSpaceItem aLR(pLR->GetLeft(), pLR->GetRight(), SID_ATTR_PAGE_HEADER_LRMARGIN); + rSet.Put(aLR); + SvxLongULSpaceItem aUL( pUL->GetUpper(), pUL->GetLower(), SID_ATTR_PAGE_HEADER_SPACING); + rSet.Put(aUL); + } + + bool bShared = !rDesc.IsHeaderShared(); + bool bFirst = !rDesc.IsFirstShared(); // FIXME control changes for both header footer - tdf#100287 + sal_uInt16 nLayout = (static_cast<int>(bShared)<<1) + static_cast<int>(bFirst); + SfxInt16Item aLayoutItem(SID_ATTR_PAGE_HEADER_LAYOUT, nLayout); + rSet.Put(aLayoutItem); + } + } + break; + case SID_ATTR_PAGE_FOOTER: + case SID_ATTR_PAGE_FOOTER_LRMARGIN: + case SID_ATTR_PAGE_FOOTER_SPACING: + case SID_ATTR_PAGE_FOOTER_LAYOUT: + { + const SwFormatFooter& rFooter = rDesc.GetMaster().GetFooter(); + bool bFooterOn = rFooter.IsActive(); + rSet.Put( SfxBoolItem(SID_ATTR_PAGE_FOOTER, bFooterOn ) ); + if(bFooterOn) + { + const SvxLRSpaceItem* rLR = rFooter.GetFooterFormat()->GetAttrSet().GetItem<SvxLRSpaceItem>(SID_ATTR_LRSPACE); + const SvxULSpaceItem* rUL = rFooter.GetFooterFormat()->GetAttrSet().GetItem<SvxULSpaceItem>(SID_ATTR_ULSPACE); + SvxLongLRSpaceItem aLR(rLR->GetLeft(), rLR->GetRight(), SID_ATTR_PAGE_FOOTER_LRMARGIN); + rSet.Put(aLR); + SvxLongULSpaceItem aUL( rUL->GetUpper(), rUL->GetLower(), SID_ATTR_PAGE_FOOTER_SPACING); + rSet.Put(aUL); + + bool bShared = !rDesc.IsFooterShared(); + bool bFirst = !rDesc.IsFirstShared(); // FIXME control changes for both header footer - tdf#100287 + sal_uInt16 nLayout = (static_cast<int>(bShared)<<1) + static_cast<int>(bFirst); + SfxInt16Item aLayoutItem(SID_ATTR_PAGE_FOOTER_LAYOUT, nLayout); + rSet.Put(aLayoutItem); + } + } + break; + + case SID_ATTR_PAGE_COLOR: + case SID_ATTR_PAGE_FILLSTYLE: + case SID_ATTR_PAGE_GRADIENT: + case SID_ATTR_PAGE_HATCH: + case SID_ATTR_PAGE_BITMAP: + { + SfxItemSet aSet = rDesc.GetMaster().GetAttrSet(); + if (const auto pFillStyleItem = aSet.GetItem(XATTR_FILLSTYLE)) + { + drawing::FillStyle eXFS = pFillStyleItem->GetValue(); + XFillStyleItem aFillStyleItem( eXFS ); + aFillStyleItem.SetWhich( SID_ATTR_PAGE_FILLSTYLE ); + rSet.Put(aFillStyleItem); + + switch(eXFS) + { + case drawing::FillStyle_SOLID: + { + if (const auto pItem = aSet.GetItem<XFillColorItem>(XATTR_FILLCOLOR, false)) + { + Color aColor = pItem->GetColorValue(); + XFillColorItem aFillColorItem( OUString(), aColor ); + aFillColorItem.SetWhich( SID_ATTR_PAGE_COLOR ); + rSet.Put( aFillColorItem ); + } + break; + } + + case drawing::FillStyle_GRADIENT: + { + const XGradient& xGradient = aSet.GetItem<XFillGradientItem>( XATTR_FILLGRADIENT )->GetGradientValue(); + XFillGradientItem aFillGradientItem( OUString(), xGradient, SID_ATTR_PAGE_GRADIENT ); + rSet.Put( aFillGradientItem ); + } + break; + + case drawing::FillStyle_HATCH: + { + const XFillHatchItem *pFillHatchItem( aSet.GetItem<XFillHatchItem>( XATTR_FILLHATCH ) ); + XFillHatchItem aFillHatchItem( pFillHatchItem->GetName(), pFillHatchItem->GetHatchValue()); + aFillHatchItem.SetWhich( SID_ATTR_PAGE_HATCH ); + rSet.Put( aFillHatchItem ); + } + break; + + case drawing::FillStyle_BITMAP: + { + const XFillBitmapItem *pFillBitmapItem = aSet.GetItem<XFillBitmapItem>( XATTR_FILLBITMAP ); + XFillBitmapItem aFillBitmapItem( pFillBitmapItem->GetName(), pFillBitmapItem->GetGraphicObject() ); + aFillBitmapItem.SetWhich( SID_ATTR_PAGE_BITMAP ); + rSet.Put( aFillBitmapItem ); + } + break; + case drawing::FillStyle_NONE: + { + } + break; + + default: + break; + } + } + break; + } + + } + nWhich = aIter.NextWhich(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |