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 <com/sun/star/text/ChapterFormat.hpp>
21 #include <doc.hxx>
22 #include <frame.hxx>
23 #include <rootfrm.hxx>
24 #include <txtfrm.hxx>
25 #include <pam.hxx>
26 #include <ndtxt.hxx>
27 #include <chpfld.hxx>
28 #include <expfld.hxx>
29 #include <unofldmid.h>
30 #include <numrule.hxx>
31
32 using namespace ::com::sun::star;
33
34 namespace
35 {
36
removeControlChars(const OUString & sIn)37 OUString removeControlChars(const OUString& sIn)
38 {
39 OUStringBuffer aBuf(sIn.replace('\n', ' '));
40 sal_Int32 nLen = aBuf.getLength();
41 for (sal_Int32 i = 0; i < nLen; ++i)
42 {
43 if (aBuf[i] < ' ')
44 {
45 sal_Int32 j = i+1;
46 while (j<nLen && aBuf[j]<' ') ++j;
47 aBuf.remove(i, j-i);
48 nLen = aBuf.getLength();
49 }
50 }
51 return aBuf.makeStringAndClear();
52 }
53
54 }
55
SwChapterFieldType()56 SwChapterFieldType::SwChapterFieldType()
57 : SwFieldType( SwFieldIds::Chapter )
58 {
59 }
60
Copy() const61 std::unique_ptr<SwFieldType> SwChapterFieldType::Copy() const
62 {
63 return std::make_unique<SwChapterFieldType>();
64 }
65
66 // chapter field
67
SwChapterField(SwChapterFieldType * pTyp,sal_uInt32 nFormat)68 SwChapterField::SwChapterField(SwChapterFieldType* pTyp, sal_uInt32 nFormat)
69 : SwField(pTyp, nFormat)
70 {
71 }
72
GetLevel(SwRootFrame const * const pLayout) const73 sal_uInt8 SwChapterField::GetLevel(SwRootFrame const*const pLayout) const
74 {
75 State const& rState(pLayout && pLayout->IsHideRedlines() ? m_StateRLHidden : m_State);
76 return rState.nLevel;
77 }
78
79 // this is called from UI or from import filters, so override both states
SetLevel(sal_uInt8 nLev)80 void SwChapterField::SetLevel(sal_uInt8 nLev)
81 {
82 m_State.nLevel = nLev;
83 m_StateRLHidden.nLevel = nLev;
84 }
85
GetNumber(SwRootFrame const * const pLayout) const86 const OUString& SwChapterField::GetNumber(SwRootFrame const*const pLayout) const
87 {
88 State const& rState(pLayout && pLayout->IsHideRedlines() ? m_StateRLHidden : m_State);
89 return rState.sNumber;
90 }
91
GetTitle(SwRootFrame const * const pLayout) const92 const OUString& SwChapterField::GetTitle(SwRootFrame const*const pLayout) const
93 {
94 State const& rState(pLayout && pLayout->IsHideRedlines() ? m_StateRLHidden : m_State);
95 return rState.sTitle;
96 }
97
ExpandImpl(SwRootFrame const * const pLayout) const98 OUString SwChapterField::ExpandImpl(SwRootFrame const*const pLayout) const
99 {
100 State const& rState(pLayout && pLayout->IsHideRedlines() ? m_StateRLHidden : m_State);
101 switch( GetFormat() )
102 {
103 case CF_TITLE:
104 return rState.sTitle;
105 case CF_NUMBER:
106 return rState.sPre + rState.sNumber + rState.sPost;
107 case CF_NUM_TITLE:
108 return rState.sPre + rState.sNumber + rState.sPost + rState.sTitle;
109 case CF_NUM_NOPREPST_TITLE:
110 return rState.sNumber + rState.sTitle;
111 }
112 // CF_NUMBER_NOPREPST
113 return rState.sNumber;
114 }
115
Copy() const116 std::unique_ptr<SwField> SwChapterField::Copy() const
117 {
118 std::unique_ptr<SwChapterField> pTmp(
119 new SwChapterField(static_cast<SwChapterFieldType*>(GetTyp()), GetFormat()));
120 pTmp->m_State = m_State;
121 pTmp->m_StateRLHidden = m_StateRLHidden;
122
123 return std::unique_ptr<SwField>(pTmp.release());
124 }
125
126 // #i53420#
ChangeExpansion(const SwFrame & rFrame,const SwContentNode * pContentNode,bool bSrchNum)127 void SwChapterField::ChangeExpansion(const SwFrame & rFrame,
128 const SwContentNode* pContentNode,
129 bool bSrchNum )
130 {
131 SwDoc* pDoc = const_cast<SwDoc*>(pContentNode->GetDoc());
132
133 const SwTextNode* pTextNode = dynamic_cast<const SwTextNode*>(pContentNode);
134 if (!pTextNode || !rFrame.IsInDocBody())
135 {
136 SwPosition aDummyPos( pDoc->GetNodes().GetEndOfContent() );
137 pTextNode = GetBodyTextNode( *pDoc, aDummyPos, rFrame );
138 }
139
140 if ( pTextNode )
141 {
142 ChangeExpansion( *pTextNode, bSrchNum, rFrame.getRootFrame() );
143 }
144 }
145
ChangeExpansion(const SwTextNode & rTextNd,bool bSrchNum,SwRootFrame const * const pLayout)146 void SwChapterField::ChangeExpansion(const SwTextNode &rTextNd, bool bSrchNum,
147 SwRootFrame const*const pLayout)
148 {
149 State & rState(pLayout && pLayout->IsHideRedlines() ? m_StateRLHidden : m_State);
150 rState.sNumber.clear();
151 rState.sTitle.clear();
152 rState.sPost.clear();
153 rState.sPre.clear();
154
155 SwDoc* pDoc = const_cast<SwDoc*>(rTextNd.GetDoc());
156 const SwTextNode *pTextNd = rTextNd.FindOutlineNodeOfLevel(rState.nLevel, pLayout);
157 if( pTextNd )
158 {
159 if( bSrchNum )
160 {
161 const SwTextNode* pONd = pTextNd;
162 do {
163 if( pONd && pONd->GetTextColl() )
164 {
165 sal_uInt8 nPrevLvl = rState.nLevel;
166
167 OSL_ENSURE( pONd->GetAttrOutlineLevel() >= 0 && pONd->GetAttrOutlineLevel() <= MAXLEVEL,
168 "<SwChapterField::ChangeExpansion(..)> - outline node with inconsistent outline level. Serious defect." );
169 rState.nLevel = static_cast<sal_uInt8>(pONd->GetAttrOutlineLevel());
170
171 if (nPrevLvl < rState.nLevel)
172 rState.nLevel = nPrevLvl;
173 else if( SVX_NUM_NUMBER_NONE != pDoc->GetOutlineNumRule()
174 ->Get( rState.nLevel ).GetNumberingType() )
175 {
176 pTextNd = pONd;
177 break;
178 }
179
180 if (!rState.nLevel--)
181 break;
182 pONd = pTextNd->FindOutlineNodeOfLevel(rState.nLevel, pLayout);
183 }
184 else
185 break;
186 } while( true );
187 }
188
189 // get the number without Pre-/Post-fixstrings
190
191 if ( pTextNd->IsOutline() )
192 {
193 // correction of refactoring done by cws swnumtree:
194 // retrieve numbering string without prefix and suffix strings
195 // as stated in the above german comment.
196 rState.sNumber = pTextNd->GetNumString(false, MAXLEVEL, pLayout);
197
198 SwNumRule* pRule( pTextNd->GetNumRule() );
199 if ( pTextNd->IsCountedInList() && pRule )
200 {
201 int nListLevel = pTextNd->GetActualListLevel();
202 if (nListLevel < 0)
203 nListLevel = 0;
204 if (nListLevel >= MAXLEVEL)
205 nListLevel = MAXLEVEL - 1;
206
207 const SwNumFormat& rNFormat = pRule->Get(nListLevel);
208 rState.sPost = rNFormat.GetSuffix();
209 rState.sPre = rNFormat.GetPrefix();
210 }
211 }
212 else
213 {
214 rState.sNumber = "??";
215 }
216
217 rState.sTitle = removeControlChars(sw::GetExpandTextMerged(pLayout,
218 *pTextNd, false, false, ExpandMode(0)));
219 }
220 }
221
QueryValue(uno::Any & rAny,sal_uInt16 nWhichId) const222 bool SwChapterField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
223 {
224 switch( nWhichId )
225 {
226 case FIELD_PROP_BYTE1:
227 rAny <<= static_cast<sal_Int8>(m_State.nLevel);
228 break;
229
230 case FIELD_PROP_USHORT1:
231 {
232 sal_Int16 nRet;
233 switch( GetFormat() )
234 {
235 case CF_NUMBER: nRet = text::ChapterFormat::NUMBER; break;
236 case CF_TITLE: nRet = text::ChapterFormat::NAME; break;
237 case CF_NUMBER_NOPREPST:
238 nRet = text::ChapterFormat::DIGIT;
239 break;
240 case CF_NUM_NOPREPST_TITLE:
241 nRet = text::ChapterFormat::NO_PREFIX_SUFFIX;
242 break;
243 case CF_NUM_TITLE:
244 default: nRet = text::ChapterFormat::NAME_NUMBER;
245 }
246 rAny <<= nRet;
247 }
248 break;
249
250 default:
251 assert(false);
252 }
253 return true;
254 }
255
PutValue(const uno::Any & rAny,sal_uInt16 nWhichId)256 bool SwChapterField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
257 {
258 bool bRet = true;
259 switch( nWhichId )
260 {
261 case FIELD_PROP_BYTE1:
262 {
263 sal_Int8 nTmp = 0;
264 rAny >>= nTmp;
265 if(nTmp >= 0 && nTmp < MAXLEVEL)
266 {
267 m_State.nLevel = nTmp;
268 m_StateRLHidden.nLevel = nTmp;
269 }
270 else
271 bRet = false;
272 break;
273 }
274
275 case FIELD_PROP_USHORT1:
276 {
277 sal_Int16 nVal = 0;
278 rAny >>= nVal;
279 switch( nVal )
280 {
281 case text::ChapterFormat::NAME: SetFormat(CF_TITLE); break;
282 case text::ChapterFormat::NUMBER: SetFormat(CF_NUMBER); break;
283 case text::ChapterFormat::NO_PREFIX_SUFFIX:
284 SetFormat(CF_NUM_NOPREPST_TITLE);
285 break;
286 case text::ChapterFormat::DIGIT:
287 SetFormat(CF_NUMBER_NOPREPST);
288 break;
289
290 default: SetFormat(CF_NUM_TITLE);
291 }
292 }
293 break;
294
295 default:
296 assert(false);
297 }
298 return bRet;
299 }
300
301 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
302