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