1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/i18n/XBreakIterator.hpp>
21 #include <osl/diagnose.h>
22 #include <fmtcntnt.hxx>
23 #include <txatbase.hxx>
30 #include <fmtfsize.hxx>
33 #include <breakit.hxx>
34 #include <UndoTable.hxx>
36 SwCallLink::SwCallLink( SwCursorShell
& rSh
)
39 // remember SPoint-values of current cursor
40 SwPaM
* pCursor
= m_rShell
.IsTableMode() ? m_rShell
.GetTableCrs() : m_rShell
.GetCursor();
41 SwNode
& rNd
= pCursor
->GetPoint()->GetNode();
42 m_nNode
= rNd
.GetIndex();
43 m_nContent
= pCursor
->GetPoint()->GetContentIndex();
44 m_nNodeType
= rNd
.GetNodeType();
45 m_bHasSelection
= ( *pCursor
->GetPoint() != *pCursor
->GetMark() );
47 if( rNd
.IsTextNode() )
48 m_nLeftFramePos
= SwCallLink::getLayoutFrame( m_rShell
.GetLayout(), *rNd
.GetTextNode(), m_nContent
,
49 !m_rShell
.ActionPend() );
54 // A special treatment for SwFeShell:
55 // When deleting the header/footer, footnotes SwFeShell sets the
56 // Cursor to NULL (Node + Content).
57 // If the Cursor is not on a ContentNode (ContentNode) this fact gets
59 if( SwNodeType::ContentMask
& m_nNodeType
)
60 m_nNodeType
= SwNodeType::NONE
;
67 An empty paragraph inside a table with a nested table preceding it
68 should be hidden, unless the cursor is positioned in the paragraph.
70 If the cursor is now (or was previously) inside such a paragraph,
71 send a size change notification on the row frame to force reformatting.
73 void NotifyTableCollapsedParagraph(const SwContentNode
*const pNode
, SwCursorShell
*const pShell
)
78 SwFrame
*const pMyFrame
= pNode
->getLayoutFrame(pShell
? pShell
->GetLayout() : nullptr);
82 // important: only invalidate layout if something is actually hidden or
83 // shown! Otherwise performance is going to suffer with "difficult" tables.
84 if (!pMyFrame
->IsCollapse())
87 SwRowFrame
*const pRow
= pMyFrame
->FindRowFrame();
91 const SwTableLine
* pLine
= pRow
->GetTabLine( );
93 if (pShell
&& (pShell
->IsTableMode() || (pShell
->StartsWith_() != SwCursorShell::StartsWith::None
&& pShell
->ExtendedSelectedAll())))
95 // If we have a table selection, then avoid the notification: it's not necessary (the text
96 // cursor needs no updating) and the notification may kill the selection overlay, leading to
98 // Same for whole-document selection when it starts with a table.
102 // notify a change in frame size to force reformatting of the row
103 const SwFormatFrameSize aSize
= pLine
->GetFrameFormat()->GetFrameSize();
104 pRow
->OnFrameSize(aSize
);
109 void SwCallLink::ImplDestroy()
111 if( m_nNodeType
== SwNodeType::NONE
|| !m_rShell
.m_bCallChgLnk
) // see ctor
114 // If travelling over Nodes check formats and register them anew at the
116 SwPaM
* pCurrentCursor
= m_rShell
.IsTableMode() ? m_rShell
.GetTableCrs() : m_rShell
.GetCursor();
117 SwContentNode
* pCNd
= pCurrentCursor
->GetPointContentNode();
121 if (pCNd
->GetIndex() != m_nNode
) // only if moved to different node
123 ::sw::NotifyTableCollapsedParagraph(pCNd
, &m_rShell
);
125 const SwDoc
*pDoc
=m_rShell
.GetDoc();
126 if (sal_Int32(m_nNode
) < sal_Int32(pDoc
->GetNodes().Count()))
128 const SwContentNode
*const pNode
= pDoc
->GetNodes()[m_nNode
]->GetContentNode();
129 ::sw::NotifyTableCollapsedParagraph(pNode
, &m_rShell
);
133 sal_Int32 nCmp
, nCurrentContent
= pCurrentCursor
->GetPoint()->GetContentIndex();
134 SwNodeType nNdWhich
= pCNd
->GetNodeType();
135 SwNodeOffset nCurrentNode
= pCurrentCursor
->GetPoint()->GetNodeIndex();
137 // Register the Shell as dependent at the current Node. By doing this all
138 // attribute changes can be signaled over the link.
139 pCNd
->Add( &m_rShell
);
141 const bool bCurrentHasSelection
= (*pCurrentCursor
->GetPoint() != *pCurrentCursor
->GetMark());
143 if( m_nNodeType
!= nNdWhich
|| m_nNode
!= nCurrentNode
)
145 // Every time a switch between nodes occurs, there is a chance that
146 // new attributes do apply - meaning text-attributes.
147 // So the currently applying attributes would have to be determined.
148 // That can be done in one go by the handler.
149 m_rShell
.CallChgLnk();
151 else if (m_bHasSelection
!= bCurrentHasSelection
)
153 // always call change link when selection changes
154 m_rShell
.CallChgLnk();
156 else if( m_rShell
.m_aChgLnk
.IsSet() && SwNodeType::Text
== nNdWhich
&&
157 m_nContent
!= nCurrentContent
)
159 // If travelling with left/right only and the frame is
160 // unchanged (columns!) then check text hints.
161 if( m_nLeftFramePos
== SwCallLink::getLayoutFrame( m_rShell
.GetLayout(), *pCNd
->GetTextNode(), nCurrentContent
,
162 !m_rShell
.ActionPend() ) &&
163 (( nCmp
= m_nContent
) + 1 == nCurrentContent
|| // Right
164 m_nContent
-1 == ( nCmp
= nCurrentContent
)) ) // Left
166 if( nCmp
== nCurrentContent
&& pCurrentCursor
->HasMark() ) // left & select
169 if ( pCNd
->GetTextNode()->HasHints() )
171 const SwpHints
&rHts
= pCNd
->GetTextNode()->GetSwpHints();
173 for( size_t n
= 0; n
< rHts
.Count(); ++n
)
175 const SwTextAttr
* pHt
= rHts
.Get( n
);
176 const sal_Int32
*pEnd
= pHt
->End();
177 const sal_Int32 nStart
= pHt
->GetStart();
179 // If "only start" or "start and end equal" then call on
180 // every overflow of start.
181 if( ( !pEnd
|| ( nStart
== *pEnd
) ) &&
182 ( nStart
== m_nContent
|| nStart
== nCurrentContent
) )
184 m_rShell
.CallChgLnk();
188 // If the attribute has an area and that area is not empty ...
189 else if( pEnd
&& nStart
< *pEnd
&&
190 // ... then test if travelling occurred via start/end.
192 ( pHt
->DontExpand() ? nCmp
== *pEnd
-1
195 m_rShell
.CallChgLnk();
201 assert(g_pBreakIt
&& g_pBreakIt
->GetBreakIter().is());
202 const OUString rText
= pCNd
->GetTextNode()->GetText();
204 g_pBreakIt
->GetBreakIter()->getScriptType( rText
, m_nContent
)
205 != g_pBreakIt
->GetBreakIter()->getScriptType(rText
, nCurrentContent
))
207 m_rShell
.CallChgLnk();
212 // If travelling more than one character with home/end/.. then
213 // always call ChgLnk, because it can not be determined here what
214 // has changed. Something may have changed.
215 m_rShell
.CallChgLnk();
218 const SwFrame
* pFrame
;
219 const SwFlyFrame
*pFlyFrame
;
220 if (m_rShell
.ActionPend())
222 pFrame
= pCNd
->getLayoutFrame(m_rShell
.GetLayout(), nullptr, nullptr);
225 pFlyFrame
= pFrame
->FindFlyFrame();
226 if ( !pFlyFrame
|| m_rShell
.IsTableMode() )
229 const SwNodeIndex
* pIndex
= pFlyFrame
->GetFormat()->GetContent().GetContentIdx();
230 OSL_ENSURE( pIndex
, "Fly without Content" );
235 const SwNode
& rStNd
= pIndex
->GetNode();
237 if( rStNd
.EndOfSectionNode()->StartOfSectionIndex() > m_nNode
||
238 m_nNode
> rStNd
.EndOfSectionIndex() )
239 m_rShell
.GetFlyMacroLnk().Call( pFlyFrame
->GetFormat() );
242 SwCallLink::~SwCallLink()
244 suppress_fun_call_w_exception(ImplDestroy());
247 tools::Long
SwCallLink::getLayoutFrame(const SwRootFrame
* pRoot
,
248 SwTextNode
const & rNd
, sal_Int32 nCntPos
, bool /*bCalcFrame*/)
250 SwTextFrame
* pFrame
= static_cast<SwTextFrame
*>(rNd
.getLayoutFrame(pRoot
, nullptr, nullptr));
252 if ( pFrame
&& !pFrame
->IsHiddenNow() )
254 if( pFrame
->HasFollow() )
256 TextFrameIndex
const nPos(pFrame
->MapModelToView(&rNd
, nCntPos
));
259 pNext
= pFrame
->GetFollow();
260 if(!pNext
|| nPos
< pNext
->GetOffset())
266 return pFrame
->getFrameArea().Left();
271 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */