new rendering customization API for Vadim
[wxWidgets.git] / src / html / htmprint.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: htmprint.cpp
3 // Purpose: html printing classes
4 // Author: Vaclav Slavik
5 // Created: 25/09/99
6 // RCS-ID: $Id$
7 // Copyright: (c) Vaclav Slavik, 1999
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11
12 #ifdef __GNUG__
13 #pragma implementation "htmprint.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx/wx.h".
17 #include "wx/wxprec.h"
18
19 #include "wx/defs.h"
20
21 #ifdef __BORLANDC__
22 #pragma hdrstop
23 #endif
24
25 #ifndef WX_PRECOMP
26 #include "wx/log.h"
27 #include "wx/intl.h"
28 #include "wx/dc.h"
29 #endif
30
31 #if wxUSE_HTML && wxUSE_PRINTING_ARCHITECTURE && wxUSE_STREAMS
32
33 #include "wx/dc.h"
34 #include "wx/print.h"
35 #include "wx/printdlg.h"
36 #include "wx/html/htmprint.h"
37 #include "wx/wxhtml.h"
38 #include "wx/wfstream.h"
39
40
41 //--------------------------------------------------------------------------------
42 // wxHtmlDCRenderer
43 //--------------------------------------------------------------------------------
44
45
46 wxHtmlDCRenderer::wxHtmlDCRenderer() : wxObject()
47 {
48 m_DC = NULL;
49 m_Width = m_Height = 0;
50 m_Cells = NULL;
51 m_Parser = new wxHtmlWinParser(NULL);
52 m_FS = new wxFileSystem();
53 m_Parser->SetFS(m_FS);
54 }
55
56
57
58 wxHtmlDCRenderer::~wxHtmlDCRenderer()
59 {
60 if (m_Cells) delete m_Cells;
61 if (m_Parser) delete m_Parser;
62 if (m_FS) delete m_FS;
63 }
64
65
66
67 void wxHtmlDCRenderer::SetDC(wxDC *dc, double pixel_scale)
68 {
69 m_DC = dc;
70 m_Parser->SetDC(m_DC, pixel_scale);
71 }
72
73
74
75 void wxHtmlDCRenderer::SetSize(int width, int height)
76 {
77 m_Width = width;
78 m_Height = height;
79 }
80
81
82 void wxHtmlDCRenderer::SetHtmlText(const wxString& html, const wxString& basepath, bool isdir)
83 {
84 if (m_DC == NULL) return;
85
86 if (m_Cells != NULL) delete m_Cells;
87
88 m_FS->ChangePathTo(basepath, isdir);
89 m_Cells = (wxHtmlContainerCell*) m_Parser->Parse(html);
90 m_Cells->SetIndent(0, wxHTML_INDENT_ALL, wxHTML_UNITS_PIXELS);
91 m_Cells->Layout(m_Width);
92 }
93
94
95 void wxHtmlDCRenderer::SetFonts(wxString normal_face, wxString fixed_face,
96 const int *sizes)
97 {
98 m_Parser->SetFonts(normal_face, fixed_face, sizes);
99 if (m_DC == NULL && m_Cells != NULL) m_Cells->Layout(m_Width);
100 }
101
102
103 int wxHtmlDCRenderer::Render(int x, int y, int from, int dont_render, int to, int *known_pagebreaks, int number_of_pages)
104 {
105 int pbreak, hght;
106
107 if (m_Cells == NULL || m_DC == NULL) return 0;
108
109 pbreak = (int)(from + m_Height);
110 while (m_Cells->AdjustPagebreak(&pbreak, known_pagebreaks, number_of_pages)) {}
111 hght = pbreak - from;
112 if(to < hght)
113 hght = to;
114
115 if (!dont_render)
116 {
117 wxHtmlRenderingInfo rinfo;
118 wxDefaultHtmlRenderingStyle rstyle;
119 rinfo.SetStyle(&rstyle);
120 m_DC->SetBrush(*wxWHITE_BRUSH);
121 m_DC->SetClippingRegion(x, y, m_Width, hght);
122 m_Cells->Draw(*m_DC,
123 x, (y - from),
124 y, pbreak + (y /*- from*/),
125 rinfo);
126 m_DC->DestroyClippingRegion();
127 }
128
129 if (pbreak < m_Cells->GetHeight()) return pbreak;
130 else return GetTotalHeight();
131 }
132
133
134
135 int wxHtmlDCRenderer::GetTotalHeight()
136 {
137 if (m_Cells) return m_Cells->GetHeight();
138 else return 0;
139 }
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156 //--------------------------------------------------------------------------------
157 // wxHtmlPrintout
158 //--------------------------------------------------------------------------------
159
160
161
162 wxHtmlPrintout::wxHtmlPrintout(const wxString& title) : wxPrintout(title)
163 {
164 m_Renderer = new wxHtmlDCRenderer;
165 m_RendererHdr = new wxHtmlDCRenderer;
166 m_NumPages = wxHTML_PRINT_MAX_PAGES;
167 m_Document = m_BasePath = wxEmptyString; m_BasePathIsDir = TRUE;
168 m_Headers[0] = m_Headers[1] = wxEmptyString;
169 m_Footers[0] = m_Footers[1] = wxEmptyString;
170 m_HeaderHeight = m_FooterHeight = 0;
171 SetMargins(); // to default values
172 }
173
174
175
176 wxHtmlPrintout::~wxHtmlPrintout()
177 {
178 delete m_Renderer;
179 delete m_RendererHdr;
180 }
181
182
183
184 bool wxHtmlPrintout::OnBeginDocument(int startPage, int endPage)
185 {
186 int pageWidth, pageHeight, mm_w, mm_h, scr_w, scr_h, dc_w, dc_h;
187 float ppmm_h, ppmm_v;
188
189 if (!wxPrintout::OnBeginDocument(startPage, endPage)) return FALSE;
190
191 GetPageSizePixels(&pageWidth, &pageHeight);
192 GetPageSizeMM(&mm_w, &mm_h);
193 ppmm_h = (float)pageWidth / mm_w;
194 ppmm_v = (float)pageHeight / mm_h;
195
196 int ppiPrinterX, ppiPrinterY;
197 GetPPIPrinter(&ppiPrinterX, &ppiPrinterY);
198 int ppiScreenX, ppiScreenY;
199 GetPPIScreen(&ppiScreenX, &ppiScreenY);
200
201 wxDisplaySize(&scr_w, &scr_h);
202 GetDC()->GetSize(&dc_w, &dc_h);
203
204 GetDC()->SetUserScale((double)dc_w / (double)pageWidth, (double)dc_w / (double)pageWidth);
205
206 /* prepare headers/footers renderer: */
207
208 m_RendererHdr->SetDC(GetDC(), (double)ppiPrinterY / (double)ppiScreenY);
209 m_RendererHdr->SetSize((int) (ppmm_h * (mm_w - m_MarginLeft - m_MarginRight)),
210 (int) (ppmm_v * (mm_h - m_MarginTop - m_MarginBottom)));
211 if (m_Headers[0] != wxEmptyString)
212 {
213 m_RendererHdr->SetHtmlText(TranslateHeader(m_Headers[0], 1));
214 m_HeaderHeight = m_RendererHdr->GetTotalHeight();
215 }
216 else if (m_Headers[1] != wxEmptyString)
217 {
218 m_RendererHdr->SetHtmlText(TranslateHeader(m_Headers[1], 1));
219 m_HeaderHeight = m_RendererHdr->GetTotalHeight();
220 }
221 if (m_Footers[0] != wxEmptyString)
222 {
223 m_RendererHdr->SetHtmlText(TranslateHeader(m_Footers[0], 1));
224 m_FooterHeight = m_RendererHdr->GetTotalHeight();
225 }
226 else if (m_Footers[1] != wxEmptyString)
227 {
228 m_RendererHdr->SetHtmlText(TranslateHeader(m_Footers[1], 1));
229 m_FooterHeight = m_RendererHdr->GetTotalHeight();
230 }
231
232 /* prepare main renderer: */
233 m_Renderer->SetDC(GetDC(), (double)ppiPrinterY / (double)ppiScreenY);
234 m_Renderer->SetSize((int) (ppmm_h * (mm_w - m_MarginLeft - m_MarginRight)),
235 (int) (ppmm_v * (mm_h - m_MarginTop - m_MarginBottom) -
236 m_FooterHeight - m_HeaderHeight -
237 ((m_HeaderHeight == 0) ? 0 : m_MarginSpace * ppmm_v) -
238 ((m_FooterHeight == 0) ? 0 : m_MarginSpace * ppmm_v)
239 ));
240 m_Renderer->SetHtmlText(m_Document, m_BasePath, m_BasePathIsDir);
241 CountPages();
242 return TRUE;
243 }
244
245
246 bool wxHtmlPrintout::OnPrintPage(int page)
247 {
248 wxDC *dc = GetDC();
249 if (dc)
250 {
251 if (HasPage(page))
252 RenderPage(dc, page);
253 return TRUE;
254 }
255 else return FALSE;
256 }
257
258
259 void wxHtmlPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo)
260 {
261 *minPage = 1;
262 *maxPage = wxHTML_PRINT_MAX_PAGES;
263 *selPageFrom = 1;
264 *selPageTo = wxHTML_PRINT_MAX_PAGES;
265 }
266
267
268
269 bool wxHtmlPrintout::HasPage(int pageNum)
270 {
271 return (pageNum >= 1 && pageNum <= m_NumPages);
272 }
273
274
275
276 void wxHtmlPrintout::SetHtmlText(const wxString& html, const wxString &basepath, bool isdir)
277 {
278 m_Document = html;
279 m_BasePath = basepath;
280 m_BasePathIsDir = isdir;
281 }
282
283 void wxHtmlPrintout::SetHtmlFile(const wxString& htmlfile)
284 {
285 wxFileSystem fs;
286 wxFSFile *ff = fs.OpenFile(htmlfile);
287
288 if (ff == NULL)
289 {
290 wxLogError(htmlfile + _(": file does not exist!"));
291 return;
292 }
293
294 wxHtmlFilterHTML filter;
295 wxString doc = filter.ReadFile(*ff);
296
297 SetHtmlText(doc, htmlfile, FALSE);
298 delete ff;
299 }
300
301
302
303 void wxHtmlPrintout::SetHeader(const wxString& header, int pg)
304 {
305 if (pg == wxPAGE_ALL || pg == wxPAGE_EVEN)
306 m_Headers[0] = header;
307 if (pg == wxPAGE_ALL || pg == wxPAGE_ODD)
308 m_Headers[1] = header;
309 }
310
311
312
313 void wxHtmlPrintout::SetFooter(const wxString& footer, int pg)
314 {
315 if (pg == wxPAGE_ALL || pg == wxPAGE_EVEN)
316 m_Footers[0] = footer;
317 if (pg == wxPAGE_ALL || pg == wxPAGE_ODD)
318 m_Footers[1] = footer;
319 }
320
321
322
323 void wxHtmlPrintout::CountPages()
324 {
325 wxBusyCursor wait;
326 int pageWidth, pageHeight, mm_w, mm_h;
327 float ppmm_h, ppmm_v;
328
329 GetPageSizePixels(&pageWidth, &pageHeight);
330 GetPageSizeMM(&mm_w, &mm_h);
331 ppmm_h = (float)pageWidth / mm_w;
332 ppmm_v = (float)pageHeight / mm_h;
333
334 int pos = 0;
335
336 m_NumPages = 0;
337
338 m_PageBreaks[0] = 0;
339 do
340 {
341 pos = m_Renderer->Render((int)( ppmm_h * m_MarginLeft),
342 (int) (ppmm_v * (m_MarginTop + (m_HeaderHeight == 0 ? 0 : m_MarginSpace)) + m_HeaderHeight),
343 pos, TRUE, INT_MAX, m_PageBreaks, m_NumPages);
344 m_PageBreaks[++m_NumPages] = pos;
345 } while (pos < m_Renderer->GetTotalHeight());
346 }
347
348
349
350 void wxHtmlPrintout::RenderPage(wxDC *dc, int page)
351 {
352 wxBusyCursor wait;
353
354 int pageWidth, pageHeight, mm_w, mm_h, scr_w, scr_h, dc_w, dc_h;
355 float ppmm_h, ppmm_v;
356
357 GetPageSizePixels(&pageWidth, &pageHeight);
358 GetPageSizeMM(&mm_w, &mm_h);
359 ppmm_h = (float)pageWidth / mm_w;
360 ppmm_v = (float)pageHeight / mm_h;
361 wxDisplaySize(&scr_w, &scr_h);
362 dc->GetSize(&dc_w, &dc_h);
363
364 int ppiPrinterX, ppiPrinterY;
365 GetPPIPrinter(&ppiPrinterX, &ppiPrinterY);
366 int ppiScreenX, ppiScreenY;
367 GetPPIScreen(&ppiScreenX, &ppiScreenY);
368
369 dc->SetUserScale((double)dc_w / (double)pageWidth, (double)dc_w / (double)pageWidth);
370
371 m_Renderer->SetDC(dc, (double)ppiPrinterY / (double)ppiScreenY);
372
373 dc->SetBackgroundMode(wxTRANSPARENT);
374
375 m_Renderer->Render((int) (ppmm_h * m_MarginLeft),
376 (int) (ppmm_v * (m_MarginTop + (m_HeaderHeight == 0 ? 0 : m_MarginSpace)) + m_HeaderHeight),
377 m_PageBreaks[page-1], FALSE, m_PageBreaks[page]-m_PageBreaks[page-1]);
378
379 m_RendererHdr->SetDC(dc, (double)ppiPrinterY / (double)ppiScreenY);
380 if (m_Headers[page % 2] != wxEmptyString)
381 {
382 m_RendererHdr->SetHtmlText(TranslateHeader(m_Headers[page % 2], page));
383 m_RendererHdr->Render((int) (ppmm_h * m_MarginLeft), (int) (ppmm_v * m_MarginTop));
384 }
385 if (m_Footers[page % 2] != wxEmptyString)
386 {
387 m_RendererHdr->SetHtmlText(TranslateHeader(m_Footers[page % 2], page));
388 m_RendererHdr->Render((int) (ppmm_h * m_MarginLeft), (int) (pageHeight - ppmm_v * m_MarginBottom - m_FooterHeight));
389 }
390 }
391
392
393
394 wxString wxHtmlPrintout::TranslateHeader(const wxString& instr, int page)
395 {
396 wxString r = instr;
397 wxString num;
398
399 num.Printf(wxT("%i"), page);
400 r.Replace(wxT("@PAGENUM@"), num);
401
402 num.Printf(wxT("%i"), m_NumPages);
403 r.Replace(wxT("@PAGESCNT@"), num);
404
405 return r;
406 }
407
408
409
410 void wxHtmlPrintout::SetMargins(float top, float bottom, float left, float right, float spaces)
411 {
412 m_MarginTop = top;
413 m_MarginBottom = bottom;
414 m_MarginLeft = left;
415 m_MarginRight = right;
416 m_MarginSpace = spaces;
417 }
418
419
420
421
422 void wxHtmlPrintout::SetFonts(wxString normal_face, wxString fixed_face,
423 const int *sizes)
424 {
425 m_Renderer->SetFonts(normal_face, fixed_face, sizes);
426 m_RendererHdr->SetFonts(normal_face, fixed_face, sizes);
427 }
428
429
430
431 //----------------------------------------------------------------------------
432 // wxHtmlEasyPrinting
433 //----------------------------------------------------------------------------
434
435
436 wxHtmlEasyPrinting::wxHtmlEasyPrinting(const wxString& name, wxWindow *parentWindow)
437 {
438 m_ParentWindow = parentWindow;
439 m_Name = name;
440 m_PrintData = new wxPrintData;
441 m_PageSetupData = new wxPageSetupDialogData;
442 m_Headers[0] = m_Headers[1] = m_Footers[0] = m_Footers[1] = wxEmptyString;
443
444 m_PageSetupData->EnableMargins(TRUE);
445 m_PageSetupData->SetMarginTopLeft(wxPoint(25, 25));
446 m_PageSetupData->SetMarginBottomRight(wxPoint(25, 25));
447
448 SetFonts(wxEmptyString, wxEmptyString, NULL);
449 }
450
451
452
453 wxHtmlEasyPrinting::~wxHtmlEasyPrinting()
454 {
455 delete m_PrintData;
456 delete m_PageSetupData;
457 }
458
459
460
461 bool wxHtmlEasyPrinting::PreviewFile(const wxString &htmlfile)
462 {
463 wxHtmlPrintout *p1 = CreatePrintout();
464 p1->SetHtmlFile(htmlfile);
465 wxHtmlPrintout *p2 = CreatePrintout();
466 p2->SetHtmlFile(htmlfile);
467 return DoPreview(p1, p2);
468 }
469
470
471
472 bool wxHtmlEasyPrinting::PreviewText(const wxString &htmltext, const wxString &basepath)
473 {
474 wxHtmlPrintout *p1 = CreatePrintout();
475 p1->SetHtmlText(htmltext, basepath, TRUE);
476 wxHtmlPrintout *p2 = CreatePrintout();
477 p2->SetHtmlText(htmltext, basepath, TRUE);
478 return DoPreview(p1, p2);
479 }
480
481
482
483 bool wxHtmlEasyPrinting::PrintFile(const wxString &htmlfile)
484 {
485 wxHtmlPrintout *p = CreatePrintout();
486 p->SetHtmlFile(htmlfile);
487 bool ret = DoPrint(p);
488 delete p;
489 return ret;
490 }
491
492
493
494 bool wxHtmlEasyPrinting::PrintText(const wxString &htmltext, const wxString &basepath)
495 {
496 wxHtmlPrintout *p = CreatePrintout();
497 p->SetHtmlText(htmltext, basepath, TRUE);
498 bool ret = DoPrint(p);
499 delete p;
500 return ret;
501 }
502
503
504
505 bool wxHtmlEasyPrinting::DoPreview(wxHtmlPrintout *printout1, wxHtmlPrintout *printout2)
506 {
507 // Pass two printout objects: for preview, and possible printing.
508 wxPrintDialogData printDialogData(*m_PrintData);
509 wxPrintPreview *preview = new wxPrintPreview(printout1, printout2, &printDialogData);
510 if (!preview->Ok())
511 {
512 delete preview;
513 return FALSE;
514 }
515
516 wxPreviewFrame *frame = new wxPreviewFrame(preview, m_ParentWindow,
517 m_Name + _(" Preview"),
518 wxPoint(100, 100), wxSize(650, 500));
519 frame->Centre(wxBOTH);
520 frame->Initialize();
521 frame->Show(TRUE);
522 return TRUE;
523 }
524
525
526
527 bool wxHtmlEasyPrinting::DoPrint(wxHtmlPrintout *printout)
528 {
529 wxPrintDialogData printDialogData(*m_PrintData);
530 wxPrinter printer(&printDialogData);
531
532 if (!printer.Print(m_ParentWindow, printout, TRUE))
533 {
534 return FALSE;
535 }
536
537 (*m_PrintData) = printer.GetPrintDialogData().GetPrintData();
538 return TRUE;
539 }
540
541
542
543 void wxHtmlEasyPrinting::PrinterSetup()
544 {
545 wxPrintDialogData printDialogData(*m_PrintData);
546 wxPrintDialog printerDialog(m_ParentWindow, &printDialogData);
547
548 printerDialog.GetPrintDialogData().SetSetupDialog(TRUE);
549
550 if (printerDialog.ShowModal() == wxID_OK)
551 (*m_PrintData) = printerDialog.GetPrintDialogData().GetPrintData();
552 }
553
554
555
556 void wxHtmlEasyPrinting::PageSetup()
557 {
558 if (!m_PrintData->Ok())
559 {
560 wxLogError(_("There was a problem during page setup: you may need to set a default printer."));
561 return;
562 }
563
564 m_PageSetupData->SetPrintData(*m_PrintData);
565 wxPageSetupDialog pageSetupDialog(m_ParentWindow, m_PageSetupData);
566
567 if (pageSetupDialog.ShowModal() == wxID_OK)
568 {
569 (*m_PrintData) = pageSetupDialog.GetPageSetupData().GetPrintData();
570 (*m_PageSetupData) = pageSetupDialog.GetPageSetupData();
571 }
572 }
573
574
575
576 void wxHtmlEasyPrinting::SetHeader(const wxString& header, int pg)
577 {
578 if (pg == wxPAGE_ALL || pg == wxPAGE_EVEN)
579 m_Headers[0] = header;
580 if (pg == wxPAGE_ALL || pg == wxPAGE_ODD)
581 m_Headers[1] = header;
582 }
583
584
585
586 void wxHtmlEasyPrinting::SetFooter(const wxString& footer, int pg)
587 {
588 if (pg == wxPAGE_ALL || pg == wxPAGE_EVEN)
589 m_Footers[0] = footer;
590 if (pg == wxPAGE_ALL || pg == wxPAGE_ODD)
591 m_Footers[1] = footer;
592 }
593
594
595 void wxHtmlEasyPrinting::SetFonts(wxString normal_face, wxString fixed_face,
596 const int *sizes)
597 {
598 m_FontFaceNormal = normal_face;
599 m_FontFaceFixed = fixed_face;
600
601 if (sizes)
602 {
603 m_FontsSizes = m_FontsSizesArr;
604 for (int i = 0; i < 7; i++) m_FontsSizes[i] = sizes[i];
605 }
606 else
607 m_FontsSizes = NULL;
608 }
609
610
611 wxHtmlPrintout *wxHtmlEasyPrinting::CreatePrintout()
612 {
613 wxHtmlPrintout *p = new wxHtmlPrintout(m_Name);
614
615 p->SetFonts(m_FontFaceNormal, m_FontFaceFixed, m_FontsSizes);
616
617 p->SetHeader(m_Headers[0], wxPAGE_EVEN);
618 p->SetHeader(m_Headers[1], wxPAGE_ODD);
619 p->SetFooter(m_Footers[0], wxPAGE_EVEN);
620 p->SetFooter(m_Footers[1], wxPAGE_ODD);
621
622 p->SetMargins(m_PageSetupData->GetMarginTopLeft().y,
623 m_PageSetupData->GetMarginBottomRight().y,
624 m_PageSetupData->GetMarginTopLeft().x,
625 m_PageSetupData->GetMarginBottomRight().x);
626
627 return p;
628 }
629
630
631 // This hack forces the linker to always link in m_* files
632 // (wxHTML doesn't work without handlers from these files)
633 #include "wx/html/forcelnk.h"
634 FORCE_WXHTML_MODULES()
635
636 #endif // wxUSE_HTML & wxUSE_PRINTING_ARCHITECTURE