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  rDoc.GetIDocumentUndoRedo().DoGroupUndo(false);
65  if( nEndCnt < nSttCnt )
66  {
67  std::swap(nSttCnt, nEndCnt);
68  }
69 
70  // In order to get Undo/Redlining etc. working correctly,
71  // we need to go through the Doc interface
72  rIdx = nSttCnt;
73  const OUString sText( pTNd->GetText().copy(nSttCnt, nEndCnt - nSttCnt));
74  if( m_bIsOverwriteCursor && !m_sOverwriteText.isEmpty() )
75  {
76  const sal_Int32 nLen = sText.getLength();
77  const sal_Int32 nOWLen = m_sOverwriteText.getLength();
78  if( nLen > nOWLen )
79  {
80  rIdx += nOWLen;
81  pTNd->EraseText( rIdx, nLen - nOWLen );
82  rIdx = nSttCnt;
83  pTNd->ReplaceText( rIdx, nOWLen, m_sOverwriteText );
84  if( m_bInsText )
85  {
86  rIdx = nSttCnt;
88  rDoc.getIDocumentContentOperations().Overwrite( *this, sText.copy( 0, nOWLen ) );
89  rDoc.getIDocumentContentOperations().InsertString( *this, sText.copy( nOWLen ) );
91  }
92  }
93  else
94  {
95  pTNd->ReplaceText( rIdx, nLen, m_sOverwriteText.copy( 0, nLen ));
96  if( m_bInsText )
97  {
98  rIdx = nSttCnt;
99  rDoc.getIDocumentContentOperations().Overwrite( *this, sText );
100  }
101  }
102  }
103  else
104  {
105  // we need to keep correct formatting
106  // ie. when we erase first, then we will lost information about format
107 
108  sal_Int32 nLenghtOfOldString = nEndCnt - nSttCnt;
109 
110  if( m_bInsText )
111  {
112  rDoc.getIDocumentContentOperations().InsertString( *this, sText );
113 
114  // Copy formatting to the inserted string
116  pTNd->GetParaAttr( aSet, nSttCnt + nLenghtOfOldString, nEndCnt + nLenghtOfOldString );
117  pTNd->SetAttr( aSet, nSttCnt, nEndCnt );
118  }
119 
120  pTNd->EraseText( rIdx, nLenghtOfOldString );
121  }
122  rDoc.GetIDocumentUndoRedo().DoGroupUndo(bKeepGroupUndo);
124  return;
125 
126  sal_uInt16 nWhich = RES_CHRATR_LANGUAGE;
128  switch(nScriptType)
129  {
130  case i18n::ScriptType::ASIAN:
131  nWhich = RES_CHRATR_CJK_LANGUAGE; break;
132  case i18n::ScriptType::COMPLEX:
133  nWhich = RES_CHRATR_CTL_LANGUAGE; break;
134  }
135  // #i41974# Only set language attribute for CJK/CTL scripts.
136  if (RES_CHRATR_LANGUAGE != nWhich && pTNd->GetLang( nSttCnt, nEndCnt-nSttCnt, nScriptType) != m_eInputLanguage)
137  {
138  SvxLanguageItem aLangItem( m_eInputLanguage, nWhich );
139  rIdx = nSttCnt;
140  GetMark()->nContent = nEndCnt;
141  rDoc.getIDocumentContentOperations().InsertPoolItem(*this, aLangItem );
142  }
143 }
144 
146 {
148  if( !pTNd )
149  return;
150 
151  sal_Int32 nSttCnt = GetPoint()->nContent.GetIndex();
152  sal_Int32 nEndCnt = GetMark()->nContent.GetIndex();
153  if( nEndCnt < nSttCnt )
154  {
155  std::swap(nSttCnt, nEndCnt);
156  }
157 
158  SwIndex aIdx( pTNd, nSttCnt );
159  const OUString& rNewStr = rData.GetText();
160 
161  if( m_bIsOverwriteCursor && !m_sOverwriteText.isEmpty() )
162  {
163  sal_Int32 nReplace = nEndCnt - nSttCnt;
164  const sal_Int32 nNewLen = rNewStr.getLength();
165  if( nNewLen < nReplace )
166  {
167  // We have to insert some characters from the saved original text
168  nReplace -= nNewLen;
169  aIdx += nNewLen;
170  pTNd->ReplaceText( aIdx, nReplace,
171  m_sOverwriteText.copy( nNewLen, nReplace ));
172  aIdx = nSttCnt;
173  nReplace = nNewLen;
174  }
175  else
176  {
177  const sal_Int32 nOWLen = m_sOverwriteText.getLength();
178  if( nOWLen < nReplace )
179  {
180  aIdx += nOWLen;
181  pTNd->EraseText( aIdx, nReplace-nOWLen );
182  aIdx = nSttCnt;
183  nReplace = nOWLen;
184  }
185  else
186  {
187  nReplace = std::min(nOWLen, nNewLen);
188  }
189  }
190 
191  pTNd->ReplaceText( aIdx, nReplace, rNewStr );
192  if( !HasMark() )
193  SetMark();
194  GetMark()->nContent = aIdx;
195  }
196  else
197  {
198  if( nSttCnt < nEndCnt )
199  {
200  pTNd->EraseText( aIdx, nEndCnt - nSttCnt );
201  }
202 
203  pTNd->InsertText( rNewStr, aIdx,
205  if( !HasMark() )
206  SetMark();
207  }
208 
209  GetPoint()->nContent = nSttCnt;
210 
211  m_aAttrs.clear();
212  if( rData.GetTextAttr() )
213  {
214  const ExtTextInputAttr *pAttrs = rData.GetTextAttr();
215  m_aAttrs.insert( m_aAttrs.begin(), pAttrs, pAttrs + rData.GetText().getLength() );
216  }
217 }
218 
220 {
221  m_bIsOverwriteCursor = bFlag;
223  return;
224 
225  const SwTextNode *const pTNd = GetPoint()->nNode.GetNode().GetTextNode();
226  if (!pTNd)
227  return;
228 
229  const sal_Int32 nSttCnt = GetPoint()->nContent.GetIndex();
230  const sal_Int32 nEndCnt = GetMark()->nContent.GetIndex();
231  m_sOverwriteText = pTNd->GetText().copy( std::min(nSttCnt, nEndCnt) );
232  if( m_sOverwriteText.isEmpty() )
233  return;
234 
235  const sal_Int32 nInPos = m_sOverwriteText.indexOf( CH_TXTATR_INWORD );
236  const sal_Int32 nBrkPos = m_sOverwriteText.indexOf( CH_TXTATR_BREAKWORD );
237 
238  // Find the first attr found, if any.
239  sal_Int32 nPos = std::min(nInPos, nBrkPos);
240  if (nPos<0)
241  {
242  nPos = std::max(nInPos, nBrkPos);
243  }
244  if (nPos>=0)
245  {
246  m_sOverwriteText = m_sOverwriteText.copy( 0, nPos );
247  }
248 }
249 
250 // The Doc interfaces
251 
253 {
254  SwExtTextInput* pNew = new SwExtTextInput( rPam, mpExtInputRing );
255  if( !mpExtInputRing )
256  mpExtInputRing = pNew;
257  pNew->SetMark();
258  return pNew;
259 }
260 
262 {
263  if( pDel == mpExtInputRing )
264  {
265  if( pDel->GetNext() != mpExtInputRing )
266  mpExtInputRing = pDel->GetNext();
267  else
268  mpExtInputRing = nullptr;
269  }
270  delete pDel;
271 }
272 
274  sal_Int32 nContentPos ) const
275 {
276  SwExtTextInput* pRet = nullptr;
277  if( mpExtInputRing )
278  {
279  sal_uLong nNdIdx = rNd.GetIndex();
281  do {
282  sal_uLong nPt = pTmp->GetPoint()->nNode.GetIndex(),
283  nMk = pTmp->GetMark()->nNode.GetIndex();
284  sal_Int32 nPtCnt = pTmp->GetPoint()->nContent.GetIndex();
285  sal_Int32 nMkCnt = pTmp->GetMark()->nContent.GetIndex();
286 
287  if( nPt < nMk || ( nPt == nMk && nPtCnt < nMkCnt ))
288  {
289  sal_uLong nTmp = nMk; nMk = nPt; nPt = nTmp;
290  sal_Int32 nTmp2 = nMkCnt; nMkCnt = nPtCnt; nPtCnt = nTmp2;
291  }
292 
293  if( nMk <= nNdIdx && nNdIdx <= nPt &&
294  ( nContentPos<0 ||
295  ( nMkCnt <= nContentPos && nContentPos <= nPtCnt )))
296  {
297  pRet = pTmp;
298  break;
299  }
300  pTmp = pTmp->GetNext();
301  } while ( pTmp!=mpExtInputRing );
302  }
303  return pRet;
304 }
305 
307 {
308  OSL_ENSURE( !mpExtInputRing || !mpExtInputRing->IsMultiSelection(),
309  "more than one InputEngine available" );
310  return mpExtInputRing;
311 }
312 
313 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uLong GetIndex() const
Definition: node.hxx:291
bool IsMultiSelection() const
Definition: pam.hxx:272
const OUString & GetText() const
Definition: ndtxt.hxx:218
virtual bool SetAttr(const SfxPoolItem &) override
overriding to handle change of certain paragraph attributes
Definition: ndtxt.cxx:4832
SwNodeIndex nNode
Definition: pam.hxx:37
virtual ~SwExtTextInput() override
Definition: extinput.cxx:47
sal_uIntPtr sal_uLong
constexpr TypedWhichId< SvxLanguageItem > RES_CHRATR_LANGUAGE(10)
const SwPosition * GetMark() const
Definition: pam.hxx:209
virtual SwUndoId EndUndo(SwUndoId const eUndoId, SwRewriter const *const pRewriter)=0
Closes undo block.
Definition: doc.hxx:188
SwNode & GetNode() const
Definition: ndindex.hxx:119
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:306
#define CH_TXTATR_BREAKWORD
Definition: hintids.hxx:170
#define CH_TXTATR_INWORD
Definition: hintids.hxx:171
SwIndex nContent
Definition: pam.hxx:38
constexpr TypedWhichId< SvxLanguageItem > RES_CHRATR_CTL_LANGUAGE(29)
sal_uLong GetIndex() const
Definition: ndindex.hxx:152
sal_Int16 GetI18NScriptTypeOfLanguage(LanguageType nLang)
void SetOverwriteCursor(bool bFlag)
Definition: extinput.cxx:219
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:136
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.
SwDoc & GetDoc()
Definition: node.hxx:212
const SwPosition * GetPoint() const
Definition: pam.hxx:207
SwExtTextInput * GetNext()
Definition: extinput.hxx:45
bool GetParaAttr(SfxItemSet &rSet, sal_Int32 nStt, sal_Int32 nEnd, const bool bOnlyTextAttr=false, const bool bGetFromChrFormat=true, const bool bMergeIndentValuesOfNumRule=false, SwRootFrame const *pLayout=nullptr) const
Query the attributes of textnode over the range.
Definition: thints.cxx:2054
WhichRangesContainer const aCharFormatSetRange(svl::Items< RES_CHRATR_BEGIN, RES_CHRATR_END-1, RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1 >)
virtual bool DoesGroupUndo() const =0
Is Group Undo enabled?
bool HasMark() const
A PaM marks a selection if Point and Mark are distinct positions.
Definition: pam.hxx:205
Marks a character position inside a document model node.
Definition: index.hxx:33
#define LANGUAGE_DONTKNOW
SwExtTextInput * CreateExtTextInput(const SwPaM &rPam)
Definition: extinput.cxx:252
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:2632
OUString InsertText(const OUString &rStr, const SwIndex &rIdx, const SwInsertFlags nMode=SwInsertFlags::DEFAULT)
insert text content
Definition: ndtxt.cxx:2241
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:3637
void DeleteExtTextInput(SwExtTextInput *pDel)
Definition: extinput.cxx:261
sal_Int32 GetIndex() const
Definition: index.hxx:91
LanguageType GetLang(const sal_Int32 nBegin, const sal_Int32 nLen=0, sal_uInt16 nScript=0) const
Definition: thints.cxx:3364
bool IsInDtor() const
Definition: doc.hxx:404
ExtTextInputAttr
SwDoc & GetDoc() const
Definition: pam.hxx:243
virtual void SetMark()
Unless this is called, the getter method of Mark will return Point.
Definition: pam.cxx:478
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:145
constexpr TypedWhichId< SvxLanguageItem > RES_CHRATR_CJK_LANGUAGE(24)
SwExtTextInput * mpExtInputRing
Definition: doc.hxx:276
sal_uInt16 nPos
const SwAttrPool & GetAttrPool() const
Definition: doc.hxx:1319
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:856
Base class of the Writer document model elements.
Definition: node.hxx:80
const ExtTextInputAttr * GetTextAttr() const