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 <ToxTextGenerator.hxx>
21 :
22 : #include "chpfld.hxx"
23 : #include "cntfrm.hxx"
24 : #include "fchrfmt.hxx"
25 : #include "doc.hxx"
26 : #include <IDocumentLayoutAccess.hxx>
27 : #include <IDocumentStylePoolAccess.hxx>
28 : #include "fmtinfmt.hxx"
29 : #include "ndtxt.hxx"
30 : #include "pagedesc.hxx"
31 : #include "tox.hxx"
32 : #include "txmsrt.hxx"
33 : #include "fmtautofmt.hxx"
34 : #include "DocumentSettingManager.hxx"
35 : #include "SwStyleNameMapper.hxx"
36 : #include "swatrset.hxx"
37 : #include "ToxWhitespaceStripper.hxx"
38 : #include "ToxLinkProcessor.hxx"
39 : #include "ToxTabStopTokenHandler.hxx"
40 : #include "txatbase.hxx"
41 :
42 : #include "svl/itemiter.hxx"
43 :
44 : #include <boost/foreach.hpp>
45 : #include <boost/make_shared.hpp>
46 : #include <cassert>
47 :
48 : namespace {
49 :
50 12 : bool sortTabHasNoToxSourcesOrFirstToxSourceHasNoNode(const SwTOXSortTabBase& sortTab)
51 : {
52 12 : if (sortTab.aTOXSources.empty()) {
53 4 : return true;
54 : }
55 8 : if (sortTab.aTOXSources.at(0).pNd != NULL) {
56 8 : return true;
57 : }
58 0 : return false;
59 : }
60 :
61 : } // end anonymous namespace
62 :
63 : namespace sw {
64 :
65 : OUString
66 12 : ToxTextGenerator::GetNumStringOfFirstNode( const SwTOXSortTabBase& rBase, bool bUsePrefix, sal_uInt8 nLevel )
67 : {
68 12 : if (sortTabHasNoToxSourcesOrFirstToxSourceHasNoNode(rBase)) {
69 12 : return OUString();
70 : }
71 :
72 0 : OUString sRet;
73 0 : if (!rBase.pTxtMark) { // only if it's not a Mark
74 0 : return sRet;
75 : }
76 :
77 0 : const SwTxtNode* pNd = rBase.aTOXSources[0].pNd->GetTxtNode();
78 0 : if (!pNd) {
79 0 : return sRet;
80 : }
81 :
82 0 : const SwNumRule* pRule = pNd->GetNumRule();
83 0 : if (!pRule) {
84 0 : return sRet;
85 : }
86 :
87 0 : if (pNd->GetActualListLevel() < MAXLEVEL) {
88 0 : sRet = pNd->GetNumString(bUsePrefix, nLevel);
89 : }
90 :
91 0 : return sRet;
92 : }
93 :
94 :
95 12 : ToxTextGenerator::ToxTextGenerator(const SwForm& toxForm,
96 : boost::shared_ptr<ToxTabStopTokenHandler> tabStopHandler)
97 : : mToxForm(toxForm),
98 0 : mLinkProcessor(new ToxLinkProcessor()),
99 12 : mTabStopTokenHandler(tabStopHandler)
100 12 : {;}
101 :
102 12 : ToxTextGenerator::~ToxTextGenerator()
103 12 : {;}
104 :
105 : OUString
106 0 : ToxTextGenerator::HandleChapterToken(const SwTOXSortTabBase& rBase, const SwFormToken& aToken,
107 : SwDoc* pDoc) const
108 : {
109 0 : if (sortTabHasNoToxSourcesOrFirstToxSourceHasNoNode(rBase)) {
110 0 : return OUString();
111 : }
112 :
113 : // A bit tricky: Find a random Frame
114 0 : const SwCntntNode* contentNode = rBase.aTOXSources.at(0).pNd->GetCntntNode();
115 0 : if (!contentNode) {
116 0 : return OUString();
117 : }
118 :
119 : // #i53420#
120 0 : const SwCntntFrm* contentFrame = contentNode->getLayoutFrm(pDoc->getIDocumentLayoutAccess().GetCurrentLayout());
121 0 : if (!contentFrame) {
122 0 : return OUString();
123 : }
124 :
125 0 : return GenerateTextForChapterToken(aToken, contentFrame, contentNode);
126 : }
127 :
128 : OUString
129 8 : ToxTextGenerator::GenerateTextForChapterToken(const SwFormToken& chapterToken, const SwCntntFrm* contentFrame,
130 : const SwCntntNode *contentNode) const
131 : {
132 8 : OUString retval;
133 :
134 16 : SwChapterFieldType chapterFieldType;
135 16 : SwChapterField aFld = ObtainChapterField(&chapterFieldType, &chapterToken, contentFrame, contentNode);
136 :
137 : //---> #i89791#
138 : // continue to support CF_NUMBER and CF_NUM_TITLE in order to handle ODF 1.0/1.1 written by OOo 3.x
139 : // in the same way as OOo 2.x would handle them.
140 8 : if (CF_NUM_NOPREPST_TITLE == chapterToken.nChapterFormat || CF_NUMBER == chapterToken.nChapterFormat) {
141 4 : retval += aFld.GetNumber(); // get the string number without pre/postfix
142 : }
143 4 : else if (CF_NUMBER_NOPREPST == chapterToken.nChapterFormat || CF_NUM_TITLE == chapterToken.nChapterFormat) {
144 4 : retval += aFld.GetNumber();
145 4 : retval += " ";
146 4 : retval += aFld.GetTitle();
147 0 : } else if (CF_TITLE == chapterToken.nChapterFormat) {
148 0 : retval += aFld.GetTitle();
149 : }
150 16 : return retval;
151 : }
152 :
153 : // Add parameter <_TOXSectNdIdx> and <_pDefaultPageDesc> in order to control,
154 : // which page description is used, no appropriate one is found.
155 : void
156 8 : ToxTextGenerator::GenerateText(SwDoc* pDoc, const std::vector<SwTOXSortTabBase*> &entries,
157 : sal_uInt16 indexOfEntryToProcess, sal_uInt16 numberOfEntriesToProcess)
158 : {
159 : // pTOXNd is only set at the first mark
160 8 : SwTxtNode* pTOXNd = (SwTxtNode*)entries.at(indexOfEntryToProcess)->pTOXNd;
161 : // FIXME this operates directly on the node text
162 8 : OUString & rTxt = const_cast<OUString&>(pTOXNd->GetTxt());
163 8 : rTxt = "";
164 16 : for(sal_uInt16 nIndex = indexOfEntryToProcess; nIndex < indexOfEntryToProcess + numberOfEntriesToProcess; nIndex++)
165 : {
166 8 : if(nIndex > indexOfEntryToProcess)
167 0 : rTxt += ", "; // comma separation
168 : // Initialize String with the Pattern from the form
169 8 : const SwTOXSortTabBase& rBase = *entries.at(nIndex);
170 8 : sal_uInt16 nLvl = rBase.GetLevel();
171 : OSL_ENSURE( nLvl < mToxForm.GetFormMax(), "invalid FORM_LEVEL");
172 :
173 8 : SvxTabStopItem aTStops( 0, 0, SVX_TAB_ADJUST_DEFAULT, RES_PARATR_TABSTOP );
174 : // create an enumerator
175 : // #i21237#
176 16 : SwFormTokens aPattern = mToxForm.GetPattern(nLvl);
177 8 : SwFormTokens::iterator aIt = aPattern.begin();
178 : // remove text from node
179 58 : while(aIt != aPattern.end()) // #i21237#
180 : {
181 42 : SwFormToken aToken = *aIt; // #i21237#
182 42 : sal_Int32 nStartCharStyle = rTxt.getLength();
183 42 : switch( aToken.eTokenType )
184 : {
185 : case TOKEN_ENTRY_NO:
186 : // for TOC numbering
187 6 : rTxt += GetNumStringOfFirstNode( rBase, aToken.nChapterFormat == CF_NUMBER, static_cast<sal_uInt8>(aToken.nOutlineLevel - 1) ) ;
188 6 : break;
189 :
190 : case TOKEN_ENTRY_TEXT: {
191 6 : HandledTextToken htt = HandleTextToken(rBase, pDoc->GetAttrPool());
192 6 : ApplyHandledTextToken(htt, *pTOXNd);
193 : }
194 6 : break;
195 :
196 : case TOKEN_ENTRY:
197 : {
198 : // for TOC numbering
199 2 : rTxt += GetNumStringOfFirstNode( rBase, true, MAXLEVEL );
200 2 : SwIndex aIdx( pTOXNd, rTxt.getLength() );
201 4 : ToxWhitespaceStripper stripper(rBase.GetTxt().sText);
202 4 : pTOXNd->InsertText(stripper.GetStrippedString(), aIdx);
203 : }
204 2 : break;
205 :
206 : case TOKEN_TAB_STOP: {
207 : ToxTabStopTokenHandler::HandledTabStopToken htst =
208 8 : mTabStopTokenHandler->HandleTabStopToken(aToken, *pTOXNd, pDoc->getIDocumentLayoutAccess().GetCurrentLayout());
209 8 : rTxt += htst.text;
210 8 : aTStops.Insert(htst.tabStop);
211 8 : break;
212 : }
213 :
214 : case TOKEN_TEXT:
215 0 : rTxt += aToken.sText;
216 0 : break;
217 :
218 : case TOKEN_PAGE_NUMS:
219 8 : rTxt += ConstructPageNumberPlaceholder(rBase.aTOXSources.size());
220 8 : break;
221 :
222 : case TOKEN_CHAPTER_INFO:
223 0 : rTxt += HandleChapterToken(rBase, aToken, pDoc);
224 0 : break;
225 :
226 : case TOKEN_LINK_START:
227 6 : mLinkProcessor->StartNewLink(rTxt.getLength(), aToken.sCharStyleName);
228 6 : break;
229 :
230 : case TOKEN_LINK_END:
231 6 : mLinkProcessor->CloseLink(rTxt.getLength(), rBase.GetURL());
232 6 : break;
233 :
234 : case TOKEN_AUTHORITY:
235 : {
236 0 : ToxAuthorityField eField = (ToxAuthorityField)aToken.nAuthorityField;
237 0 : SwIndex aIdx( pTOXNd, rTxt.getLength() );
238 0 : rBase.FillText( *pTOXNd, aIdx, static_cast<sal_uInt16>(eField) );
239 : }
240 0 : break;
241 0 : case TOKEN_END: break;
242 : }
243 :
244 42 : if ( !aToken.sCharStyleName.isEmpty() )
245 : {
246 : SwCharFmt* pCharFmt;
247 6 : if( USHRT_MAX != aToken.nPoolId )
248 0 : pCharFmt = pDoc->getIDocumentStylePoolAccess().GetCharFmtFromPool( aToken.nPoolId );
249 : else
250 6 : pCharFmt = pDoc->FindCharFmtByName( aToken.sCharStyleName);
251 :
252 6 : if (pCharFmt)
253 : {
254 4 : SwFmtCharFmt aFmt( pCharFmt );
255 : pTOXNd->InsertItem( aFmt, nStartCharStyle,
256 4 : rTxt.getLength(), nsSetAttrMode::SETATTR_DONTEXPAND );
257 : }
258 : }
259 :
260 42 : ++aIt; // #i21237#
261 42 : }
262 :
263 8 : pTOXNd->SetAttr( aTStops );
264 8 : }
265 8 : mLinkProcessor->InsertLinkAttributes(*pTOXNd);
266 8 : }
267 :
268 : /*static*/ boost::shared_ptr<SfxItemSet>
269 0 : ToxTextGenerator::CollectAttributesForTox(const SwTxtAttr& hint, SwAttrPool& pool)
270 : {
271 0 : boost::shared_ptr<SfxItemSet> retval(new SfxItemSet(pool));
272 0 : if (hint.Which() != RES_TXTATR_AUTOFMT) {
273 0 : return retval;
274 : }
275 0 : const SwFmtAutoFmt& afmt = hint.GetAutoFmt();
276 0 : SfxItemIter aIter( *afmt.GetStyleHandle());
277 0 : const SfxPoolItem* pItem = aIter.GetCurItem();
278 : while (true) {
279 0 : if (pItem->Which() == RES_CHRATR_ESCAPEMENT ||
280 0 : pItem->Which() == RES_CHRATR_POSTURE ||
281 0 : pItem->Which() == RES_CHRATR_CJK_POSTURE ||
282 0 : pItem->Which() == RES_CHRATR_CTL_POSTURE) {
283 0 : SfxPoolItem* clonedItem = pItem->Clone(NULL);
284 0 : retval->Put(*clonedItem);
285 : }
286 0 : if (aIter.IsAtEnd()) {
287 0 : break;
288 : }
289 0 : pItem = aIter.NextItem();
290 : }
291 0 : return retval;
292 : }
293 :
294 : ToxTextGenerator::HandledTextToken
295 6 : ToxTextGenerator::HandleTextToken(const SwTOXSortTabBase& source, SwAttrPool& pool)
296 : {
297 6 : HandledTextToken result;
298 12 : ToxWhitespaceStripper stripper(source.GetTxt().sText);
299 6 : result.text = stripper.GetStrippedString();
300 :
301 6 : const SwTxtNode* pSrc = source.aTOXSources.at(0).pNd->GetTxtNode();
302 6 : if (!pSrc->HasHints()) {
303 6 : return result;
304 : }
305 0 : const SwpHints& hints = pSrc->GetSwpHints();
306 0 : for (size_t i = 0; i < hints.Count(); ++i) {
307 0 : const SwTxtAttr* hint = hints[i];
308 0 : boost::shared_ptr<SfxItemSet> attributesToClone = CollectAttributesForTox(*hint, pool);
309 0 : if (attributesToClone->Count() <= 0) {
310 0 : continue;
311 : }
312 0 : SwFmtAutoFmt* clone = static_cast<SwFmtAutoFmt*>(hint->GetAutoFmt().Clone());
313 0 : clone->SetStyleHandle(attributesToClone);
314 :
315 0 : result.autoFormats.push_back(clone);
316 0 : result.startPositions.push_back(stripper.GetPositionInStrippedString(hint->GetStart()));
317 0 : result.endPositions.push_back(stripper.GetPositionInStrippedString(*hint->GetAnyEnd()));
318 0 : }
319 0 : return result;
320 : }
321 :
322 : /*static*/ void
323 6 : ToxTextGenerator::ApplyHandledTextToken(const HandledTextToken& htt, SwTxtNode& targetNode)
324 : {
325 6 : sal_Int32 offset = targetNode.GetTxt().getLength();
326 6 : SwIndex aIdx(&targetNode, offset);
327 6 : targetNode.InsertText(htt.text, aIdx);
328 6 : for (size_t i=0; i < htt.autoFormats.size(); ++i) {
329 0 : targetNode.InsertItem(*htt.autoFormats.at(i),
330 0 : htt.startPositions.at(i) + offset,
331 0 : htt.endPositions.at(i) + offset);
332 6 : }
333 6 : }
334 :
335 : /*static*/ OUString
336 14 : ToxTextGenerator::ConstructPageNumberPlaceholder(size_t numberOfToxSources)
337 : {
338 14 : OUString retval;
339 14 : if (numberOfToxSources == 0) {
340 2 : return retval;
341 : }
342 : // Place holder for the PageNumber; we only respect the first one
343 12 : retval += OUString(C_NUM_REPL);
344 14 : for (size_t i = 1; i < numberOfToxSources; ++i) {
345 2 : retval += S_PAGE_DELI;
346 2 : retval += OUString(C_NUM_REPL);
347 : }
348 12 : retval += OUString(C_END_PAGE_NUM);
349 12 : return retval;
350 : }
351 :
352 : /*virtual*/ SwChapterField
353 0 : ToxTextGenerator::ObtainChapterField(SwChapterFieldType* chapterFieldType,
354 : const SwFormToken* chapterToken, const SwCntntFrm* contentFrame,
355 : const SwCntntNode* contentNode) const
356 : {
357 : assert(chapterToken);
358 : assert(chapterToken->nOutlineLevel >= 1);
359 :
360 0 : SwChapterField retval(chapterFieldType, chapterToken->nChapterFormat);
361 0 : retval.SetLevel(static_cast<sal_uInt8>(chapterToken->nOutlineLevel - 1));
362 : // #i53420#
363 0 : retval.ChangeExpansion(contentFrame, contentNode, true);
364 0 : return retval;
365 : }
366 270 : } // end namespace sw
367 :
368 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|