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