Line data Source code
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 "inputhdl.hxx"
21 : #include "scitems.hxx"
22 : #include <editeng/eeitem.hxx>
23 :
24 : #include <sfx2/app.hxx>
25 : #include <editeng/acorrcfg.hxx>
26 : #include <svx/algitem.hxx>
27 : #include <editeng/adjustitem.hxx>
28 : #include <editeng/brushitem.hxx>
29 : #include <svtools/colorcfg.hxx>
30 : #include <editeng/colritem.hxx>
31 : #include <editeng/editobj.hxx>
32 : #include <editeng/editstat.hxx>
33 : #include <editeng/editview.hxx>
34 : #include <editeng/escapementitem.hxx>
35 : #include <editeng/forbiddencharacterstable.hxx>
36 : #include <editeng/langitem.hxx>
37 : #include <editeng/svxacorr.hxx>
38 : #include <editeng/unolingu.hxx>
39 : #include <editeng/wghtitem.hxx>
40 : #include <editeng/justifyitem.hxx>
41 : #include <editeng/misspellrange.hxx>
42 : #include <sfx2/bindings.hxx>
43 : #include <sfx2/viewfrm.hxx>
44 : #include <sfx2/dispatch.hxx>
45 : #include <sfx2/docfile.hxx>
46 : #include <sfx2/printer.hxx>
47 : #include <svl/zforlist.hxx>
48 : #include <unotools/localedatawrapper.hxx>
49 : #include <vcl/help.hxx>
50 : #include <vcl/cursor.hxx>
51 : #include <vcl/settings.hxx>
52 : #include <tools/urlobj.hxx>
53 : #include <comphelper/string.hxx>
54 : #include <formula/formulahelper.hxx>
55 :
56 : #include "inputwin.hxx"
57 : #include "tabvwsh.hxx"
58 : #include "docsh.hxx"
59 : #include "scmod.hxx"
60 : #include "uiitems.hxx"
61 : #include "global.hxx"
62 : #include "sc.hrc"
63 : #include "globstr.hrc"
64 : #include "patattr.hxx"
65 : #include "viewdata.hxx"
66 : #include "document.hxx"
67 : #include "docpool.hxx"
68 : #include "editutil.hxx"
69 : #include "appoptio.hxx"
70 : #include "docoptio.hxx"
71 : #include "validat.hxx"
72 : #include "userlist.hxx"
73 : #include "rfindlst.hxx"
74 : #include "inputopt.hxx"
75 : #include "simpleformulacalc.hxx"
76 : #include "compiler.hxx"
77 : #include "editable.hxx"
78 : #include "funcdesc.hxx"
79 : #include "markdata.hxx"
80 : #include "tokenarray.hxx"
81 : #include <gridwin.hxx>
82 :
83 : // Maximum Ranges in RangeFinder
84 : #define RANGEFIND_MAX 32
85 :
86 : using namespace formula;
87 :
88 : // STATIC DATA -----------------------------------------------------------
89 :
90 : bool ScInputHandler::bOptLoaded = false; // Evaluate App options
91 : bool ScInputHandler::bAutoComplete = false; // Is set in KeyInput
92 :
93 : extern sal_uInt16 nEditAdjust; //! Member of ViewData
94 :
95 : namespace {
96 :
97 : // Formula data replacement character for a pair of parentheses at end of
98 : // function name, to force sorting parentheses before all other characters.
99 : // Collation may treat parentheses differently.
100 : const sal_Unicode cParenthesesReplacement = 0x0001;
101 :
102 0 : sal_Unicode lcl_getSheetSeparator(ScDocument* pDoc)
103 : {
104 0 : ScCompiler aComp(pDoc, ScAddress());
105 0 : aComp.SetGrammar(pDoc->GetGrammar());
106 0 : return aComp.GetNativeAddressSymbol(ScCompiler::Convention::SHEET_SEPARATOR);
107 : }
108 :
109 0 : ScTypedCaseStrSet::const_iterator findText(
110 : const ScTypedCaseStrSet& rDataSet, ScTypedCaseStrSet::const_iterator itPos,
111 : const OUString& rStart, OUString& rResult, bool bBack)
112 : {
113 0 : if (bBack) // Backwards
114 : {
115 0 : ScTypedCaseStrSet::const_reverse_iterator it = rDataSet.rbegin(), itEnd = rDataSet.rend();
116 0 : if (itPos != rDataSet.end())
117 : {
118 0 : size_t nPos = std::distance(rDataSet.begin(), itPos);
119 0 : size_t nRPos = rDataSet.size() - 1 - nPos;
120 0 : std::advance(it, nRPos);
121 0 : ++it;
122 : }
123 :
124 0 : for (; it != itEnd; ++it)
125 : {
126 0 : const ScTypedStrData& rData = *it;
127 0 : if (rData.GetStringType() == ScTypedStrData::Value)
128 : // skip values
129 0 : continue;
130 :
131 0 : if (!ScGlobal::GetpTransliteration()->isMatch(rStart, rData.GetString()))
132 : // not a match
133 0 : continue;
134 :
135 0 : rResult = rData.GetString();
136 0 : return (++it).base(); // convert the reverse iterator back to iterator.
137 : }
138 : }
139 : else // Forwards
140 : {
141 0 : ScTypedCaseStrSet::const_iterator it = rDataSet.begin(), itEnd = rDataSet.end();
142 0 : if (itPos != rDataSet.end())
143 : {
144 0 : it = itPos;
145 0 : ++it;
146 : }
147 :
148 0 : for (; it != itEnd; ++it)
149 : {
150 0 : const ScTypedStrData& rData = *it;
151 0 : if (rData.GetStringType() == ScTypedStrData::Value)
152 : // skip values
153 0 : continue;
154 :
155 0 : if (!ScGlobal::GetpTransliteration()->isMatch(rStart, rData.GetString()))
156 : // not a match
157 0 : continue;
158 :
159 0 : rResult = rData.GetString();
160 0 : return it;
161 : }
162 : }
163 :
164 0 : return rDataSet.end(); // no matching text found
165 : }
166 :
167 0 : OUString getExactMatch(const ScTypedCaseStrSet& rDataSet, const OUString& rString)
168 : {
169 0 : ScTypedCaseStrSet::const_iterator it = rDataSet.begin(), itEnd = rDataSet.end();
170 0 : for (; it != itEnd; ++it)
171 : {
172 0 : const ScTypedStrData& rData = *it;
173 0 : if (rData.GetStringType() == ScTypedStrData::Value)
174 0 : continue;
175 :
176 0 : if (!ScGlobal::GetpTransliteration()->isEqual(rData.GetString(), rString))
177 0 : continue;
178 :
179 0 : return rData.GetString();
180 : }
181 0 : return rString;
182 : }
183 :
184 523 : void removeChars(OUString& rStr, sal_Unicode c)
185 : {
186 523 : OUStringBuffer aBuf(rStr);
187 755 : for (sal_Int32 i = 0, n = aBuf.getLength(); i < n; ++i)
188 : {
189 232 : if (aBuf[i] == c)
190 0 : aBuf[i] = ' ';
191 : }
192 523 : rStr = aBuf.makeStringAndClear();
193 523 : }
194 :
195 : }
196 :
197 0 : void ScInputHandler::InitRangeFinder( const OUString& rFormula )
198 : {
199 0 : DeleteRangeFinder();
200 0 : if ( !pActiveViewSh || !SC_MOD()->GetInputOptions().GetRangeFinder() )
201 0 : return;
202 0 : ScDocShell* pDocSh = pActiveViewSh->GetViewData().GetDocShell();
203 0 : ScDocument& rDoc = pDocSh->GetDocument();
204 0 : const sal_Unicode cSheetSep = lcl_getSheetSeparator(&rDoc);
205 :
206 0 : OUString aDelimiters = ScEditUtil::ModifyDelimiters(" !\"");
207 : // delimiters (in addition to ScEditUtil): only characters that are
208 : // allowed in formulas next to references and the quotation mark (so
209 : // string constants can be skipped)
210 :
211 0 : sal_Int32 nColon = aDelimiters.indexOf( ':' );
212 0 : if ( nColon != -1 )
213 0 : aDelimiters = aDelimiters.replaceAt( nColon, 1, ""); // Delimiter without colon
214 0 : sal_Int32 nDot = aDelimiters.indexOf(cSheetSep);
215 0 : if ( nDot != -1 )
216 0 : aDelimiters = aDelimiters.replaceAt( nDot, 1 , ""); // Delimiter without dot
217 :
218 0 : const sal_Unicode* pChar = rFormula.getStr();
219 0 : sal_Int32 nLen = rFormula.getLength();
220 0 : sal_Int32 nPos = 0;
221 0 : sal_Int32 nStart = 0;
222 0 : sal_uInt16 nCount = 0;
223 0 : ScRange aRange;
224 0 : while ( nPos < nLen && nCount < RANGEFIND_MAX )
225 : {
226 : // Skip separator
227 0 : while ( nPos<nLen && ScGlobal::UnicodeStrChr( aDelimiters.getStr(), pChar[nPos] ) )
228 : {
229 0 : if ( pChar[nPos] == '"' ) // String
230 : {
231 0 : ++nPos;
232 0 : while (nPos<nLen && pChar[nPos] != '"') // Skip until end
233 0 : ++nPos;
234 : }
235 0 : ++nPos; // Separator or closing quote
236 : }
237 :
238 : // Text zwischen Trennern
239 0 : nStart = nPos;
240 : handle_r1c1:
241 0 : while ( nPos<nLen && !ScGlobal::UnicodeStrChr( aDelimiters.getStr(), pChar[nPos] ) )
242 0 : ++nPos;
243 :
244 : // for R1C1 '-' in R[-]... or C[-]... are not delimiters
245 : // Nothing heroic here to ensure that there are '[]' around a negative
246 : // integer. we need to clean up this code.
247 0 : if( nPos < nLen && nPos > 0 &&
248 0 : '-' == pChar[nPos] && '[' == pChar[nPos-1] &&
249 0 : formula::FormulaGrammar::CONV_XL_R1C1 == rDoc.GetAddressConvention() )
250 : {
251 0 : nPos++;
252 0 : goto handle_r1c1;
253 : }
254 :
255 0 : if ( nPos > nStart )
256 : {
257 0 : OUString aTest = rFormula.copy( nStart, nPos-nStart );
258 0 : const ScAddress::Details aAddrDetails( &rDoc, aCursorPos );
259 0 : sal_uInt16 nFlags = aRange.ParseAny( aTest, &rDoc, aAddrDetails );
260 0 : if ( nFlags & SCA_VALID )
261 : {
262 : // Set tables if not specified
263 0 : if ( (nFlags & SCA_TAB_3D) == 0 )
264 0 : aRange.aStart.SetTab( pActiveViewSh->GetViewData().GetTabNo() );
265 0 : if ( (nFlags & SCA_TAB2_3D) == 0 )
266 0 : aRange.aEnd.SetTab( aRange.aStart.Tab() );
267 :
268 0 : if ( ( nFlags & ( SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2 ) ) == 0 )
269 : {
270 : // #i73766# if a single ref was parsed, set the same "abs" flags for ref2,
271 : // so Format doesn't output a double ref because of different flags.
272 0 : sal_uInt16 nAbsFlags = nFlags & ( SCA_COL_ABSOLUTE | SCA_ROW_ABSOLUTE | SCA_TAB_ABSOLUTE );
273 0 : nFlags |= nAbsFlags << 4;
274 : }
275 :
276 0 : if (!nCount)
277 : {
278 0 : pEngine->SetUpdateMode( false );
279 0 : pRangeFindList = new ScRangeFindList( pDocSh->GetTitle() );
280 : }
281 :
282 0 : ColorData nColorData = pRangeFindList->Insert( ScRangeFindData( aRange, nFlags, nStart, nPos ) );
283 :
284 0 : ESelection aSel( 0, nStart, 0, nPos );
285 0 : SfxItemSet aSet( pEngine->GetEmptyItemSet() );
286 : aSet.Put( SvxColorItem( Color( nColorData ),
287 0 : EE_CHAR_COLOR ) );
288 0 : pEngine->QuickSetAttribs( aSet, aSel );
289 0 : ++nCount;
290 0 : }
291 : }
292 :
293 : // Do not skip last separator; could be a quote (?)
294 : }
295 :
296 0 : if (nCount)
297 : {
298 0 : pEngine->SetUpdateMode( true );
299 :
300 0 : pDocSh->Broadcast( SfxSimpleHint( SC_HINT_SHOWRANGEFINDER ) );
301 0 : }
302 : }
303 :
304 345 : void ScInputHandler::SetDocumentDisposing( bool b )
305 : {
306 345 : mbDocumentDisposing = b;
307 345 : }
308 :
309 0 : static void lcl_Replace( EditView* pView, const OUString& rNewStr, const ESelection& rOldSel )
310 : {
311 0 : if ( pView )
312 : {
313 0 : ESelection aOldSel = pView->GetSelection();
314 0 : if (aOldSel.HasRange())
315 : pView->SetSelection( ESelection( aOldSel.nEndPara, aOldSel.nEndPos,
316 0 : aOldSel.nEndPara, aOldSel.nEndPos ) );
317 :
318 0 : EditEngine* pEngine = pView->GetEditEngine();
319 0 : pEngine->QuickInsertText( rNewStr, rOldSel );
320 :
321 : // Dummy InsertText for Update and Paint
322 : // To do that we need to cancel the selection from above (before QuickInsertText)
323 0 : pView->InsertText( EMPTY_OUSTRING, false );
324 :
325 0 : sal_Int32 nLen = pEngine->GetTextLen(0);
326 0 : ESelection aSel( 0, nLen, 0, nLen );
327 0 : pView->SetSelection( aSel ); // Set cursor to the end
328 : }
329 0 : }
330 :
331 0 : void ScInputHandler::UpdateRange( sal_uInt16 nIndex, const ScRange& rNew )
332 : {
333 0 : ScTabViewShell* pDocView = pRefViewSh ? pRefViewSh : pActiveViewSh;
334 0 : if ( pDocView && pRangeFindList && nIndex < pRangeFindList->Count() )
335 : {
336 0 : ScRangeFindData* pData = pRangeFindList->GetObject( nIndex );
337 0 : sal_Int32 nOldStart = pData->nSelStart;
338 0 : sal_Int32 nOldEnd = pData->nSelEnd;
339 0 : ColorData nNewColor = pRangeFindList->FindColor( rNew, nIndex );
340 :
341 0 : ScRange aJustified = rNew;
342 0 : aJustified.Justify(); // Always display Ref in the Formula the right way
343 0 : ScDocument* pDoc = pDocView->GetViewData().GetDocument();
344 0 : const ScAddress::Details aAddrDetails( pDoc, aCursorPos );
345 0 : OUString aNewStr(aJustified.Format(pData->nFlags, pDoc, aAddrDetails));
346 0 : ESelection aOldSel( 0, nOldStart, 0, nOldEnd );
347 0 : SfxItemSet aSet( pEngine->GetEmptyItemSet() );
348 :
349 0 : DataChanging();
350 :
351 0 : lcl_Replace( pTopView, aNewStr, aOldSel );
352 0 : lcl_Replace( pTableView, aNewStr, aOldSel );
353 0 : aSet.Put( SvxColorItem( Color( nNewColor ), EE_CHAR_COLOR ) );
354 0 : pEngine->QuickSetAttribs( aSet, aOldSel );
355 :
356 0 : bInRangeUpdate = true;
357 0 : DataChanged();
358 0 : bInRangeUpdate = false;
359 :
360 0 : long nDiff = aNewStr.getLength() - (long)(nOldEnd-nOldStart);
361 :
362 0 : pData->aRef = rNew;
363 0 : pData->nSelEnd = pData->nSelEnd + nDiff;
364 0 : pData->nColorData = nNewColor;
365 :
366 0 : sal_uInt16 nCount = (sal_uInt16) pRangeFindList->Count();
367 0 : for (sal_uInt16 i=nIndex+1; i<nCount; i++)
368 : {
369 0 : ScRangeFindData* pNext = pRangeFindList->GetObject( i );
370 0 : pNext->nSelStart = pNext->nSelStart + nDiff;
371 0 : pNext->nSelEnd = pNext->nSelEnd + nDiff;
372 : }
373 :
374 0 : EditView* pActiveView = pTopView ? pTopView : pTableView;
375 0 : pActiveView->ShowCursor( false, true );
376 : }
377 : else
378 : {
379 : OSL_FAIL("UpdateRange: we're missing something");
380 : }
381 0 : }
382 :
383 510 : void ScInputHandler::DeleteRangeFinder()
384 : {
385 510 : ScTabViewShell* pPaintView = pRefViewSh ? pRefViewSh : pActiveViewSh;
386 510 : if ( pRangeFindList && pPaintView )
387 : {
388 0 : ScDocShell* pDocSh = pActiveViewSh->GetViewData().GetDocShell();
389 0 : pRangeFindList->SetHidden(true);
390 0 : pDocSh->Broadcast( SfxSimpleHint( SC_HINT_SHOWRANGEFINDER ) ); // Steal
391 0 : DELETEZ(pRangeFindList);
392 : }
393 510 : }
394 :
395 510 : inline OUString GetEditText(EditEngine* pEng)
396 : {
397 510 : return ScEditUtil::GetSpaceDelimitedString(*pEng);
398 : }
399 :
400 523 : static void lcl_RemoveTabs(OUString& rStr)
401 : {
402 523 : removeChars(rStr, '\t');
403 523 : }
404 :
405 0 : static void lcl_RemoveLineEnd(OUString& rStr)
406 : {
407 0 : rStr = convertLineEnd(rStr, LINEEND_LF);
408 0 : removeChars(rStr, '\n');
409 0 : }
410 :
411 0 : static sal_Int32 lcl_MatchParenthesis( const OUString& rStr, sal_Int32 nPos )
412 : {
413 : int nDir;
414 0 : sal_Unicode c1, c2 = 0;
415 0 : c1 = rStr[nPos];
416 0 : switch ( c1 )
417 : {
418 : case '(' :
419 0 : c2 = ')';
420 0 : nDir = 1;
421 0 : break;
422 : case ')' :
423 0 : c2 = '(';
424 0 : nDir = -1;
425 0 : break;
426 : case '<' :
427 0 : c2 = '>';
428 0 : nDir = 1;
429 0 : break;
430 : case '>' :
431 0 : c2 = '<';
432 0 : nDir = -1;
433 0 : break;
434 : case '{' :
435 0 : c2 = '}';
436 0 : nDir = 1;
437 0 : break;
438 : case '}' :
439 0 : c2 = '{';
440 0 : nDir = -1;
441 0 : break;
442 : case '[' :
443 0 : c2 = ']';
444 0 : nDir = 1;
445 0 : break;
446 : case ']' :
447 0 : c2 = '[';
448 0 : nDir = -1;
449 0 : break;
450 : default:
451 0 : nDir = 0;
452 : }
453 0 : if ( !nDir )
454 0 : return -1;
455 0 : sal_Int32 nLen = rStr.getLength();
456 0 : const sal_Unicode* p0 = rStr.getStr();
457 : const sal_Unicode* p;
458 : const sal_Unicode* p1;
459 0 : sal_uInt16 nQuotes = 0;
460 0 : if ( nPos < nLen / 2 )
461 : {
462 0 : p = p0;
463 0 : p1 = p0 + nPos;
464 : }
465 : else
466 : {
467 0 : p = p0 + nPos;
468 0 : p1 = p0 + nLen;
469 : }
470 0 : while ( p < p1 )
471 : {
472 0 : if ( *p++ == '\"' )
473 0 : nQuotes++;
474 : }
475 : // Odd number of quotes that we find ourselves in a string
476 0 : bool bLookInString = ((nQuotes % 2) != 0);
477 0 : bool bInString = bLookInString;
478 0 : p = p0 + nPos;
479 0 : p1 = (nDir < 0 ? p0 : p0 + nLen) ;
480 0 : sal_uInt16 nLevel = 1;
481 0 : while ( p != p1 && nLevel )
482 : {
483 0 : p += nDir;
484 0 : if ( *p == '\"' )
485 : {
486 0 : bInString = !bInString;
487 0 : if ( bLookInString && !bInString )
488 0 : p = p1; // That's it then
489 : }
490 0 : else if ( bInString == bLookInString )
491 : {
492 0 : if ( *p == c1 )
493 0 : nLevel++;
494 0 : else if ( *p == c2 )
495 0 : nLevel--;
496 : }
497 : }
498 0 : if ( nLevel )
499 0 : return -1;
500 0 : return (sal_Int32) (p - p0);
501 : }
502 :
503 348 : ScInputHandler::ScInputHandler()
504 : : pInputWin( NULL ),
505 : pEngine( NULL ),
506 : pTableView( NULL ),
507 : pTopView( NULL ),
508 : pColumnData( NULL ),
509 : pFormulaData( NULL ),
510 : pFormulaDataPara( NULL ),
511 : pTipVisibleParent( NULL ),
512 : nTipVisible( 0 ),
513 : pTipVisibleSecParent( NULL ),
514 : nTipVisibleSec( 0 ),
515 : nFormSelStart( 0 ),
516 : nFormSelEnd( 0 ),
517 : nAutoPar( 0 ),
518 : eMode( SC_INPUT_NONE ),
519 : bUseTab( false ),
520 : bTextValid( true ),
521 : bModified( false ),
522 : bSelIsRef( false ),
523 : bFormulaMode( false ),
524 : bInRangeUpdate( false ),
525 : bParenthesisShown( false ),
526 : bCreatingFuncView( false ),
527 : bInEnterHandler( false ),
528 : bCommandErrorShown( false ),
529 : bInOwnChange( false ),
530 : bProtected( false ),
531 : bCellHasPercentFormat( false ),
532 : bLastIsSymbol( false ),
533 : mbDocumentDisposing(false),
534 : nValidation( 0 ),
535 : eAttrAdjust( SVX_HOR_JUSTIFY_STANDARD ),
536 : aScaleX( 1,1 ),
537 : aScaleY( 1,1 ),
538 : pRefViewSh( NULL ),
539 : pLastPattern( NULL ),
540 : pEditDefaults( NULL ),
541 : pLastState( NULL ),
542 : pDelayTimer( NULL ),
543 : pRangeFindList( NULL ),
544 348 : maFormulaChar()
545 : {
546 : // The InputHandler is constructed with the view, so SfxViewShell::Current
547 : // doesn't have the right view yet. pActiveViewSh is updated in NotifyChange.
548 348 : pActiveViewSh = NULL;
549 :
550 : // Bindings (only still used for Invalidate) are retrieved if needed on demand
551 348 : }
552 :
553 1035 : ScInputHandler::~ScInputHandler()
554 : {
555 : // If this is the application InputHandler, the dtor is called after SfxApplication::Main,
556 : // thus we can't rely on any Sfx functions
557 345 : if (!mbDocumentDisposing) // inplace
558 0 : EnterHandler(); // Finish input
559 :
560 345 : if (SC_MOD()->GetRefInputHdl() == this)
561 0 : SC_MOD()->SetRefInputHdl(NULL);
562 :
563 345 : if ( pInputWin && pInputWin->GetInputHandler() == this )
564 0 : pInputWin->SetInputHandler( NULL );
565 :
566 345 : delete pRangeFindList;
567 345 : delete pEditDefaults;
568 345 : delete pEngine;
569 345 : delete pLastState;
570 345 : delete pDelayTimer;
571 345 : delete pColumnData;
572 345 : delete pFormulaData;
573 345 : delete pFormulaDataPara;
574 690 : }
575 :
576 1634 : void ScInputHandler::SetRefScale( const Fraction& rX, const Fraction& rY )
577 : {
578 1634 : if ( rX != aScaleX || rY != aScaleY )
579 : {
580 10 : aScaleX = rX;
581 10 : aScaleY = rY;
582 10 : if (pEngine)
583 : {
584 6 : MapMode aMode( MAP_100TH_MM, Point(), aScaleX, aScaleY );
585 6 : pEngine->SetRefMapMode( aMode );
586 : }
587 : }
588 1634 : }
589 :
590 348 : void ScInputHandler::UpdateRefDevice()
591 : {
592 348 : if (!pEngine)
593 348 : return;
594 :
595 348 : bool bTextWysiwyg = SC_MOD()->GetInputOptions().GetTextWysiwyg();
596 348 : bool bInPlace = pActiveViewSh && pActiveViewSh->GetViewFrame()->GetFrame().IsInPlace();
597 348 : EEControlBits nCtrl = pEngine->GetControlWord();
598 348 : if ( bTextWysiwyg || bInPlace )
599 4 : nCtrl |= EEControlBits::FORMAT100; // EditEngine default: always format for 100%
600 : else
601 344 : nCtrl &= ~EEControlBits::FORMAT100; // when formatting for screen, use the actual MapMode
602 348 : pEngine->SetControlWord( nCtrl );
603 348 : if ( bTextWysiwyg && pActiveViewSh )
604 4 : pEngine->SetRefDevice( pActiveViewSh->GetViewData().GetDocument()->GetPrinter() );
605 : else
606 344 : pEngine->SetRefDevice( NULL );
607 :
608 348 : MapMode aMode( MAP_100TH_MM, Point(), aScaleX, aScaleY );
609 348 : pEngine->SetRefMapMode( aMode );
610 :
611 : // SetRefDevice(NULL) uses VirtualDevice, SetRefMapMode forces creation of a local VDev,
612 : // so the DigitLanguage can be safely modified (might use an own VDev instead of NULL).
613 348 : if ( !( bTextWysiwyg && pActiveViewSh ) )
614 : {
615 344 : pEngine->GetRefDevice()->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() );
616 348 : }
617 : }
618 :
619 2174 : void ScInputHandler::ImplCreateEditEngine()
620 : {
621 2174 : if ( !pEngine )
622 : {
623 348 : if ( pActiveViewSh )
624 : {
625 342 : ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
626 342 : pEngine = new ScFieldEditEngine(&rDoc, rDoc.GetEnginePool(), rDoc.GetEditPool());
627 : }
628 : else
629 6 : pEngine = new ScFieldEditEngine(NULL, EditEngine::CreatePool(), NULL, true);
630 348 : pEngine->SetWordDelimiters( ScEditUtil::ModifyDelimiters( pEngine->GetWordDelimiters() ) );
631 348 : UpdateRefDevice(); // also sets MapMode
632 348 : pEngine->SetPaperSize( Size( 1000000, 1000000 ) );
633 348 : pEditDefaults = new SfxItemSet( pEngine->GetEmptyItemSet() );
634 :
635 348 : pEngine->SetControlWord( pEngine->GetControlWord() | EEControlBits::AUTOCORRECT );
636 348 : pEngine->SetModifyHdl( LINK( this, ScInputHandler, ModifyHdl ) );
637 : }
638 :
639 : // set the EditEngine so that it invalidates the view instead of direct
640 : // paint
641 2174 : if (pActiveViewSh)
642 : {
643 2168 : ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
644 2168 : if (EditView* pEditView = pEngine->GetActiveView())
645 0 : pEditView->setTiledRendering(rDoc.GetDrawLayer()->isTiledRendering());
646 : }
647 2174 : }
648 :
649 0 : void ScInputHandler::UpdateAutoCorrFlag()
650 : {
651 0 : EEControlBits nCntrl = pEngine->GetControlWord();
652 0 : EEControlBits nOld = nCntrl;
653 :
654 : // Don't use pLastPattern here (may be invalid because of AutoStyle)
655 0 : bool bDisable = bLastIsSymbol || bFormulaMode;
656 0 : if ( bDisable )
657 0 : nCntrl &= ~EEControlBits::AUTOCORRECT;
658 : else
659 0 : nCntrl |= EEControlBits::AUTOCORRECT;
660 :
661 0 : if ( nCntrl != nOld )
662 0 : pEngine->SetControlWord(nCntrl);
663 0 : }
664 :
665 0 : void ScInputHandler::UpdateSpellSettings( bool bFromStartTab )
666 : {
667 0 : if ( pActiveViewSh )
668 : {
669 0 : ScViewData& rViewData = pActiveViewSh->GetViewData();
670 0 : bool bOnlineSpell = rViewData.GetDocument()->GetDocOptions().IsAutoSpell();
671 :
672 : // SetDefaultLanguage is independent of the language attributes,
673 : // ScGlobal::GetEditDefaultLanguage is always used.
674 : // It must be set every time in case the office language was changed.
675 :
676 0 : pEngine->SetDefaultLanguage( ScGlobal::GetEditDefaultLanguage() );
677 :
678 : // if called for changed options, update flags only if already editing
679 : // if called from StartTable, always update flags
680 :
681 0 : if ( bFromStartTab || eMode != SC_INPUT_NONE )
682 : {
683 0 : EEControlBits nCntrl = pEngine->GetControlWord();
684 0 : EEControlBits nOld = nCntrl;
685 0 : if( bOnlineSpell )
686 0 : nCntrl |= EEControlBits::ONLINESPELLING;
687 : else
688 0 : nCntrl &= ~EEControlBits::ONLINESPELLING;
689 : // No AutoCorrect for Symbol Font (EditEngine does no evaluate Default)
690 0 : if ( pLastPattern && pLastPattern->IsSymbolFont() )
691 0 : nCntrl &= ~EEControlBits::AUTOCORRECT;
692 : else
693 0 : nCntrl |= EEControlBits::AUTOCORRECT;
694 0 : if ( nCntrl != nOld )
695 0 : pEngine->SetControlWord(nCntrl);
696 :
697 0 : ScDocument* pDoc = rViewData.GetDocument();
698 0 : pDoc->ApplyAsianEditSettings( *pEngine );
699 : pEngine->SetDefaultHorizontalTextDirection(
700 0 : (EEHorizontalTextDirection)pDoc->GetEditTextDirection( rViewData.GetTabNo() ) );
701 0 : pEngine->SetFirstWordCapitalization( false );
702 : }
703 :
704 : // Language is set separately, so the speller is needed only if online spelling is active
705 0 : if ( bOnlineSpell ) {
706 0 : com::sun::star::uno::Reference<com::sun::star::linguistic2::XSpellChecker1> xXSpellChecker1( LinguMgr::GetSpellChecker() );
707 0 : pEngine->SetSpeller( xXSpellChecker1 );
708 : }
709 :
710 0 : bool bHyphen = pLastPattern && static_cast<const SfxBoolItem&>(pLastPattern->GetItem(ATTR_HYPHENATE)).GetValue();
711 0 : if ( bHyphen ) {
712 0 : com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
713 0 : pEngine->SetHyphenator( xXHyphenator );
714 : }
715 : }
716 0 : }
717 :
718 : // Function/Range names etc. as Tip help
719 :
720 : // The other types are defined in ScDocument::GetFormulaEntries
721 0 : void ScInputHandler::GetFormulaData()
722 : {
723 0 : if ( pActiveViewSh )
724 : {
725 0 : ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
726 :
727 0 : if ( pFormulaData )
728 0 : pFormulaData->clear();
729 : else
730 : {
731 0 : pFormulaData = new ScTypedCaseStrSet;
732 : }
733 :
734 0 : if( pFormulaDataPara )
735 0 : pFormulaDataPara->clear();
736 : else
737 0 : pFormulaDataPara = new ScTypedCaseStrSet;
738 :
739 0 : const OUString aParenthesesReplacement( cParenthesesReplacement);
740 0 : const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
741 0 : sal_uLong nListCount = pFuncList->GetCount();
742 0 : for(sal_uLong i=0;i<nListCount;i++)
743 : {
744 0 : const ScFuncDesc* pDesc = pFuncList->GetFunction( i );
745 0 : if ( pDesc->pFuncName )
746 : {
747 0 : const sal_Unicode* pName = pDesc->pFuncName->getStr();
748 0 : const sal_Int32 nLen = pDesc->pFuncName->getLength();
749 : // fdo#75264 fill maFormulaChar with all characters used in formula names
750 0 : for ( sal_Int32 j = 0; j < nLen; j++ )
751 : {
752 0 : sal_Unicode c = pName[ j ];
753 0 : maFormulaChar.insert( c );
754 : }
755 0 : OUString aFuncName = *pDesc->pFuncName + aParenthesesReplacement;
756 0 : pFormulaData->insert(ScTypedStrData(aFuncName, 0.0, ScTypedStrData::Standard));
757 0 : pDesc->initArgumentInfo();
758 0 : OUString aEntry = pDesc->getSignature();
759 0 : pFormulaDataPara->insert(ScTypedStrData(aEntry, 0.0, ScTypedStrData::Standard));
760 : }
761 : }
762 0 : miAutoPosFormula = pFormulaData->end();
763 0 : rDoc.GetFormulaEntries( *pFormulaData );
764 0 : rDoc.GetFormulaEntries( *pFormulaDataPara );
765 : }
766 0 : }
767 :
768 0 : IMPL_LINK( ScInputHandler, ShowHideTipVisibleParentListener, VclWindowEvent*, pEvent )
769 : {
770 0 : if( pEvent->GetId() == VCLEVENT_OBJECT_DYING || pEvent->GetId() == VCLEVENT_WINDOW_HIDE )
771 0 : HideTip();
772 0 : return 0;
773 : }
774 :
775 0 : IMPL_LINK( ScInputHandler, ShowHideTipVisibleSecParentListener, VclWindowEvent*, pEvent )
776 : {
777 0 : if( pEvent->GetId() == VCLEVENT_OBJECT_DYING || pEvent->GetId() == VCLEVENT_WINDOW_HIDE )
778 0 : HideTipBelow();
779 0 : return 0;
780 : }
781 :
782 2174 : void ScInputHandler::HideTip()
783 : {
784 2174 : if ( nTipVisible )
785 : {
786 0 : if (pTipVisibleParent)
787 0 : pTipVisibleParent->RemoveEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleParentListener ) );
788 0 : Help::HideTip( nTipVisible );
789 0 : nTipVisible = 0;
790 0 : pTipVisibleParent = NULL;
791 : }
792 2174 : aManualTip.clear();
793 2174 : }
794 2174 : void ScInputHandler::HideTipBelow()
795 : {
796 2174 : if ( nTipVisibleSec )
797 : {
798 0 : if (pTipVisibleSecParent)
799 0 : pTipVisibleSecParent->RemoveEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleSecParentListener ) );
800 0 : Help::HideTip( nTipVisibleSec );
801 0 : nTipVisibleSec = 0;
802 0 : pTipVisibleSecParent = NULL;
803 : }
804 2174 : aManualTip.clear();
805 2174 : }
806 :
807 0 : void ScInputHandler::ShowArgumentsTip( const OUString& rParagraph, OUString& rSelText, const ESelection& rSel,
808 : bool bTryFirstSel )
809 : {
810 0 : ScDocShell* pDocSh = pActiveViewSh->GetViewData().GetDocShell();
811 0 : const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
812 0 : const sal_Unicode cSheetSep = lcl_getSheetSeparator(&pDocSh->GetDocument());
813 0 : FormulaHelper aHelper(ScGlobal::GetStarCalcFunctionMgr());
814 0 : bool bFound = false;
815 0 : while( !bFound )
816 : {
817 0 : rSelText += ")";
818 0 : sal_Int32 nLeftParentPos = lcl_MatchParenthesis( rSelText, rSelText.getLength()-1 );
819 0 : if( nLeftParentPos != -1 )
820 : {
821 0 : sal_Int32 nNextFStart = aHelper.GetFunctionStart( rSelText, nLeftParentPos, true);
822 : const IFunctionDescription* ppFDesc;
823 0 : ::std::vector< OUString> aArgs;
824 0 : if( aHelper.GetNextFunc( rSelText, false, nNextFStart, NULL, &ppFDesc, &aArgs ) )
825 : {
826 0 : if( !ppFDesc->getFunctionName().isEmpty() )
827 : {
828 0 : sal_Int32 nArgPos = aHelper.GetArgStart( rSelText, nNextFStart, 0 );
829 0 : sal_uInt16 nArgs = static_cast<sal_uInt16>(ppFDesc->getParameterCount());
830 0 : OUString aFuncName( ppFDesc->getFunctionName() + "(");
831 0 : OUString aNew;
832 : ScTypedCaseStrSet::const_iterator it =
833 0 : findText(*pFormulaDataPara, pFormulaDataPara->end(), aFuncName, aNew, false);
834 0 : if (it != pFormulaDataPara->end())
835 : {
836 0 : bool bFlag = false;
837 0 : sal_uInt16 nActive = 0;
838 0 : for( sal_uInt16 i=0; i < nArgs; i++ )
839 : {
840 0 : sal_Int32 nLength = aArgs[i].getLength();
841 0 : if( nArgPos <= rSelText.getLength()-1 )
842 : {
843 0 : nActive = i+1;
844 0 : bFlag = true;
845 : }
846 0 : nArgPos+=nLength+1;
847 : }
848 0 : if( bFlag )
849 : {
850 0 : sal_Int32 nCountSemicolon = comphelper::string::getTokenCount(aNew, cSep) - 1;
851 0 : sal_Int32 nCountDot = comphelper::string::getTokenCount(aNew, cSheetSep) - 1;
852 0 : sal_Int32 nStartPosition = 0;
853 0 : sal_Int32 nEndPosition = 0;
854 :
855 0 : if( !nCountSemicolon )
856 : {
857 0 : for (sal_Int32 i = 0; i < aNew.getLength(); ++i)
858 : {
859 0 : sal_Unicode cNext = aNew[i];
860 0 : if( cNext == '(' )
861 : {
862 0 : nStartPosition = i+1;
863 : }
864 : }
865 : }
866 0 : else if( !nCountDot )
867 : {
868 0 : sal_uInt16 nCount = 0;
869 0 : for (sal_Int32 i = 0; i < aNew.getLength(); ++i)
870 : {
871 0 : sal_Unicode cNext = aNew[i];
872 0 : if( cNext == '(' )
873 : {
874 0 : nStartPosition = i+1;
875 : }
876 0 : else if( cNext == cSep )
877 : {
878 0 : nCount ++;
879 0 : nEndPosition = i;
880 0 : if( nCount == nActive )
881 : {
882 0 : break;
883 : }
884 0 : nStartPosition = nEndPosition+1;
885 : }
886 : }
887 : }
888 : else
889 : {
890 0 : sal_uInt16 nCount = 0;
891 0 : for (sal_Int32 i = 0; i < aNew.getLength(); ++i)
892 : {
893 0 : sal_Unicode cNext = aNew[i];
894 0 : if( cNext == '(' )
895 : {
896 0 : nStartPosition = i+1;
897 : }
898 0 : else if( cNext == cSep )
899 : {
900 0 : nCount ++;
901 0 : nEndPosition = i;
902 0 : if( nCount == nActive )
903 : {
904 0 : break;
905 : }
906 0 : nStartPosition = nEndPosition+1;
907 : }
908 0 : else if( cNext == cSheetSep )
909 : {
910 0 : continue;
911 : }
912 : }
913 : }
914 :
915 0 : if (nStartPosition > 0)
916 : {
917 0 : OUStringBuffer aBuf;
918 0 : aBuf.append(aNew.copy(0, nStartPosition));
919 0 : aBuf.append(static_cast<sal_Unicode>(0x25BA));
920 0 : aBuf.append(aNew.copy(nStartPosition));
921 0 : aNew = aBuf.makeStringAndClear();
922 0 : ShowTipBelow( aNew );
923 0 : bFound = true;
924 : }
925 : }
926 : else
927 : {
928 0 : ShowTipBelow( aNew );
929 0 : bFound = true;
930 : }
931 0 : }
932 : }
933 0 : }
934 : }
935 0 : else if (bTryFirstSel)
936 : {
937 0 : sal_Int32 nPosition = 0;
938 0 : OUString aText = pEngine->GetWord( 0, rSel.nEndPos-1 );
939 : /* XXX: dubious, what is this condition supposed to exactly match? */
940 0 : if (rSel.nEndPos <= aText.getLength() && aText[ rSel.nEndPos-1 ] == '=')
941 : {
942 0 : break;
943 : }
944 0 : OUString aNew;
945 0 : nPosition = aText.getLength()+1;
946 : ScTypedCaseStrSet::const_iterator it =
947 0 : findText(*pFormulaDataPara, pFormulaDataPara->end(), aText, aNew, false);
948 0 : if (it != pFormulaDataPara->end())
949 : {
950 0 : if( nPosition < rParagraph.getLength() && rParagraph[ nPosition ] =='(' )
951 : {
952 0 : ShowTipBelow( aNew );
953 0 : bFound = true;
954 : }
955 : else
956 0 : break;
957 : }
958 : else
959 : {
960 0 : break;
961 0 : }
962 : }
963 : else
964 : {
965 0 : break;
966 : }
967 0 : }
968 0 : }
969 :
970 0 : void ScInputHandler::ShowTipCursor()
971 : {
972 0 : HideTip();
973 0 : HideTipBelow();
974 0 : EditView* pActiveView = pTopView ? pTopView : pTableView;
975 :
976 0 : if ( bFormulaMode && pActiveView && pFormulaDataPara && pEngine->GetParagraphCount() == 1 )
977 : {
978 0 : OUString aParagraph = pEngine->GetText( 0 );
979 0 : ESelection aSel = pActiveView->GetSelection();
980 0 : aSel.Adjust();
981 :
982 0 : if ( aParagraph.getLength() < aSel.nEndPos )
983 0 : return;
984 :
985 0 : if ( aSel.nEndPos > 0 )
986 : {
987 0 : OUString aSelText( aParagraph.copy( 0, aSel.nEndPos ));
988 :
989 0 : ShowArgumentsTip( aParagraph, aSelText, aSel, true);
990 0 : }
991 : }
992 : }
993 :
994 0 : void ScInputHandler::ShowTip( const OUString& rText )
995 : {
996 : // aManualTip needs to be set afterwards from outside
997 0 : HideTip();
998 0 : EditView* pActiveView = pTopView ? pTopView : pTableView;
999 0 : if (pActiveView)
1000 : {
1001 0 : Point aPos;
1002 0 : pTipVisibleParent = pActiveView->GetWindow();
1003 0 : vcl::Cursor* pCur = pActiveView->GetCursor();
1004 0 : if (pCur)
1005 0 : aPos = pTipVisibleParent->LogicToPixel( pCur->GetPos() );
1006 0 : aPos = pTipVisibleParent->OutputToScreenPixel( aPos );
1007 0 : Rectangle aRect( aPos, aPos );
1008 :
1009 0 : QuickHelpFlags nAlign = QuickHelpFlags::Left|QuickHelpFlags::Bottom;
1010 0 : nTipVisible = Help::ShowTip(pTipVisibleParent, aRect, rText, nAlign);
1011 0 : pTipVisibleParent->AddEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleParentListener ) );
1012 : }
1013 0 : }
1014 :
1015 0 : void ScInputHandler::ShowTipBelow( const OUString& rText )
1016 : {
1017 0 : HideTipBelow();
1018 :
1019 0 : EditView* pActiveView = pTopView ? pTopView : pTableView;
1020 0 : if ( pActiveView )
1021 : {
1022 0 : Point aPos;
1023 0 : pTipVisibleSecParent = pActiveView->GetWindow();
1024 0 : vcl::Cursor* pCur = pActiveView->GetCursor();
1025 0 : if ( pCur )
1026 : {
1027 0 : Point aLogicPos = pCur->GetPos();
1028 0 : aLogicPos.Y() += pCur->GetHeight();
1029 0 : aPos = pTipVisibleSecParent->LogicToPixel( aLogicPos );
1030 : }
1031 0 : aPos = pTipVisibleSecParent->OutputToScreenPixel( aPos );
1032 0 : Rectangle aRect( aPos, aPos );
1033 0 : QuickHelpFlags nAlign = QuickHelpFlags::Left | QuickHelpFlags::Top | QuickHelpFlags::NoEvadePointer;
1034 0 : nTipVisibleSec = Help::ShowTip(pTipVisibleSecParent, aRect, rText, nAlign);
1035 0 : pTipVisibleSecParent->AddEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleSecParentListener ) );
1036 : }
1037 0 : }
1038 :
1039 0 : bool ScInputHandler::GetFuncName( OUString& aStart, OUString& aResult )
1040 : {
1041 0 : if ( aStart.isEmpty() )
1042 0 : return false;
1043 :
1044 0 : aStart = ScGlobal::pCharClass->uppercase( aStart );
1045 0 : sal_Int32 nPos = aStart.getLength() - 1;
1046 0 : sal_Unicode c = aStart[ nPos ];
1047 : // fdo#75264 use maFormulaChar to check if characters are used in function names
1048 0 : ::std::set< sal_Unicode >::const_iterator p = maFormulaChar.find( c );
1049 0 : if ( p == maFormulaChar.end() )
1050 0 : return false; // last character is not part of any function name, quit
1051 :
1052 0 : ::std::vector<sal_Unicode> aTemp;
1053 0 : aTemp.push_back( c );
1054 0 : for(sal_Int32 i = nPos - 1; i >= 0; --i)
1055 : {
1056 0 : c = aStart[ i ];
1057 0 : p = maFormulaChar.find( c );
1058 :
1059 0 : if (p == maFormulaChar.end())
1060 0 : break;
1061 :
1062 0 : aTemp.push_back( c );
1063 : }
1064 :
1065 0 : ::std::vector<sal_Unicode>::reverse_iterator rIt = aTemp.rbegin();
1066 0 : aResult = OUString( *rIt++ );
1067 0 : while ( rIt != aTemp.rend() )
1068 0 : aResult += OUString( *rIt++ );
1069 :
1070 0 : return true;
1071 : }
1072 :
1073 0 : void ScInputHandler::UseFormulaData()
1074 : {
1075 0 : EditView* pActiveView = pTopView ? pTopView : pTableView;
1076 :
1077 : // Formulas may only have 1 paragraph
1078 0 : if ( pActiveView && pFormulaData && pEngine->GetParagraphCount() == 1 )
1079 : {
1080 0 : OUString aParagraph = pEngine->GetText( 0 );
1081 0 : ESelection aSel = pActiveView->GetSelection();
1082 0 : aSel.Adjust();
1083 :
1084 : // Due to differences between table and input cell (e.g clipboard with line breaks),
1085 : // the selection may not be in line with the EditEngine anymore.
1086 : // Just return without any indication as to why.
1087 0 : if ( aSel.nEndPos > aParagraph.getLength() )
1088 0 : return;
1089 :
1090 : // Is the cursor at the end of a word?
1091 0 : if ( aSel.nEndPos > 0 )
1092 : {
1093 0 : OUString aSelText( aParagraph.copy( 0, aSel.nEndPos ));
1094 :
1095 0 : OUString aText;
1096 0 : if ( GetFuncName( aSelText, aText ) )
1097 : {
1098 : // function name is incomplete:
1099 : // show first matching function name as tip above cell
1100 0 : OUString aNew;
1101 0 : miAutoPosFormula = pFormulaData->end();
1102 0 : miAutoPosFormula = findText(*pFormulaData, miAutoPosFormula, aText, aNew, false);
1103 0 : if (miAutoPosFormula != pFormulaData->end())
1104 : {
1105 0 : if (aNew[aNew.getLength()-1] == cParenthesesReplacement)
1106 0 : aNew = aNew.copy( 0, aNew.getLength()-1) + "()";
1107 0 : ShowTip( aNew );
1108 0 : aAutoSearch = aText;
1109 : }
1110 0 : return;
1111 : }
1112 :
1113 : // function name is complete:
1114 : // show tip below the cell with function name and arguments of function
1115 0 : ShowArgumentsTip( aParagraph, aSelText, aSel, false);
1116 0 : }
1117 : }
1118 : }
1119 :
1120 0 : void ScInputHandler::NextFormulaEntry( bool bBack )
1121 : {
1122 0 : EditView* pActiveView = pTopView ? pTopView : pTableView;
1123 0 : if ( pActiveView && pFormulaData )
1124 : {
1125 0 : OUString aNew;
1126 0 : ScTypedCaseStrSet::const_iterator itNew = findText(*pFormulaData, miAutoPosFormula, aAutoSearch, aNew, bBack);
1127 0 : if (itNew != pFormulaData->end())
1128 : {
1129 0 : miAutoPosFormula = itNew;
1130 0 : if (aNew[aNew.getLength()-1] == cParenthesesReplacement)
1131 0 : aNew = aNew.copy( 0, aNew.getLength()-1) + "()";
1132 0 : ShowTip(aNew); // Display a quick help
1133 0 : }
1134 : }
1135 :
1136 : // For Tab we always call HideCursor first
1137 0 : if (pActiveView)
1138 0 : pActiveView->ShowCursor();
1139 0 : }
1140 :
1141 : namespace {
1142 :
1143 0 : bool needToExtendSelection(const OUString& rSelectedText, const OUString& rInsertText)
1144 : {
1145 0 : return !rInsertText.startsWithIgnoreAsciiCase(rSelectedText);
1146 : }
1147 :
1148 0 : void completeFunction( EditView* pView, const OUString& rInsert, bool& rParInserted )
1149 : {
1150 0 : if (pView)
1151 : {
1152 0 : ESelection aSel = pView->GetSelection();
1153 0 : --aSel.nStartPos;
1154 0 : --aSel.nEndPos;
1155 0 : pView->SetSelection(aSel);
1156 0 : pView->SelectCurrentWord();
1157 :
1158 : // a dot and underscore are word separators so we need special
1159 : // treatment for any formula containing a dot or underscore
1160 0 : if(rInsert.indexOf(".") != -1 || rInsert.indexOf("_") != -1)
1161 : {
1162 : // need to make sure that we replace also the part before the dot
1163 : // go through the word to find the match with the insert string
1164 0 : aSel = pView->GetSelection();
1165 0 : ESelection aOldSelection = aSel;
1166 0 : OUString aSelectedText = pView->GetSelected();
1167 0 : if ( needToExtendSelection( aSelectedText, rInsert ) )
1168 : {
1169 0 : while(needToExtendSelection(aSelectedText, rInsert))
1170 : {
1171 : assert(aSel.nStartPos > 0);
1172 0 : --aSel.nStartPos;
1173 0 : aSel.nEndPos = aSel.nStartPos;
1174 0 : pView->SetSelection(aSel);
1175 0 : pView->SelectCurrentWord();
1176 0 : aSelectedText = pView->GetSelected();
1177 : }
1178 0 : aSel.nStartPos = aSel.nEndPos - ( aSelectedText.getLength() - 1 );
1179 : }
1180 : else
1181 : {
1182 0 : aSel.nStartPos = aSel.nEndPos - aSelectedText.getLength();
1183 : }
1184 0 : aSel.nEndPos = aOldSelection.nEndPos;
1185 0 : pView->SetSelection(aSel);
1186 : }
1187 :
1188 0 : OUString aInsStr = rInsert;
1189 0 : sal_Int32 nInsLen = aInsStr.getLength();
1190 0 : bool bDoParen = ( nInsLen > 1 && aInsStr[nInsLen-2] == '('
1191 0 : && aInsStr[nInsLen-1] == ')' );
1192 0 : if ( bDoParen )
1193 : {
1194 : // Do not insert parentheses after function names if there already are some
1195 : // (e.g. if the function name was edited).
1196 0 : ESelection aWordSel = pView->GetSelection();
1197 0 : OUString aOld = pView->GetEditEngine()->GetText(0);
1198 :
1199 : // aWordSel.EndPos points one behind string if word at end
1200 0 : if (aWordSel.nEndPos < aOld.getLength())
1201 : {
1202 0 : sal_Unicode cNext = aOld[aWordSel.nEndPos];
1203 0 : if ( cNext == '(' )
1204 : {
1205 0 : bDoParen = false;
1206 0 : aInsStr = aInsStr.copy( 0, nInsLen - 2 ); // Skip parentheses
1207 : }
1208 0 : }
1209 : }
1210 :
1211 0 : pView->InsertText( aInsStr, false );
1212 :
1213 0 : if ( bDoParen ) // Put cursor between parentheses
1214 : {
1215 0 : aSel = pView->GetSelection();
1216 0 : --aSel.nStartPos;
1217 0 : --aSel.nEndPos;
1218 0 : pView->SetSelection(aSel);
1219 :
1220 0 : rParInserted = true;
1221 0 : }
1222 : }
1223 0 : }
1224 :
1225 : }
1226 :
1227 0 : void ScInputHandler::PasteFunctionData()
1228 : {
1229 0 : if (pFormulaData && miAutoPosFormula != pFormulaData->end())
1230 : {
1231 0 : const ScTypedStrData& rData = *miAutoPosFormula;
1232 0 : OUString aInsert = rData.GetString();
1233 0 : if (aInsert[aInsert.getLength()-1] == cParenthesesReplacement)
1234 0 : aInsert = aInsert.copy( 0, aInsert.getLength()-1) + "()";
1235 0 : bool bParInserted = false;
1236 :
1237 0 : DataChanging(); // Cannot be new
1238 0 : completeFunction( pTopView, aInsert, bParInserted );
1239 0 : completeFunction( pTableView, aInsert, bParInserted );
1240 0 : DataChanged();
1241 0 : ShowTipCursor();
1242 :
1243 0 : if (bParInserted)
1244 0 : AutoParAdded();
1245 : }
1246 :
1247 0 : HideTip();
1248 :
1249 0 : EditView* pActiveView = pTopView ? pTopView : pTableView;
1250 0 : if (pActiveView)
1251 0 : pActiveView->ShowCursor();
1252 0 : }
1253 :
1254 : // Calculate selection and display as tip help
1255 0 : static OUString lcl_Calculate( const OUString& rFormula, ScDocument* pDoc, const ScAddress &rPos )
1256 : {
1257 : //TODO: Merge with ScFormulaDlg::CalcValue and move into Document!
1258 : // Quotation marks for Strings are only inserted here.
1259 :
1260 0 : if(rFormula.isEmpty())
1261 0 : return OUString();
1262 :
1263 0 : boost::scoped_ptr<ScSimpleFormulaCalculator> pCalc( new ScSimpleFormulaCalculator( pDoc, rPos, rFormula ) );
1264 :
1265 : // FIXME: HACK! In order to not get a #REF! for ColRowNames, if a name is actually inserted as a Range
1266 : // into the whole Formula, but is interpreted as a single cell reference when displaying it on its own
1267 0 : bool bColRowName = pCalc->HasColRowName();
1268 0 : if ( bColRowName )
1269 : {
1270 : // ColRowName in RPN code?
1271 0 : if ( pCalc->GetCode()->GetCodeLen() <= 1 )
1272 : { // ==1: Single one is as a Parameter always a Range
1273 : // ==0: It might be one, if ...
1274 0 : OUStringBuffer aBraced;
1275 0 : aBraced.append('(');
1276 0 : aBraced.append(rFormula);
1277 0 : aBraced.append(')');
1278 0 : pCalc.reset( new ScSimpleFormulaCalculator( pDoc, rPos, aBraced.makeStringAndClear() ) );
1279 : }
1280 : else
1281 0 : bColRowName = false;
1282 : }
1283 :
1284 0 : sal_uInt16 nErrCode = pCalc->GetErrCode();
1285 0 : if ( nErrCode != 0 )
1286 0 : return ScGlobal::GetErrorString(nErrCode);
1287 :
1288 0 : SvNumberFormatter& aFormatter = *(pDoc->GetFormatTable());
1289 0 : OUString aValue;
1290 0 : if ( pCalc->IsValue() )
1291 : {
1292 0 : double n = pCalc->GetValue();
1293 : sal_uLong nFormat = aFormatter.GetStandardFormat( n, 0,
1294 0 : pCalc->GetFormatType(), ScGlobal::eLnge );
1295 0 : aFormatter.GetInputLineString( n, nFormat, aValue );
1296 : //! display OutputString but insert InputLineString
1297 : }
1298 : else
1299 : {
1300 0 : OUString aStr = pCalc->GetString().getString();
1301 : sal_uLong nFormat = aFormatter.GetStandardFormat(
1302 0 : pCalc->GetFormatType(), ScGlobal::eLnge);
1303 : {
1304 : Color* pColor;
1305 : aFormatter.GetOutputString( aStr, nFormat,
1306 0 : aValue, &pColor );
1307 : }
1308 :
1309 0 : aValue = "\"" + aValue + "\"";
1310 : //! Escape quotation marks in String??
1311 : }
1312 :
1313 0 : ScRange aTestRange;
1314 0 : if ( bColRowName || (aTestRange.Parse(rFormula) & SCA_VALID) )
1315 0 : aValue = aValue + " ...";
1316 :
1317 0 : return aValue;
1318 : }
1319 :
1320 0 : void ScInputHandler::FormulaPreview()
1321 : {
1322 0 : OUString aValue;
1323 0 : EditView* pActiveView = pTopView ? pTopView : pTableView;
1324 0 : if ( pActiveView && pActiveViewSh )
1325 : {
1326 0 : OUString aPart = pActiveView->GetSelected();
1327 0 : if (aPart.isEmpty())
1328 0 : aPart = pEngine->GetText(0);
1329 0 : ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
1330 0 : aValue = lcl_Calculate( aPart, &rDoc, aCursorPos );
1331 : }
1332 :
1333 0 : if (!aValue.isEmpty())
1334 : {
1335 0 : ShowTip( aValue ); // Display as QuickHelp
1336 0 : aManualTip = aValue; // Set after ShowTip
1337 0 : if (pFormulaData)
1338 0 : miAutoPosFormula = pFormulaData->end();
1339 0 : if (pColumnData)
1340 0 : miAutoPosColumn = pColumnData->end();
1341 0 : }
1342 0 : }
1343 :
1344 0 : void ScInputHandler::PasteManualTip()
1345 : {
1346 : // Three dots at the end -> Range reference -> do not insert
1347 : // FIXME: Once we have matrix constants, we can change this
1348 0 : sal_Int32 nTipLen = aManualTip.getLength();
1349 0 : sal_uInt32 const nTipLen2(sal::static_int_cast<sal_uInt32>(nTipLen));
1350 0 : if ( nTipLen && ( nTipLen < 3 || aManualTip.copy( nTipLen2-3 ) != "..." ) )
1351 : {
1352 0 : DataChanging(); // Cannot be new
1353 :
1354 0 : OUString aInsert = aManualTip;
1355 0 : EditView* pActiveView = pTopView ? pTopView : pTableView;
1356 0 : if (!pActiveView->HasSelection())
1357 : {
1358 : // Nothing selected -> select everything
1359 0 : sal_Int32 nOldLen = pEngine->GetTextLen(0);
1360 0 : ESelection aAllSel( 0, 0, 0, nOldLen );
1361 0 : if ( pTopView )
1362 0 : pTopView->SetSelection( aAllSel );
1363 0 : if ( pTableView )
1364 0 : pTableView->SetSelection( aAllSel );
1365 : }
1366 :
1367 0 : ESelection aSel = pActiveView->GetSelection();
1368 0 : aSel.Adjust();
1369 : OSL_ENSURE( !aSel.nStartPara && !aSel.nEndPara, "Too many paragraphs in Formula" );
1370 0 : if ( !aSel.nStartPos ) // Selection from the start?
1371 : {
1372 0 : if ( aSel.nEndPos == pEngine->GetTextLen(0) )
1373 : {
1374 : // Everything selected -> skip quotation marks
1375 0 : if ( aInsert[0] == '"' )
1376 0 : aInsert = aInsert.copy(1);
1377 0 : sal_Int32 nInsLen = aInsert.getLength();
1378 0 : if ( aInsert.endsWith("\"") )
1379 0 : aInsert = aInsert.copy( 0, nInsLen-1 );
1380 : }
1381 0 : else if ( aSel.nEndPos )
1382 : {
1383 : // Not everything selected -> do not overwrite equality sign
1384 : //FIXME: Even double equality signs??
1385 0 : aSel.nStartPos = 1;
1386 0 : if ( pTopView )
1387 0 : pTopView->SetSelection( aSel );
1388 0 : if ( pTableView )
1389 0 : pTableView->SetSelection( aSel );
1390 : }
1391 : }
1392 0 : if ( pTopView )
1393 0 : pTopView->InsertText( aInsert, true );
1394 0 : if ( pTableView )
1395 0 : pTableView->InsertText( aInsert, true );
1396 :
1397 0 : DataChanged();
1398 : }
1399 :
1400 0 : HideTip();
1401 0 : }
1402 :
1403 510 : void ScInputHandler::ResetAutoPar()
1404 : {
1405 510 : nAutoPar = 0;
1406 510 : }
1407 :
1408 0 : void ScInputHandler::AutoParAdded()
1409 : {
1410 0 : ++nAutoPar; // Closing parenthesis can be overwritten
1411 0 : }
1412 :
1413 0 : bool ScInputHandler::CursorAtClosingPar()
1414 : {
1415 : // Test if the cursor is before a closing parenthesis
1416 : // Selection from SetReference has been removed before
1417 0 : EditView* pActiveView = pTopView ? pTopView : pTableView;
1418 0 : if ( pActiveView && !pActiveView->HasSelection() && bFormulaMode )
1419 : {
1420 0 : ESelection aSel = pActiveView->GetSelection();
1421 0 : sal_Int32 nPos = aSel.nStartPos;
1422 0 : OUString aFormula = pEngine->GetText(0);
1423 0 : if ( nPos < aFormula.getLength() && aFormula[nPos] == ')' )
1424 0 : return true;
1425 : }
1426 0 : return false;
1427 : }
1428 :
1429 0 : void ScInputHandler::SkipClosingPar()
1430 : {
1431 : // this is called when a ')' is typed and the cursor is before a ')'
1432 : // that can be overwritten -> just set the cursor behind the ')'
1433 :
1434 0 : EditView* pActiveView = pTopView ? pTopView : pTableView;
1435 0 : if (pActiveView)
1436 : {
1437 0 : ESelection aSel = pActiveView->GetSelection();
1438 0 : ++aSel.nStartPos;
1439 0 : ++aSel.nEndPos;
1440 :
1441 : // this is in a formula (only one paragraph), so the selection
1442 : // can be used directly for the TopView
1443 :
1444 0 : if ( pTopView )
1445 0 : pTopView->SetSelection( aSel );
1446 0 : if ( pTableView )
1447 0 : pTableView->SetSelection( aSel );
1448 : }
1449 :
1450 : OSL_ENSURE(nAutoPar, "SkipClosingPar: count is wrong");
1451 0 : --nAutoPar;
1452 0 : }
1453 :
1454 : // Auto input
1455 :
1456 0 : void ScInputHandler::GetColData()
1457 : {
1458 0 : if ( pActiveViewSh )
1459 : {
1460 0 : ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
1461 :
1462 0 : if ( pColumnData )
1463 0 : pColumnData->clear();
1464 : else
1465 0 : pColumnData = new ScTypedCaseStrSet;
1466 :
1467 0 : std::vector<ScTypedStrData> aEntries;
1468 : rDoc.GetDataEntries(
1469 0 : aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab(), true, aEntries, true);
1470 0 : if (!aEntries.empty())
1471 0 : pColumnData->insert(aEntries.begin(), aEntries.end());
1472 :
1473 0 : miAutoPosColumn = pColumnData->end();
1474 : }
1475 0 : }
1476 :
1477 0 : void ScInputHandler::UseColData() // When typing
1478 : {
1479 0 : EditView* pActiveView = pTopView ? pTopView : pTableView;
1480 0 : if ( pActiveView && pColumnData )
1481 : {
1482 : // Only change when cursor is at the end
1483 0 : ESelection aSel = pActiveView->GetSelection();
1484 0 : aSel.Adjust();
1485 :
1486 0 : sal_Int32 nParCnt = pEngine->GetParagraphCount();
1487 0 : if ( aSel.nEndPara+1 == nParCnt )
1488 : {
1489 0 : sal_Int32 nParLen = pEngine->GetTextLen( aSel.nEndPara );
1490 0 : if ( aSel.nEndPos == nParLen )
1491 : {
1492 0 : OUString aText = GetEditText(pEngine);
1493 0 : if (!aText.isEmpty())
1494 : {
1495 0 : OUString aNew;
1496 0 : miAutoPosColumn = pColumnData->end();
1497 0 : miAutoPosColumn = findText(*pColumnData, miAutoPosColumn, aText, aNew, false);
1498 0 : if (miAutoPosColumn != pColumnData->end())
1499 : {
1500 : // Strings can contain line endings (e.g. due to dBase import),
1501 : // which would result in multiple paragraphs here, which is not desirable.
1502 : //! Then GetExactMatch doesn't work either
1503 0 : lcl_RemoveLineEnd( aNew );
1504 :
1505 : // Keep paragraph, just append the rest
1506 : //! Exact replacement in EnterHandler !!!
1507 : // One Space between paragraphs:
1508 0 : sal_Int32 nEdLen = pEngine->GetTextLen() + nParCnt - 1;
1509 0 : OUString aIns = aNew.copy(nEdLen);
1510 :
1511 : // Selection must be "backwards", so the cursor stays behind the last
1512 : // typed character
1513 0 : ESelection aSelection( aSel.nEndPara, aSel.nEndPos + aIns.getLength(),
1514 0 : aSel.nEndPara, aSel.nEndPos );
1515 :
1516 : // When editing in input line, apply to both edit views
1517 0 : if ( pTableView )
1518 : {
1519 0 : pTableView->InsertText( aIns, false );
1520 0 : pTableView->SetSelection( aSelection );
1521 : }
1522 0 : if ( pTopView )
1523 : {
1524 0 : pTopView->InsertText( aIns, false );
1525 0 : pTopView->SetSelection( aSelection );
1526 : }
1527 :
1528 0 : aAutoSearch = aText; // To keep searching - nAutoPos is set
1529 :
1530 0 : if (aText.getLength() == aNew.getLength())
1531 : {
1532 : // If the inserted text is found, consume TAB only if there's more coming
1533 0 : OUString aDummy;
1534 : ScTypedCaseStrSet::const_iterator itNextPos =
1535 0 : findText(*pColumnData, miAutoPosColumn, aText, aDummy, false);
1536 0 : bUseTab = itNextPos != pColumnData->end();
1537 : }
1538 : else
1539 0 : bUseTab = true;
1540 0 : }
1541 0 : }
1542 : }
1543 : }
1544 : }
1545 0 : }
1546 :
1547 0 : void ScInputHandler::NextAutoEntry( bool bBack )
1548 : {
1549 0 : EditView* pActiveView = pTopView ? pTopView : pTableView;
1550 0 : if ( pActiveView && pColumnData )
1551 : {
1552 0 : if (miAutoPosColumn != pColumnData->end() && !aAutoSearch.isEmpty())
1553 : {
1554 : // Is the selection still valid (could be changed via the mouse)?
1555 0 : ESelection aSel = pActiveView->GetSelection();
1556 0 : aSel.Adjust();
1557 0 : sal_Int32 nParCnt = pEngine->GetParagraphCount();
1558 0 : if ( aSel.nEndPara+1 == nParCnt && aSel.nStartPara == aSel.nEndPara )
1559 : {
1560 0 : OUString aText = GetEditText(pEngine);
1561 0 : sal_Int32 nSelLen = aSel.nEndPos - aSel.nStartPos;
1562 0 : sal_Int32 nParLen = pEngine->GetTextLen( aSel.nEndPara );
1563 0 : if ( aSel.nEndPos == nParLen && aText.getLength() == aAutoSearch.getLength() + nSelLen )
1564 : {
1565 0 : OUString aNew;
1566 : ScTypedCaseStrSet::const_iterator itNew =
1567 0 : findText(*pColumnData, miAutoPosColumn, aAutoSearch, aNew, bBack);
1568 :
1569 0 : if (itNew != pColumnData->end())
1570 : {
1571 : // match found!
1572 0 : miAutoPosColumn = itNew;
1573 0 : bInOwnChange = true; // disable ModifyHdl (reset below)
1574 :
1575 0 : lcl_RemoveLineEnd( aNew );
1576 0 : OUString aIns = aNew.copy(aAutoSearch.getLength());
1577 :
1578 : // when editing in input line, apply to both edit views
1579 0 : if ( pTableView )
1580 : {
1581 0 : pTableView->DeleteSelected();
1582 0 : pTableView->InsertText( aIns, false );
1583 : pTableView->SetSelection( ESelection(
1584 0 : aSel.nEndPara, aSel.nStartPos + aIns.getLength(),
1585 0 : aSel.nEndPara, aSel.nStartPos ) );
1586 : }
1587 0 : if ( pTopView )
1588 : {
1589 0 : pTopView->DeleteSelected();
1590 0 : pTopView->InsertText( aIns, false );
1591 : pTopView->SetSelection( ESelection(
1592 0 : aSel.nEndPara, aSel.nStartPos + aIns.getLength(),
1593 0 : aSel.nEndPara, aSel.nStartPos ) );
1594 : }
1595 :
1596 0 : bInOwnChange = false;
1597 0 : }
1598 0 : }
1599 : }
1600 : }
1601 : }
1602 :
1603 : // For Tab, HideCursor was always called first
1604 0 : if (pActiveView)
1605 0 : pActiveView->ShowCursor();
1606 0 : }
1607 :
1608 : // Highlight parentheses
1609 0 : void ScInputHandler::UpdateParenthesis()
1610 : {
1611 : // Find parentheses
1612 : //TODO: Can we disable parentheses highlighting per parentheses?
1613 0 : bool bFound = false;
1614 0 : if ( bFormulaMode && eMode != SC_INPUT_TOP )
1615 : {
1616 0 : if ( pTableView && !pTableView->HasSelection() ) // Selection is always at the bottom
1617 : {
1618 0 : ESelection aSel = pTableView->GetSelection();
1619 0 : if (aSel.nStartPos)
1620 : {
1621 : // Examine character left to the cursor
1622 0 : sal_Int32 nPos = aSel.nStartPos - 1;
1623 0 : OUString aFormula = pEngine->GetText(0);
1624 0 : sal_Unicode c = aFormula[nPos];
1625 0 : if ( c == '(' || c == ')' )
1626 : {
1627 0 : sal_Int32 nOther = lcl_MatchParenthesis( aFormula, nPos );
1628 0 : if ( nOther != -1 )
1629 : {
1630 0 : SfxItemSet aSet( pEngine->GetEmptyItemSet() );
1631 0 : aSet.Put( SvxWeightItem( WEIGHT_BOLD, EE_CHAR_WEIGHT ) );
1632 :
1633 : //! Distinguish if cell is already highlighted!!!!
1634 0 : if (bParenthesisShown)
1635 : {
1636 : // Remove old highlighting
1637 0 : sal_Int32 nCount = pEngine->GetParagraphCount();
1638 0 : for (sal_Int32 i=0; i<nCount; i++)
1639 0 : pEngine->RemoveCharAttribs( i, EE_CHAR_WEIGHT );
1640 : }
1641 :
1642 0 : ESelection aSelThis( 0,nPos, 0,nPos+1 );
1643 0 : pEngine->QuickSetAttribs( aSet, aSelThis );
1644 0 : ESelection aSelOther( 0,nOther, 0,nOther+1 );
1645 0 : pEngine->QuickSetAttribs( aSet, aSelOther );
1646 :
1647 : // Dummy InsertText for Update and Paint (selection is empty)
1648 0 : pTableView->InsertText( EMPTY_OUSTRING, false );
1649 :
1650 0 : bFound = true;
1651 : }
1652 0 : }
1653 : }
1654 :
1655 : // mark parenthesis right of cursor if it will be overwritten (nAutoPar)
1656 : // with different color (COL_LIGHTBLUE) ??
1657 : }
1658 : }
1659 :
1660 : // Remove old highlighting, if no new one is set
1661 0 : if ( bParenthesisShown && !bFound && pTableView )
1662 : {
1663 0 : sal_Int32 nCount = pEngine->GetParagraphCount();
1664 0 : for (sal_Int32 i=0; i<nCount; i++)
1665 0 : pTableView->RemoveCharAttribs( i, EE_CHAR_WEIGHT );
1666 : }
1667 :
1668 0 : bParenthesisShown = bFound;
1669 0 : }
1670 :
1671 8 : void ScInputHandler::ViewShellGone(ScTabViewShell* pViewSh) // Executed synchronously!
1672 : {
1673 8 : if ( pViewSh == pActiveViewSh )
1674 : {
1675 0 : delete pLastState;
1676 0 : pLastState = NULL;
1677 0 : pLastPattern = NULL;
1678 : }
1679 :
1680 8 : if ( pViewSh == pRefViewSh )
1681 : {
1682 : //! The input from the EnterHandler does not arrive anymore
1683 : // We end the EditMode anyways
1684 0 : EnterHandler();
1685 0 : bFormulaMode = false;
1686 0 : pRefViewSh = NULL;
1687 0 : SfxGetpApp()->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
1688 0 : SC_MOD()->SetRefInputHdl(NULL);
1689 0 : if (pInputWin)
1690 0 : pInputWin->SetFormulaMode(false);
1691 0 : UpdateAutoCorrFlag();
1692 : }
1693 :
1694 8 : pActiveViewSh = PTR_CAST( ScTabViewShell, SfxViewShell::Current() );
1695 :
1696 8 : if ( pActiveViewSh && pActiveViewSh == pViewSh )
1697 : {
1698 : OSL_FAIL("pActiveViewSh is gone");
1699 0 : pActiveViewSh = NULL;
1700 : }
1701 :
1702 8 : if ( SC_MOD()->GetInputOptions().GetTextWysiwyg() )
1703 0 : UpdateRefDevice(); // Don't keep old document's printer as RefDevice
1704 8 : }
1705 :
1706 0 : void ScInputHandler::UpdateActiveView()
1707 : {
1708 0 : ImplCreateEditEngine();
1709 :
1710 : // #i20588# Don't rely on focus to find the active edit view. Instead, the
1711 : // active pane at the start of editing is now stored (GetEditActivePart).
1712 : // GetActiveWin (the currently active pane) fails for ref input across the
1713 : // panes of a split view.
1714 :
1715 : vcl::Window* pShellWin = pActiveViewSh ?
1716 0 : pActiveViewSh->GetWindowByPos( pActiveViewSh->GetViewData().GetEditActivePart() ) :
1717 0 : NULL;
1718 :
1719 0 : sal_uInt16 nCount = pEngine->GetViewCount();
1720 0 : if (nCount > 0)
1721 : {
1722 0 : pTableView = pEngine->GetView(0);
1723 0 : for (sal_uInt16 i=1; i<nCount; i++)
1724 : {
1725 0 : EditView* pThis = pEngine->GetView(i);
1726 0 : vcl::Window* pWin = pThis->GetWindow();
1727 0 : if ( pWin==pShellWin )
1728 0 : pTableView = pThis;
1729 : }
1730 : }
1731 : else
1732 0 : pTableView = NULL;
1733 :
1734 : // setup the pTableView editeng for tiled rendering to get cursor and selections
1735 0 : if (pActiveViewSh && pTableView)
1736 : {
1737 0 : ScDocShell* pDocShell = pActiveViewSh->GetViewData().GetDocShell();
1738 0 : ScDocument& rDoc = pDocShell->GetDocument();
1739 0 : if (rDoc.GetDrawLayer()->isTiledRendering())
1740 : {
1741 0 : ScDrawLayer *pDrawLayer = pDocShell->GetDocument().GetDrawLayer();
1742 0 : pTableView->registerLibreOfficeKitCallback(pDrawLayer->getLibreOfficeKitCallback(), pDrawLayer->getLibreOfficeKitData());
1743 0 : pTableView->setTiledRendering(true);
1744 : }
1745 : }
1746 :
1747 0 : if (pInputWin && eMode == SC_INPUT_TOP )
1748 0 : pTopView = pInputWin->GetEditView();
1749 : else
1750 0 : pTopView = NULL;
1751 0 : }
1752 :
1753 674 : void ScInputHandler::SetInputWindow( ScInputWindow* pNew )
1754 : {
1755 674 : pInputWin = pNew;
1756 674 : }
1757 :
1758 846 : void ScInputHandler::StopInputWinEngine( bool bAll )
1759 : {
1760 846 : if (pInputWin)
1761 191 : pInputWin->StopEditEngine( bAll );
1762 :
1763 846 : pTopView = NULL; // invalid now
1764 846 : }
1765 :
1766 0 : EditView* ScInputHandler::GetActiveView()
1767 : {
1768 0 : UpdateActiveView();
1769 0 : return pTopView ? pTopView : pTableView;
1770 : }
1771 :
1772 6 : void ScInputHandler::ForgetLastPattern()
1773 : {
1774 6 : pLastPattern = NULL;
1775 6 : if ( !pLastState && pActiveViewSh )
1776 0 : pActiveViewSh->UpdateInputHandler( true ); // Get status again
1777 : else
1778 6 : NotifyChange( pLastState, true );
1779 6 : }
1780 :
1781 0 : void ScInputHandler::UpdateAdjust( sal_Unicode cTyped )
1782 : {
1783 : SvxAdjust eSvxAdjust;
1784 0 : switch (eAttrAdjust)
1785 : {
1786 : case SVX_HOR_JUSTIFY_STANDARD:
1787 : {
1788 0 : bool bNumber = false;
1789 0 : if (cTyped) // Restarted
1790 0 : bNumber = (cTyped>='0' && cTyped<='9'); // Ony ciphers are numbers
1791 0 : else if ( pActiveViewSh )
1792 : {
1793 0 : ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
1794 0 : bNumber = ( rDoc.GetCellType( aCursorPos ) == CELLTYPE_VALUE );
1795 : }
1796 0 : eSvxAdjust = bNumber ? SVX_ADJUST_RIGHT : SVX_ADJUST_LEFT;
1797 : }
1798 0 : break;
1799 : case SVX_HOR_JUSTIFY_BLOCK:
1800 0 : eSvxAdjust = SVX_ADJUST_BLOCK;
1801 0 : break;
1802 : case SVX_HOR_JUSTIFY_CENTER:
1803 0 : eSvxAdjust = SVX_ADJUST_CENTER;
1804 0 : break;
1805 : case SVX_HOR_JUSTIFY_RIGHT:
1806 0 : eSvxAdjust = SVX_ADJUST_RIGHT;
1807 0 : break;
1808 : default: // SVX_HOR_JUSTIFY_LEFT
1809 0 : eSvxAdjust = SVX_ADJUST_LEFT;
1810 0 : break;
1811 : }
1812 :
1813 0 : bool bAsianVertical = pLastPattern &&
1814 0 : static_cast<const SfxBoolItem&>(pLastPattern->GetItem( ATTR_STACKED )).GetValue() &&
1815 0 : static_cast<const SfxBoolItem&>(pLastPattern->GetItem( ATTR_VERTICAL_ASIAN )).GetValue();
1816 0 : if ( bAsianVertical )
1817 : {
1818 : // Always edit at top of cell -> LEFT when editing vertically
1819 0 : eSvxAdjust = SVX_ADJUST_LEFT;
1820 : }
1821 :
1822 0 : pEditDefaults->Put( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
1823 0 : pEngine->SetDefaults( *pEditDefaults );
1824 :
1825 0 : nEditAdjust = sal::static_int_cast<sal_uInt16>(eSvxAdjust); //! set at ViewData or with PostEditView
1826 :
1827 0 : pEngine->SetVertical( bAsianVertical );
1828 0 : }
1829 :
1830 0 : void ScInputHandler::RemoveAdjust()
1831 : {
1832 : // Delete hard alignement attributes
1833 0 : bool bUndo = pEngine->IsUndoEnabled();
1834 0 : if ( bUndo )
1835 0 : pEngine->EnableUndo( false );
1836 :
1837 : // Non-default paragraph attributes (e.g. from clipboard)
1838 : // must be turned into character attributes
1839 0 : pEngine->RemoveParaAttribs();
1840 :
1841 0 : if ( bUndo )
1842 0 : pEngine->EnableUndo( true );
1843 :
1844 0 : }
1845 :
1846 0 : void ScInputHandler::RemoveRangeFinder()
1847 : {
1848 : // Delete pRangeFindList and colors
1849 0 : pEngine->SetUpdateMode(false);
1850 0 : sal_Int32 nCount = pEngine->GetParagraphCount(); // Could just have been inserted
1851 0 : for (sal_Int32 i=0; i<nCount; i++)
1852 0 : pEngine->RemoveCharAttribs( i, EE_CHAR_COLOR );
1853 0 : pEngine->SetUpdateMode(true);
1854 :
1855 0 : EditView* pActiveView = pTopView ? pTopView : pTableView;
1856 0 : pActiveView->ShowCursor( false, true );
1857 :
1858 0 : DeleteRangeFinder(); // Deletes the list and the labels on the table
1859 0 : }
1860 :
1861 0 : bool ScInputHandler::StartTable( sal_Unicode cTyped, bool bFromCommand, bool bInputActivated )
1862 : {
1863 0 : bool bNewTable = false;
1864 :
1865 0 : if (bModified || !ValidCol(aCursorPos.Col()))
1866 0 : return false;
1867 :
1868 0 : if (pActiveViewSh)
1869 : {
1870 0 : ImplCreateEditEngine();
1871 0 : UpdateActiveView();
1872 0 : SyncViews();
1873 :
1874 0 : ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
1875 :
1876 0 : const ScMarkData& rMark = pActiveViewSh->GetViewData().GetMarkData();
1877 0 : ScEditableTester aTester;
1878 0 : if ( rMark.IsMarked() || rMark.IsMultiMarked() )
1879 0 : aTester.TestSelection( &rDoc, rMark );
1880 : else
1881 : aTester.TestSelectedBlock(
1882 0 : &rDoc, aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Col(), aCursorPos.Row(), rMark );
1883 :
1884 0 : bool bStartInputMode = true;
1885 :
1886 0 : if (!aTester.IsEditable())
1887 : {
1888 0 : bProtected = true;
1889 : // We allow read-only input mode activation regardless
1890 : // whether it's part of an array or not or whether explicit cell
1891 : // activation is requested (double-click or F2) or a click in input
1892 : // line.
1893 0 : bool bShowError = (!bInputActivated || aTester.GetMessageId() != STR_PROTECTIONERR) &&
1894 0 : !pActiveViewSh->GetViewData().GetDocShell()->IsReadOnly();
1895 0 : if (bShowError)
1896 : {
1897 0 : eMode = SC_INPUT_NONE;
1898 0 : StopInputWinEngine( true );
1899 0 : UpdateFormulaMode();
1900 0 : if ( pActiveViewSh && ( !bFromCommand || !bCommandErrorShown ) )
1901 : {
1902 : // Prevent repeated error messages for the same cell from command events
1903 : // (for keyboard events, multiple messages are wanted).
1904 : // Set the flag before showing the error message because the command handler
1905 : // for the next IME command may be called when showing the dialog.
1906 0 : if ( bFromCommand )
1907 0 : bCommandErrorShown = true;
1908 :
1909 0 : pActiveViewSh->GetActiveWin()->GrabFocus();
1910 0 : pActiveViewSh->ErrorMessage(aTester.GetMessageId());
1911 : }
1912 0 : bStartInputMode = false;
1913 : }
1914 : }
1915 :
1916 0 : if (bStartInputMode)
1917 : {
1918 : // UpdateMode is enabled again in ScViewData::SetEditEngine (and not needed otherwise)
1919 0 : pEngine->SetUpdateMode( false );
1920 :
1921 : // Take over attributes in EditEngine
1922 0 : const ScPatternAttr* pPattern = rDoc.GetPattern( aCursorPos.Col(),
1923 : aCursorPos.Row(),
1924 0 : aCursorPos.Tab() );
1925 0 : if (pPattern != pLastPattern)
1926 : {
1927 : // Percent format?
1928 0 : const SfxItemSet& rAttrSet = pPattern->GetItemSet();
1929 : const SfxPoolItem* pItem;
1930 :
1931 0 : if ( SfxItemState::SET == rAttrSet.GetItemState( ATTR_VALUE_FORMAT, true, &pItem ) )
1932 : {
1933 0 : sal_uLong nFormat = static_cast<const SfxUInt32Item*>(pItem)->GetValue();
1934 0 : bCellHasPercentFormat = ( css::util::NumberFormat::PERCENT ==
1935 0 : rDoc.GetFormatTable()->GetType( nFormat ) );
1936 : }
1937 : else
1938 0 : bCellHasPercentFormat = false; // Default: no percent
1939 :
1940 : // Validity specified?
1941 0 : if ( SfxItemState::SET == rAttrSet.GetItemState( ATTR_VALIDDATA, true, &pItem ) )
1942 0 : nValidation = static_cast<const SfxUInt32Item*>(pItem)->GetValue();
1943 : else
1944 0 : nValidation = 0;
1945 :
1946 : // EditEngine Defaults
1947 : // In no case SetParaAttribs, because the EditEngine might already
1948 : // be filled (for Edit cells).
1949 : // SetParaAttribs would change the content.
1950 :
1951 : //! The SetDefaults is now (since MUST/src602
1952 : //! EditEngine changes) implemented as a SetParaAttribs.
1953 : //! Any problems?
1954 :
1955 0 : pPattern->FillEditItemSet( pEditDefaults );
1956 0 : pEngine->SetDefaults( *pEditDefaults );
1957 0 : pLastPattern = pPattern;
1958 0 : bLastIsSymbol = pPattern->IsSymbolFont();
1959 :
1960 : // Background color must be known for automatic font color.
1961 : // For transparent cell background, the document background color must be used.
1962 :
1963 : Color aBackCol = static_cast<const SvxBrushItem&>(
1964 0 : pPattern->GetItem( ATTR_BACKGROUND )).GetColor();
1965 0 : ScModule* pScMod = SC_MOD();
1966 0 : if ( aBackCol.GetTransparency() > 0 ||
1967 0 : Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
1968 0 : aBackCol.SetColor( pScMod->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor );
1969 0 : pEngine->SetBackgroundColor( aBackCol );
1970 :
1971 : // Adjustment
1972 : eAttrAdjust = (SvxCellHorJustify)static_cast<const SvxHorJustifyItem&>(pPattern->
1973 0 : GetItem(ATTR_HOR_JUSTIFY)).GetValue();
1974 0 : if ( eAttrAdjust == SVX_HOR_JUSTIFY_REPEAT &&
1975 0 : static_cast<const SfxBoolItem&>(pPattern->GetItem(ATTR_LINEBREAK)).GetValue() )
1976 : {
1977 : // #i31843# "repeat" with "line breaks" is treated as default alignement
1978 0 : eAttrAdjust = SVX_HOR_JUSTIFY_STANDARD;
1979 : }
1980 : }
1981 :
1982 : // UpdateSpellSettings enables online spelling if needed
1983 : // -> also call if attributes are unchanged
1984 0 : UpdateSpellSettings( true ); // uses pLastPattern
1985 :
1986 : // Fill EditEngine
1987 0 : OUString aStr;
1988 0 : if (bTextValid)
1989 : {
1990 0 : pEngine->SetText(aCurrentText);
1991 0 : aStr = aCurrentText;
1992 0 : bTextValid = false;
1993 0 : aCurrentText.clear();
1994 : }
1995 : else
1996 0 : aStr = GetEditText(pEngine);
1997 :
1998 0 : if (aStr.startsWith("{=") && aStr.endsWith("}") ) // Matrix formula?
1999 : {
2000 0 : aStr = aStr.copy(1, aStr.getLength() -2);
2001 0 : pEngine->SetText(aStr);
2002 0 : if ( pInputWin )
2003 0 : pInputWin->SetTextString(aStr);
2004 : }
2005 :
2006 0 : UpdateAdjust( cTyped );
2007 :
2008 0 : if ( bAutoComplete )
2009 0 : GetColData();
2010 :
2011 0 : if ( !aStr.isEmpty() && ( aStr[0] == '=' || aStr[0] == '+' || aStr[0] == '-' ) &&
2012 0 : !cTyped && !bCreatingFuncView )
2013 0 : InitRangeFinder(aStr); // Formula is being edited -> RangeFinder
2014 :
2015 0 : bNewTable = true; // -> PostEditView Call
2016 : }
2017 : }
2018 :
2019 0 : if (!bProtected && pInputWin)
2020 0 : pInputWin->SetOkCancelMode();
2021 :
2022 0 : return bNewTable;
2023 : }
2024 :
2025 0 : static void lcl_SetTopSelection( EditView* pEditView, ESelection& rSel )
2026 : {
2027 : OSL_ENSURE( rSel.nStartPara==0 && rSel.nEndPara==0, "SetTopSelection: Para != 0" );
2028 :
2029 0 : EditEngine* pEngine = pEditView->GetEditEngine();
2030 0 : sal_Int32 nCount = pEngine->GetParagraphCount();
2031 0 : if (nCount > 1)
2032 : {
2033 0 : sal_Int32 nParLen = pEngine->GetTextLen(rSel.nStartPara);
2034 0 : while (rSel.nStartPos > nParLen && rSel.nStartPara+1 < nCount)
2035 : {
2036 0 : rSel.nStartPos -= nParLen + 1; // Including space from line break
2037 0 : nParLen = pEngine->GetTextLen(++rSel.nStartPara);
2038 : }
2039 :
2040 0 : nParLen = pEngine->GetTextLen(rSel.nEndPara);
2041 0 : while (rSel.nEndPos > nParLen && rSel.nEndPara+1 < nCount)
2042 : {
2043 0 : rSel.nEndPos -= nParLen + 1; // Including space from line break
2044 0 : nParLen = pEngine->GetTextLen(++rSel.nEndPara);
2045 : }
2046 : }
2047 :
2048 0 : ESelection aSel = pEditView->GetSelection();
2049 :
2050 0 : if ( rSel.nStartPara != aSel.nStartPara || rSel.nEndPara != aSel.nEndPara
2051 0 : || rSel.nStartPos != aSel.nStartPos || rSel.nEndPos != aSel.nEndPos )
2052 0 : pEditView->SetSelection( rSel );
2053 0 : }
2054 :
2055 0 : void ScInputHandler::SyncViews( EditView* pSourceView )
2056 : {
2057 0 : if (pSourceView)
2058 : {
2059 0 : bool bSelectionForTopView = false;
2060 0 : if (pTopView && pTopView != pSourceView)
2061 0 : bSelectionForTopView = true;
2062 0 : bool bSelectionForTableView = false;
2063 0 : if (pTableView && pTableView != pSourceView)
2064 0 : bSelectionForTableView = true;
2065 0 : if (bSelectionForTopView || bSelectionForTableView)
2066 : {
2067 0 : ESelection aSel(pSourceView->GetSelection());
2068 0 : if (bSelectionForTopView)
2069 0 : pTopView->SetSelection(aSel);
2070 0 : if (bSelectionForTableView)
2071 0 : lcl_SetTopSelection(pTableView, aSel);
2072 : }
2073 : }
2074 : // Only sync selection from topView if we are actually editiing there
2075 0 : else if (pTopView && pTableView)
2076 : {
2077 0 : ESelection aSel(pTopView->GetSelection());
2078 0 : lcl_SetTopSelection( pTableView, aSel );
2079 : }
2080 0 : }
2081 :
2082 88 : IMPL_LINK_NOARG(ScInputHandler, ModifyHdl)
2083 : {
2084 88 : if ( !bInOwnChange && ( eMode==SC_INPUT_TYPE || eMode==SC_INPUT_TABLE ) &&
2085 44 : pEngine && pEngine->GetUpdateMode() && pInputWin )
2086 : {
2087 : // Update input line from ModifyHdl for changes that are not
2088 : // wrapped by DataChanging/DataChanged calls (like Drag&Drop)
2089 0 : OUString aText;
2090 0 : if ( pInputWin->IsMultiLineInput() )
2091 0 : aText = ScEditUtil::GetMultilineString(*pEngine);
2092 : else
2093 0 : aText = GetEditText(pEngine);
2094 0 : lcl_RemoveTabs(aText);
2095 0 : pInputWin->SetTextString(aText);
2096 : }
2097 44 : return 0;
2098 : }
2099 :
2100 : /**
2101 : * @return true means new view created
2102 : */
2103 0 : bool ScInputHandler::DataChanging( sal_Unicode cTyped, bool bFromCommand )
2104 : {
2105 0 : if (pActiveViewSh)
2106 0 : pActiveViewSh->GetViewData().SetPasteMode( SC_PASTE_NONE );
2107 0 : bInOwnChange = true; // disable ModifyHdl (reset in DataChanged)
2108 :
2109 0 : if ( eMode == SC_INPUT_NONE )
2110 0 : return StartTable( cTyped, bFromCommand, false );
2111 : else
2112 0 : return false;
2113 : }
2114 :
2115 0 : void ScInputHandler::DataChanged( bool bFromTopNotify, bool bSetModified )
2116 : {
2117 0 : ImplCreateEditEngine();
2118 :
2119 0 : if (eMode==SC_INPUT_NONE)
2120 0 : eMode = SC_INPUT_TYPE;
2121 :
2122 0 : if ( eMode == SC_INPUT_TOP && pTopView && !bFromTopNotify )
2123 : {
2124 : // table EditEngine is formatted below, input line needs formatting after paste
2125 : // #i20282# not when called from the input line's modify handler
2126 0 : pTopView->GetEditEngine()->QuickFormatDoc( true );
2127 :
2128 : // #i23720# QuickFormatDoc hides the cursor, but can't show it again because it
2129 : // can't safely access the EditEngine's current view, so the cursor has to be
2130 : // shown again here.
2131 0 : pTopView->ShowCursor();
2132 : }
2133 :
2134 0 : if (bSetModified)
2135 0 : bModified = true;
2136 0 : bSelIsRef = false;
2137 :
2138 0 : if ( pRangeFindList && !bInRangeUpdate )
2139 0 : RemoveRangeFinder(); // Delete attributes and labels
2140 :
2141 0 : UpdateParenthesis(); // Highlight parentheses anew
2142 :
2143 0 : if (eMode==SC_INPUT_TYPE || eMode==SC_INPUT_TABLE)
2144 : {
2145 0 : OUString aText;
2146 0 : if ( pInputWin && pInputWin->IsMultiLineInput() )
2147 0 : aText = ScEditUtil::GetMultilineString(*pEngine);
2148 : else
2149 0 : aText = GetEditText(pEngine);
2150 0 : lcl_RemoveTabs(aText);
2151 :
2152 0 : if ( pInputWin )
2153 0 : pInputWin->SetTextString( aText );
2154 : }
2155 :
2156 : // If the cursor is before the end of a paragraph, parts are being pushed to
2157 : // the right (independently from the eMode) -> Adapt View!
2158 : // If the cursor is at the end, the StatusHandler of the ViewData is sufficient.
2159 : //
2160 : // First make sure the status handler is called now if the cursor
2161 : // is outside the visible area
2162 0 : pEngine->QuickFormatDoc();
2163 :
2164 0 : EditView* pActiveView = pTopView ? pTopView : pTableView;
2165 0 : if (pActiveView && pActiveViewSh)
2166 : {
2167 0 : ScViewData& rViewData = pActiveViewSh->GetViewData();
2168 :
2169 0 : bool bNeedGrow = ( nEditAdjust != SVX_ADJUST_LEFT ); // Always right-aligned
2170 0 : if (!bNeedGrow)
2171 : {
2172 : // Cursor before the end?
2173 0 : ESelection aSel = pActiveView->GetSelection();
2174 0 : aSel.Adjust();
2175 0 : bNeedGrow = ( aSel.nEndPos != pEngine->GetTextLen(aSel.nEndPara) );
2176 : }
2177 0 : if (!bNeedGrow)
2178 : {
2179 0 : bNeedGrow = rViewData.GetDocument()->IsLayoutRTL( rViewData.GetTabNo() );
2180 : }
2181 0 : if (bNeedGrow)
2182 : {
2183 : // Adjust inplace view
2184 0 : rViewData.EditGrowY();
2185 0 : rViewData.EditGrowX();
2186 : }
2187 : }
2188 :
2189 0 : UpdateFormulaMode();
2190 0 : bTextValid = false; // Changes only in the EditEngine
2191 0 : bInOwnChange = false;
2192 0 : }
2193 :
2194 0 : void ScInputHandler::UpdateFormulaMode()
2195 : {
2196 0 : SfxApplication* pSfxApp = SfxGetpApp();
2197 :
2198 0 : bool bIsFormula = !bProtected && pEngine->GetParagraphCount() == 1;
2199 0 : if (bIsFormula)
2200 : {
2201 0 : const OUString& rText = pEngine->GetText(0);
2202 0 : bIsFormula = !rText.isEmpty() &&
2203 0 : (rText[0] == '=' || rText[0] == '+' || rText[0] == '-');
2204 : }
2205 :
2206 0 : if ( bIsFormula )
2207 : {
2208 0 : if (!bFormulaMode)
2209 : {
2210 0 : bFormulaMode = true;
2211 0 : pRefViewSh = pActiveViewSh;
2212 0 : pSfxApp->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
2213 0 : SC_MOD()->SetRefInputHdl(this);
2214 0 : if (pInputWin)
2215 0 : pInputWin->SetFormulaMode(true);
2216 :
2217 0 : if ( bAutoComplete )
2218 0 : GetFormulaData();
2219 :
2220 0 : UpdateParenthesis();
2221 0 : UpdateAutoCorrFlag();
2222 : }
2223 : }
2224 : else // Deactivate
2225 : {
2226 0 : if (bFormulaMode)
2227 : {
2228 0 : ShowRefFrame();
2229 0 : bFormulaMode = false;
2230 0 : pRefViewSh = NULL;
2231 0 : pSfxApp->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
2232 0 : SC_MOD()->SetRefInputHdl(NULL);
2233 0 : if (pInputWin)
2234 0 : pInputWin->SetFormulaMode(false);
2235 0 : UpdateAutoCorrFlag();
2236 : }
2237 : }
2238 0 : }
2239 :
2240 0 : void ScInputHandler::ShowRefFrame()
2241 : {
2242 : // Modifying pActiveViewSh here would interfere with the bInEnterHandler / bRepeat
2243 : // checks in NotifyChange, and lead to keeping the wrong value in pActiveViewSh.
2244 : // A local variable is used instead.
2245 0 : ScTabViewShell* pVisibleSh = PTR_CAST( ScTabViewShell, SfxViewShell::Current() );
2246 0 : if ( pRefViewSh && pRefViewSh != pVisibleSh )
2247 : {
2248 0 : bool bFound = false;
2249 0 : SfxViewFrame* pRefFrame = pRefViewSh->GetViewFrame();
2250 0 : SfxViewFrame* pOneFrame = SfxViewFrame::GetFirst();
2251 0 : while ( pOneFrame && !bFound )
2252 : {
2253 0 : if ( pOneFrame == pRefFrame )
2254 0 : bFound = true;
2255 0 : pOneFrame = SfxViewFrame::GetNext( *pOneFrame );
2256 : }
2257 :
2258 0 : if (bFound)
2259 : {
2260 : // We count on Activate working synchronously here
2261 : // (pActiveViewSh is set while doing so)
2262 0 : pRefViewSh->SetActive(); // Appear and SetViewFrame
2263 :
2264 : // pLastState is set correctly in the NotifyChange from the Activate
2265 : }
2266 : else
2267 : {
2268 : OSL_FAIL("ViewFrame for reference input is not here anymore");
2269 : }
2270 : }
2271 0 : }
2272 :
2273 0 : void ScInputHandler::RemoveSelection()
2274 : {
2275 0 : EditView* pActiveView = pTopView ? pTopView : pTableView;
2276 0 : if (!pActiveView)
2277 0 : return;
2278 :
2279 0 : ESelection aSel = pActiveView->GetSelection();
2280 0 : aSel.nStartPara = aSel.nEndPara;
2281 0 : aSel.nStartPos = aSel.nEndPos;
2282 0 : if (pTableView)
2283 0 : pTableView->SetSelection( aSel );
2284 0 : if (pTopView)
2285 0 : pTopView->SetSelection( aSel );
2286 : }
2287 :
2288 0 : void ScInputHandler::InvalidateAttribs()
2289 : {
2290 0 : SfxViewFrame* pViewFrm = SfxViewFrame::Current();
2291 0 : if (pViewFrm)
2292 : {
2293 0 : SfxBindings& rBindings = pViewFrm->GetBindings();
2294 :
2295 0 : rBindings.Invalidate( SID_ATTR_CHAR_FONT );
2296 0 : rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
2297 0 : rBindings.Invalidate( SID_ATTR_CHAR_COLOR );
2298 :
2299 0 : rBindings.Invalidate( SID_ATTR_CHAR_WEIGHT );
2300 0 : rBindings.Invalidate( SID_ATTR_CHAR_POSTURE );
2301 0 : rBindings.Invalidate( SID_ATTR_CHAR_UNDERLINE );
2302 0 : rBindings.Invalidate( SID_ULINE_VAL_NONE );
2303 0 : rBindings.Invalidate( SID_ULINE_VAL_SINGLE );
2304 0 : rBindings.Invalidate( SID_ULINE_VAL_DOUBLE );
2305 0 : rBindings.Invalidate( SID_ULINE_VAL_DOTTED );
2306 :
2307 0 : rBindings.Invalidate( SID_HYPERLINK_GETLINK );
2308 :
2309 0 : rBindings.Invalidate( SID_ATTR_CHAR_KERNING );
2310 0 : rBindings.Invalidate( SID_SET_SUPER_SCRIPT );
2311 0 : rBindings.Invalidate( SID_SET_SUB_SCRIPT );
2312 0 : rBindings.Invalidate( SID_ATTR_CHAR_STRIKEOUT );
2313 0 : rBindings.Invalidate( SID_ATTR_CHAR_SHADOWED );
2314 : }
2315 0 : }
2316 :
2317 : // --------------- public methods --------------------------------------------
2318 :
2319 0 : void ScInputHandler::SetMode( ScInputMode eNewMode, const OUString* pInitText )
2320 : {
2321 0 : if ( eMode == eNewMode )
2322 0 : return;
2323 :
2324 0 : ImplCreateEditEngine();
2325 :
2326 0 : if (bProtected)
2327 : {
2328 0 : eMode = SC_INPUT_NONE;
2329 0 : StopInputWinEngine( true );
2330 0 : if (pActiveViewSh)
2331 0 : pActiveViewSh->GetActiveWin()->GrabFocus();
2332 0 : return;
2333 : }
2334 :
2335 0 : if (eNewMode != SC_INPUT_NONE && pActiveViewSh)
2336 : // Disable paste mode when edit mode starts.
2337 0 : pActiveViewSh->GetViewData().SetPasteMode( SC_PASTE_NONE );
2338 :
2339 0 : bInOwnChange = true; // disable ModifyHdl (reset below)
2340 :
2341 0 : ScInputMode eOldMode = eMode;
2342 0 : eMode = eNewMode;
2343 0 : if (eOldMode == SC_INPUT_TOP && eNewMode != eOldMode)
2344 0 : StopInputWinEngine( false );
2345 :
2346 0 : if (eMode==SC_INPUT_TOP || eMode==SC_INPUT_TABLE)
2347 : {
2348 0 : if (eOldMode == SC_INPUT_NONE) // not if switching between modes
2349 : {
2350 0 : if (StartTable(0, false, eMode == SC_INPUT_TABLE))
2351 : {
2352 0 : if (pActiveViewSh)
2353 0 : pActiveViewSh->GetViewData().GetDocShell()->PostEditView( pEngine, aCursorPos );
2354 : }
2355 : }
2356 :
2357 0 : if (pInitText)
2358 : {
2359 0 : pEngine->SetText(*pInitText);
2360 0 : bModified = true;
2361 : }
2362 :
2363 0 : sal_Int32 nPara = pEngine->GetParagraphCount()-1;
2364 0 : sal_Int32 nLen = pEngine->GetText(nPara).getLength();
2365 0 : sal_uInt16 nCount = pEngine->GetViewCount();
2366 :
2367 0 : for (sal_uInt16 i=0; i<nCount; i++)
2368 : {
2369 0 : if ( eMode == SC_INPUT_TABLE && eOldMode == SC_INPUT_TOP )
2370 : {
2371 : // Keep Selection
2372 : }
2373 : else
2374 : {
2375 : pEngine->GetView(i)->
2376 0 : SetSelection( ESelection( nPara, nLen, nPara, nLen ) );
2377 : }
2378 0 : pEngine->GetView(i)->ShowCursor(false);
2379 : }
2380 : }
2381 :
2382 0 : UpdateActiveView();
2383 0 : if (eMode==SC_INPUT_TABLE || eMode==SC_INPUT_TYPE)
2384 : {
2385 0 : if (pTableView)
2386 0 : pTableView->SetEditEngineUpdateMode(true);
2387 : }
2388 : else
2389 : {
2390 0 : if (pTopView)
2391 0 : pTopView->SetEditEngineUpdateMode(true);
2392 : }
2393 :
2394 0 : if (eNewMode != eOldMode)
2395 0 : UpdateFormulaMode();
2396 :
2397 0 : bInOwnChange = false;
2398 : }
2399 :
2400 : /**
2401 : * @return true if rString only contains digits (no autocorrect then)
2402 : */
2403 0 : static bool lcl_IsNumber(const OUString& rString)
2404 : {
2405 0 : sal_Int32 nLen = rString.getLength();
2406 0 : for (sal_Int32 i=0; i<nLen; i++)
2407 : {
2408 0 : sal_Unicode c = rString[i];
2409 0 : if ( c < '0' || c > '9' )
2410 0 : return false;
2411 : }
2412 0 : return true;
2413 : }
2414 :
2415 0 : static void lcl_SelectionToEnd( EditView* pView )
2416 : {
2417 0 : if ( pView )
2418 : {
2419 0 : EditEngine* pEngine = pView->GetEditEngine();
2420 0 : sal_Int32 nParCnt = pEngine->GetParagraphCount();
2421 0 : if ( nParCnt == 0 )
2422 0 : nParCnt = 1;
2423 0 : ESelection aSel( nParCnt-1, pEngine->GetTextLen(nParCnt-1) ); // empty selection, cursor at the end
2424 0 : pView->SetSelection( aSel );
2425 : }
2426 0 : }
2427 :
2428 510 : void ScInputHandler::EnterHandler( sal_uInt8 nBlockMode )
2429 : {
2430 : // Macro calls for validity can cause a lot of problems, so inhibit
2431 : // nested calls of EnterHandler().
2432 1020 : if (bInEnterHandler) return;
2433 510 : bInEnterHandler = true;
2434 510 : bInOwnChange = true; // disable ModifyHdl (reset below)
2435 :
2436 510 : ImplCreateEditEngine();
2437 :
2438 510 : bool bMatrix = ( nBlockMode == SC_ENTER_MATRIX );
2439 :
2440 510 : SfxApplication* pSfxApp = SfxGetpApp();
2441 510 : EditTextObject* pObject = NULL;
2442 510 : ScPatternAttr* pCellAttrs = NULL;
2443 510 : bool bForget = false; // Remove due to validity?
2444 :
2445 510 : OUString aString = GetEditText(pEngine);
2446 510 : EditView* pActiveView = pTopView ? pTopView : pTableView;
2447 510 : if (bModified && pActiveView && !aString.isEmpty() && !lcl_IsNumber(aString))
2448 : {
2449 0 : if (pColumnData && miAutoPosColumn != pColumnData->end())
2450 : {
2451 : // #i47125# If AutoInput appended something, do the final AutoCorrect
2452 : // with the cursor at the end of the input.
2453 0 : lcl_SelectionToEnd(pTopView);
2454 0 : lcl_SelectionToEnd(pTableView);
2455 : }
2456 :
2457 0 : vcl::Window* pFrameWin = pActiveViewSh ? pActiveViewSh->GetFrameWin() : NULL;
2458 :
2459 0 : if (pTopView)
2460 0 : pTopView->CompleteAutoCorrect(); // CompleteAutoCorrect for both Views
2461 0 : if (pTableView)
2462 0 : pTableView->CompleteAutoCorrect(pFrameWin);
2463 0 : aString = GetEditText(pEngine);
2464 : }
2465 510 : lcl_RemoveTabs(aString);
2466 :
2467 : // Test if valid (always with simple string)
2468 510 : if ( bModified && nValidation && pActiveViewSh )
2469 : {
2470 0 : ScDocument* pDoc = pActiveViewSh->GetViewData().GetDocument();
2471 0 : const ScValidationData* pData = pDoc->GetValidationEntry( nValidation );
2472 0 : if (pData && pData->HasErrMsg())
2473 : {
2474 : // #i67990# don't use pLastPattern in EnterHandler
2475 0 : const ScPatternAttr* pPattern = pDoc->GetPattern( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
2476 0 : bool bOk = pData->IsDataValid( aString, *pPattern, aCursorPos );
2477 :
2478 0 : if (!bOk)
2479 : {
2480 0 : if ( pActiveViewSh ) // If it came from MouseButtonDown
2481 0 : pActiveViewSh->StopMarking(); // (the InfoBox consumes the MouseButtonUp)
2482 :
2483 : //FIXME: We still run into problems if the input is triggered by activating another View
2484 0 : vcl::Window* pParent = Application::GetDefDialogParent();
2485 0 : if ( pData->DoError( pParent, aString, aCursorPos ) )
2486 0 : bForget = true; // Do not take over input
2487 : }
2488 : }
2489 : }
2490 :
2491 : // Check for input into DataPilot table
2492 510 : if ( bModified && pActiveViewSh && !bForget )
2493 : {
2494 0 : ScDocument* pDoc = pActiveViewSh->GetViewData().GetDocument();
2495 0 : ScDPObject* pDPObj = pDoc->GetDPAtCursor( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
2496 0 : if ( pDPObj )
2497 : {
2498 : // Any input within the DataPilot table is either a valid renaming
2499 : // or an invalid action - normal cell input is always aborted
2500 0 : pActiveViewSh->DataPilotInput( aCursorPos, aString );
2501 0 : bForget = true;
2502 : }
2503 : }
2504 :
2505 1020 : std::vector<editeng::MisspellRanges> aMisspellRanges;
2506 510 : pEngine->CompleteOnlineSpelling();
2507 510 : bool bSpellErrors = !bFormulaMode && pEngine->HasOnlineSpellErrors();
2508 510 : if ( bSpellErrors )
2509 : {
2510 : // #i3820# If the spell checker flags numerical input as error,
2511 : // it still has to be treated as number, not EditEngine object.
2512 0 : if ( pActiveViewSh )
2513 : {
2514 0 : ScDocument* pDoc = pActiveViewSh->GetViewData().GetDocument();
2515 : // #i67990# don't use pLastPattern in EnterHandler
2516 0 : const ScPatternAttr* pPattern = pDoc->GetPattern( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
2517 0 : if (pPattern)
2518 : {
2519 0 : SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
2520 : // without conditional format, as in ScColumn::SetString
2521 0 : sal_uInt32 nFormat = pPattern->GetNumberFormat( pFormatter );
2522 : double nVal;
2523 0 : if ( pFormatter->IsNumberFormat( aString, nFormat, nVal ) )
2524 : {
2525 0 : bSpellErrors = false; // ignore the spelling errors
2526 : }
2527 : }
2528 : }
2529 : }
2530 :
2531 : // After RemoveAdjust, the EditView must not be repainted (has wrong font size etc).
2532 : // SetUpdateMode must come after CompleteOnlineSpelling.
2533 : // The view is hidden in any case below (Broadcast).
2534 510 : pEngine->SetUpdateMode( false );
2535 :
2536 510 : if ( bModified && !bForget ) // What is being entered (text/object)?
2537 : {
2538 0 : sal_Int32 nParCnt = pEngine->GetParagraphCount();
2539 0 : if ( nParCnt == 0 )
2540 0 : nParCnt = 1;
2541 :
2542 0 : bool bUniformAttribs = true;
2543 0 : SfxItemSet aPara1Attribs = pEngine->GetAttribs(0, 0, pEngine->GetTextLen(0));
2544 0 : for (sal_Int32 nPara = 1; nPara < nParCnt; ++nPara)
2545 : {
2546 0 : SfxItemSet aPara2Attribs = pEngine->GetAttribs(nPara, 0, pEngine->GetTextLen(nPara));
2547 0 : if (!(aPara1Attribs == aPara2Attribs))
2548 : {
2549 : // Paragraph format different from that of the 1st paragraph.
2550 0 : bUniformAttribs = false;
2551 0 : break;
2552 : }
2553 0 : }
2554 :
2555 0 : ESelection aSel( 0, 0, nParCnt-1, pEngine->GetTextLen(nParCnt-1) );
2556 0 : SfxItemSet aOldAttribs = pEngine->GetAttribs( aSel );
2557 0 : const SfxPoolItem* pItem = NULL;
2558 :
2559 : // Find common (cell) attributes before RemoveAdjust
2560 0 : if ( pActiveViewSh && bUniformAttribs )
2561 : {
2562 0 : SfxItemSet* pCommonAttrs = NULL;
2563 0 : for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END; nId++)
2564 : {
2565 0 : SfxItemState eState = aOldAttribs.GetItemState( nId, false, &pItem );
2566 0 : if ( eState == SfxItemState::SET &&
2567 0 : nId != EE_CHAR_ESCAPEMENT && nId != EE_CHAR_PAIRKERNING &&
2568 0 : nId != EE_CHAR_KERNING && nId != EE_CHAR_XMLATTRIBS &&
2569 0 : *pItem != pEditDefaults->Get(nId) )
2570 : {
2571 0 : if ( !pCommonAttrs )
2572 0 : pCommonAttrs = new SfxItemSet( pEngine->GetEmptyItemSet() );
2573 0 : pCommonAttrs->Put( *pItem );
2574 : }
2575 : }
2576 :
2577 0 : if ( pCommonAttrs )
2578 : {
2579 0 : ScDocument* pDoc = pActiveViewSh->GetViewData().GetDocument();
2580 0 : pCellAttrs = new ScPatternAttr( pDoc->GetPool() );
2581 0 : pCellAttrs->GetFromEditItemSet( pCommonAttrs );
2582 0 : delete pCommonAttrs;
2583 : }
2584 : }
2585 :
2586 : // Clear ParaAttribs (including adjustment)
2587 0 : RemoveAdjust();
2588 :
2589 0 : bool bAttrib = false; // Formatting present?
2590 :
2591 : // check if EditObject is needed
2592 0 : if (nParCnt > 1)
2593 0 : bAttrib = true;
2594 : else
2595 : {
2596 0 : for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END && !bAttrib; nId++)
2597 : {
2598 0 : SfxItemState eState = aOldAttribs.GetItemState( nId, false, &pItem );
2599 0 : if (eState == SfxItemState::DONTCARE)
2600 0 : bAttrib = true;
2601 0 : else if (eState == SfxItemState::SET)
2602 : {
2603 : // Keep same items in EditEngine as in ScEditAttrTester
2604 0 : if ( nId == EE_CHAR_ESCAPEMENT || nId == EE_CHAR_PAIRKERNING ||
2605 0 : nId == EE_CHAR_KERNING || nId == EE_CHAR_XMLATTRIBS )
2606 : {
2607 0 : if ( *pItem != pEditDefaults->Get(nId) )
2608 0 : bAttrib = true;
2609 : }
2610 : }
2611 : }
2612 :
2613 : // Contains fields?
2614 0 : SfxItemState eFieldState = aOldAttribs.GetItemState( EE_FEATURE_FIELD, false );
2615 0 : if ( eFieldState == SfxItemState::DONTCARE || eFieldState == SfxItemState::SET )
2616 0 : bAttrib = true;
2617 :
2618 : // Not converted characters?
2619 0 : SfxItemState eConvState = aOldAttribs.GetItemState( EE_FEATURE_NOTCONV, false );
2620 0 : if ( eConvState == SfxItemState::DONTCARE || eConvState == SfxItemState::SET )
2621 0 : bAttrib = true;
2622 :
2623 : // Always recognize formulas as formulas
2624 : // We still need the preceding test due to cell attributes
2625 : }
2626 :
2627 0 : if (bSpellErrors)
2628 0 : pEngine->GetAllMisspellRanges(aMisspellRanges);
2629 :
2630 0 : if (bMatrix)
2631 0 : bAttrib = false;
2632 :
2633 0 : if (bAttrib)
2634 : {
2635 0 : pEngine->ClearSpellErrors();
2636 0 : pObject = pEngine->CreateTextObject();
2637 : }
2638 0 : else if (bAutoComplete) // Adjust Upper/Lower case
2639 : {
2640 : // Perform case-matching only when the typed text is partial.
2641 0 : if (pColumnData && aAutoSearch.getLength() < aString.getLength())
2642 0 : aString = getExactMatch(*pColumnData, aString);
2643 0 : }
2644 : }
2645 :
2646 : // Don't rely on ShowRefFrame switching the active view synchronously
2647 : // execute the function directly on the correct view's bindings instead
2648 : // pRefViewSh is reset in ShowRefFrame - get pointer before ShowRefFrame call
2649 510 : ScTabViewShell* pExecuteSh = pRefViewSh ? pRefViewSh : pActiveViewSh;
2650 :
2651 510 : if (bFormulaMode)
2652 : {
2653 0 : ShowRefFrame();
2654 :
2655 0 : if (pExecuteSh)
2656 : {
2657 0 : pExecuteSh->SetTabNo(aCursorPos.Tab());
2658 0 : pExecuteSh->ActiveGrabFocus();
2659 : }
2660 :
2661 0 : bFormulaMode = false;
2662 0 : pSfxApp->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
2663 0 : SC_MOD()->SetRefInputHdl(NULL);
2664 0 : if (pInputWin)
2665 0 : pInputWin->SetFormulaMode(false);
2666 0 : UpdateAutoCorrFlag();
2667 : }
2668 510 : pRefViewSh = NULL; // Also without FormulaMode due to FunctionsAutoPilot
2669 510 : DeleteRangeFinder();
2670 510 : ResetAutoPar();
2671 :
2672 510 : bool bOldMod = bModified;
2673 :
2674 510 : bModified = false;
2675 510 : bSelIsRef = false;
2676 510 : eMode = SC_INPUT_NONE;
2677 510 : StopInputWinEngine(true);
2678 :
2679 : // Text input (through number formats) or ApplySelectionPattern modify
2680 : // the cell's attributes, so pLastPattern is no longer valid
2681 510 : pLastPattern = NULL;
2682 :
2683 510 : if (bOldMod && !bProtected && !bForget)
2684 : {
2685 : // No typographic quotes in formulas
2686 0 : if (aString.startsWith("="))
2687 : {
2688 0 : SvxAutoCorrect* pAuto = SvxAutoCorrCfg::Get().GetAutoCorrect();
2689 0 : if ( pAuto )
2690 : {
2691 0 : OUString aReplace(pAuto->GetStartDoubleQuote());
2692 0 : if( aReplace.isEmpty() )
2693 0 : aReplace = ScGlobal::pLocaleData->getDoubleQuotationMarkStart();
2694 0 : if( aReplace != "\"" )
2695 0 : aString = aString.replaceAll( aReplace, "\"" );
2696 :
2697 0 : aReplace = OUString(pAuto->GetEndDoubleQuote());
2698 0 : if( aReplace.isEmpty() )
2699 0 : aReplace = ScGlobal::pLocaleData->getDoubleQuotationMarkEnd();
2700 0 : if( aReplace != "\"" )
2701 0 : aString = aString.replaceAll( aReplace, "\"" );
2702 :
2703 0 : aReplace = OUString(pAuto->GetStartSingleQuote());
2704 0 : if( aReplace.isEmpty() )
2705 0 : aReplace = ScGlobal::pLocaleData->getQuotationMarkStart();
2706 0 : if( aReplace != "'" )
2707 0 : aString = aString.replaceAll( aReplace, "'" );
2708 :
2709 0 : aReplace = OUString(pAuto->GetEndSingleQuote());
2710 0 : if( aReplace.isEmpty() )
2711 0 : aReplace = ScGlobal::pLocaleData->getQuotationMarkEnd();
2712 0 : if( aReplace != "'" )
2713 0 : aString = aString.replaceAll( aReplace, "'");
2714 : }
2715 : }
2716 :
2717 0 : pSfxApp->Broadcast( SfxSimpleHint( FID_KILLEDITVIEW_NOPAINT ) );
2718 :
2719 0 : if ( pExecuteSh )
2720 : {
2721 0 : SfxBindings& rBindings = pExecuteSh->GetViewFrame()->GetBindings();
2722 :
2723 0 : sal_uInt16 nId = FID_INPUTLINE_ENTER;
2724 0 : if ( nBlockMode == SC_ENTER_BLOCK )
2725 0 : nId = FID_INPUTLINE_BLOCK;
2726 0 : else if ( nBlockMode == SC_ENTER_MATRIX )
2727 0 : nId = FID_INPUTLINE_MATRIX;
2728 :
2729 : ScInputStatusItem aItem( FID_INPUTLINE_STATUS,
2730 : aCursorPos, aCursorPos, aCursorPos,
2731 0 : aString, pObject );
2732 :
2733 0 : if (!aMisspellRanges.empty())
2734 0 : aItem.SetMisspellRanges(&aMisspellRanges);
2735 :
2736 : const SfxPoolItem* aArgs[2];
2737 0 : aArgs[0] = &aItem;
2738 0 : aArgs[1] = NULL;
2739 0 : rBindings.Execute( nId, aArgs );
2740 : }
2741 :
2742 0 : delete pLastState; // pLastState still contains the old text
2743 0 : pLastState = NULL;
2744 : }
2745 : else
2746 510 : pSfxApp->Broadcast( SfxSimpleHint( FID_KILLEDITVIEW ) );
2747 :
2748 510 : if ( bOldMod && pExecuteSh && pCellAttrs && !bForget )
2749 : {
2750 : // Combine with input?
2751 0 : pExecuteSh->ApplySelectionPattern( *pCellAttrs, true, true );
2752 0 : pExecuteSh->AdjustBlockHeight();
2753 : }
2754 :
2755 510 : delete pCellAttrs;
2756 510 : delete pObject;
2757 :
2758 510 : HideTip();
2759 510 : HideTipBelow();
2760 :
2761 510 : nFormSelStart = nFormSelEnd = 0;
2762 510 : aFormText.clear();
2763 :
2764 510 : bInOwnChange = false;
2765 1020 : bInEnterHandler = false;
2766 : }
2767 :
2768 0 : void ScInputHandler::CancelHandler()
2769 : {
2770 0 : bInOwnChange = true; // Also without FormulaMode due to FunctionsAutoPilot
2771 :
2772 0 : ImplCreateEditEngine();
2773 :
2774 0 : bModified = false;
2775 :
2776 : // Don't rely on ShowRefFrame switching the active view synchronously
2777 : // execute the function directly on the correct view's bindings instead
2778 : // pRefViewSh is reset in ShowRefFrame - get pointer before ShowRefFrame call
2779 0 : ScTabViewShell* pExecuteSh = pRefViewSh ? pRefViewSh : pActiveViewSh;
2780 :
2781 0 : if (bFormulaMode)
2782 : {
2783 0 : ShowRefFrame();
2784 0 : if (pExecuteSh)
2785 : {
2786 0 : pExecuteSh->SetTabNo(aCursorPos.Tab());
2787 0 : pExecuteSh->ActiveGrabFocus();
2788 : }
2789 0 : bFormulaMode = false;
2790 0 : SfxGetpApp()->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
2791 0 : SC_MOD()->SetRefInputHdl(NULL);
2792 0 : if (pInputWin)
2793 0 : pInputWin->SetFormulaMode(false);
2794 0 : UpdateAutoCorrFlag();
2795 : }
2796 0 : pRefViewSh = NULL; // Also without FormulaMode due to FunctionsAutoPilot
2797 0 : DeleteRangeFinder();
2798 0 : ResetAutoPar();
2799 :
2800 0 : eMode = SC_INPUT_NONE;
2801 0 : StopInputWinEngine( true );
2802 0 : if (pExecuteSh)
2803 0 : pExecuteSh->StopEditShell();
2804 :
2805 0 : aCursorPos.Set(MAXCOL+1,0,0); // Invalid flag
2806 0 : pEngine->SetText(OUString());
2807 :
2808 0 : if ( !pLastState && pExecuteSh )
2809 0 : pExecuteSh->UpdateInputHandler( true ); // Update status again
2810 : else
2811 0 : NotifyChange( pLastState, true );
2812 :
2813 0 : nFormSelStart = nFormSelEnd = 0;
2814 0 : aFormText.clear();
2815 :
2816 0 : bInOwnChange = false;
2817 0 : }
2818 :
2819 0 : bool ScInputHandler::IsModalMode( SfxObjectShell* pDocSh )
2820 : {
2821 : // References to unnamed document; that doesn't work
2822 0 : return bFormulaMode && pRefViewSh
2823 0 : && pRefViewSh->GetViewData().GetDocument()->GetDocumentShell() != pDocSh
2824 0 : && !pDocSh->HasName();
2825 : }
2826 :
2827 0 : void ScInputHandler::AddRefEntry()
2828 : {
2829 0 : const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
2830 0 : UpdateActiveView();
2831 0 : if (!pTableView && !pTopView)
2832 0 : return; // E.g. FillMode
2833 :
2834 0 : DataChanging(); // Cannot be new
2835 :
2836 0 : RemoveSelection();
2837 0 : if (pTableView)
2838 0 : pTableView->InsertText( OUString(cSep), false );
2839 0 : if (pTopView)
2840 0 : pTopView->InsertText( OUString(cSep), false );
2841 :
2842 0 : DataChanged();
2843 : }
2844 :
2845 0 : void ScInputHandler::SetReference( const ScRange& rRef, ScDocument* pDoc )
2846 : {
2847 0 : HideTip();
2848 :
2849 0 : bool bOtherDoc = ( pRefViewSh &&
2850 0 : pRefViewSh->GetViewData().GetDocument() != pDoc );
2851 0 : if (bOtherDoc)
2852 0 : if (!pDoc->GetDocumentShell()->HasName())
2853 : {
2854 : // References to unnamed document; that doesn't work
2855 : // SetReference should not be called, then
2856 0 : return;
2857 : }
2858 :
2859 0 : UpdateActiveView();
2860 0 : if (!pTableView && !pTopView)
2861 0 : return; // E.g. FillMode
2862 :
2863 : // Never overwrite the "="!
2864 0 : EditView* pActiveView = pTopView ? pTopView : pTableView;
2865 0 : ESelection aSel = pActiveView->GetSelection();
2866 0 : aSel.Adjust();
2867 0 : if ( aSel.nStartPara == 0 && aSel.nStartPos == 0 )
2868 0 : return;
2869 :
2870 0 : DataChanging(); // Cannot be new
2871 :
2872 : // Turn around selection if backwards (TODO: Do we really need to do that?)
2873 0 : if (pTableView)
2874 : {
2875 0 : ESelection aTabSel = pTableView->GetSelection();
2876 0 : if (aTabSel.nStartPos > aTabSel.nEndPos && aTabSel.nStartPara == aTabSel.nEndPara)
2877 : {
2878 0 : aTabSel.Adjust();
2879 0 : pTableView->SetSelection(aTabSel);
2880 : }
2881 : }
2882 0 : if (pTopView)
2883 : {
2884 0 : ESelection aTopSel = pTopView->GetSelection();
2885 0 : if (aTopSel.nStartPos > aTopSel.nEndPos && aTopSel.nStartPara == aTopSel.nEndPara)
2886 : {
2887 0 : aTopSel.Adjust();
2888 0 : pTopView->SetSelection(aTopSel);
2889 : }
2890 : }
2891 :
2892 : // Create string from reference
2893 0 : OUString aRefStr;
2894 0 : const ScAddress::Details aAddrDetails( pDoc, aCursorPos );
2895 0 : if (bOtherDoc)
2896 : {
2897 : // Reference to other document
2898 : OSL_ENSURE(rRef.aStart.Tab()==rRef.aEnd.Tab(), "nStartTab!=nEndTab");
2899 :
2900 0 : OUString aTmp(rRef.Format(SCA_VALID|SCA_TAB_3D, pDoc, aAddrDetails)); // Always 3D
2901 :
2902 0 : SfxObjectShell* pObjSh = pDoc->GetDocumentShell();
2903 : // #i75893# convert escaped URL of the document to something user friendly
2904 0 : OUString aFileName = pObjSh->GetMedium()->GetURLObject().GetMainURL( INetURLObject::DECODE_UNAMBIGUOUS );
2905 :
2906 0 : switch(aAddrDetails.eConv)
2907 : {
2908 : case formula::FormulaGrammar::CONV_XL_A1 :
2909 : case formula::FormulaGrammar::CONV_XL_OOX :
2910 : case formula::FormulaGrammar::CONV_XL_R1C1 :
2911 0 : aRefStr = "[\'";
2912 0 : aRefStr += aFileName;
2913 0 : aRefStr += "']";
2914 0 : break;
2915 : case formula::FormulaGrammar::CONV_OOO :
2916 : default:
2917 0 : aRefStr = "\'";
2918 0 : aRefStr += aFileName;
2919 0 : aRefStr += "'#";
2920 0 : break;
2921 : }
2922 0 : aRefStr += aTmp;
2923 : }
2924 : else
2925 : {
2926 0 : if ( rRef.aStart.Tab() != aCursorPos.Tab() ||
2927 0 : rRef.aStart.Tab() != rRef.aEnd.Tab() )
2928 0 : aRefStr = rRef.Format(SCA_VALID|SCA_TAB_3D, pDoc, aAddrDetails);
2929 : else
2930 0 : aRefStr = rRef.Format(SCA_VALID, pDoc, aAddrDetails);
2931 : }
2932 :
2933 0 : if (pTableView || pTopView)
2934 : {
2935 0 : if (pTableView)
2936 0 : pTableView->InsertText( aRefStr, true );
2937 0 : if (pTopView)
2938 0 : pTopView->InsertText( aRefStr, true );
2939 :
2940 0 : DataChanged();
2941 : }
2942 :
2943 0 : bSelIsRef = true;
2944 : }
2945 :
2946 0 : void ScInputHandler::InsertFunction( const OUString& rFuncName, bool bAddPar )
2947 : {
2948 0 : if ( eMode == SC_INPUT_NONE )
2949 : {
2950 : OSL_FAIL("InsertFunction, nicht im Eingabemodus");
2951 0 : return;
2952 : }
2953 :
2954 0 : UpdateActiveView();
2955 0 : if (!pTableView && !pTopView)
2956 0 : return; // E.g. FillMode
2957 :
2958 0 : DataChanging(); // Cannot be new
2959 :
2960 0 : OUString aText = rFuncName;
2961 0 : if (bAddPar)
2962 0 : aText += "()";
2963 :
2964 0 : if (pTableView)
2965 : {
2966 0 : pTableView->InsertText( aText, false );
2967 0 : if (bAddPar)
2968 : {
2969 0 : ESelection aSel = pTableView->GetSelection();
2970 0 : --aSel.nStartPos;
2971 0 : --aSel.nEndPos;
2972 0 : pTableView->SetSelection(aSel);
2973 : }
2974 : }
2975 0 : if (pTopView)
2976 : {
2977 0 : pTopView->InsertText( aText, false );
2978 0 : if (bAddPar)
2979 : {
2980 0 : ESelection aSel = pTopView->GetSelection();
2981 0 : --aSel.nStartPos;
2982 0 : --aSel.nEndPos;
2983 0 : pTopView->SetSelection(aSel);
2984 : }
2985 : }
2986 :
2987 0 : DataChanged();
2988 :
2989 0 : if (bAddPar)
2990 0 : AutoParAdded();
2991 : }
2992 :
2993 0 : void ScInputHandler::ClearText()
2994 : {
2995 0 : if ( eMode == SC_INPUT_NONE )
2996 : {
2997 : OSL_FAIL("ClearText, nicht im Eingabemodus");
2998 0 : return;
2999 : }
3000 :
3001 0 : UpdateActiveView();
3002 0 : if (!pTableView && !pTopView)
3003 0 : return; // E.g. FillMode
3004 :
3005 0 : DataChanging(); // Cannot be new
3006 :
3007 0 : OUString aEmpty;
3008 0 : if (pTableView)
3009 : {
3010 0 : pTableView->GetEditEngine()->SetText( aEmpty );
3011 0 : pTableView->SetSelection( ESelection(0,0, 0,0) );
3012 : }
3013 0 : if (pTopView)
3014 : {
3015 0 : pTopView->GetEditEngine()->SetText( aEmpty );
3016 0 : pTopView->SetSelection( ESelection(0,0, 0,0) );
3017 : }
3018 :
3019 0 : DataChanged();
3020 : }
3021 :
3022 0 : bool ScInputHandler::KeyInput( const KeyEvent& rKEvt, bool bStartEdit /* = false */ )
3023 : {
3024 0 : if (!bOptLoaded)
3025 : {
3026 0 : bAutoComplete = SC_MOD()->GetAppOptions().GetAutoComplete();
3027 0 : bOptLoaded = true;
3028 : }
3029 :
3030 0 : vcl::KeyCode aCode = rKEvt.GetKeyCode();
3031 0 : sal_uInt16 nModi = aCode.GetModifier();
3032 0 : bool bShift = aCode.IsShift();
3033 0 : bool bControl = aCode.IsMod1();
3034 0 : bool bAlt = aCode.IsMod2();
3035 0 : sal_uInt16 nCode = aCode.GetCode();
3036 0 : sal_Unicode nChar = rKEvt.GetCharCode();
3037 :
3038 0 : if (bAlt && !bControl && nCode != KEY_RETURN)
3039 : // Alt-Return and Alt-Ctrl-* are accepted. Everything else with ALT are not.
3040 0 : return false;
3041 :
3042 0 : if (!bControl && nCode == KEY_TAB)
3043 : {
3044 : // Normal TAB moves the cursor right.
3045 0 : EnterHandler();
3046 :
3047 0 : if (pActiveViewSh)
3048 0 : pActiveViewSh->FindNextUnprot( bShift );
3049 0 : return true;
3050 : }
3051 :
3052 0 : bool bInputLine = ( eMode==SC_INPUT_TOP );
3053 :
3054 0 : bool bUsed = false;
3055 0 : bool bSkip = false;
3056 0 : bool bDoEnter = false;
3057 :
3058 0 : switch ( nCode )
3059 : {
3060 : case KEY_RETURN:
3061 0 : if (bControl && !bShift && ( !bInputLine || ( pInputWin && pInputWin->IsMultiLineInput() ) ) )
3062 0 : bDoEnter = true;
3063 0 : else if (nModi == 0 && nTipVisible && pFormulaData && miAutoPosFormula != pFormulaData->end())
3064 : {
3065 0 : PasteFunctionData();
3066 0 : bUsed = true;
3067 : }
3068 0 : else if ( nModi == 0 && nTipVisible && !aManualTip.isEmpty() )
3069 : {
3070 0 : PasteManualTip();
3071 0 : bUsed = true;
3072 : }
3073 : else
3074 : {
3075 0 : sal_uInt8 nMode = SC_ENTER_NORMAL;
3076 0 : if ( bShift && bControl )
3077 0 : nMode = SC_ENTER_MATRIX;
3078 0 : else if ( bAlt )
3079 0 : nMode = SC_ENTER_BLOCK;
3080 0 : EnterHandler( nMode );
3081 :
3082 0 : if (pActiveViewSh)
3083 0 : pActiveViewSh->MoveCursorEnter( bShift && !bControl );
3084 :
3085 0 : bUsed = true;
3086 : }
3087 0 : break;
3088 : case KEY_TAB:
3089 0 : if (bControl && !bAlt)
3090 : {
3091 0 : if (pFormulaData && nTipVisible && miAutoPosFormula != pFormulaData->end())
3092 : {
3093 : // Iterate
3094 0 : NextFormulaEntry( bShift );
3095 0 : bUsed = true;
3096 : }
3097 0 : else if (pColumnData && bUseTab && miAutoPosColumn != pColumnData->end())
3098 : {
3099 : // Iterate through AutoInput entries
3100 0 : NextAutoEntry( bShift );
3101 0 : bUsed = true;
3102 : }
3103 : }
3104 0 : break;
3105 : case KEY_ESCAPE:
3106 0 : if ( nTipVisible )
3107 : {
3108 0 : HideTip();
3109 0 : bUsed = true;
3110 : }
3111 0 : else if( nTipVisibleSec )
3112 : {
3113 0 : HideTipBelow();
3114 0 : bUsed = true;
3115 : }
3116 0 : else if (eMode != SC_INPUT_NONE)
3117 : {
3118 0 : CancelHandler();
3119 0 : bUsed = true;
3120 : }
3121 : else
3122 0 : bSkip = true;
3123 0 : break;
3124 : case KEY_F2:
3125 0 : if ( !bShift && !bControl && !bAlt && eMode == SC_INPUT_TABLE )
3126 : {
3127 0 : eMode = SC_INPUT_TYPE;
3128 0 : bUsed = true;
3129 : }
3130 0 : break;
3131 : }
3132 :
3133 : // Only execute cursor keys if already in EditMode
3134 : // E.g. due to Shift-Ctrl-PageDn (not defined as an accelerator)
3135 0 : bool bCursorKey = EditEngine::DoesKeyMoveCursor(rKEvt);
3136 0 : bool bInsKey = ( nCode == KEY_INSERT && !nModi ); // Treat Insert like Cursorkeys
3137 0 : if ( !bUsed && !bSkip && ( bDoEnter || EditEngine::DoesKeyChangeText(rKEvt) ||
3138 0 : ( eMode != SC_INPUT_NONE && ( bCursorKey || bInsKey ) ) ) )
3139 : {
3140 0 : HideTip();
3141 0 : HideTipBelow();
3142 :
3143 0 : if (bSelIsRef)
3144 : {
3145 0 : RemoveSelection();
3146 0 : bSelIsRef = false;
3147 : }
3148 :
3149 0 : UpdateActiveView();
3150 0 : bool bNewView = DataChanging( nChar );
3151 :
3152 0 : if (bProtected) // Protected cell?
3153 0 : bUsed = true; // Don't forward KeyEvent
3154 : else // Changes allowed
3155 : {
3156 0 : if (bNewView ) // Create anew
3157 : {
3158 0 : if (pActiveViewSh)
3159 0 : pActiveViewSh->GetViewData().GetDocShell()->PostEditView( pEngine, aCursorPos );
3160 0 : UpdateActiveView();
3161 0 : if (eMode==SC_INPUT_NONE)
3162 0 : if (pTableView || pTopView)
3163 : {
3164 0 : OUString aStrLoP;
3165 :
3166 0 : if ( bStartEdit && bCellHasPercentFormat && ((nChar >= '0' && nChar <= '9') || nChar == '-') )
3167 0 : aStrLoP = "%";
3168 :
3169 0 : if (pTableView)
3170 : {
3171 0 : pTableView->GetEditEngine()->SetText( aStrLoP );
3172 0 : if ( !aStrLoP.isEmpty() )
3173 0 : pTableView->SetSelection( ESelection(0,0, 0,0) ); // before the '%'
3174 :
3175 : // Don't call SetSelection if the string is empty anyway,
3176 : // to avoid breaking the bInitial handling in ScViewData::EditGrowY
3177 : }
3178 0 : if (pTopView)
3179 : {
3180 0 : pTopView->GetEditEngine()->SetText( aStrLoP );
3181 0 : if ( !aStrLoP.isEmpty() )
3182 0 : pTopView->SetSelection( ESelection(0,0, 0,0) ); // before the '%'
3183 0 : }
3184 : }
3185 0 : SyncViews();
3186 : }
3187 :
3188 0 : if (pTableView || pTopView)
3189 : {
3190 0 : if (bDoEnter)
3191 : {
3192 0 : if (pTableView)
3193 0 : if( pTableView->PostKeyEvent( KeyEvent( CHAR_CR, vcl::KeyCode(KEY_RETURN) ) ) )
3194 0 : bUsed = true;
3195 0 : if (pTopView)
3196 0 : if( pTopView->PostKeyEvent( KeyEvent( CHAR_CR, vcl::KeyCode(KEY_RETURN) ) ) )
3197 0 : bUsed = true;
3198 : }
3199 0 : else if ( nAutoPar && nChar == ')' && CursorAtClosingPar() )
3200 : {
3201 0 : SkipClosingPar();
3202 0 : bUsed = true;
3203 : }
3204 : else
3205 : {
3206 0 : if (pTableView)
3207 : {
3208 0 : vcl::Window* pFrameWin = pActiveViewSh ? pActiveViewSh->GetFrameWin() : NULL;
3209 0 : if ( pTableView->PostKeyEvent( rKEvt, pFrameWin ) )
3210 0 : bUsed = true;
3211 : }
3212 0 : if (pTopView)
3213 0 : if ( pTopView->PostKeyEvent( rKEvt ) )
3214 0 : bUsed = true;
3215 : }
3216 :
3217 : // AutoInput:
3218 0 : if ( bUsed && bAutoComplete )
3219 : {
3220 0 : bUseTab = false;
3221 0 : if (pFormulaData)
3222 0 : miAutoPosFormula = pFormulaData->end(); // do not search further
3223 0 : if (pColumnData)
3224 0 : miAutoPosColumn = pColumnData->end();
3225 :
3226 0 : KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction();
3227 0 : if ( nChar && nChar != 8 && nChar != 127 && // no 'backspace', no 'delete'
3228 : KeyFuncType::CUT != eFunc) // and no 'CTRL-X'
3229 : {
3230 0 : if (bFormulaMode)
3231 0 : UseFormulaData();
3232 : else
3233 0 : UseColData();
3234 : }
3235 : }
3236 :
3237 : // When the selection is changed manually or an opening parenthesis
3238 : // is typed, stop overwriting parentheses
3239 0 : if ( bUsed && nChar == '(' )
3240 0 : ResetAutoPar();
3241 :
3242 0 : if ( KEY_INSERT == nCode )
3243 : {
3244 0 : SfxViewFrame* pViewFrm = SfxViewFrame::Current();
3245 0 : if (pViewFrm)
3246 0 : pViewFrm->GetBindings().Invalidate( SID_ATTR_INSERT );
3247 : }
3248 0 : if( bUsed && bFormulaMode && ( bCursorKey || bInsKey || nCode == KEY_DELETE || nCode == KEY_BACKSPACE ) )
3249 : {
3250 0 : ShowTipCursor();
3251 : }
3252 : }
3253 :
3254 : // #i114511# don't count cursor keys as modification
3255 0 : bool bSetModified = !bCursorKey;
3256 0 : DataChanged(false, bSetModified); // also calls UpdateParenthesis()
3257 0 : InvalidateAttribs(); //! in DataChanged?
3258 : }
3259 : }
3260 :
3261 0 : if (pTopView && eMode != SC_INPUT_NONE)
3262 0 : SyncViews();
3263 :
3264 0 : return bUsed;
3265 : }
3266 :
3267 0 : bool ScInputHandler::InputCommand( const CommandEvent& rCEvt, bool bForce )
3268 : {
3269 0 : bool bUsed = false;
3270 :
3271 0 : if ( rCEvt.GetCommand() == CommandEventId::CursorPos )
3272 : {
3273 : // For CommandEventId::CursorPos, do as little as possible, because
3274 : // with remote VCL, even a ShowCursor will generate another event.
3275 0 : if ( eMode != SC_INPUT_NONE )
3276 : {
3277 0 : UpdateActiveView();
3278 0 : if (pTableView || pTopView)
3279 : {
3280 0 : if (pTableView)
3281 0 : pTableView->Command( rCEvt );
3282 0 : else if (pTopView) // call only once
3283 0 : pTopView->Command( rCEvt );
3284 0 : bUsed = true;
3285 : }
3286 : }
3287 : }
3288 0 : else if ( rCEvt.GetCommand() == CommandEventId::QueryCharPosition )
3289 : {
3290 0 : if ( eMode != SC_INPUT_NONE )
3291 : {
3292 0 : UpdateActiveView();
3293 0 : if (pTableView || pTopView)
3294 : {
3295 0 : if (pTableView)
3296 0 : pTableView->Command( rCEvt );
3297 0 : else if (pTopView) // call only once
3298 0 : pTopView->Command( rCEvt );
3299 0 : bUsed = true;
3300 : }
3301 : }
3302 : }
3303 : else
3304 : {
3305 0 : if ( bForce || eMode != SC_INPUT_NONE )
3306 : {
3307 0 : if (!bOptLoaded)
3308 : {
3309 0 : bAutoComplete = SC_MOD()->GetAppOptions().GetAutoComplete();
3310 0 : bOptLoaded = true;
3311 : }
3312 :
3313 0 : HideTip();
3314 0 : HideTipBelow();
3315 :
3316 0 : if ( bSelIsRef )
3317 : {
3318 0 : RemoveSelection();
3319 0 : bSelIsRef = false;
3320 : }
3321 :
3322 0 : UpdateActiveView();
3323 0 : bool bNewView = DataChanging( 0, true );
3324 :
3325 0 : if (bProtected) // cell protected
3326 0 : bUsed = true; // event is used
3327 : else // changes allowed
3328 : {
3329 0 : if (bNewView) // create new edit view
3330 : {
3331 0 : if (pActiveViewSh)
3332 0 : pActiveViewSh->GetViewData().GetDocShell()->PostEditView( pEngine, aCursorPos );
3333 0 : UpdateActiveView();
3334 0 : if (eMode==SC_INPUT_NONE)
3335 0 : if (pTableView || pTopView)
3336 : {
3337 0 : OUString aStrLoP;
3338 0 : if (pTableView)
3339 : {
3340 0 : pTableView->GetEditEngine()->SetText( aStrLoP );
3341 0 : pTableView->SetSelection( ESelection(0,0, 0,0) );
3342 : }
3343 0 : if (pTopView)
3344 : {
3345 0 : pTopView->GetEditEngine()->SetText( aStrLoP );
3346 0 : pTopView->SetSelection( ESelection(0,0, 0,0) );
3347 0 : }
3348 : }
3349 0 : SyncViews();
3350 : }
3351 :
3352 0 : if (pTableView || pTopView)
3353 : {
3354 0 : if (pTableView)
3355 0 : pTableView->Command( rCEvt );
3356 0 : if (pTopView)
3357 0 : pTopView->Command( rCEvt );
3358 :
3359 0 : bUsed = true;
3360 :
3361 0 : if ( rCEvt.GetCommand() == CommandEventId::EndExtTextInput )
3362 : {
3363 : // AutoInput after ext text input
3364 :
3365 0 : if (pFormulaData)
3366 0 : miAutoPosFormula = pFormulaData->end();
3367 0 : if (pColumnData)
3368 0 : miAutoPosColumn = pColumnData->end();
3369 :
3370 0 : if (bFormulaMode)
3371 0 : UseFormulaData();
3372 : else
3373 0 : UseColData();
3374 : }
3375 : }
3376 :
3377 0 : DataChanged(); // calls UpdateParenthesis()
3378 0 : InvalidateAttribs(); //! in DataChanged ?
3379 : }
3380 : }
3381 :
3382 0 : if (pTopView && eMode != SC_INPUT_NONE)
3383 0 : SyncViews();
3384 : }
3385 :
3386 0 : return bUsed;
3387 : }
3388 :
3389 3368 : void ScInputHandler::NotifyChange( const ScInputHdlState* pState,
3390 : bool bForce, ScTabViewShell* pSourceSh,
3391 : bool bStopEditing)
3392 : {
3393 : // If the call originates from a macro call in the EnterHandler,
3394 : // return immediately and don't mess up the status
3395 3368 : if (bInEnterHandler)
3396 0 : return;
3397 :
3398 3368 : bool bRepeat = (pState == pLastState);
3399 3368 : if (!bRepeat && pState && pLastState)
3400 2675 : bRepeat = (*pState == *pLastState);
3401 3368 : if (bRepeat && !bForce)
3402 1704 : return;
3403 :
3404 1664 : bInOwnChange = true; // disable ModifyHdl (reset below)
3405 :
3406 1664 : if ( pState && !pLastState ) // Enable again
3407 351 : bForce = true;
3408 :
3409 1664 : bool bHadObject = pLastState && pLastState->GetEditData();
3410 :
3411 : //! Before EditEngine gets eventually created (so it gets the right pools)
3412 1664 : if ( pSourceSh )
3413 1322 : pActiveViewSh = pSourceSh;
3414 : else
3415 342 : pActiveViewSh = PTR_CAST(ScTabViewShell, SfxViewShell::Current());
3416 :
3417 1664 : ImplCreateEditEngine();
3418 :
3419 1664 : if ( pState != pLastState )
3420 : {
3421 1658 : delete pLastState;
3422 1658 : pLastState = pState ? new ScInputHdlState( *pState ) : NULL;
3423 : }
3424 :
3425 1664 : if ( pState && pActiveViewSh )
3426 : {
3427 1322 : ScModule* pScMod = SC_MOD();
3428 :
3429 1322 : if ( pState )
3430 : {
3431 :
3432 : // Also take foreign reference input into account here (e.g. FunctionsAutoPilot),
3433 : // FormEditData, if we're switching from Help to Calc:
3434 1322 : if ( !bFormulaMode && !pScMod->IsFormulaMode() && !pScMod->GetFormEditData() )
3435 : {
3436 1322 : bool bIgnore = false;
3437 1322 : if ( bModified )
3438 : {
3439 0 : if (pState->GetPos() != aCursorPos)
3440 : {
3441 0 : if (!bProtected)
3442 0 : EnterHandler();
3443 : }
3444 : else
3445 0 : bIgnore = true;
3446 : }
3447 :
3448 1322 : if ( !bIgnore )
3449 : {
3450 1322 : const ScAddress& rSPos = pState->GetStartPos();
3451 1322 : const ScAddress& rEPos = pState->GetEndPos();
3452 1322 : const EditTextObject* pData = pState->GetEditData();
3453 1322 : OUString aString = pState->GetString();
3454 1322 : bool bTxtMod = false;
3455 1322 : ScDocShell* pDocSh = pActiveViewSh->GetViewData().GetDocShell();
3456 1322 : ScDocument& rDoc = pDocSh->GetDocument();
3457 :
3458 1322 : aCursorPos = pState->GetPos();
3459 :
3460 1322 : if ( pData )
3461 13 : bTxtMod = true;
3462 1309 : else if ( bHadObject )
3463 0 : bTxtMod = true;
3464 1309 : else if ( bTextValid )
3465 1309 : bTxtMod = ( !aString.equals(aCurrentText) );
3466 : else
3467 0 : bTxtMod = ( !aString.equals(GetEditText(pEngine)) );
3468 :
3469 1322 : if ( bTxtMod || bForce )
3470 : {
3471 1080 : if (pData)
3472 : {
3473 13 : pEngine->SetText( *pData );
3474 13 : if ( pInputWin && pInputWin->IsMultiLineInput() )
3475 13 : aString = ScEditUtil::GetMultilineString(*pEngine);
3476 : else
3477 0 : aString = GetEditText(pEngine);
3478 13 : lcl_RemoveTabs(aString);
3479 13 : bTextValid = false;
3480 13 : aCurrentText.clear();
3481 : }
3482 : else
3483 : {
3484 1067 : aCurrentText = aString;
3485 1067 : bTextValid = true; //! To begin with remember as a string
3486 : }
3487 :
3488 1080 : if ( pInputWin )
3489 1069 : pInputWin->SetTextString(aString);
3490 : }
3491 :
3492 1322 : if ( pInputWin ) // Named range input
3493 : {
3494 1311 : OUString aPosStr;
3495 1311 : const ScAddress::Details aAddrDetails( &rDoc, aCursorPos );
3496 :
3497 : // Is the range a name?
3498 : //! Find by Timer?
3499 1311 : if ( pActiveViewSh )
3500 1311 : pActiveViewSh->GetViewData().GetDocument()->
3501 2622 : GetRangeAtBlock( ScRange( rSPos, rEPos ), &aPosStr );
3502 :
3503 1311 : if ( aPosStr.isEmpty() ) // Not a name -> format
3504 : {
3505 1305 : sal_uInt16 nFlags = 0;
3506 1305 : if( aAddrDetails.eConv == formula::FormulaGrammar::CONV_XL_R1C1 )
3507 0 : nFlags |= SCA_COL_ABSOLUTE | SCA_ROW_ABSOLUTE;
3508 1305 : if ( rSPos != rEPos )
3509 : {
3510 50 : ScRange r(rSPos, rEPos);
3511 50 : nFlags |= (nFlags << 4);
3512 50 : aPosStr = r.Format(SCA_VALID | nFlags, &rDoc, aAddrDetails);
3513 : }
3514 : else
3515 1255 : aPosStr = aCursorPos.Format(SCA_VALID | nFlags, &rDoc, aAddrDetails);
3516 : }
3517 :
3518 : // Disable the accessible VALUE_CHANGE event
3519 1311 : bool bIsSuppressed = pInputWin->IsAccessibilityEventsSuppressed(false);
3520 1311 : pInputWin->SetAccessibilityEventsSuppressed(true);
3521 1311 : pInputWin->SetPosString(aPosStr);
3522 1311 : pInputWin->SetAccessibilityEventsSuppressed(bIsSuppressed);
3523 1311 : pInputWin->SetSumAssignMode();
3524 : }
3525 :
3526 1322 : if (bStopEditing)
3527 1322 : SfxGetpApp()->Broadcast( SfxSimpleHint( FID_KILLEDITVIEW ) );
3528 :
3529 : // As long as the content is not edited, turn off online spelling.
3530 : // Online spelling is turned back on in StartTable, after setting
3531 : // the right language from cell attributes.
3532 :
3533 1322 : EEControlBits nCntrl = pEngine->GetControlWord();
3534 1322 : if ( nCntrl & EEControlBits::ONLINESPELLING )
3535 0 : pEngine->SetControlWord( nCntrl & ~EEControlBits::ONLINESPELLING );
3536 :
3537 1322 : bModified = false;
3538 1322 : bSelIsRef = false;
3539 1322 : bProtected = false;
3540 1322 : bCommandErrorShown = false;
3541 : }
3542 : }
3543 : }
3544 :
3545 1322 : if ( pInputWin)
3546 : {
3547 : // Do not enable if RefDialog is open
3548 1311 : if(!pScMod->IsFormulaMode()&& !pScMod->IsRefDialogOpen())
3549 : {
3550 1311 : if ( !pInputWin->IsEnabled())
3551 : {
3552 0 : pInputWin->Enable();
3553 0 : if(pDelayTimer )
3554 : {
3555 0 : DELETEZ( pDelayTimer );
3556 : }
3557 : }
3558 : }
3559 0 : else if(pScMod->IsRefDialogOpen())
3560 : { // Because every document has its own InputWin,
3561 : // we should start Timer again, because the input line may
3562 : // still be active
3563 0 : if ( !pDelayTimer )
3564 : {
3565 0 : pDelayTimer = new Timer;
3566 0 : pDelayTimer->SetTimeout( 500 ); // 500 ms delay
3567 0 : pDelayTimer->SetTimeoutHdl( LINK( this, ScInputHandler, DelayTimer ) );
3568 0 : pDelayTimer->Start();
3569 : }
3570 : }
3571 1322 : }
3572 : }
3573 : else // !pState || !pActiveViewSh
3574 : {
3575 342 : if ( !pDelayTimer )
3576 : {
3577 342 : pDelayTimer = new Timer;
3578 342 : pDelayTimer->SetTimeout( 500 ); // 500 ms delay
3579 342 : pDelayTimer->SetTimeoutHdl( LINK( this, ScInputHandler, DelayTimer ) );
3580 342 : pDelayTimer->Start();
3581 : }
3582 : }
3583 :
3584 1664 : HideTip();
3585 1664 : HideTipBelow();
3586 1664 : bInOwnChange = false;
3587 : }
3588 :
3589 0 : void ScInputHandler::UpdateCellAdjust( SvxCellHorJustify eJust )
3590 : {
3591 0 : eAttrAdjust = eJust;
3592 0 : UpdateAdjust( 0 );
3593 0 : }
3594 :
3595 150 : void ScInputHandler::ResetDelayTimer()
3596 : {
3597 150 : if(pDelayTimer!=NULL)
3598 : {
3599 6 : DELETEZ( pDelayTimer );
3600 :
3601 6 : if ( pInputWin)
3602 : {
3603 6 : pInputWin->Enable();
3604 : }
3605 : }
3606 150 : }
3607 :
3608 10 : IMPL_LINK_TYPED( ScInputHandler, DelayTimer, Timer*, pTimer, void )
3609 : {
3610 5 : if ( pTimer == pDelayTimer )
3611 : {
3612 5 : DELETEZ( pDelayTimer );
3613 :
3614 5 : if ( NULL == pLastState || SC_MOD()->IsFormulaMode() || SC_MOD()->IsRefDialogOpen())
3615 : {
3616 : //! New method at ScModule to query if function autopilot is open
3617 5 : SfxViewFrame* pViewFrm = SfxViewFrame::Current();
3618 5 : if ( pViewFrm && pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) )
3619 : {
3620 0 : if ( pInputWin)
3621 : {
3622 0 : pInputWin->EnableButtons( false );
3623 0 : pInputWin->Disable();
3624 : }
3625 : }
3626 5 : else if ( !bFormulaMode ) // Keep formula e.g. for help
3627 : {
3628 5 : bInOwnChange = true; // disable ModifyHdl (reset below)
3629 :
3630 5 : pActiveViewSh = NULL;
3631 5 : pEngine->SetText( EMPTY_OUSTRING );
3632 5 : if ( pInputWin )
3633 : {
3634 5 : pInputWin->SetPosString( EMPTY_OUSTRING );
3635 5 : pInputWin->SetTextString( EMPTY_OUSTRING );
3636 5 : pInputWin->Disable();
3637 : }
3638 :
3639 5 : bInOwnChange = false;
3640 : }
3641 : }
3642 : }
3643 5 : }
3644 :
3645 0 : void ScInputHandler::InputSelection( EditView* pView )
3646 : {
3647 0 : SyncViews( pView );
3648 0 : ShowTipCursor();
3649 0 : UpdateParenthesis(); // Selection changed -> update parentheses highlighting
3650 :
3651 : // When the selection is changed manually, stop overwriting parentheses
3652 0 : ResetAutoPar();
3653 0 : }
3654 :
3655 0 : void ScInputHandler::InputChanged( EditView* pView, bool bFromNotify )
3656 : {
3657 0 : UpdateActiveView();
3658 :
3659 : // #i20282# DataChanged needs to know if this is from the input line's modify handler
3660 0 : bool bFromTopNotify = ( bFromNotify && pView == pTopView );
3661 :
3662 0 : bool bNewView = DataChanging(); //FIXME: Is this at all possible?
3663 0 : aCurrentText = pView->GetEditEngine()->GetText(); // Also remember the string
3664 0 : pEngine->SetText( aCurrentText );
3665 0 : DataChanged( bFromTopNotify );
3666 0 : bTextValid = true; // Is set to false in DataChanged
3667 :
3668 0 : if ( pActiveViewSh )
3669 : {
3670 0 : ScViewData& rViewData = pActiveViewSh->GetViewData();
3671 0 : if ( bNewView )
3672 0 : rViewData.GetDocShell()->PostEditView( pEngine, aCursorPos );
3673 :
3674 0 : rViewData.EditGrowY();
3675 0 : rViewData.EditGrowX();
3676 : }
3677 :
3678 0 : SyncViews( pView );
3679 0 : }
3680 :
3681 0 : const OUString& ScInputHandler::GetEditString()
3682 : {
3683 0 : if (pEngine)
3684 : {
3685 0 : aCurrentText = pEngine->GetText(); // Always new from Engine
3686 0 : bTextValid = true;
3687 : }
3688 :
3689 0 : return aCurrentText;
3690 : }
3691 :
3692 0 : Size ScInputHandler::GetTextSize()
3693 : {
3694 0 : Size aSize;
3695 0 : if ( pEngine )
3696 0 : aSize = Size( pEngine->CalcTextWidth(), pEngine->GetTextHeight() );
3697 :
3698 0 : return aSize;
3699 : }
3700 :
3701 239 : bool ScInputHandler::GetTextAndFields( ScEditEngineDefaulter& rDestEngine )
3702 : {
3703 239 : bool bRet = false;
3704 239 : if (pEngine)
3705 : {
3706 : // Contains field?
3707 239 : sal_Int32 nParCnt = pEngine->GetParagraphCount();
3708 239 : SfxItemSet aSet = pEngine->GetAttribs( ESelection(0,0,nParCnt,0) );
3709 239 : SfxItemState eFieldState = aSet.GetItemState( EE_FEATURE_FIELD, false );
3710 239 : if ( eFieldState == SfxItemState::DONTCARE || eFieldState == SfxItemState::SET )
3711 : {
3712 : // Copy content
3713 0 : EditTextObject* pObj = pEngine->CreateTextObject();
3714 0 : rDestEngine.SetText(*pObj);
3715 0 : delete pObj;
3716 :
3717 : // Delete attributes
3718 0 : for (sal_Int32 i=0; i<nParCnt; i++)
3719 0 : rDestEngine.RemoveCharAttribs( i );
3720 :
3721 : // Combine paragraphs
3722 0 : while ( nParCnt > 1 )
3723 : {
3724 0 : sal_Int32 nLen = rDestEngine.GetTextLen( 0 );
3725 0 : ESelection aSel( 0,nLen, 1,0 );
3726 0 : rDestEngine.QuickInsertText( OUString(' '), aSel ); // Replace line break with space
3727 0 : --nParCnt;
3728 : }
3729 :
3730 0 : bRet = true;
3731 239 : }
3732 : }
3733 239 : return bRet;
3734 : }
3735 :
3736 : /**
3737 : * Methods for FunctionAutoPilot:
3738 : * InputGetSelection, InputSetSelection, InputReplaceSelection, InputGetFormulaStr
3739 : */
3740 0 : void ScInputHandler::InputGetSelection( sal_Int32& rStart, sal_Int32& rEnd )
3741 : {
3742 0 : rStart = nFormSelStart;
3743 0 : rEnd = nFormSelEnd;
3744 0 : }
3745 :
3746 0 : EditView* ScInputHandler::GetFuncEditView()
3747 : {
3748 0 : UpdateActiveView(); // Due to pTableView
3749 :
3750 0 : EditView* pView = NULL;
3751 0 : if ( pInputWin )
3752 : {
3753 0 : pInputWin->MakeDialogEditView();
3754 0 : pView = pInputWin->GetEditView();
3755 : }
3756 : else
3757 : {
3758 0 : if ( eMode != SC_INPUT_TABLE )
3759 : {
3760 0 : bCreatingFuncView = true; // Don't display RangeFinder
3761 0 : SetMode( SC_INPUT_TABLE );
3762 0 : bCreatingFuncView = false;
3763 0 : if ( pTableView )
3764 0 : pTableView->GetEditEngine()->SetText( EMPTY_OUSTRING );
3765 : }
3766 0 : pView = pTableView;
3767 : }
3768 :
3769 0 : return pView;
3770 : }
3771 :
3772 0 : void ScInputHandler::InputSetSelection( sal_Int32 nStart, sal_Int32 nEnd )
3773 : {
3774 0 : if ( nStart <= nEnd )
3775 : {
3776 0 : nFormSelStart = nStart;
3777 0 : nFormSelEnd = nEnd;
3778 : }
3779 : else
3780 : {
3781 0 : nFormSelEnd = nStart;
3782 0 : nFormSelStart = nEnd;
3783 : }
3784 :
3785 0 : EditView* pView = GetFuncEditView();
3786 0 : if (pView)
3787 0 : pView->SetSelection( ESelection(0,nStart, 0,nEnd) );
3788 :
3789 0 : bModified = true;
3790 0 : }
3791 :
3792 0 : void ScInputHandler::InputReplaceSelection( const OUString& rStr )
3793 : {
3794 0 : if (!pRefViewSh)
3795 0 : pRefViewSh = pActiveViewSh;
3796 :
3797 : OSL_ENSURE(nFormSelEnd>=nFormSelStart,"Selection broken...");
3798 :
3799 0 : sal_Int32 nOldLen = nFormSelEnd - nFormSelStart;
3800 0 : sal_Int32 nNewLen = rStr.getLength();
3801 :
3802 0 : OUStringBuffer aBuf(aFormText);
3803 0 : if (nOldLen)
3804 0 : aBuf.remove(nFormSelStart, nOldLen);
3805 0 : if (nNewLen)
3806 0 : aBuf.insert(nFormSelStart, rStr);
3807 :
3808 0 : aFormText = aBuf.makeStringAndClear();
3809 :
3810 0 : nFormSelEnd = nFormSelStart + nNewLen;
3811 :
3812 0 : EditView* pView = GetFuncEditView();
3813 0 : if (pView)
3814 : {
3815 0 : pView->SetEditEngineUpdateMode( false );
3816 0 : pView->GetEditEngine()->SetText( aFormText );
3817 0 : pView->SetSelection( ESelection(0,nFormSelStart, 0,nFormSelEnd) );
3818 0 : pView->SetEditEngineUpdateMode( true );
3819 : }
3820 0 : bModified = true;
3821 0 : }
3822 :
3823 0 : void ScInputHandler::InputTurnOffWinEngine()
3824 : {
3825 0 : bInOwnChange = true; // disable ModifyHdl (reset below)
3826 :
3827 0 : eMode = SC_INPUT_NONE;
3828 : /* TODO: it would be better if there was some way to reset the input bar
3829 : * engine instead of deleting and having it recreate through
3830 : * GetFuncEditView(), but first least invasively let this fix fdo#71667 and
3831 : * fdo#72278 without reintroducing fdo#69971. */
3832 0 : StopInputWinEngine(true);
3833 :
3834 0 : bInOwnChange = false;
3835 0 : }
3836 :
3837 : /**
3838 : * ScInputHdlState
3839 : */
3840 3026 : ScInputHdlState::ScInputHdlState( const ScAddress& rCurPos,
3841 : const ScAddress& rStartPos,
3842 : const ScAddress& rEndPos,
3843 : const OUString& rString,
3844 : const EditTextObject* pData )
3845 : : aCursorPos ( rCurPos ),
3846 : aStartPos ( rStartPos ),
3847 : aEndPos ( rEndPos ),
3848 : aString ( rString ),
3849 3026 : pEditData ( pData ? pData->Clone() : NULL )
3850 : {
3851 3026 : }
3852 :
3853 1322 : ScInputHdlState::ScInputHdlState( const ScInputHdlState& rCpy )
3854 1322 : : pEditData ( NULL )
3855 : {
3856 1322 : *this = rCpy;
3857 1322 : }
3858 :
3859 8690 : ScInputHdlState::~ScInputHdlState()
3860 : {
3861 4345 : delete pEditData;
3862 4345 : }
3863 :
3864 2675 : bool ScInputHdlState::operator==( const ScInputHdlState& r ) const
3865 : {
3866 2675 : return ( (aStartPos == r.aStartPos)
3867 2158 : && (aEndPos == r.aEndPos)
3868 2122 : && (aCursorPos == r.aCursorPos)
3869 2106 : && (aString == r.aString)
3870 4730 : && ScGlobal::EETextObjEqual( pEditData, r.pEditData ) );
3871 : }
3872 :
3873 1322 : ScInputHdlState& ScInputHdlState::operator=( const ScInputHdlState& r )
3874 : {
3875 1322 : delete pEditData;
3876 :
3877 1322 : aCursorPos = r.aCursorPos;
3878 1322 : aStartPos = r.aStartPos;
3879 1322 : aEndPos = r.aEndPos;
3880 1322 : aString = r.aString;
3881 1322 : pEditData = r.pEditData ? r.pEditData->Clone() : NULL;
3882 :
3883 1322 : return *this;
3884 156 : }
3885 :
3886 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|