LibreOffice Module sw (master) 1
extinput.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <algorithm>
21
22#include <com/sun/star/i18n/ScriptType.hpp>
23
24#include <editeng/langitem.hxx>
25#include <osl/diagnose.h>
27#include <vcl/commandevent.hxx>
28
29#include <hintids.hxx>
30#include <extinput.hxx>
31#include <doc.hxx>
32#include <IDocumentUndoRedo.hxx>
33#include <contentindex.hxx>
34#include <ndtxt.hxx>
35#include <swundo.hxx>
36
37using namespace ::com::sun::star;
38
39SwExtTextInput::SwExtTextInput( const SwPaM& rPam, Ring* pRing )
40 : SwPaM( *rPam.GetPoint(), static_cast<SwPaM*>(pRing) ),
41 m_eInputLanguage(LANGUAGE_DONTKNOW)
42{
44 m_bInsText = true;
45}
46
48{
49 SwDoc& rDoc = GetDoc();
50 if (rDoc.IsInDtor()) { return; /* #i58606# */ }
51
53 if( !pTNd )
54 return;
55
56 SwPosition& rPtPos = *GetPoint();
57 sal_Int32 nSttCnt = rPtPos.GetContentIndex();
58 sal_Int32 nEndCnt = GetMark()->GetContentIndex();
59 if( nEndCnt == nSttCnt )
60 return;
61
62 // Prevent IME edited text being grouped with non-IME edited text.
63 bool bKeepGroupUndo = rDoc.GetIDocumentUndoRedo().DoesGroupUndo();
64 bool bWasIME = rDoc.GetIDocumentUndoRedo().GetUndoActionCount() == 0 || rDoc.getIDocumentContentOperations().GetIME();
65 if (!bWasIME)
66 {
68 }
70 if( nEndCnt < nSttCnt )
71 {
72 std::swap(nSttCnt, nEndCnt);
73 }
74
75 // In order to get Undo/Redlining etc. working correctly,
76 // we need to go through the Doc interface
77 rPtPos.SetContent(nSttCnt);
78 const OUString sText( pTNd->GetText().copy(nSttCnt, nEndCnt - nSttCnt));
79 if( m_bIsOverwriteCursor && !m_sOverwriteText.isEmpty() )
80 {
81 const sal_Int32 nLen = sText.getLength();
82 const sal_Int32 nOWLen = m_sOverwriteText.getLength();
83 if( nLen > nOWLen )
84 {
85 rPtPos.AdjustContent(+nOWLen);
86 pTNd->EraseText( rPtPos, nLen - nOWLen );
87 rPtPos.SetContent(nSttCnt);
88 pTNd->ReplaceText( rPtPos, nOWLen, m_sOverwriteText );
89 if( m_bInsText )
90 {
91 rPtPos.SetContent(nSttCnt);
93 rDoc.getIDocumentContentOperations().Overwrite( *this, sText.copy( 0, nOWLen ) );
94 rDoc.getIDocumentContentOperations().InsertString( *this, sText.copy( nOWLen ) );
96 }
97 }
98 else
99 {
100 pTNd->ReplaceText( rPtPos, nLen, m_sOverwriteText.copy( 0, nLen ));
101 if( m_bInsText )
102 {
103 rPtPos.SetContent(nSttCnt);
104 rDoc.getIDocumentContentOperations().Overwrite( *this, sText );
105 }
106 }
107 }
108 else
109 {
110 // 1. Insert text at start position with EMPTYEXPAND to use correct formatting
111 // ABC<NEW><OLD>
112 // 2. Then remove old (not tracked) content
113 // ABC<NEW>
114
115 sal_Int32 nLenghtOfOldString = nEndCnt - nSttCnt;
116
117 if( m_bInsText )
118 {
119 rPtPos.SetContent(nSttCnt);
121 }
122
123 pTNd->EraseText( rPtPos, nLenghtOfOldString );
124 }
125 if (!bWasIME)
126 {
127 rDoc.GetIDocumentUndoRedo().DoGroupUndo(bKeepGroupUndo);
128 }
130 return;
131
132 sal_uInt16 nWhich = RES_CHRATR_LANGUAGE;
134 switch(nScriptType)
135 {
136 case i18n::ScriptType::ASIAN:
137 nWhich = RES_CHRATR_CJK_LANGUAGE; break;
138 case i18n::ScriptType::COMPLEX:
139 nWhich = RES_CHRATR_CTL_LANGUAGE; break;
140 }
141 // #i41974# Only set language attribute for CJK/CTL scripts.
142 if (RES_CHRATR_LANGUAGE != nWhich && pTNd->GetLang( nSttCnt, nEndCnt-nSttCnt, nScriptType) != m_eInputLanguage)
143 {
144 SvxLanguageItem aLangItem( m_eInputLanguage, nWhich );
145 rPtPos.SetContent(nSttCnt);
146 GetMark()->SetContent(nEndCnt);
147 rDoc.getIDocumentContentOperations().InsertPoolItem(*this, aLangItem );
148 }
149}
150
152{
153 SwTextNode* pTNd = GetPoint()->GetNode().GetTextNode();
154 if( !pTNd )
155 return;
156
157 sal_Int32 nSttCnt = Start()->GetContentIndex();
158 sal_Int32 nEndCnt = End()->GetContentIndex();
159
160 SwContentIndex aIdx( pTNd, nSttCnt );
161 const OUString& rNewStr = rData.GetText();
162
163 if( m_bIsOverwriteCursor && !m_sOverwriteText.isEmpty() )
164 {
165 sal_Int32 nReplace = nEndCnt - nSttCnt;
166 const sal_Int32 nNewLen = rNewStr.getLength();
167 if( nNewLen < nReplace )
168 {
169 // We have to insert some characters from the saved original text
170 nReplace -= nNewLen;
171 aIdx += nNewLen;
172 pTNd->ReplaceText( aIdx, nReplace,
173 m_sOverwriteText.copy( nNewLen, nReplace ));
174 aIdx = nSttCnt;
175 nReplace = nNewLen;
176 }
177 else
178 {
179 const sal_Int32 nOWLen = m_sOverwriteText.getLength();
180 if( nOWLen < nReplace )
181 {
182 aIdx += nOWLen;
183 pTNd->EraseText( aIdx, nReplace-nOWLen );
184 aIdx = nSttCnt;
185 nReplace = nOWLen;
186 }
187 else
188 {
189 nReplace = std::min(nOWLen, nNewLen);
190 }
191 }
192
193 pTNd->ReplaceText( aIdx, nReplace, rNewStr );
194 if( !HasMark() )
195 SetMark();
196 GetMark()->Assign(*aIdx.GetContentNode(), aIdx.GetIndex());
197 }
198 else
199 {
200 if( nSttCnt < nEndCnt )
201 {
202 pTNd->EraseText( aIdx, nEndCnt - nSttCnt );
203 }
204
205 // NOHINTEXPAND so we can use correct formatting in destructor when we finish composing
206 pTNd->InsertText( rNewStr, aIdx, SwInsertFlags::NOHINTEXPAND );
207 if( !HasMark() )
208 SetMark();
209 }
210
211 GetPoint()->SetContent(nSttCnt);
212
213 m_aAttrs.clear();
214 if( rData.GetTextAttr() )
215 {
216 const ExtTextInputAttr *pAttrs = rData.GetTextAttr();
217 m_aAttrs.insert( m_aAttrs.begin(), pAttrs, pAttrs + rData.GetText().getLength() );
218 }
219}
220
222{
223 m_bIsOverwriteCursor = bFlag;
225 return;
226
227 const SwTextNode *const pTNd = GetPoint()->GetNode().GetTextNode();
228 if (!pTNd)
229 return;
230
231 const sal_Int32 nSttCnt = GetPoint()->GetContentIndex();
232 const sal_Int32 nEndCnt = GetMark()->GetContentIndex();
233 m_sOverwriteText = pTNd->GetText().copy( std::min(nSttCnt, nEndCnt) );
234 if( m_sOverwriteText.isEmpty() )
235 return;
236
237 const sal_Int32 nInPos = m_sOverwriteText.indexOf( CH_TXTATR_INWORD );
238 const sal_Int32 nBrkPos = m_sOverwriteText.indexOf( CH_TXTATR_BREAKWORD );
239
240 // Find the first attr found, if any.
241 sal_Int32 nPos = std::min(nInPos, nBrkPos);
242 if (nPos<0)
243 {
244 nPos = std::max(nInPos, nBrkPos);
245 }
246 if (nPos>=0)
247 {
249 }
250}
251
252// The Doc interfaces
253
255{
256 SwExtTextInput* pNew = new SwExtTextInput( rPam, mpExtInputRing );
257 if( !mpExtInputRing )
258 mpExtInputRing = pNew;
259 pNew->SetMark();
260 return pNew;
261}
262
264{
265 if( pDel == mpExtInputRing )
266 {
267 if( pDel->GetNext() != mpExtInputRing )
268 mpExtInputRing = pDel->GetNext();
269 else
270 mpExtInputRing = nullptr;
271 }
272 delete pDel;
273}
274
276 sal_Int32 nContentPos ) const
277{
278 SwExtTextInput* pRet = nullptr;
279 if( mpExtInputRing )
280 {
281 SwNodeOffset nNdIdx = rNd.GetIndex();
283 do {
284 SwNodeOffset nStartNode = pTmp->Start()->GetNodeIndex(),
285 nEndNode = pTmp->End()->GetNodeIndex();
286 sal_Int32 nStartCnt = pTmp->Start()->GetContentIndex();
287 sal_Int32 nEndCnt = pTmp->End()->GetContentIndex();
288
289 if( nStartNode <= nNdIdx && nNdIdx <= nEndNode &&
290 ( nContentPos<0 ||
291 ( nStartCnt <= nContentPos && nContentPos <= nEndCnt )))
292 {
293 pRet = pTmp;
294 break;
295 }
296 pTmp = pTmp->GetNext();
297 } while ( pTmp!=mpExtInputRing );
298 }
299 return pRet;
300}
301
303{
305 "more than one InputEngine available" );
306 return mpExtInputRing;
307}
308
309/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const OUString & GetText() const
const ExtTextInputAttr * GetTextAttr() const
virtual bool Overwrite(const SwPaM &rRg, const OUString &rStr)=0
Overwrite string in an existing text node.
virtual bool GetIME() const =0
Did the last inserted string come from IME?
virtual void SetIME(bool bIME)=0
States that the last inserted string came from IME.
virtual bool InsertPoolItem(const SwPaM &rRg, const SfxPoolItem &, const SetAttrMode nFlags=SetAttrMode::DEFAULT, SwRootFrame const *pLayout=nullptr, SwTextAttr **ppNewTextAttr=nullptr)=0
Insert an attribute.
virtual bool InsertString(const SwPaM &rRg, const OUString &, const SwInsertFlags nInsertMode=SwInsertFlags::EMPTYEXPAND)=0
Insert string into existing text node at position rRg.Point().
virtual void DoGroupUndo(bool const bDoUndo)=0
Enable/Disable Group Undo.
virtual SwUndoId EndUndo(SwUndoId const eUndoId, SwRewriter const *const pRewriter)=0
Closes undo block.
virtual bool DoesGroupUndo() const =0
Is Group Undo enabled?
virtual size_t GetUndoActionCount(const bool bCurrentLevel=true) const =0
Get the number of Undo actions.
virtual SwUndoId StartUndo(SwUndoId const eUndoId, SwRewriter const *const pRewriter)=0
Opens undo block.
Marks a character position inside a document model content node (SwContentNode)
sal_Int32 GetIndex() const
const SwContentNode * GetContentNode() const
Definition: doc.hxx:194
bool IsInDtor() const
Definition: doc.hxx:412
void DeleteExtTextInput(SwExtTextInput *pDel)
Definition: extinput.cxx:263
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:321
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:150
SwExtTextInput * mpExtInputRing
Definition: doc.hxx:282
SwExtTextInput * GetExtTextInput() const
Definition: extinput.cxx:302
SwExtTextInput * CreateExtTextInput(const SwPaM &rPam)
Definition: extinput.cxx:254
bool m_bIsOverwriteCursor
Definition: extinput.hxx:32
LanguageType m_eInputLanguage
Definition: extinput.hxx:33
void SetInputData(const CommandExtTextInputData &rData)
Definition: extinput.cxx:151
void SetOverwriteCursor(bool bFlag)
Definition: extinput.cxx:221
SwExtTextInput(const SwPaM &rPam, Ring *pRing)
Definition: extinput.cxx:39
OUString m_sOverwriteText
Definition: extinput.hxx:30
virtual ~SwExtTextInput() override
Definition: extinput.cxx:47
SwExtTextInput * GetNext()
Definition: extinput.hxx:45
std::vector< ExtTextInputAttr > m_aAttrs
Definition: extinput.hxx:29
Base class of the Writer document model elements.
Definition: node.hxx:98
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:897
SwNodeOffset GetIndex() const
Definition: node.hxx:312
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:187
const SwPosition * GetMark() const
Definition: pam.hxx:263
virtual void SetMark()
Unless this is called, the getter method of Mark will return Point.
Definition: pam.cxx:642
bool IsMultiSelection() const
Definition: pam.hxx:328
const SwPosition * End() const
Definition: pam.hxx:271
SwDoc & GetDoc() const
Definition: pam.hxx:299
const SwPosition * GetPoint() const
Definition: pam.hxx:261
const SwPosition * Start() const
Definition: pam.hxx:266
bool HasMark() const
A PaM marks a selection if Point and Mark are distinct positions.
Definition: pam.hxx:259
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:111
void EraseText(const SwContentIndex &rIdx, const sal_Int32 nCount=SAL_MAX_INT32, const SwInsertFlags nMode=SwInsertFlags::DEFAULT)
delete text content ATTENTION: must not be called with a range that overlaps the start of an attribut...
Definition: ndtxt.cxx:2763
OUString InsertText(const OUString &rStr, const SwContentIndex &rIdx, const SwInsertFlags nMode=SwInsertFlags::DEFAULT)
insert text content
Definition: ndtxt.cxx:2358
void ReplaceText(const SwContentIndex &rStart, const sal_Int32 nDelLen, const OUString &rText)
replace nDelLen characters at rStart with rText in case the replacement does not fit,...
Definition: ndtxt.cxx:3788
const OUString & GetText() const
Definition: ndtxt.hxx:242
LanguageType GetLang(const sal_Int32 nBegin, const sal_Int32 nLen=0, sal_uInt16 nScript=0) const
Definition: thints.cxx:3462
ExtTextInputAttr
constexpr TypedWhichId< SvxLanguageItem > RES_CHRATR_LANGUAGE(10)
constexpr TypedWhichId< SvxLanguageItem > RES_CHRATR_CTL_LANGUAGE(29)
constexpr TypedWhichId< SvxLanguageItem > RES_CHRATR_CJK_LANGUAGE(24)
#define CH_TXTATR_INWORD
Definition: hintids.hxx:171
#define CH_TXTATR_BREAKWORD
Definition: hintids.hxx:170
#define LANGUAGE_DONTKNOW
sal_uInt16 nPos
sal_Int16 GetI18NScriptTypeOfLanguage(LanguageType nLang)
SwNodeOffset min(const SwNodeOffset &a, const SwNodeOffset &b)
Definition: nodeoffset.hxx:35
Marks a position in the document model.
Definition: pam.hxx:37
SwNode & GetNode() const
Definition: pam.hxx:80
void Assign(const SwNode &rNd, SwNodeOffset nDelta, sal_Int32 nContentOffset=0)
These all set both nNode and nContent.
Definition: pam.cxx:230
void SetContent(sal_Int32 nContentIndex)
Set content index, only valid to call this if the position points to a SwContentNode subclass.
Definition: pam.cxx:266
SwNodeOffset GetNodeIndex() const
Definition: pam.hxx:77
sal_Int32 GetContentIndex() const
Definition: pam.hxx:84
void AdjustContent(sal_Int32 nDelta)
Adjust content index, only valid to call this if the position points to a SwContentNode subclass.
Definition: pam.cxx:261