1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        steprint.cpp
3 // Purpose:     wxSTEditorPrintout
4 // Author:      John Labenski, parts taken from wxGuide by Otto Wyss
5 // Modified by:
6 // Created:     11/05/2002
7 // RCS-ID:
8 // Copyright:   (c) John Labenski, Otto Wyss
9 // Licence:     wxWidgets licence
10 ///////////////////////////////////////////////////////////////////////////////
11 
12 #include "precomp.h"
13 
14 #include "wx/stedit/steprint.h"
15 #include "wx/stedit/stedit.h"
16 #include "wx/stedit/steart.h"
17 #include "wx/stedit/stemenum.h"
18 #include "stedlgs_wdr.h"
19 
20 #include <wx/progdlg.h>   // wxProgressDialog
21 
22 #if wxUSE_PRINTING_ARCHITECTURE
23 
24 //-----------------------------------------------------------------------------
25 // wxSTEditorModule - setup anything after init and delete before closing
26 //-----------------------------------------------------------------------------
27 
28 class wxSTEditorModule : public wxModule
29 {
30 DECLARE_DYNAMIC_CLASS(wxSTEditorModule)
31 public:
wxSTEditorModule()32     wxSTEditorModule() : wxModule() {}
OnInit()33     bool OnInit()
34     {
35         wxArtProvider::Push(new wxSTEditorArtProvider);
36         return true;
37     }
OnExit()38     void OnExit()
39     {
40 #if wxUSE_PRINTING_ARCHITECTURE
41         wxSTEditorPrintout::SetPrintData(NULL, false);
42         wxSTEditorPrintout::SetPageSetupData(NULL, false);
43 #endif // wxUSE_PRINTING_ARCHITECTURE
44     }
45 };
46 
47 IMPLEMENT_DYNAMIC_CLASS(wxSTEditorModule, wxModule)
48 
49 //----------------------------------------------------------------------------
50 // wxSTEditorPrintout
51 //----------------------------------------------------------------------------
52 
53 IMPLEMENT_ABSTRACT_CLASS(wxSTEditorPrintout, wxPrintout)
54 
55 wxPrintData *wxSTEditorPrintout::sm_STE_printData = NULL;
56 wxPageSetupData *wxSTEditorPrintout::sm_STE_pageSetupData = NULL;
57 bool wxSTEditorPrintout::sm_STE_printdata_static = false;
58 bool wxSTEditorPrintout::sm_STE_pagesetupdata_static = false;
59 bool wxSTEditorPrintout::sm_warn_on_font_scale = true;
60 
GetPrintData(bool create_on_demand)61 wxPrintData *wxSTEditorPrintout::GetPrintData(bool create_on_demand)
62 {
63     if (create_on_demand && (sm_STE_printData == NULL))
64     {
65         wxPrintData *printData = new wxPrintData;
66         printData->SetPaperId(wxPAPER_LETTER);
67         SetPrintData(printData, false);
68     }
69 
70     return sm_STE_printData;
71 }
GetPageSetupData(bool create_on_demand)72 wxPageSetupData *wxSTEditorPrintout::GetPageSetupData(bool create_on_demand)
73 {
74     if (create_on_demand && (sm_STE_pageSetupData == NULL))
75     {
76         wxPageSetupData *pageSetupData = new wxPageSetupData;
77         pageSetupData->SetPaperSize(wxPAPER_LETTER);
78         pageSetupData->SetMarginTopLeft(wxPoint(20, 20));
79         pageSetupData->SetMarginBottomRight(wxPoint(20, 20));
80         SetPageSetupData(pageSetupData, false);
81     }
82 
83     return sm_STE_pageSetupData;
84 }
85 
GetPrintDataStatic()86 bool wxSTEditorPrintout::GetPrintDataStatic()     { return sm_STE_printdata_static; }
GetPageSetupDataStatic()87 bool wxSTEditorPrintout::GetPageSetupDataStatic() { return sm_STE_pagesetupdata_static; }
88 
SetPrintData(wxPrintData * printData,bool is_static)89 void wxSTEditorPrintout::SetPrintData( wxPrintData *printData, bool is_static )
90 {
91     if (sm_STE_printData && !sm_STE_printdata_static)
92         delete sm_STE_printData;
93 
94     sm_STE_printData        = printData;
95     sm_STE_printdata_static = is_static;
96 }
SetPageSetupData(wxPageSetupData * pageSetupData,bool is_static)97 void wxSTEditorPrintout::SetPageSetupData( wxPageSetupData *pageSetupData, bool is_static )
98 {
99     if (sm_STE_pageSetupData && !sm_STE_pagesetupdata_static)
100         delete sm_STE_pageSetupData;
101 
102     sm_STE_pageSetupData        = pageSetupData;
103     sm_STE_pagesetupdata_static = is_static;
104 }
105 
wxSTEditorPrintout(wxSTEditor * editor,const wxString & title)106 wxSTEditorPrintout::wxSTEditorPrintout(wxSTEditor *editor,
107                                        const wxString& title)
108                    :wxPrintout(title), m_editor(editor),
109                     m_margin0_width(-1), m_margin1_width(-1), m_margin2_width(-1),
110                     m_edge_mode(-1)
111 {
112     wxCHECK_RET(m_editor, wxT("Invalid editor in wxSTEditorPrintout"));
113 
114     // This is a simple check to see if the font can be scaled. Otherwise
115     //   the user will be confused and disappointed by the output.
116 
117     // You cannot show this dialog later if this is used in a wxPrintPreview.
118     //   It leads to a crash in MSW in the paint handler for the preview,
119     //   probably something to do with having two modal dialogs.
120     if (sm_warn_on_font_scale && m_editor->GetEditorStyles().IsOk())
121     {
122         wxClientDC dc(m_editor);
123         wxFont font = m_editor->GetEditorStyles().GetFont(STE_STYLE_DEFAULT);
124         int font_width = 0, font_height = 0;
125         dc.SetUserScale(1.0, 1.0);
126         dc.GetTextExtent(wxT("W"), &font_width, &font_height, NULL, NULL, &font);
127         int font_width_2 = 0, font_height_2 = 0;
128         dc.SetUserScale(0.5, 0.5);
129         dc.GetTextExtent(wxT("W"), &font_width_2, &font_height_2, NULL, NULL, &font);
130 
131         if (!(font_height_2 < font_height))
132         {
133             int ret = wxMessageBox(_("The font cannot be properly scaled for the printout\nand the output may be corrupted.\nPress cancel to not see this warning again."),
134                                    _("Unscalable font"),
135                                    wxOK|wxCANCEL|wxCENTRE|wxICON_INFORMATION, m_editor);
136 
137             if (ret == wxCANCEL)
138                 sm_warn_on_font_scale = false;
139         }
140     }
141 }
142 
OnBeginDocument(int startPage,int endPage)143 bool wxSTEditorPrintout::OnBeginDocument(int startPage, int endPage)
144 {
145     if (!m_editor)
146         return false;
147 
148     // save the original values for edge mode and margin widths
149     m_edge_mode = m_editor->GetEdgeMode();  // nobody wants to see this?
150     m_editor->SetEdgeMode(wxSTC_EDGE_NONE);
151 
152     wxSTEditorPrefs prefs = m_editor->GetEditorPrefs();
153 
154     m_margin0_width = m_editor->GetMarginWidth(STE_MARGIN_0);
155     m_margin1_width = m_editor->GetMarginWidth(STE_MARGIN_1);
156     m_margin2_width = m_editor->GetMarginWidth(STE_MARGIN_2);
157 
158     // this defaults to wysiwyg for linenumbers if no prefs
159     bool has_linenums    = (m_margin0_width != 0) && (m_editor->GetMarginType(STE_MARGIN_0) == wxSTC_MARGIN_NUMBER);
160     bool linenums_never  = prefs.IsOk() && (prefs.GetPrefInt(STE_PREF_PRINT_LINENUMBERS) == STE_PRINT_LINENUMBERS_NEVER);
161     bool linenums_always = prefs.IsOk() && (prefs.GetPrefInt(STE_PREF_PRINT_LINENUMBERS) == STE_PRINT_LINENUMBERS_ALWAYS);
162 
163     if (!linenums_never && (has_linenums || linenums_always))
164     {
165         // calculate the smallest line number width to save space
166         int line_count = m_editor->GetLineCount(); line_count = wxMax(line_count, 1);
167         wxString lineStr((int)log10((double)line_count)+1, wxT('5'));
168 
169         int line_margin_width = m_editor->TextWidth(wxSTC_STYLE_LINENUMBER, lineStr);
170         m_editor->SetMarginWidth(STE_MARGIN_0, line_margin_width);
171     }
172     else
173     {
174         m_editor->SetMarginWidth(STE_MARGIN_0, 0);
175     }
176 
177     // the markers are not drawn by scintilla anyway so set margin widths to 0
178     m_editor->SetMarginWidth(STE_MARGIN_1, 0);
179     m_editor->SetMarginWidth(STE_MARGIN_2, 0);
180 
181     return wxPrintout::OnBeginDocument(startPage, endPage);
182 }
183 
OnEndDocument()184 void wxSTEditorPrintout::OnEndDocument()
185 {
186     if (m_editor)
187     {
188         // restore the original values for edge mode and margin widths
189         if (m_edge_mode >= 0)
190             m_editor->SetEdgeMode(m_edge_mode);
191 
192         if (m_margin0_width >= 0)
193             m_editor->SetMarginWidth(STE_MARGIN_0, m_margin0_width);
194         if (m_margin1_width >= 0)
195             m_editor->SetMarginWidth(STE_MARGIN_1, m_margin1_width);
196         if (m_margin2_width >= 0)
197             m_editor->SetMarginWidth(STE_MARGIN_2, m_margin2_width);
198     }
199 
200     wxPrintout::OnEndDocument();
201 }
202 
HasPage(int page)203 bool wxSTEditorPrintout::HasPage(int page)
204 {
205     return (page > 0) && (page-1 < int(m_pages.GetCount())); // pages start at 1
206 }
207 
OnPrintPage(int page)208 bool wxSTEditorPrintout::OnPrintPage(int page)
209 {
210     wxDC *dc = GetDC();
211     if (!m_editor || !HasPage(page) || !dc)
212         return false;
213 
214     PrintScaling(dc);             // scale DC for preview
215 
216 #if 0 // FIXME test code for visualizing the rectangles
217     //dc->SetBrush(*wxTRANSPARENT_BRUSH);
218     dc->SetBrush(*wxGREEN_BRUSH);
219     dc->SetPen(wxPen(wxColour(255,0,0), 2, wxSOLID));
220     dc->DrawRectangle(m_pageRect); dc->DrawRectangle(m_pageRect.Inflate(-20, -20));
221     dc->SetPen(wxPen(wxColour(255,0,0), 2, wxSOLID));
222     dc->SetBrush(*wxBLUE_BRUSH);
223     dc->DrawRectangle(m_printRect);
224 #endif // test for visualizing printout
225 
226     m_editor->FormatRange(true,
227                           m_pages[page-1],
228                           (int(m_pages.GetCount()) > page) ? m_pages[page] : m_editor->GetLength(),
229                           dc, dc,
230                           m_printRect, m_pageRect);
231 
232     return true;
233 }
234 
GetPageInfo(int * minPage,int * maxPage,int * pageFrom,int * pageTo)235 void wxSTEditorPrintout::GetPageInfo(int *minPage, int *maxPage,
236                                      int *pageFrom, int *pageTo)
237 {
238     wxCHECK_RET(m_editor && minPage && maxPage && pageFrom && pageTo,
239                 wxT("Null value in wxSTEditorPrintout::GetPageInfo"));
240 
241     // initialize values
242     *minPage  = 0;
243     *maxPage  = 0;
244     *pageFrom = 0;
245     *pageTo   = 0;
246 
247     // scale DC if possible
248     wxDC *dc = GetDC();
249     if (!dc) return;
250     PrintScaling(dc);
251 
252     // count pages
253     int length = m_editor->GetLength();
254     int lines  = m_editor->GetLineCount();
255     int pages  = 1;
256     m_pages.Clear();
257 
258     wxWindow* parent = wxGetTopLevelParent(wxWindow::FindFocus()); // find wxPreviewFrame
259 
260     // Using the default wxPD_APP_MODAL flag, or using the frame window or NULL as parent, will mess up the z-order when displaying wxPreviewFrame
261     wxProgressDialog progDialog(_("Formatting printout"), _("Page 1 of ?"), 100, parent, wxPD_AUTO_HIDE);
262 #if (wxVERSION_NUMBER < 2900)
263     progDialog.SetFocus(); // grab focus from wxPreviewFrame
264 #endif
265 
266     for (int pos = 0; pos < length; )
267     {
268         if (*maxPage >= (int)m_pages.GetCount())
269             m_pages.Add(pos);
270         else
271             m_pages[*maxPage] = pos;
272 
273         pos = m_editor->FormatRange(false,
274                                     pos,
275                                     length,
276                                     dc, dc,
277                                     m_printRect, m_pageRect);
278         *maxPage += 1;
279 
280         int current_line = m_editor->LineFromPosition(wxMax(pos-1, 0));
281         current_line = wxMax(current_line, 1);
282         pages = 1+(*maxPage)*lines/current_line;
283         progDialog.Update(int(pos*100.0/length),
284                           wxString::Format(_("Page %d of %d"), *maxPage, pages));
285     }
286 
287     if (*maxPage > 0)
288         *minPage = 1;
289 
290     *pageFrom = *minPage;
291     *pageTo   = *maxPage;
292 }
293 
PrintScaling(wxDC * dc)294 bool wxSTEditorPrintout::PrintScaling(wxDC *dc)
295 {
296     if (!dc)
297         return false;
298 
299     // Get the whole size of the page in mm
300     wxSize pageMMSize;
301     GetPageSizeMM(&pageMMSize.x, &pageMMSize.y);
302 
303     // Get the ppi of the screen and printer
304     wxSize ppiScr,ppiPrn;
305     GetPPIScreen( &ppiScr.x, &ppiScr.y);
306     GetPPIPrinter(&ppiPrn.x, &ppiPrn.y);
307 
308     float ppi_scale_x = float(ppiPrn.x)/float(ppiScr.x);
309     float ppi_scale_y = float(ppiPrn.y)/float(ppiScr.y);
310 
311     // Get the size of DC in pixels and the number of pixels in the page
312     wxSize dcSize, pagePixSize;
313     dc->GetSize(&dcSize.x, &dcSize.y);
314     GetPageSizePixels(&pagePixSize.x, &pagePixSize.y);
315 
316     float dc_pagepix_scale_x = float(dcSize.x)/float(pagePixSize.x);
317     float dc_pagepix_scale_y = float(dcSize.y)/float(pagePixSize.y);
318 
319     // the actual ppi using the size of the dc or page in pixels
320     //wxSize pixelSize = IsPreview() ? dcSize : pagePixSize;
321     //float page_ppi_x = float(pixelSize.x) * (25.4 / float(pageMMSize.x));
322     //float page_ppi_y = float(pixelSize.y) * (25.4 / float(pageMMSize.y));
323 
324     // If printer pageWidth == current DC width, then this doesn't
325     // change. But w might be the preview bitmap width, so scale down.
326     float dc_scale_x = ppi_scale_x * dc_pagepix_scale_x;
327     float dc_scale_y = ppi_scale_y * dc_pagepix_scale_y;
328 
329     // calculate the pixels / mm (25.4 mm = 1 inch)
330     float ppmm_x = float(ppiScr.x) / 25.4;
331     float ppmm_y = float(ppiScr.y) / 25.4;
332 
333     // Adjust the page size for the pixels / mm scaling factor
334     //wxSize paperSize = GetPageSetupData(true)->GetPaperSize();
335     wxSize page = pageMMSize;
336     page.x      = int(page.x * ppmm_x);
337     page.y      = int(page.y * ppmm_y);
338     m_pageRect  = wxRect(0, 0, page.x, page.y);
339 
340     // get margins informations and convert to printer pixels
341     wxPoint topLeft     = GetPageSetupData(true)->GetMarginTopLeft();
342     wxPoint bottomRight = GetPageSetupData(true)->GetMarginBottomRight();
343 
344     int top    = int(topLeft.y     * ppmm_y);
345     int bottom = int(bottomRight.y * ppmm_y);
346     int left   = int(topLeft.x     * ppmm_x);
347     int right  = int(bottomRight.x * ppmm_x);
348 
349     m_printRect = wxRect(left, top, page.x-(left+right), page.y-(top+bottom));
350 
351     dc->SetUserScale(dc_scale_x, dc_scale_y);
352 
353     //wxPrintf(wxT("GetPageInfo ppiScr %d %d, ppiPrn %d %d, paperSize %d %d page %d %d, preview %d\n"), ppiScr.x, ppiScr.y, ppiPrn.x, ppiPrn.y, paperSize.x, paperSize.y, page.x, page.y, IsPreview());
354     //wxPrintf(wxT("GetPageInfo m_pageRect x%d y%d w%d h%d m_printRect x%d y%d w%d h%d\n"), m_pageRect.x, m_pageRect.y, m_pageRect.width, m_pageRect.height,
355     //                                                                                      m_printRect.x, m_printRect.y, m_printRect.width, m_printRect.height);
356     //wxPrintf(wxT("PrintScaling dc size %d %d, page pixels %d %d, dc_scale %g %g ppmm %g %g\n"), dcSize.x, dcSize.y, pagePixSize.x, pagePixSize.y, dc_scale_x, dc_scale_y, ppmm_x, ppmm_y);
357     //wxPrintf(wxT("ppi_scale %g %g, dc_pagepix_scale %g %g\n\n"), ppi_scale_x, ppi_scale_y, dc_pagepix_scale_x, dc_pagepix_scale_y);
358     //fflush(stdout);
359 
360     return true;
361 }
362 
363 #endif // wxUSE_PRINTING_ARCHITECTURE
364 
365 //-----------------------------------------------------------------------------
366 // wxSTEditorPrintOptionsDialog - display STC printer options
367 //-----------------------------------------------------------------------------
368 IMPLEMENT_ABSTRACT_CLASS(wxSTEditorPrintOptionsDialog, wxDialog);
369 
wxSTEditorPrintOptionsDialog(wxWindow * parent)370 wxSTEditorPrintOptionsDialog::wxSTEditorPrintOptionsDialog(wxWindow *parent)
371                              :wxDialog(parent, wxID_ANY, _("Printer options"),
372                                        wxDefaultPosition, wxDefaultSize,
373                                        wxDEFAULT_DIALOG_STYLE_RESIZE)
374 {
375     SetIcons(wxSTEditorArtProvider::GetDialogIconBundle());
376     wxSTEditorPrintPrefsSizer(this, false, true);
377     wxSTEditorStdDialogButtonSizer(this, wxOK|wxCANCEL);
378     GetSizer()->SetSizeHints( this );
379 
380     if (wxDynamicCast(parent, wxSTEditor))
381     {
382         wxSTEditor *edit = wxStaticCast(parent, wxSTEditor);
383         SetPrintMagnification(edit->GetPrintMagnification());
384         SetPrintColourMode(edit->GetPrintColourMode());
385         SetPrintWrapMode(edit->GetPrintWrapMode() == wxSTC_WRAP_WORD);
386         wxSTEditorPrefs prefs = edit->GetEditorPrefs();
387         if (prefs.IsOk())
388             SetPrintLinenumbers(prefs.GetPrefInt(STE_PREF_PRINT_LINENUMBERS));
389         else
390             SetPrintLinenumbers(STE_PRINT_LINENUMBERS_DEFAULT);
391     }
392     else
393     {
394         SetPrintMagnification(-2);
395         SetPrintColourMode(wxSTC_PRINT_COLOURONWHITE);
396         SetPrintWrapMode(false);
397         SetPrintLinenumbers(STE_PRINT_LINENUMBERS_DEFAULT);
398     }
399     Centre();
400 }
401 
SetPrintMagnification(int val)402 void wxSTEditorPrintOptionsDialog::SetPrintMagnification( int val )
403 {
404     wxStaticCast(FindWindow(ID_STEDLG_PRINT_MAGNIFICATION_SPINCTRL), wxSpinCtrl)->SetValue(val);
405 }
406 
SetPrintColourMode(int val)407 void wxSTEditorPrintOptionsDialog::SetPrintColourMode( int val )
408 {
409     wxChoice* choice = wxStaticCast(FindWindow(ID_STEDLG_PRINT_COLOURMODE_CHOICE), wxChoice);
410     wxCHECK_RET((val >= 0) && (val < (int)choice->GetCount()),
411                 wxT("Invalid selection in wxSTEditorPrintOptionsDialog::SetPrintColourMode"));
412     choice->SetSelection(val);
413 }
SetPrintWrapMode(bool val)414 void wxSTEditorPrintOptionsDialog::SetPrintWrapMode( bool val )
415 {
416     wxStaticCast(FindWindow(ID_STEDLG_PRINT_WRAPMODE_CHECKBOX), wxCheckBox)->SetValue(val);
417 }
SetPrintLinenumbers(int show_linenumbers)418 void wxSTEditorPrintOptionsDialog::SetPrintLinenumbers( int show_linenumbers )
419 {
420     wxCHECK_RET((show_linenumbers >= 0) && (show_linenumbers <= 2), wxT("Invalid value"));
421     wxStaticCast(FindWindow(ID_STEDLG_PRINT_LINENUMBERS_CHOICE), wxChoice)->SetSelection(show_linenumbers);
422 }
423 
GetPrintMagnification()424 int wxSTEditorPrintOptionsDialog::GetPrintMagnification()
425 {
426     return wxStaticCast(FindWindow(ID_STEDLG_PRINT_MAGNIFICATION_SPINCTRL), wxSpinCtrl)->GetValue();
427 }
GetPrintColourMode()428 int wxSTEditorPrintOptionsDialog::GetPrintColourMode()
429 {
430     return wxStaticCast(FindWindow(ID_STEDLG_PRINT_COLOURMODE_CHOICE), wxChoice)->GetSelection();
431 }
GetPrintWrapMode()432 bool wxSTEditorPrintOptionsDialog::GetPrintWrapMode()
433 {
434     return wxStaticCast(FindWindow(ID_STEDLG_PRINT_WRAPMODE_CHECKBOX), wxCheckBox)->GetValue();
435 }
GetPrintLinenumbers()436 int wxSTEditorPrintOptionsDialog::GetPrintLinenumbers()
437 {
438     return wxStaticCast(FindWindow(ID_STEDLG_PRINT_LINENUMBERS_CHOICE), wxChoice)->GetSelection();
439 }
440