|
1 /* |
|
2 * Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include "FRMPAGE.H" |
|
20 #include "FRMTLAY.H" |
|
21 #include "FRMCONST.H" |
|
22 #include <txtlaydc.h> |
|
23 |
|
24 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS |
|
25 #include "FRMCONST_INTERNAL.H" |
|
26 #include "FRMCONST_PARTNER.H" |
|
27 #endif |
|
28 |
|
29 /** Allocates and constructs a CTextPaginator object with a page list, the |
|
30 printer device for which the document is to be paginated and an active object |
|
31 priority. |
|
32 |
|
33 @param aPrinterDevice Pointer to the printer device for which the document is |
|
34 to be paginated. This must be provided. |
|
35 @param aCharsPerPage The page list. This is a client-provided array into which |
|
36 characters-per-page values are written. Ownership of the array remains with the |
|
37 client. |
|
38 @param aPriority Integer specifying the active object priority. A number of |
|
39 standard priorities are specified in CActive::TPriority. |
|
40 @return Pointer to the new paginator object. */ |
|
41 EXPORT_C CTextPaginator* CTextPaginator::NewL(CPrinterDevice* aPrinterDevice,CArrayFix<TInt>* aPageList,TInt aPriority) |
|
42 { |
|
43 CTextPaginator* self=new(ELeave) CTextPaginator(aPriority); |
|
44 CleanupStack::PushL(self); |
|
45 self->ConstructL(aPrinterDevice,aPageList); |
|
46 CleanupStack::Pop(); |
|
47 return self; |
|
48 } |
|
49 |
|
50 /** Destructor. Cancels the active object, if any. */ |
|
51 EXPORT_C CTextPaginator::~CTextPaginator() |
|
52 { |
|
53 Cancel(); |
|
54 delete iLayout; |
|
55 delete iPageLineArray; |
|
56 delete iTempPageList; |
|
57 } |
|
58 |
|
59 /** Sets a pagination observer (an instance of a class inherited from |
|
60 MPaginateObserver). The use of an observer is optional. |
|
61 |
|
62 An observer may be used when paginating a complete document in the background |
|
63 using the function PaginateCompleteDocumentL(). The observer notifies |
|
64 completion of pages, cancellation, errors, and on completion of multiple |
|
65 pagination. |
|
66 |
|
67 @param aObserver Observer object inherited from MPaginateObserver. */ |
|
68 EXPORT_C void CTextPaginator::SetObserver(MPaginateObserver* aObserver) |
|
69 { |
|
70 |
|
71 iObserver=aObserver; |
|
72 } |
|
73 |
|
74 /** Sets a pointer to the document which is to be paginated. |
|
75 @param aLayDoc The document to paginate. */ |
|
76 EXPORT_C void CTextPaginator::SetDocumentL(MLayDoc* aLayDoc) |
|
77 { |
|
78 |
|
79 SetOrReplaceDocumentL(aLayDoc); |
|
80 iPaginator.Reset(); |
|
81 iDocPos=0; |
|
82 SetLayoutDimensions(); |
|
83 } |
|
84 |
|
85 /** Sets a pointer to the printer device for which the document is to be |
|
86 paginated. |
|
87 |
|
88 Note: This function must be called, and SetDocumentL() must have been called |
|
89 beforehand. |
|
90 |
|
91 @param aPrinterDevice The printer device. */ |
|
92 EXPORT_C void CTextPaginator::SetPrinterDevice(CPrinterDevice* aPrinterDevice) |
|
93 { |
|
94 __ASSERT_ALWAYS(iLayout,FormPanic(EFDocumentToPaginateNotSet)); |
|
95 iPrinterDevice=aPrinterDevice; |
|
96 iLayout->SetImageDeviceMap(aPrinterDevice); |
|
97 |
|
98 iPageSizeInTwips=aPrinterDevice->CurrentPageSpecInTwips().OrientedPageSize(); |
|
99 SetLayoutDimensions(); |
|
100 } |
|
101 |
|
102 /** Sets the page width and height in twips, overriding the current values |
|
103 specified in the printer device. |
|
104 @param aPageSpec Contains the new page dimensions. */ |
|
105 EXPORT_C void CTextPaginator::SetPageSpecInTwips(const TPageSpec& aPageSpec) |
|
106 { |
|
107 |
|
108 iPageSizeInTwips=aPageSpec.OrientedPageSize(); |
|
109 SetLayoutDimensions(); |
|
110 } |
|
111 |
|
112 /** Sets the widths of the page margins in twips. |
|
113 |
|
114 The page margin exists on all four sides of the page. It does not include the |
|
115 line cursor or labels margins. The labels and line cursor margins are set using |
|
116 SetTextMarginWidthsInTwips(). |
|
117 |
|
118 @param aPageMargins The page margin widths. */ |
|
119 EXPORT_C void CTextPaginator::SetPageMarginsInTwips(const TMargins& aPageMargins) |
|
120 { |
|
121 iPageMarginsInTwips=aPageMargins; |
|
122 SetLayoutDimensions(); |
|
123 } |
|
124 |
|
125 /** Sets the widths in twips of: |
|
126 |
|
127 the labels margin the area within which paragraph labels are displayed, |
|
128 |
|
129 the gutter margin (also known as the line cursor margin) exists between the |
|
130 labels margin and the text area. |
|
131 |
|
132 @param aLabelMarginWidth The labels margin width. |
|
133 @param aGutterMarginWidth The gutter margin width. */ |
|
134 EXPORT_C void CTextPaginator::SetTextMarginWidthsInTwips(TInt aLabelMarginWidth |
|
135 ,TInt aGutterMarginWidth) |
|
136 { |
|
137 iLabelMarginWidthInTwips=aLabelMarginWidth; |
|
138 iGutterMarginWidthInTwips=aGutterMarginWidth; |
|
139 SetLayoutDimensions(); |
|
140 } |
|
141 |
|
142 CTextPaginator::CTextPaginator(TInt aPriority) |
|
143 :CActive(aPriority) |
|
144 { |
|
145 } |
|
146 |
|
147 void CTextPaginator::ConstructL(CPrinterDevice* aPrinterDevice,CArrayFix<TInt>* aPageList) |
|
148 { |
|
149 |
|
150 iPageLineArray=new(ELeave) CArrayFixFlat<TPageLine>(EPageLineArrayGranularity); |
|
151 iTempPageList=new(ELeave) CArrayFixFlat<TInt>(EPageListArrayGranularity); |
|
152 iPrinterDevice=aPrinterDevice; |
|
153 iPageList=aPageList; |
|
154 |
|
155 iPaginator.SetArray(iTempPageList); |
|
156 iPaginator.SetPageHeight(TextSizeInPixels().iHeight); |
|
157 |
|
158 iPageSizeInTwips=iPrinterDevice->CurrentPageSpecInTwips().OrientedPageSize(); |
|
159 SetLayoutDimensions(); |
|
160 ResetPaginator(); |
|
161 } |
|
162 |
|
163 /** Initiates pagination of a complete document in the background using an |
|
164 active object. To start pagination, use either this function, or else |
|
165 incrementally paginate with AppendTextL() do not try to use both functions |
|
166 together. |
|
167 |
|
168 Note: SetDocumentL() must have been called beforehand, or a panic occurs. */ |
|
169 EXPORT_C void CTextPaginator::PaginateCompleteDocumentL() |
|
170 { |
|
171 __ASSERT_ALWAYS(iLayout,FormPanic(EFDocumentToPaginateNotSet)); |
|
172 if (iPageList->Count()==0) |
|
173 iPageList->AppendL(iLayDoc->LdDocumentLength()); |
|
174 if (!IsAdded()) |
|
175 CActiveScheduler::Add(this); // Adds itself to the active scheduler |
|
176 iMode=EFPaginateCompleteDocument; |
|
177 ResetPaginator(); |
|
178 Reque(); |
|
179 } |
|
180 |
|
181 /** Paginates incrementally as a document is being constructed (by appending |
|
182 paragraphs, for example). Call this function every time text is added to the |
|
183 document. |
|
184 |
|
185 The function PaginationCompletedL() should be called at the end (in order to |
|
186 complete the last entry in the characters-per-page array). |
|
187 |
|
188 Use either this function, or else paginate in the background with |
|
189 PaginateCompleteDocumentL() - do not try to use both functions together. |
|
190 |
|
191 Note: SetDocumentL() must have been called beforehand, or a panic occurs. |
|
192 |
|
193 @param aCumulativeDocPos The first time the function is called, this should be |
|
194 given a value of zero. Returns the last document position which has been |
|
195 paginated. |
|
196 @return A count of the current number of pages. */ |
|
197 EXPORT_C TInt CTextPaginator::AppendTextL(TInt& aCumulativeDocPos) |
|
198 { |
|
199 __ASSERT_ALWAYS(iLayout,FormPanic(EFDocumentToPaginateNotSet)); |
|
200 __ASSERT_ALWAYS(aCumulativeDocPos<iLayout->DocumentLength(),FormPanic(EFInvalidDocPos)); |
|
201 iMode=EFPaginateIncrementally; |
|
202 |
|
203 if (iPageList->Count()==0) |
|
204 ResetPaginator(); |
|
205 |
|
206 TBool moreToDo=ETrue; |
|
207 while(moreToDo) |
|
208 { |
|
209 moreToDo = iDocPos<=iLayDoc->LdDocumentLength(); |
|
210 if (moreToDo) |
|
211 { |
|
212 TrapPaginateParagraphL(); |
|
213 } |
|
214 else |
|
215 { |
|
216 if (iMode==EFPaginateCompleteDocument) |
|
217 { |
|
218 iPaginator.FlushL(iDocPos); |
|
219 PageCompleted(); |
|
220 } |
|
221 iPageLineArray->Reset(); |
|
222 iPageLineArray->Compress(); |
|
223 } |
|
224 } |
|
225 |
|
226 aCumulativeDocPos=iDocPos; |
|
227 |
|
228 TRAPD(err,CopyTempPageListL()); |
|
229 if (err) |
|
230 LeaveL(err); |
|
231 return iPageList->Count(); |
|
232 } |
|
233 |
|
234 /** This function should be called when incremental pagination has completed |
|
235 (see AppendTextL()), to complete the final entry in the page list. If an |
|
236 observer has been set, calls its NotifyCompletion() function. |
|
237 |
|
238 @return Count of total number of pages. */ |
|
239 EXPORT_C TInt CTextPaginator::PaginationCompletedL() |
|
240 { |
|
241 TRAPD(err,iPaginator.FlushL(iDocPos)); |
|
242 if (err) |
|
243 LeaveL(err); |
|
244 iLayout->DiscardFormat(); |
|
245 TRAP(err,CopyTempPageListL()); |
|
246 if (err) |
|
247 LeaveL(err); |
|
248 if (iObserver) |
|
249 iObserver->NotifyCompletion(); |
|
250 return iPageList->Count(); |
|
251 } |
|
252 |
|
253 void CTextPaginator::RunL() |
|
254 // |
|
255 // Called by active scheduler. |
|
256 // Paginates a document one paragraph at a time through succeeding |
|
257 // calls. |
|
258 // |
|
259 { |
|
260 TBool moreToDo = iDocPos<=iLayDoc->LdDocumentLength(); |
|
261 if (moreToDo) |
|
262 { |
|
263 TrapPaginateParagraphL(); |
|
264 } |
|
265 else |
|
266 { |
|
267 if (iMode==EFPaginateCompleteDocument) |
|
268 { |
|
269 iPaginator.FlushL(iDocPos); |
|
270 PageCompleted(); |
|
271 } |
|
272 iPageLineArray->Reset(); |
|
273 iPageLineArray->Compress(); |
|
274 } |
|
275 |
|
276 if (moreToDo) |
|
277 Reque(); |
|
278 else |
|
279 { |
|
280 iLayout->DiscardFormat(); |
|
281 TRAPD(err,CopyTempPageListL()); |
|
282 if (err) |
|
283 LeaveL(err); |
|
284 if (iObserver) |
|
285 iObserver->NotifyCompletion(); |
|
286 } |
|
287 } |
|
288 |
|
289 void CTextPaginator::DoCancel() |
|
290 { |
|
291 iPaginator.Reset(); |
|
292 iLayout->DiscardFormat(); |
|
293 iDocPos=0; |
|
294 iPageBreakChar=EFalse; |
|
295 |
|
296 if (iObserver) |
|
297 iObserver->NotifyError(KErrCancel); |
|
298 } |
|
299 |
|
300 void CTextPaginator::SetLayoutDimensions() |
|
301 { |
|
302 iPaginator.SetPageHeight(TextSizeInPixels().iHeight); |
|
303 if (iLayout) |
|
304 iLayout->SetFormatMode(CLayoutData::EFPrintMode,TextRectInTwips().Width(),iPrinterDevice); |
|
305 } |
|
306 |
|
307 void CTextPaginator::SetOrReplaceDocumentL(MLayDoc* aLayDoc) |
|
308 { |
|
309 |
|
310 iLayDoc=aLayDoc; |
|
311 if (iLayout) |
|
312 iLayout->SetLayDoc(aLayDoc); |
|
313 else |
|
314 iLayout=CTextLayout::NewL(aLayDoc,TextSizeInPixels().iWidth); |
|
315 iLayout->SetImageDeviceMap(iPrinterDevice); |
|
316 } |
|
317 |
|
318 TRect CTextPaginator::TextRectInTwips() const |
|
319 { |
|
320 TRect textRect; |
|
321 |
|
322 textRect.iTl.iX=iPageMarginsInTwips.iLeft+iGutterMarginWidthInTwips+iLabelMarginWidthInTwips; |
|
323 textRect.iTl.iY=iPageMarginsInTwips.iTop; |
|
324 textRect.iBr.iX=iPageSizeInTwips.iWidth-iPageMarginsInTwips.iRight; |
|
325 textRect.iBr.iY=iPageSizeInTwips.iHeight-iPageMarginsInTwips.iBottom; |
|
326 |
|
327 return textRect; |
|
328 } |
|
329 |
|
330 TSize CTextPaginator::TextSizeInPixels() const |
|
331 { |
|
332 TRect textRect=iPrinterDevice->TwipsToPixels(TextRectInTwips()); |
|
333 |
|
334 return textRect.Size(); |
|
335 } |
|
336 |
|
337 void CTextPaginator::TrapPaginateParagraphL() |
|
338 { |
|
339 TRAPD(err,PaginateParagraphL()); |
|
340 if (err) |
|
341 LeaveL(err); |
|
342 } |
|
343 |
|
344 void CTextPaginator::PaginateParagraphL() |
|
345 { |
|
346 TInt lineHeight; |
|
347 TBool keepTogether; // Prevents page break in a paragraph when ETrue. |
|
348 TBool keepWithNext; // Prevents page break between this & next para when ETrue. |
|
349 TBool startNewPage; // Inserts page break before this paragraph when ETrue. |
|
350 TBool widowOrphan; // Prevents widowing/orphaning of para. lines when ETrue. |
|
351 TPageLine pageLine; |
|
352 TInt numLines; |
|
353 CParaFormat* paraFormat=NULL; |
|
354 |
|
355 paraFormat=CParaFormat::NewLC(); |
|
356 iLayDoc->GetParagraphFormatL(paraFormat,iDocPos); |
|
357 TInt docPos=iDocPos; |
|
358 TBool startOfPara=(iLayDoc->LdToParagraphStart(docPos)==0); |
|
359 |
|
360 keepTogether=paraFormat->iKeepTogether; |
|
361 keepWithNext=paraFormat->iKeepWithNext; |
|
362 startNewPage=paraFormat->iStartNewPage; |
|
363 widowOrphan=paraFormat->iWidowOrphan; |
|
364 |
|
365 iPageLineArray->Reset(); // Better safe than sorry at the moment ### |
|
366 iPageLineArray->Compress(); |
|
367 |
|
368 TInt lines=0; |
|
369 TBool moreToDo = ETrue; |
|
370 do |
|
371 { |
|
372 pageLine.iDocPos=iDocPos; |
|
373 pageLine.iStartNewPage=EFalse; |
|
374 if (iPageBreakChar) |
|
375 pageLine.iStartNewPage=ETrue; |
|
376 moreToDo=iLayout->FormatLineL(paraFormat,iDocPos,lineHeight,iPageBreakChar); |
|
377 lines++; |
|
378 pageLine.iLineHeight=lineHeight; |
|
379 if (keepTogether) |
|
380 pageLine.iKeepWithNext=ETrue; |
|
381 else |
|
382 pageLine.iKeepWithNext=EFalse; |
|
383 iPageLineArray->AppendL(pageLine); |
|
384 } while (moreToDo && lines<EFMaximumNumberLinesInBlock); |
|
385 |
|
386 |
|
387 TBool endOfPara=(!moreToDo); |
|
388 TBool penultimateLine=EFalse; |
|
389 numLines=iPageLineArray->Count(); |
|
390 if (!endOfPara) |
|
391 { |
|
392 docPos=iDocPos; |
|
393 TBool pageBreakChar; |
|
394 penultimateLine=(!iLayout->FormatLineL(paraFormat,docPos,lineHeight,pageBreakChar)); |
|
395 } |
|
396 |
|
397 if (startNewPage && startOfPara) |
|
398 (*iPageLineArray)[0].iStartNewPage=ETrue; |
|
399 |
|
400 if (keepTogether && endOfPara) |
|
401 (*iPageLineArray)[numLines-1].iKeepWithNext=EFalse; |
|
402 |
|
403 if (keepWithNext && endOfPara) |
|
404 (*iPageLineArray)[numLines-1].iKeepWithNext=ETrue; |
|
405 |
|
406 if (widowOrphan) |
|
407 { |
|
408 if (startOfPara) |
|
409 (*iPageLineArray)[0].iKeepWithNext=ETrue; |
|
410 if (endOfPara && numLines>=2) |
|
411 (*iPageLineArray)[numLines-2].iKeepWithNext=ETrue; |
|
412 else if (penultimateLine) |
|
413 (*iPageLineArray)[numLines-1].iKeepWithNext=ETrue; |
|
414 } |
|
415 |
|
416 TBool pageBreak = EFalse; |
|
417 for (TInt i=0; i<numLines; i++) |
|
418 { |
|
419 pageBreak=iPaginator.AppendLineL((*iPageLineArray)[i]); |
|
420 if (pageBreak) |
|
421 PageCompleted(); |
|
422 } |
|
423 |
|
424 iPageLineArray->Reset(); |
|
425 iPageLineArray->Compress(); |
|
426 |
|
427 CleanupStack::PopAndDestroy(); // delete format; |
|
428 } |
|
429 |
|
430 void CTextPaginator::PageCompleted() |
|
431 { |
|
432 if (iObserver) |
|
433 iObserver->NotifyPageCompletion(iTempPageList->Count()); |
|
434 } |
|
435 |
|
436 void CTextPaginator::Reque() |
|
437 // |
|
438 // Called just before Paginate Process goes to sleep to set it active |
|
439 // |
|
440 { |
|
441 TRequestStatus *pS=(&iStatus); |
|
442 User::RequestComplete(pS,0); |
|
443 SetActive(); |
|
444 } |
|
445 |
|
446 void CTextPaginator::ResetPaginator() |
|
447 // |
|
448 { |
|
449 |
|
450 iDocPos=0; |
|
451 iPageBreakChar=EFalse; |
|
452 iPaginator.Reset(); |
|
453 } |
|
454 |
|
455 void CTextPaginator::CopyTempPageListL() |
|
456 // |
|
457 // Copies temp page list to one that external user sees |
|
458 // |
|
459 { |
|
460 __ASSERT_DEBUG(iTempPageList->Count()>=1||iMode==EFPaginateIncrementally,FormPanic(EFPageListEmpty)); |
|
461 TRAPD(err,iPageList->ResizeL(iTempPageList->Count())); |
|
462 if (err) |
|
463 LeaveL(err); |
|
464 |
|
465 {for(TInt ii=0;ii<iTempPageList->Count();ii++) |
|
466 (*iPageList)[ii]=(*iTempPageList)[ii]; |
|
467 } |
|
468 } |
|
469 |
|
470 |
|
471 void CTextPaginator::LeaveL(TInt aErr) |
|
472 // |
|
473 // Something has left |
|
474 // Reset everything. |
|
475 // |
|
476 { |
|
477 iPaginator.Reset(); |
|
478 iLayout->DiscardFormat(); |
|
479 iDocPos=0; |
|
480 |
|
481 iPageLineArray->Reset(); |
|
482 iPageLineArray->Compress(); |
|
483 iTempPageList->Reset(); |
|
484 iTempPageList->Compress(); |
|
485 |
|
486 if (iObserver) |
|
487 iObserver->NotifyError(aErr); |
|
488 |
|
489 User::Leave(aErr); |
|
490 } |
|
491 |