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>
26 #include <svl/languageoptions.hxx>
27 #include <vcl/commandevent.hxx>
28 
29 #include <hintids.hxx>
30 #include <extinput.hxx>
31 #include <doc.hxx>
32 #include <IDocumentUndoRedo.hxx>
33 #include <index.hxx>
34 #include <ndtxt.hxx>
35 #include <swundo.hxx>
36 
37 using namespace ::com::sun::star;
38 
39 SwExtTextInput::SwExtTextInput( const SwPaM& rPam, Ring* pRing )
40  : SwPaM( *rPam.GetPoint(), static_cast<SwPaM*>(pRing) ),
41  m_eInputLanguage(LANGUAGE_DONTKNOW)
42 {
43  m_bIsOverwriteCursor = false;
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  SwIndex& rIdx = GetPoint()->nContent;
57  sal_Int32 nSttCnt = rIdx.GetIndex();
58  sal_Int32 nEndCnt = GetMark()->nContent.GetIndex();
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  {
67  rDoc.GetIDocumentUndoRedo().DoGroupUndo(false);
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  rIdx = 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  rIdx += nOWLen;
86  pTNd->EraseText( rIdx, nLen - nOWLen );
87  rIdx = nSttCnt;
88  pTNd->ReplaceText( rIdx, nOWLen, m_sOverwriteText );
89  if( m_bInsText )
90  {
91  rIdx = 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( rIdx, nLen, m_sOverwriteText.copy( 0, nLen ));
101  if( m_bInsText )
102  {
103  rIdx = 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 )
119 
120  rIdx = nEndCnt;
121 
122  pTNd->EraseText( rIdx, nLenghtOfOldString );
123  }
124  if (!bWasIME)
125  {
126  rDoc.GetIDocumentUndoRedo().DoGroupUndo(bKeepGroupUndo);
127  }
129  return;
130 
131  sal_uInt16 nWhich = RES_CHRATR_LANGUAGE;
133  switch(nScriptType)
134  {
135  case i18n::ScriptType::ASIAN:
136  nWhich = RES_CHRATR_CJK_LANGUAGE; break;
137  case i18n::ScriptType::COMPLEX:
138  nWhich = RES_CHRATR_CTL_LANGUAGE; break;
139  }
140  // #i41974# Only set language attribute for CJK/CTL scripts.
141  if (RES_CHRATR_LANGUAGE != nWhich && pTNd->GetLang( nSttCnt, nEndCnt-nSttCnt, nScriptType) != m_eInputLanguage)
142  {
143  SvxLanguageItem aLangItem( m_eInputLanguage, nWhich );
144  rIdx = nSttCnt;
145  GetMark()->nContent = nEndCnt;
146  rDoc.getIDocumentContentOperations().InsertPoolItem(*this, aLangItem );
147  }
148 }
149 
151 {
153  if( !pTNd )
154  return;
155 
156  sal_Int32 nSttCnt = Start()->nContent.GetIndex();
157  sal_Int32 nEndCnt = End()->nContent.GetIndex();
158 
159  SwIndex aIdx( pTNd, nSttCnt );
160  const OUString& rNewStr = rData.GetText();
161 
162  if( m_bIsOverwriteCursor && !m_sOverwriteText.isEmpty() )
163  {
164  sal_Int32 nReplace = nEndCnt - nSttCnt;
165  const sal_Int32 nNewLen = rNewStr.getLength();
166  if( nNewLen < nReplace )
167  {
168  // We have to insert some characters from the saved original text
169  nReplace -= nNewLen;
170  aIdx += nNewLen;
171  pTNd->ReplaceText( aIdx, nReplace,
172  m_sOverwriteText.copy( nNewLen, nReplace ));
173  aIdx = nSttCnt;
174  nReplace = nNewLen;
175  }
176  else
177  {
178  const sal_Int32 nOWLen = m_sOverwriteText.getLength();
179  if( nOWLen < nReplace )
180  {
181  aIdx += nOWLen;
182  pTNd->EraseText( aIdx, nReplace-nOWLen );
183  aIdx = nSttCnt;
184  nReplace = nOWLen;
185  }
186  else
187  {
188  nReplace = std::min(nOWLen, nNewLen);
189  }
190  }
191 
192  pTNd->ReplaceText( aIdx, nReplace, rNewStr );
193  if( !HasMark() )
194  SetMark();
195  GetMark()->nContent = aIdx;
196  }
197  else
198  {
199  if( nSttCnt < nEndCnt )
200  {
201  pTNd->EraseText( aIdx, nEndCnt - nSttCnt );
202  }
203 
204  // NOHINTEXPAND so we can use correct formatting in destructor when we finish composing
205  pTNd->InsertText( rNewStr, aIdx, SwInsertFlags::NOHINTEXPAND );
206  if( !HasMark() )
207  SetMark();
208  }
209 
210  GetPoint()->nContent = nSttCnt;
211 
212  m_aAttrs.clear();
213  if( rData.GetTextAttr() )
214  {
215  const ExtTextInputAttr *pAttrs = rData.GetTextAttr();
216  m_aAttrs.insert( m_aAttrs.begin(), pAttrs, pAttrs + rData.GetText().getLength() );
217  }
218 }
219 
221 {
222  m_bIsOverwriteCursor = bFlag;
224  return;
225 
226  const SwTextNode *const pTNd = GetPoint()->nNode.GetNode().GetTextNode();
227  if (!pTNd)
228  return;
229 
230  const sal_Int32 nSttCnt = GetPoint()->nContent.GetIndex();
231  const sal_Int32 nEndCnt = GetMark()->nContent.GetIndex();
232  m_sOverwriteText = pTNd->GetText().copy( std::min(nSttCnt, nEndCnt) );
233  if( m_sOverwriteText.isEmpty() )
234  return;
235 
236  const sal_Int32 nInPos = m_sOverwriteText.indexOf( CH_TXTATR_INWORD );
237  const sal_Int32 nBrkPos = m_sOverwriteText.indexOf( CH_TXTATR_BREAKWORD );
238 
239  // Find the first attr found, if any.
240  sal_Int32 nPos = std::min(nInPos, nBrkPos);
241  if (nPos<0)
242  {
243  nPos = std::max(nInPos, nBrkPos);
244  }
245  if (nPos>=0)
246  {
247  m_sOverwriteText = m_sOverwriteText.copy( 0, nPos );
248  }
249 }
250 
251 // The Doc interfaces
252 
254 {
255  SwExtTextInput* pNew = new SwExtTextInput( rPam, mpExtInputRing );
256  if( !mpExtInputRing )
257  mpExtInputRing = pNew;
258  pNew->SetMark();
259  return pNew;
260 }
261 
263 {
264  if( pDel == mpExtInputRing )
265  {
266  if( pDel->GetNext() != mpExtInputRing )
267  mpExtInputRing = pDel->GetNext();
268  else
269  mpExtInputRing = nullptr;
270  }
271  delete pDel;
272 }
273 
275  sal_Int32 nContentPos ) const
276 {
277  SwExtTextInput* pRet = nullptr;
278  if( mpExtInputRing )
279  {
280  SwNodeOffset nNdIdx = rNd.GetIndex();
282  do {
283  SwNodeOffset nStartNode = pTmp->Start()->nNode.GetIndex(),
284  nEndNode = pTmp->End()->nNode.GetIndex();
285  sal_Int32 nStartCnt = pTmp->Start()->nContent.GetIndex();
286  sal_Int32 nEndCnt = pTmp->End()->nContent.GetIndex();
287 
288  if( nStartNode <= nNdIdx && nNdIdx <= nEndNode &&
289  ( nContentPos<0 ||
290  ( nStartCnt <= nContentPos && nContentPos <= nEndCnt )))
291  {
292  pRet = pTmp;
293  break;
294  }
295  pTmp = pTmp->GetNext();
296  } while ( pTmp!=mpExtInputRing );
297  }
298  return pRet;
299 }
300 
302 {
303  OSL_ENSURE( !mpExtInputRing || !mpExtInputRing->IsMultiSelection(),
304  "more than one InputEngine available" );
305  return mpExtInputRing;
306 }
307 
308 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SwNodeOffset min(const SwNodeOffset &a, const SwNodeOffset &b)
Definition: nodeoffset.hxx:35
bool IsMultiSelection() const
Definition: pam.hxx:273
const OUString & GetText() const
Definition: ndtxt.hxx:218
SwNodeIndex nNode
Definition: pam.hxx:38
virtual ~SwExtTextInput() override
Definition: extinput.cxx:47
constexpr TypedWhichId< SvxLanguageItem > RES_CHRATR_LANGUAGE(10)
const SwPosition * GetMark() const
Definition: pam.hxx:210
virtual SwUndoId EndUndo(SwUndoId const eUndoId, SwRewriter const *const pRewriter)=0
Closes undo block.
Definition: doc.hxx:187
SwNode & GetNode() const
Definition: ndindex.hxx:128
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:144
virtual bool InsertPoolItem(const SwPaM &rRg, const SfxPoolItem &, const SetAttrMode nFlags=SetAttrMode::DEFAULT, SwRootFrame const *pLayout=nullptr, SwTextAttr **ppNewTextAttr=nullptr)=0
Insert an attribute.
OUString m_sOverwriteText
Definition: extinput.hxx:30
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:315
SwExtTextInput * GetExtTextInput() const
Definition: extinput.cxx:301
#define CH_TXTATR_BREAKWORD
Definition: hintids.hxx:173
#define CH_TXTATR_INWORD
Definition: hintids.hxx:174
SwIndex nContent
Definition: pam.hxx:39
constexpr TypedWhichId< SvxLanguageItem > RES_CHRATR_CTL_LANGUAGE(29)
SwNodeOffset GetIndex() const
Definition: ndindex.hxx:161
virtual void SetIME(bool bIME)=0
States that the last inserted string came from IME.
sal_Int16 GetI18NScriptTypeOfLanguage(LanguageType nLang)
void SetOverwriteCursor(bool bFlag)
Definition: extinput.cxx:220
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:137
virtual bool GetIME() const =0
Did the last inserted string come from IME?
const OUString & GetText() const
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 bool Overwrite(const SwPaM &rRg, const OUString &rStr)=0
Overwrite string in an existing text node.
bool m_bIsOverwriteCursor
Definition: extinput.hxx:32
virtual SwUndoId StartUndo(SwUndoId const eUndoId, SwRewriter const *const pRewriter)=0
Opens undo block.
const SwPosition * GetPoint() const
Definition: pam.hxx:208
SwExtTextInput * GetNext()
Definition: extinput.hxx:45
virtual bool DoesGroupUndo() const =0
Is Group Undo enabled?
SwNodeOffset GetIndex() const
Definition: node.hxx:292
bool HasMark() const
A PaM marks a selection if Point and Mark are distinct positions.
Definition: pam.hxx:206
Marks a character position inside a document model node.
Definition: index.hxx:33
#define LANGUAGE_DONTKNOW
SwExtTextInput * CreateExtTextInput(const SwPaM &rPam)
Definition: extinput.cxx:253
const SwPosition * Start() const
Definition: pam.hxx:213
virtual void DoGroupUndo(bool const bDoUndo)=0
Enable/Disable Group Undo.
void EraseText(const SwIndex &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:2689
OUString InsertText(const OUString &rStr, const SwIndex &rIdx, const SwInsertFlags nMode=SwInsertFlags::DEFAULT)
insert text content
Definition: ndtxt.cxx:2297
virtual size_t GetUndoActionCount(const bool bCurrentLevel=true) const =0
Get the number of Undo actions.
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
LanguageType m_eInputLanguage
Definition: extinput.hxx:33
void ReplaceText(const SwIndex &rStart, const sal_Int32 nDelLen, const OUString &rText)
replace nDelLen characters at rStart with rText in case the replacement does not fit, it is partially inserted up to the capacity of the node
Definition: ndtxt.cxx:3715
void DeleteExtTextInput(SwExtTextInput *pDel)
Definition: extinput.cxx:262
sal_Int32 GetIndex() const
Definition: index.hxx:91
const SwPosition * End() const
Definition: pam.hxx:218
LanguageType GetLang(const sal_Int32 nBegin, const sal_Int32 nLen=0, sal_uInt16 nScript=0) const
Definition: thints.cxx:3433
bool IsInDtor() const
Definition: doc.hxx:403
ExtTextInputAttr
SwDoc & GetDoc() const
Definition: pam.hxx:244
virtual void SetMark()
Unless this is called, the getter method of Mark will return Point.
Definition: pam.cxx:476
std::vector< ExtTextInputAttr > m_aAttrs
Definition: extinput.hxx:29
SwExtTextInput(const SwPaM &rPam, Ring *pRing)
Definition: extinput.cxx:39
void SetInputData(const CommandExtTextInputData &rData)
Definition: extinput.cxx:150
constexpr TypedWhichId< SvxLanguageItem > RES_CHRATR_CJK_LANGUAGE(24)
SwExtTextInput * mpExtInputRing
Definition: doc.hxx:275
sal_uInt16 nPos
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:864
Base class of the Writer document model elements.
Definition: node.hxx:81
const ExtTextInputAttr * GetTextAttr() const