1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <scitems.hxx>
22 #include <editeng/eeitem.hxx>
23 #include <i18nlangtag/mslangid.hxx>
24 #include <editeng/borderline.hxx>
25 #include <editeng/boxitem.hxx>
26 #include <editeng/brushitem.hxx>
27 #include <editeng/editeng.hxx>
28 #include <editeng/editobj.hxx>
29 #include <editeng/flditem.hxx>
30 #include <editeng/fontitem.hxx>
31 #include <svx/pageitem.hxx>
32 #include <svl/itemset.hxx>
33 #include <svl/zforlist.hxx>
34 #include <svl/IndexedStyleSheets.hxx>
35 #include <unotools/charclass.hxx>
36 #include <vcl/outdev.hxx>
37 #include <vcl/svapp.hxx>
38 #include <vcl/settings.hxx>
39 #include <osl/diagnose.h>
44 #include <globstr.hrc>
45 #include <scresid.hxx>
46 #include <document.hxx>
47 #include <docpool.hxx>
48 #include <stlpool.hxx>
49 #include <stlsheet.hxx>
50 #include <editutil.hxx>
51 #include <stylehelper.hxx>
53 ScStyleSheetPool::ScStyleSheetPool( const SfxItemPool
& rPoolP
,
54 ScDocument
* pDocument
)
55 : SfxStyleSheetPool( rPoolP
),
56 pActualStyleSheet( nullptr ),
58 bHasStandardStyles( false )
62 ScStyleSheetPool::~ScStyleSheetPool()
66 void ScStyleSheetPool::SetDocument( ScDocument
* pDocument
)
71 SfxStyleSheetBase
& ScStyleSheetPool::Make( const OUString
& rName
,
72 SfxStyleFamily eFam
, SfxStyleSearchBits mask
,
73 const OUString
& rParentStyleSheetName
)
75 if ( rName
== STRING_STANDARD
&& Find( rName
, eFam
) != nullptr )
77 // When updating styles from a template, Office 5.1 sometimes created
78 // files with multiple default styles.
79 // Create new styles in that case:
81 //TODO: only when loading?
83 OSL_FAIL("renaming additional default style");
84 sal_uInt32 nCount
= GetIndexedStyleSheets().GetNumberOfStyleSheets();
85 for ( sal_uInt32 nAdd
= 1; nAdd
<= nCount
; nAdd
++ )
87 OUString aNewName
= ScResId(STR_STYLENAME_STANDARD
) + OUString::number( nAdd
);
88 if ( Find( aNewName
, eFam
) == nullptr )
89 return SfxStyleSheetPool::Make(aNewName
, eFam
, mask
, rParentStyleSheetName
);
93 // Core uses translated names for both naming and display.
94 // This for all three, loading standard builtin styles from styles.xml
95 // configuration, loading documents and updating from templates.
96 return SfxStyleSheetPool::Make( ScStyleNameConversion::ProgrammaticToDisplayName( rName
, eFam
), eFam
, mask
, rParentStyleSheetName
);
99 rtl::Reference
<SfxStyleSheetBase
> ScStyleSheetPool::Create( const OUString
& rName
,
100 SfxStyleFamily eFamily
,
101 SfxStyleSearchBits nMaskP
,
102 const OUString
& rParentStyleSheetName
)
104 rtl::Reference
<ScStyleSheet
> pSheet
= new ScStyleSheet( rName
, *this, eFamily
, nMaskP
, rParentStyleSheetName
);
105 if ( eFamily
!= SfxStyleFamily::Page
&& ScResId(STR_STYLENAME_STANDARD
) != rName
)
106 pSheet
->SetParent( ScResId(STR_STYLENAME_STANDARD
) );
111 rtl::Reference
<SfxStyleSheetBase
> ScStyleSheetPool::Create( const SfxStyleSheetBase
& rStyle
)
113 OSL_ENSURE( rStyle
.isScStyleSheet(), "Invalid StyleSheet-class! :-/" );
114 return new ScStyleSheet( static_cast<const ScStyleSheet
&>(rStyle
) );
117 void ScStyleSheetPool::Remove( SfxStyleSheetBase
* pStyle
)
121 OSL_ENSURE( SfxStyleSearchBits::UserDefined
& pStyle
->GetMask(),
122 "SfxStyleSearchBits::UserDefined not set!" );
124 assert(nullptr != pDoc
);
125 pDoc
->getCellAttributeHelper().CellStyleDeleted(static_cast<ScStyleSheet
&>(*pStyle
));
126 SfxStyleSheetPool::Remove(pStyle
);
130 void ScStyleSheetPool::CopyStyleFrom( SfxStyleSheetBasePool
* pSrcPool
,
131 const OUString
& rName
, SfxStyleFamily eFamily
,
132 bool bNewStyleHierarchy
)
134 // this is the Dest-Pool
136 SfxStyleSheetBase
* pStyleSheet
= pSrcPool
->Find( rName
, eFamily
);
140 const SfxItemSet
& rSourceSet
= pStyleSheet
->GetItemSet();
141 SfxStyleSheetBase
* pDestSheet
= Find( rName
, eFamily
);
142 if (pDestSheet
&& bNewStyleHierarchy
)
145 pDestSheet
= &Make( rName
, eFamily
, pStyleSheet
->GetMask() );
146 SfxItemSet
& rDestSet
= pDestSheet
->GetItemSet();
147 rDestSet
.PutExtended( rSourceSet
, SfxItemState::INVALID
, SfxItemState::DEFAULT
);
149 if ( eFamily
== SfxStyleFamily::Page
)
153 if ( const SvxSetItem
* pSetItem
= rSourceSet
.GetItemIfSet( ATTR_PAGE_HEADERSET
, false ) )
155 const SfxItemSet
& rSrcSub
= pSetItem
->GetItemSet();
156 SfxItemSet
aDestSub( *rDestSet
.GetPool(), rSrcSub
.GetRanges() );
157 aDestSub
.PutExtended( rSrcSub
, SfxItemState::INVALID
, SfxItemState::DEFAULT
);
159 if ( const SvxSetItem
* pSetItem
= rSourceSet
.GetItemIfSet( ATTR_PAGE_FOOTERSET
, false ) )
161 const SfxItemSet
& rSrcSub
= pSetItem
->GetItemSet();
162 SfxItemSet
aDestSub( *rDestSet
.GetPool(), rSrcSub
.GetRanges() );
163 aDestSub
.PutExtended( rSrcSub
, SfxItemState::INVALID
, SfxItemState::DEFAULT
);
164 rDestSet
.Put( SvxSetItem( ATTR_PAGE_FOOTERSET
, aDestSub
) );
167 else if ( eFamily
== SfxStyleFamily::Para
)
169 // number format exchange list has to be handled here, too
171 const SfxUInt32Item
* pItem
;
172 if ( pDoc
&& pDoc
->GetFormatExchangeList() &&
173 (pItem
= rSourceSet
.GetItemIfSet( ATTR_VALUE_FORMAT
, false )) )
175 sal_uInt32 nOldFormat
= pItem
->GetValue();
176 SvNumberFormatterIndexTable::const_iterator it
= pDoc
->GetFormatExchangeList()->find(nOldFormat
);
177 if (it
!= pDoc
->GetFormatExchangeList()->end())
179 sal_uInt32 nNewFormat
= it
->second
;
180 rDestSet
.Put( SfxUInt32Item( ATTR_VALUE_FORMAT
, nNewFormat
) );
185 const OUString aParentName
= pStyleSheet
->GetParent();
186 if (!bNewStyleHierarchy
|| aParentName
.isEmpty())
189 CopyStyleFrom(pSrcPool
, aParentName
, eFamily
, bNewStyleHierarchy
);
190 pDestSheet
->SetParent(aParentName
);
193 void ScStyleSheetPool::CopyUsedGraphicStylesFrom(SfxStyleSheetBasePool
* pSrcPool
)
195 // this is the Dest-Pool
197 std::vector
<std::pair
<SfxStyleSheetBase
*, OUString
>> aNewStyles
;
199 auto pSrcSheet
= pSrcPool
->First(SfxStyleFamily::Frame
);
202 if (pSrcSheet
->IsUsed() && !Find(pSrcSheet
->GetName(), pSrcSheet
->GetFamily()))
204 auto pDestSheet
= &Make(pSrcSheet
->GetName(), pSrcSheet
->GetFamily(), pSrcSheet
->GetMask());
205 aNewStyles
.emplace_back(pDestSheet
, pSrcSheet
->GetParent());
207 SfxItemSet
& rDestSet
= pDestSheet
->GetItemSet();
208 rDestSet
.Put(pSrcSheet
->GetItemSet());
211 pSrcSheet
= pSrcPool
->Next();
214 for (const auto& style
: aNewStyles
)
215 style
.first
->SetParent(style
.second
);
218 // Standard templates
220 void ScStyleSheetPool::CopyStdStylesFrom( ScStyleSheetPool
* pSrcPool
)
222 // Copy Default styles
224 CopyStyleFrom( pSrcPool
, ScResId(STR_STYLENAME_STANDARD
), SfxStyleFamily::Para
);
225 CopyStyleFrom( pSrcPool
, ScResId(STR_STYLENAME_STANDARD
), SfxStyleFamily::Frame
);
226 CopyStyleFrom( pSrcPool
, ScResId(STR_STYLENAME_STANDARD
), SfxStyleFamily::Page
);
227 CopyStyleFrom( pSrcPool
, ScResId(STR_STYLENAME_REPORT
), SfxStyleFamily::Page
);
230 static void lcl_CheckFont( SfxItemSet
& rSet
, LanguageType eLang
, DefaultFontType nFontType
, sal_uInt16 nItemId
)
232 if ( eLang
!= LANGUAGE_NONE
&& eLang
!= LANGUAGE_DONTKNOW
&& eLang
!= LANGUAGE_SYSTEM
)
234 vcl::Font aDefFont
= OutputDevice::GetDefaultFont( nFontType
, eLang
, GetDefaultFontFlags::OnlyOne
);
235 SvxFontItem
aNewItem( aDefFont
.GetFamilyType(), aDefFont
.GetFamilyName(), aDefFont
.GetStyleName(),
236 aDefFont
.GetPitch(), aDefFont
.GetCharSet(), nItemId
);
237 if ( aNewItem
!= rSet
.Get( nItemId
) )
239 // put item into style's ItemSet only if different from (static) default
240 rSet
.Put( aNewItem
);
245 void ScStyleSheetPool::CreateStandardStyles()
247 // Add new entries even for CopyStdStylesFrom
249 Color
aColBlack ( COL_BLACK
);
252 const OUString aHelpFile
;//which text???
253 SfxItemSet
* pSet
= nullptr;
254 SfxItemSet
* pHFSet
= nullptr;
255 ScEditEngineDefaulter
aEdEngine( EditEngine::CreatePool().get(), true );
256 aEdEngine
.SetUpdateLayout( false );
257 std::unique_ptr
<EditTextObject
> pEmptyTxtObj
= aEdEngine
.CreateTextObject();
258 std::unique_ptr
<EditTextObject
> pTxtObj
;
259 ScPageHFItem
aHeaderItem( ATTR_PAGE_HEADERRIGHT
);
260 ScPageHFItem
aFooterItem( ATTR_PAGE_FOOTERRIGHT
);
261 ScStyleSheet
* pSheet
= nullptr;
262 ::editeng::SvxBorderLine
aBorderLine ( &aColBlack
, SvxBorderLineWidth::Medium
);
263 SvxBoxItem
aBoxItem ( ATTR_BORDER
);
264 SvxBoxInfoItem
aBoxInfoItem ( ATTR_BORDER_INNER
);
266 OUString aStrStandard
= ScResId(STR_STYLENAME_STANDARD
);
268 // Cell format templates:
272 pSheet
= static_cast<ScStyleSheet
*>( &Make( aStrStandard
, SfxStyleFamily::Para
, SfxStyleSearchBits::ScStandard
) );
273 pSheet
->SetHelpId( aHelpFile
, HID_SC_SHEET_CELL_STD
);
275 // if default fonts for the document's languages are different from the pool default,
276 // put them into the default style
277 // (not as pool defaults, because pool defaults can't be changed by the user)
278 // the document languages must be set before creating the default styles!
280 pSet
= &pSheet
->GetItemSet();
281 LanguageType eLatin
, eCjk
, eCtl
;
282 pDoc
->GetLanguage( eLatin
, eCjk
, eCtl
);
284 // If the UI language is Korean, the default Latin font has to
285 // be queried for Korean, too (the Latin language from the document can't be Korean).
286 // This is the same logic as in SwDocShell::InitNew.
287 LanguageType eUiLanguage
= Application::GetSettings().GetUILanguageTag().getLanguageType();
288 if (MsLangId::isKorean(eUiLanguage
))
289 eLatin
= eUiLanguage
;
291 lcl_CheckFont( *pSet
, eLatin
, DefaultFontType::LATIN_SPREADSHEET
, ATTR_FONT
);
292 lcl_CheckFont( *pSet
, eCjk
, DefaultFontType::CJK_SPREADSHEET
, ATTR_CJK_FONT
);
293 lcl_CheckFont( *pSet
, eCtl
, DefaultFontType::CTL_SPREADSHEET
, ATTR_CTL_FONT
);
295 // #i55300# default CTL font size for Thai has to be larger
296 // #i59408# The 15 point size causes problems with row heights, so no different
297 // size is used for Thai in Calc for now.
298 // if ( eCtl == LANGUAGE_THAI )
299 // pSet->Put( SvxFontHeightItem( 300, 100, ATTR_CTL_FONT_HEIGHT ) ); // 15 pt
301 // Page format template:
305 pSheet
= static_cast<ScStyleSheet
*>( &Make( aStrStandard
,
306 SfxStyleFamily::Page
,
307 SfxStyleSearchBits::ScStandard
) );
309 pSet
= &pSheet
->GetItemSet();
310 pSheet
->SetHelpId( aHelpFile
, HID_SC_SHEET_PAGE_STD
);
312 // distance to header/footer for the sheet
313 SvxSetItem aHFSetItem
= pSet
->Get( ATTR_PAGE_HEADERSET
);
314 aHFSetItem
.SetWhich(ATTR_PAGE_HEADERSET
);
315 pSet
->Put( aHFSetItem
);
316 aHFSetItem
.SetWhich(ATTR_PAGE_FOOTERSET
);
317 pSet
->Put( aHFSetItem
);
320 // [empty][\sheet\][empty]
322 aEdEngine
.SetTextCurrentDefaults(OUString());
323 aEdEngine
.QuickInsertField( SvxFieldItem(SvxTableField(), EE_FEATURE_FIELD
), ESelection() );
324 pTxtObj
= aEdEngine
.CreateTextObject();
325 aHeaderItem
.SetLeftArea ( *pEmptyTxtObj
);
326 aHeaderItem
.SetCenterArea( *pTxtObj
);
327 aHeaderItem
.SetRightArea ( *pEmptyTxtObj
);
328 pSet
->Put( aHeaderItem
);
331 // [empty][Page \STR_PAGE\][empty]
333 aStr
= ScResId( STR_PAGE
) + " ";
334 aEdEngine
.SetTextCurrentDefaults( aStr
);
335 nStrLen
= aStr
.getLength();
336 aEdEngine
.QuickInsertField( SvxFieldItem(SvxPageField(), EE_FEATURE_FIELD
), ESelection(0,nStrLen
) );
337 pTxtObj
= aEdEngine
.CreateTextObject();
338 aFooterItem
.SetLeftArea ( *pEmptyTxtObj
);
339 aFooterItem
.SetCenterArea( *pTxtObj
);
340 aFooterItem
.SetRightArea ( *pEmptyTxtObj
);
341 pSet
->Put( aFooterItem
);
345 pSheet
= static_cast<ScStyleSheet
*>( &Make( ScResId( STR_STYLENAME_REPORT
),
346 SfxStyleFamily::Page
,
347 SfxStyleSearchBits::ScStandard
) );
348 pSet
= &pSheet
->GetItemSet();
349 pSheet
->SetHelpId( aHelpFile
, HID_SC_SHEET_PAGE_REP
);
351 // Background and border
352 aBoxItem
.SetLine( &aBorderLine
, SvxBoxItemLine::TOP
);
353 aBoxItem
.SetLine( &aBorderLine
, SvxBoxItemLine::BOTTOM
);
354 aBoxItem
.SetLine( &aBorderLine
, SvxBoxItemLine::LEFT
);
355 aBoxItem
.SetLine( &aBorderLine
, SvxBoxItemLine::RIGHT
);
356 aBoxItem
.SetAllDistances( 10 ); // 0.2mm
357 aBoxInfoItem
.SetValid( SvxBoxInfoItemValidFlags::TOP
);
358 aBoxInfoItem
.SetValid( SvxBoxInfoItemValidFlags::BOTTOM
);
359 aBoxInfoItem
.SetValid( SvxBoxInfoItemValidFlags::LEFT
);
360 aBoxInfoItem
.SetValid( SvxBoxInfoItemValidFlags::RIGHT
);
361 aBoxInfoItem
.SetValid( SvxBoxInfoItemValidFlags::DISTANCE
);
362 aBoxInfoItem
.SetTable( false );
363 aBoxInfoItem
.SetDist ( true );
365 SvxSetItem aHFSetItem2
= pSet
->Get( ATTR_PAGE_HEADERSET
);
366 pHFSet
= &(aHFSetItem2
.GetItemSet());
368 pHFSet
->Put( SvxBrushItem( COL_LIGHTGRAY
, ATTR_BACKGROUND
) );
369 pHFSet
->Put( aBoxItem
);
370 pHFSet
->Put( aBoxInfoItem
);
371 aHFSetItem2
.SetWhich(ATTR_PAGE_HEADERSET
);
372 pSet
->Put( aHFSetItem2
);
373 aHFSetItem2
.SetWhich(ATTR_PAGE_FOOTERSET
);
374 pSet
->Put( aHFSetItem2
);
377 // [\TABLE\ (\DATA\)][empty][\DATE\, \TIME\]
380 aEdEngine
.SetTextCurrentDefaults( aStr
);
381 aEdEngine
.QuickInsertField( SvxFieldItem(SvxFileField(), EE_FEATURE_FIELD
), ESelection(0,2) );
382 aEdEngine
.QuickInsertField( SvxFieldItem(SvxTableField(), EE_FEATURE_FIELD
), ESelection() );
383 pTxtObj
= aEdEngine
.CreateTextObject();
384 aHeaderItem
.SetLeftArea( *pTxtObj
);
385 aHeaderItem
.SetCenterArea( *pEmptyTxtObj
);
387 aEdEngine
.SetTextCurrentDefaults( aStr
);
388 aEdEngine
.QuickInsertField( SvxFieldItem(SvxTimeField(), EE_FEATURE_FIELD
), ESelection(0,2) );
389 aEdEngine
.QuickInsertField( SvxFieldItem(SvxDateField(Date( Date::SYSTEM
),SvxDateType::Var
), EE_FEATURE_FIELD
),
391 pTxtObj
= aEdEngine
.CreateTextObject();
392 aHeaderItem
.SetRightArea( *pTxtObj
);
393 pSet
->Put( aHeaderItem
);
396 // [empty][Page: \PAGE\ / \PAGE\][empty]
398 aStr
= ScResId( STR_PAGE
) + " ";
399 nStrLen
= aStr
.getLength();
401 sal_Int32 nStrLen2
= aStr
.getLength();
402 aEdEngine
.SetTextCurrentDefaults( aStr
);
403 aEdEngine
.QuickInsertField( SvxFieldItem(SvxPagesField(), EE_FEATURE_FIELD
), ESelection(0,nStrLen2
) );
404 aEdEngine
.QuickInsertField( SvxFieldItem(SvxPageField(), EE_FEATURE_FIELD
), ESelection(0,nStrLen
) );
405 pTxtObj
= aEdEngine
.CreateTextObject();
406 aFooterItem
.SetLeftArea ( *pEmptyTxtObj
);
407 aFooterItem
.SetCenterArea( *pTxtObj
);
408 aFooterItem
.SetRightArea ( *pEmptyTxtObj
);
409 pSet
->Put( aFooterItem
);
411 bHasStandardStyles
= true;
416 struct CaseInsensitiveNamePredicate
: svl::StyleSheetPredicate
418 CaseInsensitiveNamePredicate(const OUString
& rName
, SfxStyleFamily eFam
)
419 : mUppercaseName(ScGlobal::getCharClass().uppercase(rName
)), mFamily(eFam
)
424 Check(const SfxStyleSheetBase
& rStyleSheet
) override
426 if (rStyleSheet
.GetFamily() == mFamily
)
428 OUString aUpName
= ScGlobal::getCharClass().uppercase(rStyleSheet
.GetName());
429 if (mUppercaseName
== aUpName
)
437 OUString mUppercaseName
;
438 SfxStyleFamily mFamily
;
443 // Functor object to find all style sheets of a family which match a given name caseinsensitively
444 ScStyleSheet
* ScStyleSheetPool::FindCaseIns( const OUString
& rName
, SfxStyleFamily eFam
)
446 CaseInsensitiveNamePredicate
aPredicate(rName
, eFam
);
447 std::vector
<sal_Int32
> aFoundPositions
= GetIndexedStyleSheets().FindPositionsByPredicate(aPredicate
);
449 ScStyleSheet
* first
= nullptr; // first case insensitive match found
450 for (const auto& rPos
: aFoundPositions
)
452 SfxStyleSheetBase
*pFound
= GetStyleSheetByPositionInIndex(rPos
);
453 // we do not know what kind of sheets we have.
454 if (pFound
->isScStyleSheet())
456 if (pFound
->GetName() == rName
) // exact case sensitive match
457 return static_cast<ScStyleSheet
*>(pFound
);
459 first
= static_cast<ScStyleSheet
*>(pFound
);
465 ScStyleSheet
* ScStyleSheetPool::FindAutoStyle(const OUString
& rName
)
467 ScStyleSheet
* pStyleSheet
= FindCaseIns(rName
, SfxStyleFamily::Para
);
469 if (auto pFound
= Find(ScResId(STR_STYLENAME_STANDARD
), SfxStyleFamily::Para
))
470 if (pFound
->isScStyleSheet()) // we do not know what kind of sheets we have
471 pStyleSheet
= static_cast<ScStyleSheet
*>(pFound
);
475 void ScStyleSheetPool::setAllParaStandard()
477 SfxStyleSheetBase
* pSheet
= First(SfxStyleFamily::Para
);
480 pSheet
->SetMask(SfxStyleSearchBits::ScStandard
);
485 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */