xref: /core/sc/source/core/tool/editutil.cxx (revision 8da8cc3c)
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 <scitems.hxx>
21 #include <comphelper/processfactory.hxx>
22 #include <editeng/eeitem.hxx>
23 
24 #include <svx/algitem.hxx>
25 #include <svtools/colorcfg.hxx>
26 #include <editeng/editview.hxx>
27 #include <editeng/editstat.hxx>
28 #include <editeng/escapementitem.hxx>
29 #include <editeng/flditem.hxx>
30 #include <editeng/numitem.hxx>
31 #include <editeng/justifyitem.hxx>
32 #include <editeng/editobj.hxx>
33 #include <vcl/svapp.hxx>
34 #include <vcl/outdev.hxx>
35 #include <svl/inethist.hxx>
36 #include <unotools/syslocale.hxx>
37 #include <sfx2/objsh.hxx>
38 #include <osl/diagnose.h>
39 
40 #include <com/sun/star/text/textfield/Type.hpp>
41 #include <com/sun/star/document/XDocumentProperties.hpp>
42 
43 #include <editutil.hxx>
44 #include <global.hxx>
45 #include <attrib.hxx>
46 #include <document.hxx>
47 #include <docpool.hxx>
48 #include <patattr.hxx>
49 #include <scmod.hxx>
50 #include <inputopt.hxx>
51 #include <compiler.hxx>
52 
53 using namespace com::sun::star;
54 
55 //  delimiters additionally to EditEngine default:
56 
57 ScEditUtil::ScEditUtil( ScDocument* pDocument, SCCOL nX, SCROW nY, SCTAB nZ,
58                             const Point& rScrPosPixel,
59                             OutputDevice* pDevice, double nScaleX, double nScaleY,
60                             const Fraction& rX, const Fraction& rY ) :
61                     pDoc(pDocument),nCol(nX),nRow(nY),nTab(nZ),
62                     aScrPos(rScrPosPixel),pDev(pDevice),
63                     nPPTX(nScaleX),nPPTY(nScaleY),aZoomX(rX),aZoomY(rY) {}
64 
65 OUString ScEditUtil::ModifyDelimiters( const OUString& rOld )
66 {
67     // underscore is used in function argument names
68     OUString aRet = rOld.replaceAll("_", "") +
69         "=()+-*/^&<>" +
70         ScCompiler::GetNativeSymbol(ocSep); // argument separator is localized.
71     return aRet;
72 }
73 
74 static OUString lcl_GetDelimitedString( const EditEngine& rEngine, const sal_Char c )
75 {
76     sal_Int32 nParCount = rEngine.GetParagraphCount();
77     OUStringBuffer aRet( nParCount * 80 );
78     for (sal_Int32 nPar=0; nPar<nParCount; nPar++)
79     {
80         if (nPar > 0)
81             aRet.append(c);
82         aRet.append( rEngine.GetText( nPar ));
83     }
84     return aRet.makeStringAndClear();
85 }
86 
87 static OUString lcl_GetDelimitedString( const EditTextObject& rEdit, const sal_Char c )
88 {
89     sal_Int32 nParCount = rEdit.GetParagraphCount();
90     OUStringBuffer aRet( nParCount * 80 );
91     for (sal_Int32 nPar=0; nPar<nParCount; nPar++)
92     {
93         if (nPar > 0)
94             aRet.append(c);
95         aRet.append( rEdit.GetText( nPar ));
96     }
97     return aRet.makeStringAndClear();
98 }
99 
100 OUString ScEditUtil::GetSpaceDelimitedString( const EditEngine& rEngine )
101 {
102     return lcl_GetDelimitedString(rEngine, ' ');
103 }
104 OUString ScEditUtil::GetMultilineString( const EditEngine& rEngine )
105 {
106     return lcl_GetDelimitedString(rEngine, '\n');
107 }
108 
109 OUString ScEditUtil::GetMultilineString( const EditTextObject& rEdit )
110 {
111     return lcl_GetDelimitedString(rEdit, '\n');
112 }
113 
114 OUString ScEditUtil::GetString( const EditTextObject& rEditText, const ScDocument* pDoc )
115 {
116     if( !rEditText.HasField())
117         return GetMultilineString( rEditText );
118 
119     static osl::Mutex aMutex;
120     osl::MutexGuard aGuard( aMutex);
121     // ScFieldEditEngine is needed to resolve field contents.
122     if (pDoc)
123     {
124         /* TODO: make ScDocument::GetEditEngine() const? Most likely it's only
125          * not const because of the pointer assignment, make that mutable, and
126          * then remove the ugly const_cast here. */
127         EditEngine& rEE = const_cast<ScDocument*>(pDoc)->GetEditEngine();
128         rEE.SetText( rEditText);
129         return GetMultilineString( rEE);
130     }
131     else
132     {
133         EditEngine& rEE = ScGlobal::GetStaticFieldEditEngine();
134         rEE.SetText( rEditText);
135         return GetMultilineString( rEE);
136     }
137 }
138 
139 std::unique_ptr<EditTextObject> ScEditUtil::CreateURLObjectFromURL( ScDocument& rDoc, const OUString& rURL, const OUString& rText )
140 {
141     SvxURLField aUrlField( rURL, rText, SvxURLFormat::AppDefault);
142     EditEngine& rEE = rDoc.GetEditEngine();
143     rEE.SetText( EMPTY_OUSTRING );
144     rEE.QuickInsertField( SvxFieldItem( aUrlField, EE_FEATURE_FIELD ),
145             ESelection( EE_PARA_MAX_COUNT, EE_TEXTPOS_MAX_COUNT ) );
146 
147     return rEE.CreateTextObject();
148 }
149 
150 void ScEditUtil::RemoveCharAttribs( EditTextObject& rEditText, const ScPatternAttr& rAttr )
151 {
152     static const struct {
153         sal_uInt16 nAttrType;
154         sal_uInt16 nCharType;
155     } AttrTypeMap[] = {
156         { ATTR_FONT,        EE_CHAR_FONTINFO },
157         { ATTR_FONT_HEIGHT, EE_CHAR_FONTHEIGHT },
158         { ATTR_FONT_WEIGHT, EE_CHAR_WEIGHT },
159         { ATTR_FONT_COLOR,  EE_CHAR_COLOR }
160     };
161 
162     const SfxItemSet& rSet = rAttr.GetItemSet();
163     const SfxPoolItem* pItem;
164     for (size_t i = 0; i < SAL_N_ELEMENTS(AttrTypeMap); ++i)
165     {
166         if ( rSet.GetItemState(AttrTypeMap[i].nAttrType, false, &pItem) == SfxItemState::SET )
167             rEditText.RemoveCharAttribs(AttrTypeMap[i].nCharType);
168     }
169 }
170 
171 std::unique_ptr<EditTextObject> ScEditUtil::Clone( const EditTextObject& rObj, ScDocument& rDestDoc )
172 {
173     std::unique_ptr<EditTextObject> pNew;
174 
175     EditEngine& rEngine = rDestDoc.GetEditEngine();
176     if (rObj.HasOnlineSpellErrors())
177     {
178         EEControlBits nControl = rEngine.GetControlWord();
179         const EEControlBits nSpellControl = EEControlBits::ONLINESPELLING | EEControlBits::ALLOWBIGOBJS;
180         bool bNewControl = ( (nControl & nSpellControl) != nSpellControl );
181         if (bNewControl)
182             rEngine.SetControlWord(nControl | nSpellControl);
183         rEngine.SetText(rObj);
184         pNew = rEngine.CreateTextObject();
185         if (bNewControl)
186             rEngine.SetControlWord(nControl);
187     }
188     else
189     {
190         rEngine.SetText(rObj);
191         pNew = rEngine.CreateTextObject();
192     }
193 
194     return pNew;
195 }
196 
197 OUString ScEditUtil::GetCellFieldValue(
198     const SvxFieldData& rFieldData, const ScDocument* pDoc, boost::optional<Color>* ppTextColor )
199 {
200     OUString aRet;
201     switch (rFieldData.GetClassId())
202     {
203         case text::textfield::Type::URL:
204         {
205             const SvxURLField& rField = static_cast<const SvxURLField&>(rFieldData);
206             const OUString& aURL = rField.GetURL();
207 
208             switch (rField.GetFormat())
209             {
210                 case SvxURLFormat::AppDefault: //TODO: configurable with App???
211                 case SvxURLFormat::Repr:
212                     aRet = rField.GetRepresentation();
213                 break;
214                 case SvxURLFormat::Url:
215                     aRet = aURL;
216                 break;
217                 default:
218                     ;
219             }
220 
221             svtools::ColorConfigEntry eEntry =
222                 INetURLHistory::GetOrCreate()->QueryUrl(aURL) ? svtools::LINKSVISITED : svtools::LINKS;
223 
224             if (ppTextColor)
225                 *ppTextColor = SC_MOD()->GetColorConfig().GetColorValue(eEntry).nColor;
226         }
227         break;
228         case text::textfield::Type::EXTENDED_TIME:
229         {
230             const SvxExtTimeField& rField = static_cast<const SvxExtTimeField&>(rFieldData);
231             if (pDoc)
232                 aRet = rField.GetFormatted(*pDoc->GetFormatTable(), ScGlobal::eLnge);
233             else
234             {
235                 /* TODO: quite expensive, we could have a global formatter? */
236                 SvNumberFormatter aFormatter( comphelper::getProcessComponentContext(), ScGlobal::eLnge );
237                 aRet = rField.GetFormatted(aFormatter, ScGlobal::eLnge);
238             }
239         }
240         break;
241         case text::textfield::Type::DATE:
242         {
243             Date aDate(Date::SYSTEM);
244             aRet = ScGlobal::pLocaleData->getDate(aDate);
245         }
246         break;
247         case text::textfield::Type::DOCINFO_TITLE:
248         {
249             if (pDoc)
250             {
251                 SfxObjectShell* pDocShell = pDoc->GetDocumentShell();
252                 if (pDocShell)
253                 {
254                     aRet = pDocShell->getDocProperties()->getTitle();
255                     if (aRet.isEmpty())
256                         aRet = pDocShell->GetTitle();
257                 }
258             }
259             if (aRet.isEmpty())
260                 aRet = "?";
261         }
262         break;
263         case text::textfield::Type::TABLE:
264         {
265             const SvxTableField& rField = static_cast<const SvxTableField&>(rFieldData);
266             SCTAB nTab = rField.GetTab();
267             OUString aName;
268             if (pDoc && pDoc->GetName(nTab, aName))
269                 aRet = aName;
270             else
271                 aRet = "?";
272         }
273         break;
274         default:
275             aRet = "?";
276     }
277 
278     if (aRet.isEmpty())        // empty is yuck
279         aRet = " ";         // space is default of EditEngine
280 
281     return aRet;
282 }
283 
284 tools::Rectangle ScEditUtil::GetEditArea( const ScPatternAttr* pPattern, bool bForceToTop )
285 {
286     // bForceToTop = always align to top, for editing
287     // (sal_False for querying URLs etc.)
288 
289     if (!pPattern)
290         pPattern = pDoc->GetPattern( nCol, nRow, nTab );
291 
292     Point aStartPos = aScrPos;
293 
294     bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );
295     long nLayoutSign = bLayoutRTL ? -1 : 1;
296 
297     const ScMergeAttr* pMerge = &pPattern->GetItem(ATTR_MERGE);
298     long nCellX = static_cast<long>( pDoc->GetColWidth(nCol,nTab) * nPPTX );
299     if ( pMerge->GetColMerge() > 1 )
300     {
301         SCCOL nCountX = pMerge->GetColMerge();
302         for (SCCOL i=1; i<nCountX; i++)
303             nCellX += static_cast<long>( pDoc->GetColWidth(nCol+i,nTab) * nPPTX );
304     }
305     long nCellY = static_cast<long>( pDoc->GetRowHeight(nRow,nTab) * nPPTY );
306     if ( pMerge->GetRowMerge() > 1 )
307     {
308         SCROW nCountY = pMerge->GetRowMerge();
309         nCellY += static_cast<long>(pDoc->GetScaledRowHeight( nRow+1, nRow+nCountY-1, nTab, nPPTY));
310     }
311 
312     const SvxMarginItem* pMargin = &pPattern->GetItem(ATTR_MARGIN);
313     sal_uInt16 nIndent = 0;
314     if ( pPattern->GetItem(ATTR_HOR_JUSTIFY).GetValue() ==
315                 SvxCellHorJustify::Left )
316         nIndent = pPattern->GetItem(ATTR_INDENT).GetValue();
317     long nPixDifX   = static_cast<long>( ( pMargin->GetLeftMargin() + nIndent ) * nPPTX );
318     aStartPos.AdjustX(nPixDifX * nLayoutSign );
319     nCellX          -= nPixDifX + static_cast<long>( pMargin->GetRightMargin() * nPPTX );     // due to line feed, etc.
320 
321     //  align vertical position to the one in the table
322 
323     long nPixDifY;
324     long nTopMargin = static_cast<long>( pMargin->GetTopMargin() * nPPTY );
325     SvxCellVerJustify eJust = pPattern->GetItem(ATTR_VER_JUSTIFY).GetValue();
326 
327     //  asian vertical is always edited top-aligned
328     bool bAsianVertical = pPattern->GetItem( ATTR_STACKED ).GetValue() &&
329         pPattern->GetItem( ATTR_VERTICAL_ASIAN ).GetValue();
330 
331     if ( eJust == SvxCellVerJustify::Top ||
332             ( bForceToTop && ( SC_MOD()->GetInputOptions().GetTextWysiwyg() || bAsianVertical ) ) )
333         nPixDifY = nTopMargin;
334     else
335     {
336         MapMode aMode = pDev->GetMapMode();
337         pDev->SetMapMode(MapMode(MapUnit::MapPixel));
338 
339         long nTextHeight = pDoc->GetNeededSize( nCol, nRow, nTab,
340                                                 pDev, nPPTX, nPPTY, aZoomX, aZoomY, false );
341         if (!nTextHeight)
342         {                                   // empty cell
343             vcl::Font aFont;
344             // font color doesn't matter here
345             pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &aZoomY );
346             pDev->SetFont(aFont);
347             nTextHeight = pDev->GetTextHeight() + nTopMargin +
348                             static_cast<long>( pMargin->GetBottomMargin() * nPPTY );
349         }
350 
351         pDev->SetMapMode(aMode);
352 
353         if ( nTextHeight > nCellY + nTopMargin || bForceToTop )
354             nPixDifY = 0;                           // too large -> begin at the top
355         else
356         {
357             if ( eJust == SvxCellVerJustify::Center )
358                 nPixDifY = nTopMargin + ( nCellY - nTextHeight ) / 2;
359             else
360                 nPixDifY = nCellY - nTextHeight + nTopMargin;       // JUSTIFY_BOTTOM
361         }
362     }
363 
364     aStartPos.AdjustY(nPixDifY );
365     nCellY      -= nPixDifY;
366 
367     if ( bLayoutRTL )
368         aStartPos.AdjustX( -(nCellX - 2) );    // excluding grid on both sides
369 
370                                                         //  -1 -> don't overwrite grid
371     return tools::Rectangle( aStartPos, Size(nCellX-1,nCellY-1) );
372 }
373 
374 ScEditAttrTester::ScEditAttrTester( ScEditEngineDefaulter* pEng ) :
375     pEngine( pEng ),
376     bNeedsObject( false ),
377     bNeedsCellAttr( false )
378 {
379     if ( pEngine->GetParagraphCount() > 1 )
380     {
381         bNeedsObject = true;            //TODO: find cell attributes ?
382     }
383     else
384     {
385         const SfxPoolItem* pItem = nullptr;
386         pEditAttrs.reset( new SfxItemSet( pEngine->GetAttribs(
387                                         ESelection(0,0,0,pEngine->GetTextLen(0)), EditEngineAttribs::OnlyHard ) ) );
388         const SfxItemSet& rEditDefaults = pEngine->GetDefaults();
389 
390         for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END && !bNeedsObject; nId++)
391         {
392             SfxItemState eState = pEditAttrs->GetItemState( nId, false, &pItem );
393             if (eState == SfxItemState::DONTCARE)
394                 bNeedsObject = true;
395             else if (eState == SfxItemState::SET)
396             {
397                 if ( nId == EE_CHAR_ESCAPEMENT || nId == EE_CHAR_PAIRKERNING ||
398                         nId == EE_CHAR_KERNING || nId == EE_CHAR_XMLATTRIBS )
399                 {
400                     //  Escapement and kerning are kept in EditEngine because there are no
401                     //  corresponding cell format items. User defined attributes are kept in
402                     //  EditEngine because "user attributes applied to all the text" is different
403                     //  from "user attributes applied to the cell".
404 
405                     if ( *pItem != rEditDefaults.Get(nId) )
406                         bNeedsObject = true;
407                 }
408                 else
409                     if (!bNeedsCellAttr)
410                         if ( *pItem != rEditDefaults.Get(nId) )
411                             bNeedsCellAttr = true;
412                 //  rEditDefaults contains the defaults from the cell format
413             }
414         }
415 
416         //  contains field commands?
417 
418         SfxItemState eFieldState = pEditAttrs->GetItemState( EE_FEATURE_FIELD, false );
419         if ( eFieldState == SfxItemState::DONTCARE || eFieldState == SfxItemState::SET )
420             bNeedsObject = true;
421 
422         //  not converted characters?
423 
424         SfxItemState eConvState = pEditAttrs->GetItemState( EE_FEATURE_NOTCONV, false );
425         if ( eConvState == SfxItemState::DONTCARE || eConvState == SfxItemState::SET )
426             bNeedsObject = true;
427     }
428 }
429 
430 ScEditAttrTester::~ScEditAttrTester()
431 {
432 }
433 
434 ScEnginePoolHelper::ScEnginePoolHelper( SfxItemPool* pEnginePoolP,
435                 bool bDeleteEnginePoolP )
436             :
437             pEnginePool( pEnginePoolP ),
438             pDefaults( nullptr ),
439             bDeleteEnginePool( bDeleteEnginePoolP ),
440             bDeleteDefaults( false )
441 {
442 }
443 
444 ScEnginePoolHelper::ScEnginePoolHelper( const ScEnginePoolHelper& rOrg )
445             :
446             pEnginePool( rOrg.bDeleteEnginePool ? rOrg.pEnginePool->Clone() : rOrg.pEnginePool ),
447             pDefaults( nullptr ),
448             bDeleteEnginePool( rOrg.bDeleteEnginePool ),
449             bDeleteDefaults( false )
450 {
451 }
452 
453 ScEnginePoolHelper::~ScEnginePoolHelper()
454 {
455     if ( bDeleteDefaults )
456         delete pDefaults;
457     if ( bDeleteEnginePool )
458         SfxItemPool::Free(pEnginePool);
459 }
460 
461 ScEditEngineDefaulter::ScEditEngineDefaulter( SfxItemPool* pEnginePoolP,
462                 bool bDeleteEnginePoolP )
463             :
464             ScEnginePoolHelper( pEnginePoolP, bDeleteEnginePoolP ),
465             EditEngine( pEnginePoolP )
466 {
467     //  All EditEngines use ScGlobal::GetEditDefaultLanguage as DefaultLanguage.
468     //  DefaultLanguage for InputHandler's EditEngine is updated later.
469 
470     SetDefaultLanguage( ScGlobal::GetEditDefaultLanguage() );
471 }
472 
473 ScEditEngineDefaulter::ScEditEngineDefaulter( const ScEditEngineDefaulter& rOrg )
474             :
475             ScEnginePoolHelper( rOrg ),
476             EditEngine( pEnginePool )
477 {
478     SetDefaultLanguage( ScGlobal::GetEditDefaultLanguage() );
479 }
480 
481 ScEditEngineDefaulter::~ScEditEngineDefaulter()
482 {
483 }
484 
485 void ScEditEngineDefaulter::SetDefaults( const SfxItemSet& rSet, bool bRememberCopy )
486 {
487     if ( bRememberCopy )
488     {
489         if ( bDeleteDefaults )
490             delete pDefaults;
491         pDefaults = new SfxItemSet( rSet );
492         bDeleteDefaults = true;
493     }
494     const SfxItemSet& rNewSet = bRememberCopy ? *pDefaults : rSet;
495     bool bUndo = IsUndoEnabled();
496     EnableUndo( false );
497     bool bUpdateMode = GetUpdateMode();
498     if ( bUpdateMode )
499         SetUpdateMode( false );
500     sal_Int32 nPara = GetParagraphCount();
501     for ( sal_Int32 j=0; j<nPara; j++ )
502     {
503         SetParaAttribs( j, rNewSet );
504     }
505     if ( bUpdateMode )
506         SetUpdateMode( true );
507     if ( bUndo )
508         EnableUndo( true );
509 }
510 
511 void ScEditEngineDefaulter::SetDefaults( SfxItemSet* pSet )
512 {
513     if ( bDeleteDefaults )
514         delete pDefaults;
515     pDefaults = pSet;
516     bDeleteDefaults = true;
517     if ( pDefaults )
518         SetDefaults( *pDefaults, false );
519 }
520 
521 void ScEditEngineDefaulter::SetDefaultItem( const SfxPoolItem& rItem )
522 {
523     if ( !pDefaults )
524     {
525         pDefaults = new SfxItemSet( GetEmptyItemSet() );
526         bDeleteDefaults = true;
527     }
528     pDefaults->Put( rItem );
529     SetDefaults( *pDefaults, false );
530 }
531 
532 const SfxItemSet& ScEditEngineDefaulter::GetDefaults()
533 {
534     if ( !pDefaults )
535     {
536         pDefaults = new SfxItemSet( GetEmptyItemSet() );
537         bDeleteDefaults = true;
538     }
539     return *pDefaults;
540 }
541 
542 void ScEditEngineDefaulter::SetText( const EditTextObject& rTextObject )
543 {
544     bool bUpdateMode = GetUpdateMode();
545     if ( bUpdateMode )
546         SetUpdateMode( false );
547     EditEngine::SetText( rTextObject );
548     if ( pDefaults )
549         SetDefaults( *pDefaults, false );
550     if ( bUpdateMode )
551         SetUpdateMode( true );
552 }
553 
554 void ScEditEngineDefaulter::SetTextNewDefaults( const EditTextObject& rTextObject,
555             const SfxItemSet& rSet, bool bRememberCopy )
556 {
557     bool bUpdateMode = GetUpdateMode();
558     if ( bUpdateMode )
559         SetUpdateMode( false );
560     EditEngine::SetText( rTextObject );
561     SetDefaults( rSet, bRememberCopy );
562     if ( bUpdateMode )
563         SetUpdateMode( true );
564 }
565 
566 void ScEditEngineDefaulter::SetTextNewDefaults( const EditTextObject& rTextObject,
567             SfxItemSet* pSet )
568 {
569     bool bUpdateMode = GetUpdateMode();
570     if ( bUpdateMode )
571         SetUpdateMode( false );
572     EditEngine::SetText( rTextObject );
573     SetDefaults( pSet );
574     if ( bUpdateMode )
575         SetUpdateMode( true );
576 }
577 
578 void ScEditEngineDefaulter::SetText( const OUString& rText )
579 {
580     bool bUpdateMode = GetUpdateMode();
581     if ( bUpdateMode )
582         SetUpdateMode( false );
583     EditEngine::SetText( rText );
584     if ( pDefaults )
585         SetDefaults( *pDefaults, false );
586     if ( bUpdateMode )
587         SetUpdateMode( true );
588 }
589 
590 void ScEditEngineDefaulter::SetTextNewDefaults( const OUString& rText,
591             const SfxItemSet& rSet )
592 {
593     bool bUpdateMode = GetUpdateMode();
594     if ( bUpdateMode )
595         SetUpdateMode( false );
596     EditEngine::SetText( rText );
597     SetDefaults( rSet );
598     if ( bUpdateMode )
599         SetUpdateMode( true );
600 }
601 
602 void ScEditEngineDefaulter::SetTextNewDefaults( const OUString& rText,
603             SfxItemSet* pSet )
604 {
605     bool bUpdateMode = GetUpdateMode();
606     if ( bUpdateMode )
607         SetUpdateMode( false );
608     EditEngine::SetText( rText );
609     SetDefaults( pSet );
610     if ( bUpdateMode )
611         SetUpdateMode( true );
612 }
613 
614 void ScEditEngineDefaulter::RepeatDefaults()
615 {
616     if ( pDefaults )
617     {
618         sal_Int32 nPara = GetParagraphCount();
619         for ( sal_Int32 j=0; j<nPara; j++ )
620             SetParaAttribs( j, *pDefaults );
621     }
622 }
623 
624 void ScEditEngineDefaulter::RemoveParaAttribs()
625 {
626     std::unique_ptr<SfxItemSet> pCharItems;
627     bool bUpdateMode = GetUpdateMode();
628     if ( bUpdateMode )
629         SetUpdateMode( false );
630     sal_Int32 nParCount = GetParagraphCount();
631     for (sal_Int32 nPar=0; nPar<nParCount; nPar++)
632     {
633         const SfxItemSet& rParaAttribs = GetParaAttribs( nPar );
634         sal_uInt16 nWhich;
635         for (nWhich = EE_CHAR_START; nWhich <= EE_CHAR_END; nWhich ++)
636         {
637             const SfxPoolItem* pParaItem;
638             if ( rParaAttribs.GetItemState( nWhich, false, &pParaItem ) == SfxItemState::SET )
639             {
640                 //  if defaults are set, use only items that are different from default
641                 if ( !pDefaults || *pParaItem != pDefaults->Get(nWhich) )
642                 {
643                     if (!pCharItems)
644                         pCharItems.reset(new SfxItemSet( GetEmptyItemSet() ));
645                     pCharItems->Put( *pParaItem );
646                 }
647             }
648         }
649 
650         if ( pCharItems )
651         {
652             std::vector<sal_Int32> aPortions;
653             GetPortions( nPar, aPortions );
654 
655             //  loop through the portions of the paragraph, and set only those items
656             //  that are not overridden by existing character attributes
657 
658             sal_Int32 nStart = 0;
659             for ( const sal_Int32 nEnd : aPortions )
660             {
661                 ESelection aSel( nPar, nStart, nPar, nEnd );
662                 SfxItemSet aOldCharAttrs = GetAttribs( aSel );
663                 SfxItemSet aNewCharAttrs = *pCharItems;
664                 for (nWhich = EE_CHAR_START; nWhich <= EE_CHAR_END; nWhich ++)
665                 {
666                     //  Clear those items that are different from existing character attributes.
667                     //  Where no character attributes are set, GetAttribs returns the paragraph attributes.
668                     const SfxPoolItem* pItem;
669                     if ( aNewCharAttrs.GetItemState( nWhich, false, &pItem ) == SfxItemState::SET &&
670                          *pItem != aOldCharAttrs.Get(nWhich) )
671                     {
672                         aNewCharAttrs.ClearItem(nWhich);
673                     }
674                 }
675                 if ( aNewCharAttrs.Count() )
676                     QuickSetAttribs( aNewCharAttrs, aSel );
677 
678                 nStart = nEnd;
679             }
680 
681             pCharItems.reset();
682         }
683 
684         if ( rParaAttribs.Count() )
685         {
686             //  clear all paragraph attributes (including defaults),
687             //  so they are not contained in resulting EditTextObjects
688 
689             SetParaAttribs( nPar, SfxItemSet( *rParaAttribs.GetPool(), rParaAttribs.GetRanges() ) );
690         }
691     }
692     if ( bUpdateMode )
693         SetUpdateMode( true );
694 }
695 
696 ScTabEditEngine::ScTabEditEngine( ScDocument* pDoc )
697         : ScFieldEditEngine( pDoc, pDoc->GetEnginePool() )
698 {
699     SetEditTextObjectPool( pDoc->GetEditPool() );
700     Init(pDoc->GetPool()->GetDefaultItem(ATTR_PATTERN));
701 }
702 
703 ScTabEditEngine::ScTabEditEngine( const ScPatternAttr& rPattern,
704             SfxItemPool* pEngineItemPool, ScDocument* pDoc, SfxItemPool* pTextObjectPool )
705         : ScFieldEditEngine( pDoc, pEngineItemPool, pTextObjectPool )
706 {
707     if ( pTextObjectPool )
708         SetEditTextObjectPool( pTextObjectPool );
709     Init( rPattern );
710 }
711 
712 void ScTabEditEngine::Init( const ScPatternAttr& rPattern )
713 {
714     SetRefMapMode(MapMode(MapUnit::Map100thMM));
715     SfxItemSet* pEditDefaults = new SfxItemSet( GetEmptyItemSet() );
716     rPattern.FillEditItemSet( pEditDefaults );
717     SetDefaults( pEditDefaults );
718     // we have no StyleSheets for text
719     SetControlWord( GetControlWord() & ~EEControlBits::RTFSTYLESHEETS );
720 }
721 
722 //      field commands for header and footer
723 
724 //      numbers from \sw\source\core\doc\numbers.cxx
725 
726 static OUString lcl_GetCharStr( sal_Int32 nNo )
727 {
728     OSL_ENSURE( nNo, "0 is an invalid number !!" );
729     OUString aStr;
730 
731     const sal_Int32 coDiff = 'Z' - 'A' +1;
732     sal_Int32 nCalc;
733 
734     do {
735         nCalc = nNo % coDiff;
736         if( !nCalc )
737             nCalc = coDiff;
738         aStr = OUStringLiteral1( 'a' - 1 + nCalc ) + aStr;
739         nNo = sal::static_int_cast<sal_Int32>( nNo - nCalc );
740         if( nNo )
741             nNo /= coDiff;
742     } while( nNo );
743     return aStr;
744 }
745 
746 static OUString lcl_GetNumStr(sal_Int32 nNo, SvxNumType eType)
747 {
748     OUString aTmpStr('0');
749     if( nNo )
750     {
751         switch( eType )
752         {
753         case css::style::NumberingType::CHARS_UPPER_LETTER:
754         case css::style::NumberingType::CHARS_LOWER_LETTER:
755             aTmpStr = lcl_GetCharStr( nNo );
756             break;
757 
758         case css::style::NumberingType::ROMAN_UPPER:
759         case css::style::NumberingType::ROMAN_LOWER:
760             if( nNo < 4000 )
761                 aTmpStr = SvxNumberFormat::CreateRomanString( nNo, ( eType == css::style::NumberingType::ROMAN_UPPER ) );
762             else
763                 aTmpStr.clear();
764             break;
765 
766         case css::style::NumberingType::NUMBER_NONE:
767             aTmpStr.clear();
768             break;
769 
770 //      CHAR_SPECIAL:
771 //          ????
772 
773 //      case ARABIC:    is default now
774         default:
775             aTmpStr = OUString::number(nNo);
776             break;
777         }
778 
779         if( css::style::NumberingType::CHARS_UPPER_LETTER == eType )
780             aTmpStr = aTmpStr.toAsciiUpperCase();
781     }
782     return aTmpStr;
783 }
784 
785 ScHeaderFieldData::ScHeaderFieldData()
786     : aDateTime ( DateTime::EMPTY )
787 {
788     nPageNo = nTotalPages = 0;
789     eNumType = SVX_NUM_ARABIC;
790 }
791 
792 ScHeaderEditEngine::ScHeaderEditEngine( SfxItemPool* pEnginePoolP )
793         : ScEditEngineDefaulter( pEnginePoolP,true/*bDeleteEnginePoolP*/ )
794 {
795 }
796 
797 OUString ScHeaderEditEngine::CalcFieldValue( const SvxFieldItem& rField,
798                                     sal_Int32 /* nPara */, sal_Int32 /* nPos */,
799                                     boost::optional<Color>& /* rTxtColor */, boost::optional<Color>& /* rFldColor */ )
800 {
801     const SvxFieldData* pFieldData = rField.GetField();
802     if (!pFieldData)
803         return OUString("?");
804 
805     OUString aRet;
806     sal_Int32 nClsId = pFieldData->GetClassId();
807     switch (nClsId)
808     {
809         case text::textfield::Type::PAGE:
810             aRet = lcl_GetNumStr( aData.nPageNo,aData.eNumType );
811         break;
812         case text::textfield::Type::PAGES:
813             aRet = lcl_GetNumStr( aData.nTotalPages,aData.eNumType );
814         break;
815         case text::textfield::Type::EXTENDED_TIME:
816         case text::textfield::Type::TIME:
817             // For now, time field in the header / footer is always dynamic.
818             aRet = ScGlobal::pLocaleData->getTime(aData.aDateTime);
819         break;
820         case text::textfield::Type::DOCINFO_TITLE:
821             aRet = aData.aTitle;
822         break;
823         case text::textfield::Type::EXTENDED_FILE:
824         {
825             switch (static_cast<const SvxExtFileField*>(pFieldData)->GetFormat())
826             {
827                 case SvxFileFormat::PathFull :
828                     aRet = aData.aLongDocName;
829                 break;
830                 default:
831                     aRet = aData.aShortDocName;
832             }
833         }
834         break;
835         case text::textfield::Type::TABLE:
836             aRet = aData.aTabName;
837         break;
838         case text::textfield::Type::DATE:
839             aRet = ScGlobal::pLocaleData->getDate(aData.aDateTime);
840         break;
841         default:
842             aRet = "?";
843     }
844 
845     return aRet;
846 }
847 
848 //                          field data
849 
850 ScFieldEditEngine::ScFieldEditEngine(
851     ScDocument* pDoc, SfxItemPool* pEnginePoolP,
852     SfxItemPool* pTextObjectPool, bool bDeleteEnginePoolP) :
853         ScEditEngineDefaulter( pEnginePoolP, bDeleteEnginePoolP ),
854         mpDoc(pDoc), bExecuteURL(true)
855 {
856     if ( pTextObjectPool )
857         SetEditTextObjectPool( pTextObjectPool );
858     SetControlWord( EEControlBits(GetControlWord() | EEControlBits::MARKFIELDS) & ~EEControlBits::RTFSTYLESHEETS );
859 }
860 
861 OUString ScFieldEditEngine::CalcFieldValue( const SvxFieldItem& rField,
862                                     sal_Int32 /* nPara */, sal_Int32 /* nPos */,
863                                     boost::optional<Color>& rTxtColor, boost::optional<Color>& /* rFldColor */ )
864 {
865     const SvxFieldData* pFieldData = rField.GetField();
866 
867     if (!pFieldData)
868         return OUString(" ");
869 
870     return ScEditUtil::GetCellFieldValue(*pFieldData, mpDoc, &rTxtColor);
871 }
872 
873 void ScFieldEditEngine::FieldClicked( const SvxFieldItem& rField, sal_Int32, sal_Int32 )
874 {
875     if (!bExecuteURL)
876         return;
877     if (const SvxURLField* pURLField = dynamic_cast<const SvxURLField*>(rField.GetField()))
878     {
879         ScGlobal::OpenURL(pURLField->GetURL(), pURLField->GetTargetFrame());
880     }
881 }
882 
883 ScNoteEditEngine::ScNoteEditEngine( SfxItemPool* pEnginePoolP,
884             SfxItemPool* pTextObjectPool ) :
885     ScEditEngineDefaulter( pEnginePoolP, false/*bDeleteEnginePoolP*/ )
886 {
887     if ( pTextObjectPool )
888         SetEditTextObjectPool( pTextObjectPool );
889     SetControlWord( EEControlBits(GetControlWord() | EEControlBits::MARKFIELDS) & ~EEControlBits::RTFSTYLESHEETS );
890 }
891 
892 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
893