1/////////////////////////////////////////////////////////////////////////////
2// Name:        samples/richtext/richtext.cpp
3// Purpose:     wxWidgets rich text editor sample
4// Author:      Julian Smart
5// Modified by:
6// Created:     2005-10-02
7// RCS-ID:      $Id: richtext.cpp 51739 2008-02-12 17:05:32Z JS $
8// Copyright:   (c) Julian Smart
9// Licence:     wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20// For compilers that support precompilation, includes "wx/wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24    #pragma hdrstop
25#endif
26
27// for all others, include the necessary headers (this file is usually all you
28// need because it includes almost all "standard" wxWidgets headers)
29#ifndef WX_PRECOMP
30    #include "wx/wx.h"
31#endif
32
33#include "wx/fontdlg.h"
34#include "wx/splitter.h"
35#include "wx/sstream.h"
36#include "wx/html/htmlwin.h"
37
38#if wxUSE_FILESYSTEM
39#include "wx/filesys.h"
40#include "wx/fs_mem.h"
41#endif
42
43#if wxUSE_HELP
44#include "wx/cshelp.h"
45#endif
46
47#ifndef __WXMSW__
48    #include "../sample.xpm"
49#endif
50
51#include "bitmaps/smiley.xpm"
52// #include "bitmaps/idea.xpm"
53#include "bitmaps/zebra.xpm"
54
55#include "bitmaps/open.xpm"
56#include "bitmaps/save.xpm"
57#include "bitmaps/copy.xpm"
58#include "bitmaps/cut.xpm"
59#include "bitmaps/paste.xpm"
60#include "bitmaps/undo.xpm"
61#include "bitmaps/redo.xpm"
62#include "bitmaps/bold.xpm"
63#include "bitmaps/italic.xpm"
64#include "bitmaps/underline.xpm"
65
66#include "bitmaps/alignleft.xpm"
67#include "bitmaps/alignright.xpm"
68#include "bitmaps/centre.xpm"
69#include "bitmaps/font.xpm"
70#include "bitmaps/indentless.xpm"
71#include "bitmaps/indentmore.xpm"
72
73#include "wx/richtext/richtextctrl.h"
74#include "wx/richtext/richtextstyles.h"
75#include "wx/richtext/richtextxml.h"
76#include "wx/richtext/richtexthtml.h"
77#include "wx/richtext/richtextformatdlg.h"
78#include "wx/richtext/richtextsymboldlg.h"
79#include "wx/richtext/richtextstyledlg.h"
80#include "wx/richtext/richtextprint.h"
81
82// ----------------------------------------------------------------------------
83// resources
84// ----------------------------------------------------------------------------
85
86// ----------------------------------------------------------------------------
87// private classes
88// ----------------------------------------------------------------------------
89
90// Define a new application type, each program should derive a class from wxApp
91class MyApp : public wxApp
92{
93public:
94    // override base class virtuals
95    // ----------------------------
96
97    // this one is called on application startup and is a good place for the app
98    // initialization (doing it here and not in the ctor allows to have an error
99    // return: if OnInit() returns false, the application terminates)
100    virtual bool OnInit();
101    virtual int OnExit();
102
103    void CreateStyles();
104
105    wxRichTextStyleSheet* GetStyleSheet() const { return m_styleSheet; }
106    wxRichTextPrinting* GetPrinting() const { return m_printing; }
107
108    wxRichTextStyleSheet*   m_styleSheet;
109    wxRichTextPrinting*     m_printing;
110};
111
112// Define a new frame type: this is going to be our main frame
113class MyFrame : public wxFrame
114{
115public:
116    // ctor(s)
117    MyFrame(const wxString& title, wxWindowID id, const wxPoint& pos = wxDefaultPosition,
118        const wxSize& size = wxDefaultSize, long style = wxDEFAULT_FRAME_STYLE);
119
120    // event handlers (these functions should _not_ be virtual)
121    void OnQuit(wxCommandEvent& event);
122    void OnAbout(wxCommandEvent& event);
123
124    void OnOpen(wxCommandEvent& event);
125    void OnSave(wxCommandEvent& event);
126    void OnSaveAs(wxCommandEvent& event);
127
128    void OnBold(wxCommandEvent& event);
129    void OnItalic(wxCommandEvent& event);
130    void OnUnderline(wxCommandEvent& event);
131
132    void OnUpdateBold(wxUpdateUIEvent& event);
133    void OnUpdateItalic(wxUpdateUIEvent& event);
134    void OnUpdateUnderline(wxUpdateUIEvent& event);
135
136    void OnAlignLeft(wxCommandEvent& event);
137    void OnAlignCentre(wxCommandEvent& event);
138    void OnAlignRight(wxCommandEvent& event);
139
140    void OnUpdateAlignLeft(wxUpdateUIEvent& event);
141    void OnUpdateAlignCentre(wxUpdateUIEvent& event);
142    void OnUpdateAlignRight(wxUpdateUIEvent& event);
143
144    void OnIndentMore(wxCommandEvent& event);
145    void OnIndentLess(wxCommandEvent& event);
146
147    void OnFont(wxCommandEvent& event);
148    void OnParagraph(wxCommandEvent& event);
149    void OnFormat(wxCommandEvent& event);
150    void OnUpdateFormat(wxUpdateUIEvent& event);
151
152    void OnInsertSymbol(wxCommandEvent& event);
153
154    void OnLineSpacingHalf(wxCommandEvent& event);
155    void OnLineSpacingDouble(wxCommandEvent& event);
156    void OnLineSpacingSingle(wxCommandEvent& event);
157
158    void OnParagraphSpacingMore(wxCommandEvent& event);
159    void OnParagraphSpacingLess(wxCommandEvent& event);
160
161    void OnNumberList(wxCommandEvent& event);
162    void OnBulletsAndNumbering(wxCommandEvent& event);
163    void OnItemizeList(wxCommandEvent& event);
164    void OnRenumberList(wxCommandEvent& event);
165    void OnPromoteList(wxCommandEvent& event);
166    void OnDemoteList(wxCommandEvent& event);
167    void OnClearList(wxCommandEvent& event);
168
169    void OnReload(wxCommandEvent& event);
170
171    void OnViewHTML(wxCommandEvent& event);
172
173    void OnSwitchStyleSheets(wxCommandEvent& event);
174    void OnManageStyles(wxCommandEvent& event);
175
176    void OnInsertURL(wxCommandEvent& event);
177    void OnURL(wxTextUrlEvent& event);
178    void OnStyleSheetReplacing(wxRichTextEvent& event);
179
180    void OnPrint(wxCommandEvent& event);
181    void OnPreview(wxCommandEvent& event);
182    void OnPageSetup(wxCommandEvent& event);
183
184    // Forward command events to the current rich text control, if any
185    bool ProcessEvent(wxEvent& event);
186
187    // Write text
188    void WriteInitialText();
189
190private:
191    // any class wishing to process wxWidgets events must use this macro
192    DECLARE_EVENT_TABLE()
193
194    wxRichTextCtrl*         m_richTextCtrl;
195};
196
197// ----------------------------------------------------------------------------
198// constants
199// ----------------------------------------------------------------------------
200
201// IDs for the controls and the menu commands
202enum
203{
204    // menu items
205    ID_Quit = wxID_EXIT,
206    ID_About = wxID_ABOUT,
207
208    ID_FORMAT_BOLD = 100,
209    ID_FORMAT_ITALIC,
210    ID_FORMAT_UNDERLINE,
211    ID_FORMAT_FONT,
212    ID_FORMAT_PARAGRAPH,
213    ID_FORMAT_CONTENT,
214
215    ID_RELOAD,
216
217    ID_INSERT_SYMBOL,
218    ID_INSERT_URL,
219
220    ID_FORMAT_ALIGN_LEFT,
221    ID_FORMAT_ALIGN_CENTRE,
222    ID_FORMAT_ALIGN_RIGHT,
223
224    ID_FORMAT_INDENT_MORE,
225    ID_FORMAT_INDENT_LESS,
226
227    ID_FORMAT_PARAGRAPH_SPACING_MORE,
228    ID_FORMAT_PARAGRAPH_SPACING_LESS,
229
230    ID_FORMAT_LINE_SPACING_HALF,
231    ID_FORMAT_LINE_SPACING_DOUBLE,
232    ID_FORMAT_LINE_SPACING_SINGLE,
233
234    ID_FORMAT_NUMBER_LIST,
235    ID_FORMAT_BULLETS_AND_NUMBERING,
236    ID_FORMAT_ITEMIZE_LIST,
237    ID_FORMAT_RENUMBER_LIST,
238    ID_FORMAT_PROMOTE_LIST,
239    ID_FORMAT_DEMOTE_LIST,
240    ID_FORMAT_CLEAR_LIST,
241
242    ID_VIEW_HTML,
243    ID_SWITCH_STYLE_SHEETS,
244    ID_MANAGE_STYLES,
245
246    ID_PRINT,
247    ID_PREVIEW,
248    ID_PAGE_SETUP,
249
250    ID_RICHTEXT_CTRL,
251    ID_RICHTEXT_STYLE_LIST,
252    ID_RICHTEXT_STYLE_COMBO
253};
254
255// ----------------------------------------------------------------------------
256// event tables and other macros for wxWidgets
257// ----------------------------------------------------------------------------
258
259// the event tables connect the wxWidgets events with the functions (event
260// handlers) which process them. It can be also done at run-time, but for the
261// simple menu events like this the static method is much simpler.
262BEGIN_EVENT_TABLE(MyFrame, wxFrame)
263    EVT_MENU(ID_Quit,  MyFrame::OnQuit)
264    EVT_MENU(ID_About, MyFrame::OnAbout)
265
266    EVT_MENU(wxID_OPEN,  MyFrame::OnOpen)
267    EVT_MENU(wxID_SAVE,  MyFrame::OnSave)
268    EVT_MENU(wxID_SAVEAS,  MyFrame::OnSaveAs)
269
270    EVT_MENU(ID_FORMAT_BOLD,  MyFrame::OnBold)
271    EVT_MENU(ID_FORMAT_ITALIC,  MyFrame::OnItalic)
272    EVT_MENU(ID_FORMAT_UNDERLINE,  MyFrame::OnUnderline)
273
274    EVT_UPDATE_UI(ID_FORMAT_BOLD,  MyFrame::OnUpdateBold)
275    EVT_UPDATE_UI(ID_FORMAT_ITALIC,  MyFrame::OnUpdateItalic)
276    EVT_UPDATE_UI(ID_FORMAT_UNDERLINE,  MyFrame::OnUpdateUnderline)
277
278    EVT_MENU(ID_FORMAT_ALIGN_LEFT,  MyFrame::OnAlignLeft)
279    EVT_MENU(ID_FORMAT_ALIGN_CENTRE,  MyFrame::OnAlignCentre)
280    EVT_MENU(ID_FORMAT_ALIGN_RIGHT,  MyFrame::OnAlignRight)
281
282    EVT_UPDATE_UI(ID_FORMAT_ALIGN_LEFT,  MyFrame::OnUpdateAlignLeft)
283    EVT_UPDATE_UI(ID_FORMAT_ALIGN_CENTRE,  MyFrame::OnUpdateAlignCentre)
284    EVT_UPDATE_UI(ID_FORMAT_ALIGN_RIGHT,  MyFrame::OnUpdateAlignRight)
285
286    EVT_MENU(ID_FORMAT_FONT,  MyFrame::OnFont)
287    EVT_MENU(ID_FORMAT_PARAGRAPH,  MyFrame::OnParagraph)
288    EVT_MENU(ID_FORMAT_CONTENT,  MyFrame::OnFormat)
289    EVT_UPDATE_UI(ID_FORMAT_CONTENT,  MyFrame::OnUpdateFormat)
290    EVT_UPDATE_UI(ID_FORMAT_FONT,  MyFrame::OnUpdateFormat)
291    EVT_UPDATE_UI(ID_FORMAT_PARAGRAPH,  MyFrame::OnUpdateFormat)
292    EVT_MENU(ID_FORMAT_INDENT_MORE,  MyFrame::OnIndentMore)
293    EVT_MENU(ID_FORMAT_INDENT_LESS,  MyFrame::OnIndentLess)
294
295    EVT_MENU(ID_FORMAT_LINE_SPACING_HALF,  MyFrame::OnLineSpacingHalf)
296    EVT_MENU(ID_FORMAT_LINE_SPACING_SINGLE,  MyFrame::OnLineSpacingSingle)
297    EVT_MENU(ID_FORMAT_LINE_SPACING_DOUBLE,  MyFrame::OnLineSpacingDouble)
298
299    EVT_MENU(ID_FORMAT_PARAGRAPH_SPACING_MORE,  MyFrame::OnParagraphSpacingMore)
300    EVT_MENU(ID_FORMAT_PARAGRAPH_SPACING_LESS,  MyFrame::OnParagraphSpacingLess)
301
302    EVT_MENU(ID_RELOAD,  MyFrame::OnReload)
303
304    EVT_MENU(ID_INSERT_SYMBOL,  MyFrame::OnInsertSymbol)
305    EVT_MENU(ID_INSERT_URL,  MyFrame::OnInsertURL)
306
307    EVT_MENU(ID_FORMAT_NUMBER_LIST, MyFrame::OnNumberList)
308    EVT_MENU(ID_FORMAT_BULLETS_AND_NUMBERING, MyFrame::OnBulletsAndNumbering)
309    EVT_MENU(ID_FORMAT_ITEMIZE_LIST, MyFrame::OnItemizeList)
310    EVT_MENU(ID_FORMAT_RENUMBER_LIST, MyFrame::OnRenumberList)
311    EVT_MENU(ID_FORMAT_PROMOTE_LIST, MyFrame::OnPromoteList)
312    EVT_MENU(ID_FORMAT_DEMOTE_LIST, MyFrame::OnDemoteList)
313    EVT_MENU(ID_FORMAT_CLEAR_LIST, MyFrame::OnClearList)
314
315    EVT_MENU(ID_VIEW_HTML, MyFrame::OnViewHTML)
316    EVT_MENU(ID_SWITCH_STYLE_SHEETS, MyFrame::OnSwitchStyleSheets)
317    EVT_MENU(ID_MANAGE_STYLES, MyFrame::OnManageStyles)
318
319    EVT_MENU(ID_PRINT, MyFrame::OnPrint)
320    EVT_MENU(ID_PREVIEW, MyFrame::OnPreview)
321    EVT_MENU(ID_PAGE_SETUP, MyFrame::OnPageSetup)
322
323    EVT_TEXT_URL(wxID_ANY, MyFrame::OnURL)
324    EVT_RICHTEXT_STYLESHEET_REPLACING(wxID_ANY, MyFrame::OnStyleSheetReplacing)
325END_EVENT_TABLE()
326
327// Create a new application object: this macro will allow wxWidgets to create
328// the application object during program execution (it's better than using a
329// static object for many reasons) and also implements the accessor function
330// wxGetApp() which will return the reference of the right type (i.e. MyApp and
331// not wxApp)
332IMPLEMENT_APP(MyApp)
333
334// ============================================================================
335// implementation
336// ============================================================================
337
338// ----------------------------------------------------------------------------
339// the application class
340// ----------------------------------------------------------------------------
341
342// 'Main program' equivalent: the program execution "starts" here
343bool MyApp::OnInit()
344{
345#if wxUSE_HELP
346    wxHelpProvider::Set(new wxSimpleHelpProvider);
347#endif
348
349    m_styleSheet = new wxRichTextStyleSheet;
350    m_printing = new wxRichTextPrinting(wxT("Test Document"));
351
352    m_printing->SetFooterText(wxT("@TITLE@"), wxRICHTEXT_PAGE_ALL, wxRICHTEXT_PAGE_CENTRE);
353    m_printing->SetFooterText(wxT("Page @PAGENUM@"), wxRICHTEXT_PAGE_ALL, wxRICHTEXT_PAGE_RIGHT);
354
355    CreateStyles();
356
357    // Add extra handlers (plain text is automatically added)
358    wxRichTextBuffer::AddHandler(new wxRichTextXMLHandler);
359    wxRichTextBuffer::AddHandler(new wxRichTextHTMLHandler);
360
361    // Add image handlers
362#if wxUSE_LIBPNG
363    wxImage::AddHandler( new wxPNGHandler );
364#endif
365
366#if wxUSE_LIBJPEG
367    wxImage::AddHandler( new wxJPEGHandler );
368#endif
369
370#if wxUSE_GIF
371    wxImage::AddHandler( new wxGIFHandler );
372#endif
373
374#if wxUSE_FILESYSTEM
375    wxFileSystem::AddHandler( new wxMemoryFSHandler );
376#endif
377
378    // create the main application window
379    MyFrame *frame = new MyFrame(_T("wxRichTextCtrl Sample"), wxID_ANY, wxDefaultPosition, wxSize(700, 600));
380
381    m_printing->SetParentWindow(frame);
382
383    // and show it (the frames, unlike simple controls, are not shown when
384    // created initially)
385    frame->Show(true);
386
387    // success: wxApp::OnRun() will be called which will enter the main message
388    // loop and the application will run. If we returned false here, the
389    // application would exit immediately.
390    return true;
391}
392
393int MyApp::OnExit()
394{
395    delete m_printing;
396    delete m_styleSheet;
397
398    return 0;
399}
400
401void MyApp::CreateStyles()
402{
403    // Paragraph styles
404
405    wxFont romanFont(12, wxROMAN, wxNORMAL, wxNORMAL);
406    wxFont swissFont(12, wxSWISS, wxNORMAL, wxNORMAL);
407
408    wxRichTextParagraphStyleDefinition* normalPara = new wxRichTextParagraphStyleDefinition(wxT("Normal"));
409    wxRichTextAttr normalAttr;
410    normalAttr.SetFontFaceName(romanFont.GetFaceName());
411    normalAttr.SetFontSize(12);
412    // Let's set all attributes for this style
413    normalAttr.SetFlags(wxTEXT_ATTR_FONT | wxTEXT_ATTR_BACKGROUND_COLOUR | wxTEXT_ATTR_TEXT_COLOUR|wxTEXT_ATTR_ALIGNMENT|wxTEXT_ATTR_LEFT_INDENT|wxTEXT_ATTR_RIGHT_INDENT|wxTEXT_ATTR_TABS|
414                            wxTEXT_ATTR_PARA_SPACING_BEFORE|wxTEXT_ATTR_PARA_SPACING_AFTER|wxTEXT_ATTR_LINE_SPACING|
415                            wxTEXT_ATTR_BULLET_STYLE|wxTEXT_ATTR_BULLET_NUMBER);
416    normalPara->SetStyle(normalAttr);
417
418    m_styleSheet->AddParagraphStyle(normalPara);
419
420    wxRichTextParagraphStyleDefinition* indentedPara = new wxRichTextParagraphStyleDefinition(wxT("Indented"));
421    wxRichTextAttr indentedAttr;
422    indentedAttr.SetFontFaceName(romanFont.GetFaceName());
423    indentedAttr.SetFontSize(12);
424    indentedAttr.SetLeftIndent(100, 0);
425    // We only want to affect indentation
426    indentedAttr.SetFlags(wxTEXT_ATTR_LEFT_INDENT|wxTEXT_ATTR_RIGHT_INDENT);
427    indentedPara->SetStyle(indentedAttr);
428
429    m_styleSheet->AddParagraphStyle(indentedPara);
430
431    wxRichTextParagraphStyleDefinition* indentedPara2 = new wxRichTextParagraphStyleDefinition(wxT("Red Bold Indented"));
432    wxRichTextAttr indentedAttr2;
433    indentedAttr2.SetFontFaceName(romanFont.GetFaceName());
434    indentedAttr2.SetFontSize(12);
435    indentedAttr2.SetFontWeight(wxBOLD);
436    indentedAttr2.SetTextColour(*wxRED);
437    indentedAttr2.SetFontSize(12);
438    indentedAttr2.SetLeftIndent(100, 0);
439    // We want to affect indentation, font and text colour
440    indentedAttr2.SetFlags(wxTEXT_ATTR_LEFT_INDENT|wxTEXT_ATTR_RIGHT_INDENT|wxTEXT_ATTR_FONT|wxTEXT_ATTR_TEXT_COLOUR);
441    indentedPara2->SetStyle(indentedAttr2);
442
443    m_styleSheet->AddParagraphStyle(indentedPara2);
444
445    wxRichTextParagraphStyleDefinition* flIndentedPara = new wxRichTextParagraphStyleDefinition(wxT("First Line Indented"));
446    wxRichTextAttr flIndentedAttr;
447    flIndentedAttr.SetFontFaceName(swissFont.GetFaceName());
448    flIndentedAttr.SetFontSize(12);
449    flIndentedAttr.SetLeftIndent(100, -100);
450    // We only want to affect indentation
451    flIndentedAttr.SetFlags(wxTEXT_ATTR_LEFT_INDENT|wxTEXT_ATTR_RIGHT_INDENT);
452    flIndentedPara->SetStyle(flIndentedAttr);
453
454    m_styleSheet->AddParagraphStyle(flIndentedPara);
455
456    // Character styles
457
458    wxRichTextCharacterStyleDefinition* boldDef = new wxRichTextCharacterStyleDefinition(wxT("Bold"));
459    wxRichTextAttr boldAttr;
460    boldAttr.SetFontFaceName(romanFont.GetFaceName());
461    boldAttr.SetFontSize(12);
462    boldAttr.SetFontWeight(wxBOLD);
463    // We only want to affect boldness
464    boldAttr.SetFlags(wxTEXT_ATTR_FONT_WEIGHT);
465    boldDef->SetStyle(boldAttr);
466
467    m_styleSheet->AddCharacterStyle(boldDef);
468
469    wxRichTextCharacterStyleDefinition* italicDef = new wxRichTextCharacterStyleDefinition(wxT("Italic"));
470    wxRichTextAttr italicAttr;
471    italicAttr.SetFontFaceName(romanFont.GetFaceName());
472    italicAttr.SetFontSize(12);
473    italicAttr.SetFontStyle(wxITALIC);
474    // We only want to affect italics
475    italicAttr.SetFlags(wxTEXT_ATTR_FONT_ITALIC);
476    italicDef->SetStyle(italicAttr);
477
478    m_styleSheet->AddCharacterStyle(italicDef);
479
480    wxRichTextCharacterStyleDefinition* redDef = new wxRichTextCharacterStyleDefinition(wxT("Red Bold"));
481    wxRichTextAttr redAttr;
482    redAttr.SetFontFaceName(romanFont.GetFaceName());
483    redAttr.SetFontSize(12);
484    redAttr.SetFontWeight(wxBOLD);
485    redAttr.SetTextColour(*wxRED);
486    // We only want to affect colour, weight and face
487    redAttr.SetFlags(wxTEXT_ATTR_FONT_FACE|wxTEXT_ATTR_FONT_WEIGHT|wxTEXT_ATTR_TEXT_COLOUR);
488    redDef->SetStyle(redAttr);
489
490    m_styleSheet->AddCharacterStyle(redDef);
491
492    wxRichTextListStyleDefinition* bulletList = new wxRichTextListStyleDefinition(wxT("Bullet List 1"));
493    int i;
494    for (i = 0; i < 10; i++)
495    {
496        wxString bulletText;
497        if (i == 0)
498            bulletText = wxT("standard/circle");
499        else if (i == 1)
500            bulletText = wxT("standard/square");
501        else if (i == 2)
502            bulletText = wxT("standard/circle");
503        else if (i == 3)
504            bulletText = wxT("standard/square");
505        else
506            bulletText = wxT("standard/circle");
507
508        bulletList->SetAttributes(i, (i+1)*60, 60, wxTEXT_ATTR_BULLET_STYLE_STANDARD, bulletText);
509    }
510
511    m_styleSheet->AddListStyle(bulletList);
512
513    wxRichTextListStyleDefinition* numberedList = new wxRichTextListStyleDefinition(wxT("Numbered List 1"));
514    for (i = 0; i < 10; i++)
515    {
516        long numberStyle;
517        if (i == 0)
518            numberStyle = wxTEXT_ATTR_BULLET_STYLE_ARABIC|wxTEXT_ATTR_BULLET_STYLE_PERIOD;
519        else if (i == 1)
520            numberStyle = wxTEXT_ATTR_BULLET_STYLE_LETTERS_LOWER|wxTEXT_ATTR_BULLET_STYLE_PARENTHESES;
521        else if (i == 2)
522            numberStyle = wxTEXT_ATTR_BULLET_STYLE_ROMAN_LOWER|wxTEXT_ATTR_BULLET_STYLE_PARENTHESES;
523        else if (i == 3)
524            numberStyle = wxTEXT_ATTR_BULLET_STYLE_ROMAN_UPPER|wxTEXT_ATTR_BULLET_STYLE_PARENTHESES;
525        else
526            numberStyle = wxTEXT_ATTR_BULLET_STYLE_ARABIC|wxTEXT_ATTR_BULLET_STYLE_PERIOD;
527
528        numberStyle |= wxTEXT_ATTR_BULLET_STYLE_ALIGN_RIGHT;
529
530        numberedList->SetAttributes(i, (i+1)*60, 60, numberStyle);
531    }
532
533    m_styleSheet->AddListStyle(numberedList);
534
535    wxRichTextListStyleDefinition* outlineList = new wxRichTextListStyleDefinition(wxT("Outline List 1"));
536    for (i = 0; i < 10; i++)
537    {
538        long numberStyle;
539        if (i < 4)
540            numberStyle = wxTEXT_ATTR_BULLET_STYLE_OUTLINE|wxTEXT_ATTR_BULLET_STYLE_PERIOD;
541        else
542            numberStyle = wxTEXT_ATTR_BULLET_STYLE_ARABIC|wxTEXT_ATTR_BULLET_STYLE_PERIOD;
543
544        outlineList->SetAttributes(i, (i+1)*120, 120, numberStyle);
545    }
546
547    m_styleSheet->AddListStyle(outlineList);
548}
549
550// ----------------------------------------------------------------------------
551// main frame
552// ----------------------------------------------------------------------------
553
554// frame constructor
555MyFrame::MyFrame(const wxString& title, wxWindowID id, const wxPoint& pos,
556        const wxSize& size, long style)
557       : wxFrame(NULL, id, title, pos, size, style)
558{
559    // set the frame icon
560    SetIcon(wxICON(sample));
561
562    // create a menu bar
563    wxMenu *fileMenu = new wxMenu;
564
565    // the "About" item should be in the help menu
566    wxMenu *helpMenu = new wxMenu;
567    helpMenu->Append(ID_About, _T("&About...\tF1"), _T("Show about dialog"));
568
569    fileMenu->Append(wxID_OPEN, _T("&Open\tCtrl+O"), _T("Open a file"));
570    fileMenu->Append(wxID_SAVE, _T("&Save\tCtrl+S"), _T("Save a file"));
571    fileMenu->Append(wxID_SAVEAS, _T("&Save As...\tF12"), _T("Save to a new file"));
572    fileMenu->AppendSeparator();
573    fileMenu->Append(ID_RELOAD, _T("&Reload Text\tF2"), _T("Reload the initial text"));
574    fileMenu->AppendSeparator();
575    fileMenu->Append(ID_PAGE_SETUP, _T("Page Set&up..."), _T("Page setup"));
576    fileMenu->Append(ID_PRINT, _T("&Print...\tCtrl+P"), _T("Print"));
577    fileMenu->Append(ID_PREVIEW, _T("Print Pre&view"), _T("Print preview"));
578    fileMenu->AppendSeparator();
579    fileMenu->Append(ID_VIEW_HTML, _T("&View as HTML"), _T("View HTML"));
580    fileMenu->AppendSeparator();
581    fileMenu->Append(ID_Quit, _T("E&xit\tAlt+X"), _T("Quit this program"));
582
583    wxMenu* editMenu = new wxMenu;
584    editMenu->Append(wxID_UNDO, _("&Undo\tCtrl+Z"));
585    editMenu->Append(wxID_REDO, _("&Redo\tCtrl+Y"));
586    editMenu->AppendSeparator();
587    editMenu->Append(wxID_CUT, _("Cu&t\tCtrl+X"));
588    editMenu->Append(wxID_COPY, _("&Copy\tCtrl+C"));
589    editMenu->Append(wxID_PASTE, _("&Paste\tCtrl+V"));
590
591    editMenu->AppendSeparator();
592    editMenu->Append(wxID_SELECTALL, _("Select A&ll\tCtrl+A"));
593#if 0
594    editMenu->AppendSeparator();
595    editMenu->Append(wxID_FIND, _("&Find...\tCtrl+F"));
596    editMenu->Append(stID_FIND_REPLACE, _("&Replace...\tCtrl+R"));
597#endif
598
599    wxMenu* formatMenu = new wxMenu;
600    formatMenu->AppendCheckItem(ID_FORMAT_BOLD, _("&Bold\tCtrl+B"));
601    formatMenu->AppendCheckItem(ID_FORMAT_ITALIC, _("&Italic\tCtrl+I"));
602    formatMenu->AppendCheckItem(ID_FORMAT_UNDERLINE, _("&Underline\tCtrl+U"));
603    formatMenu->AppendSeparator();
604    formatMenu->AppendCheckItem(ID_FORMAT_ALIGN_LEFT, _("L&eft Align"));
605    formatMenu->AppendCheckItem(ID_FORMAT_ALIGN_RIGHT, _("&Right Align"));
606    formatMenu->AppendCheckItem(ID_FORMAT_ALIGN_CENTRE, _("&Centre"));
607    formatMenu->AppendSeparator();
608    formatMenu->Append(ID_FORMAT_INDENT_MORE, _("Indent &More"));
609    formatMenu->Append(ID_FORMAT_INDENT_LESS, _("Indent &Less"));
610    formatMenu->AppendSeparator();
611    formatMenu->Append(ID_FORMAT_PARAGRAPH_SPACING_MORE, _("Increase Paragraph &Spacing"));
612    formatMenu->Append(ID_FORMAT_PARAGRAPH_SPACING_LESS, _("Decrease &Paragraph Spacing"));
613    formatMenu->AppendSeparator();
614    formatMenu->Append(ID_FORMAT_LINE_SPACING_SINGLE, _("Normal Line Spacing"));
615    formatMenu->Append(ID_FORMAT_LINE_SPACING_HALF, _("1.5 Line Spacing"));
616    formatMenu->Append(ID_FORMAT_LINE_SPACING_DOUBLE, _("Double Line Spacing"));
617    formatMenu->AppendSeparator();
618    formatMenu->Append(ID_FORMAT_FONT, _("&Font..."));
619    formatMenu->Append(ID_FORMAT_PARAGRAPH, _("&Paragraph..."));
620    formatMenu->Append(ID_FORMAT_CONTENT, _("Font and Pa&ragraph...\tShift+Ctrl+F"));
621    formatMenu->AppendSeparator();
622    formatMenu->Append(ID_SWITCH_STYLE_SHEETS, _("&Switch Style Sheets"));
623    formatMenu->Append(ID_MANAGE_STYLES, _("&Manage Styles"));
624
625    wxMenu* listsMenu = new wxMenu;
626    listsMenu->Append(ID_FORMAT_BULLETS_AND_NUMBERING, _("Bullets and &Numbering..."));
627    listsMenu->AppendSeparator();
628    listsMenu->Append(ID_FORMAT_NUMBER_LIST, _("Number List"));
629    listsMenu->Append(ID_FORMAT_ITEMIZE_LIST, _("Itemize List"));
630    listsMenu->Append(ID_FORMAT_RENUMBER_LIST, _("Renumber List"));
631    listsMenu->Append(ID_FORMAT_PROMOTE_LIST, _("Promote List Items"));
632    listsMenu->Append(ID_FORMAT_DEMOTE_LIST, _("Demote List Items"));
633    listsMenu->Append(ID_FORMAT_CLEAR_LIST, _("Clear List Formatting"));
634
635    wxMenu* insertMenu = new wxMenu;
636    insertMenu->Append(ID_INSERT_SYMBOL, _("&Symbol...\tCtrl+I"));
637    insertMenu->Append(ID_INSERT_URL, _("&URL..."));
638
639    // now append the freshly created menu to the menu bar...
640    wxMenuBar *menuBar = new wxMenuBar();
641    menuBar->Append(fileMenu, _T("&File"));
642    menuBar->Append(editMenu, _T("&Edit"));
643    menuBar->Append(formatMenu, _T("F&ormat"));
644    menuBar->Append(listsMenu, _T("&Lists"));
645    menuBar->Append(insertMenu, _T("&Insert"));
646    menuBar->Append(helpMenu, _T("&Help"));
647
648    // ... and attach this menu bar to the frame
649    SetMenuBar(menuBar);
650
651    // create a status bar just for fun (by default with 1 pane only)
652    // but don't create it on limited screen space (WinCE)
653    bool is_pda = wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA;
654
655#if wxUSE_STATUSBAR
656    if ( !is_pda )
657    {
658        CreateStatusBar(2);
659        SetStatusText(_T("Welcome to wxRichTextCtrl!"));
660    }
661#endif
662
663    wxToolBar* toolBar = CreateToolBar();
664
665    toolBar->AddTool(wxID_OPEN, wxBitmap(open_xpm), wxNullBitmap, false, -1, -1, (wxObject *) NULL, _("Open"));
666    toolBar->AddTool(wxID_SAVEAS, wxBitmap(save_xpm), wxNullBitmap, false, -1, -1, (wxObject *) NULL, _("Save"));
667    toolBar->AddSeparator();
668    toolBar->AddTool(wxID_CUT, wxBitmap(cut_xpm), wxNullBitmap, false, -1, -1, (wxObject *) NULL, _("Cut"));
669    toolBar->AddTool(wxID_COPY, wxBitmap(copy_xpm), wxNullBitmap, false, -1, -1, (wxObject *) NULL, _("Copy"));
670    toolBar->AddTool(wxID_PASTE, wxBitmap(paste_xpm), wxNullBitmap, false, -1, -1, (wxObject *) NULL, _("Paste"));
671    toolBar->AddSeparator();
672    toolBar->AddTool(wxID_UNDO, wxBitmap(undo_xpm), wxNullBitmap, false, -1, -1, (wxObject *) NULL, _("Undo"));
673    toolBar->AddTool(wxID_REDO, wxBitmap(redo_xpm), wxNullBitmap, false, -1, -1, (wxObject *) NULL, _("Redo"));
674    toolBar->AddSeparator();
675    toolBar->AddTool(ID_FORMAT_BOLD, wxBitmap(bold_xpm), wxNullBitmap, true, -1, -1, (wxObject *) NULL, _("Bold"));
676    toolBar->AddTool(ID_FORMAT_ITALIC, wxBitmap(italic_xpm), wxNullBitmap, true, -1, -1, (wxObject *) NULL, _("Italic"));
677    toolBar->AddTool(ID_FORMAT_UNDERLINE, wxBitmap(underline_xpm), wxNullBitmap, true, -1, -1, (wxObject *) NULL, _("Underline"));
678    toolBar->AddSeparator();
679    toolBar->AddTool(ID_FORMAT_ALIGN_LEFT, wxBitmap(alignleft_xpm), wxNullBitmap, true, -1, -1, (wxObject *) NULL, _("Align Left"));
680    toolBar->AddTool(ID_FORMAT_ALIGN_CENTRE, wxBitmap(centre_xpm), wxNullBitmap, true, -1, -1, (wxObject *) NULL, _("Centre"));
681    toolBar->AddTool(ID_FORMAT_ALIGN_RIGHT, wxBitmap(alignright_xpm), wxNullBitmap, true, -1, -1, (wxObject *) NULL, _("Align Right"));
682    toolBar->AddSeparator();
683    toolBar->AddTool(ID_FORMAT_INDENT_LESS, wxBitmap(indentless_xpm), wxNullBitmap, false, -1, -1, (wxObject *) NULL, _("Indent Less"));
684    toolBar->AddTool(ID_FORMAT_INDENT_MORE, wxBitmap(indentmore_xpm), wxNullBitmap, false, -1, -1, (wxObject *) NULL, _("Indent More"));
685    toolBar->AddSeparator();
686    toolBar->AddTool(ID_FORMAT_FONT, wxBitmap(font_xpm), wxNullBitmap, false, -1, -1, (wxObject *) NULL, _("Font"));
687
688    wxRichTextStyleComboCtrl* combo = new wxRichTextStyleComboCtrl(toolBar, ID_RICHTEXT_STYLE_COMBO, wxDefaultPosition, wxSize(200, -1));
689    toolBar->AddControl(combo);
690
691    toolBar->Realize();
692
693    wxSplitterWindow* splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, GetClientSize(), wxSP_NO_XP_THEME|wxSP_3D|wxSP_LIVE_UPDATE);
694
695    wxFont textFont = wxFont(12, wxROMAN, wxNORMAL, wxNORMAL);
696    wxFont boldFont = wxFont(12, wxROMAN, wxNORMAL, wxBOLD);
697    wxFont italicFont = wxFont(12, wxROMAN, wxITALIC, wxNORMAL);
698
699    m_richTextCtrl = new wxRichTextCtrl(splitter, ID_RICHTEXT_CTRL, wxEmptyString, wxDefaultPosition, wxSize(200, 200), wxVSCROLL|wxHSCROLL|wxNO_BORDER|wxWANTS_CHARS);
700    wxFont font(12, wxROMAN, wxNORMAL, wxNORMAL);
701
702    m_richTextCtrl->SetFont(font);
703
704    m_richTextCtrl->SetStyleSheet(wxGetApp().GetStyleSheet());
705
706    combo->SetStyleSheet(wxGetApp().GetStyleSheet());
707    combo->SetRichTextCtrl(m_richTextCtrl);
708    combo->UpdateStyles();
709
710    wxRichTextStyleListCtrl* styleListCtrl = new wxRichTextStyleListCtrl(splitter, ID_RICHTEXT_STYLE_LIST);
711
712    wxSize display = wxGetDisplaySize();
713    if ( is_pda && ( display.GetWidth() < display.GetHeight() ) )
714    {
715        splitter->SplitHorizontally(m_richTextCtrl, styleListCtrl);
716    }
717    else
718    {
719        splitter->SplitVertically(m_richTextCtrl, styleListCtrl, 500);
720    }
721
722    splitter->UpdateSize();
723
724    styleListCtrl->SetStyleSheet(wxGetApp().GetStyleSheet());
725    styleListCtrl->SetRichTextCtrl(m_richTextCtrl);
726    styleListCtrl->UpdateStyles();
727
728    WriteInitialText();
729}
730
731// Write text
732void MyFrame::WriteInitialText()
733{
734    wxRichTextCtrl& r = *m_richTextCtrl;
735
736    r.SetDefaultStyle(wxRichTextAttr());
737
738    r.BeginSuppressUndo();
739
740    r.BeginParagraphSpacing(0, 20);
741
742    r.BeginAlignment(wxTEXT_ALIGNMENT_CENTRE);
743    r.BeginBold();
744
745    r.BeginFontSize(14);
746
747    wxString lineBreak = (wxChar) 29;
748
749    r.WriteText(wxString(wxT("Welcome to wxRichTextCtrl, a wxWidgets control")) + lineBreak + wxT("for editing and presenting styled text and images\n"));
750    r.EndFontSize();
751    //r.Newline();
752
753    r.BeginItalic();
754    r.WriteText(wxT("by Julian Smart"));
755    r.EndItalic();
756
757    r.EndBold();
758    r.Newline();
759
760    r.WriteImage(wxBitmap(zebra_xpm));
761
762    r.Newline();
763    r.Newline();
764
765    r.EndAlignment();
766
767    r.WriteText(wxT("What can you do with this thing? "));
768
769    r.WriteImage(wxBitmap(smiley_xpm));
770    r.WriteText(wxT(" Well, you can change text "));
771
772    r.BeginTextColour(wxColour(255, 0, 0));
773    r.WriteText(wxT("colour, like this red bit."));
774    r.EndTextColour();
775
776    wxRichTextAttr backgroundColourAttr;
777    backgroundColourAttr.SetBackgroundColour(*wxGREEN);
778    backgroundColourAttr.SetTextColour(wxColour(0, 0, 255));
779    r.BeginStyle(backgroundColourAttr);
780    r.WriteText(wxT(" And this blue on green bit."));
781    r.EndStyle();
782
783    r.WriteText(wxT(" Naturally you can make things "));
784    r.BeginBold();
785    r.WriteText(wxT("bold "));
786    r.EndBold();
787    r.BeginItalic();
788    r.WriteText(wxT("or italic "));
789    r.EndItalic();
790    r.BeginUnderline();
791    r.WriteText(wxT("or underlined."));
792    r.EndUnderline();
793
794    r.BeginFontSize(14);
795    r.WriteText(wxT(" Different font sizes on the same line is allowed, too."));
796    r.EndFontSize();
797
798    r.WriteText(wxT(" Next we'll show an indented paragraph."));
799
800    r.Newline();
801
802    r.BeginLeftIndent(60);
803    r.WriteText(wxT("It was in January, the most down-trodden month of an Edinburgh winter. An attractive woman came into the cafe, which is nothing remarkable."));
804    r.Newline();
805
806    r.EndLeftIndent();
807
808    r.WriteText(wxT("Next, we'll show a first-line indent, achieved using BeginLeftIndent(100, -40)."));
809
810    r.Newline();
811
812    r.BeginLeftIndent(100, -40);
813
814    r.WriteText(wxT("It was in January, the most down-trodden month of an Edinburgh winter. An attractive woman came into the cafe, which is nothing remarkable."));
815    r.Newline();
816
817    r.EndLeftIndent();
818
819    r.WriteText(wxT("Numbered bullets are possible, again using subindents:"));
820    r.Newline();
821
822    r.BeginNumberedBullet(1, 100, 60);
823    r.WriteText(wxT("This is my first item. Note that wxRichTextCtrl can apply numbering and bullets automatically based on list styles, but this list is formatted explicitly by setting indents."));
824    r.Newline();
825
826    r.EndNumberedBullet();
827
828    r.BeginNumberedBullet(2, 100, 60);
829    r.WriteText(wxT("This is my second item."));
830    r.Newline();
831
832    r.EndNumberedBullet();
833
834    r.WriteText(wxT("The following paragraph is right-indented:"));
835    r.Newline();
836
837    r.BeginRightIndent(200);
838
839    r.WriteText(wxT("It was in January, the most down-trodden month of an Edinburgh winter. An attractive woman came into the cafe, which is nothing remarkable."));
840    r.Newline();
841
842    r.EndRightIndent();
843
844    r.WriteText(wxT("The following paragraph is right-aligned with 1.5 line spacing:"));
845    r.Newline();
846
847    r.BeginAlignment(wxTEXT_ALIGNMENT_RIGHT);
848    r.BeginLineSpacing(wxTEXT_ATTR_LINE_SPACING_HALF);
849    r.WriteText(wxT("It was in January, the most down-trodden month of an Edinburgh winter. An attractive woman came into the cafe, which is nothing remarkable."));
850    r.Newline();
851    r.EndLineSpacing();
852    r.EndAlignment();
853
854    wxArrayInt tabs;
855    tabs.Add(400);
856    tabs.Add(600);
857    tabs.Add(800);
858    tabs.Add(1000);
859    wxTextAttrEx attr;
860    attr.SetFlags(wxTEXT_ATTR_TABS);
861    attr.SetTabs(tabs);
862    r.SetDefaultStyle(attr);
863
864    r.WriteText(wxT("This line contains tabs:\tFirst tab\tSecond tab\tThird tab"));
865    r.Newline();
866
867    r.WriteText(wxT("Other notable features of wxRichTextCtrl include:"));
868    r.Newline();
869
870    r.BeginSymbolBullet(wxT('*'), 100, 60);
871    r.WriteText(wxT("Compatibility with wxTextCtrl API"));
872    r.Newline();
873    r.EndSymbolBullet();
874
875    r.BeginSymbolBullet(wxT('*'), 100, 60);
876    r.WriteText(wxT("Easy stack-based BeginXXX()...EndXXX() style setting in addition to SetStyle()"));
877    r.Newline();
878    r.EndSymbolBullet();
879
880    r.BeginSymbolBullet(wxT('*'), 100, 60);
881    r.WriteText(wxT("XML loading and saving"));
882    r.Newline();
883    r.EndSymbolBullet();
884
885    r.BeginSymbolBullet(wxT('*'), 100, 60);
886    r.WriteText(wxT("Undo/Redo, with batching option and Undo suppressing"));
887    r.Newline();
888    r.EndSymbolBullet();
889
890    r.BeginSymbolBullet(wxT('*'), 100, 60);
891    r.WriteText(wxT("Clipboard copy and paste"));
892    r.Newline();
893    r.EndSymbolBullet();
894
895    r.BeginSymbolBullet(wxT('*'), 100, 60);
896    r.WriteText(wxT("wxRichTextStyleSheet with named character and paragraph styles, and control for applying named styles"));
897    r.Newline();
898    r.EndSymbolBullet();
899
900    r.BeginSymbolBullet(wxT('*'), 100, 60);
901    r.WriteText(wxT("A design that can easily be extended to other content types, ultimately with text boxes, tables, controls, and so on"));
902    r.Newline();
903    r.EndSymbolBullet();
904
905    // Make a style suitable for showing a URL
906    wxRichTextAttr urlStyle;
907    urlStyle.SetTextColour(*wxBLUE);
908    urlStyle.SetFontUnderlined(true);
909
910    r.WriteText(wxT("wxRichTextCtrl can also display URLs, such as this one: "));
911    r.BeginStyle(urlStyle);
912    r.BeginURL(wxT("http://www.wxwidgets.org"));
913    r.WriteText(wxT("The wxWidgets Web Site"));
914    r.EndURL();
915    r.EndStyle();
916    r.WriteText(wxT(". Click on the URL to generate an event."));
917
918    r.Newline();
919
920    r.WriteText(wxT("Note: this sample content was generated programmatically from within the MyFrame constructor in the demo. The images were loaded from inline XPMs. Enjoy wxRichTextCtrl!"));
921
922    r.Newline();
923
924    r.EndParagraphSpacing();
925
926    r.EndSuppressUndo();
927}
928
929
930// event handlers
931
932void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
933{
934    // true is to force the frame to close
935    Close(true);
936}
937
938void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
939{
940    wxString msg;
941    msg.Printf( _T("This is a demo for wxRichTextCtrl, a control for editing styled text.\n(c) Julian Smart, 2005"));
942    wxMessageBox(msg, _T("About wxRichTextCtrl Sample"), wxOK | wxICON_INFORMATION, this);
943}
944
945// Forward command events to the current rich text control, if any
946bool MyFrame::ProcessEvent(wxEvent& event)
947{
948    if (event.IsCommandEvent() && !event.IsKindOf(CLASSINFO(wxChildFocusEvent)))
949    {
950        // Problem: we can get infinite recursion because the events
951        // climb back up to this frame, and repeat.
952        // Assume that command events don't cause another command event
953        // to be called, so we can rely on inCommand not being overwritten
954
955        static int s_eventType = 0;
956        static wxWindowID s_id = 0;
957
958        if (s_id != event.GetId() && s_eventType != event.GetEventType())
959        {
960            s_eventType = event.GetEventType();
961            s_id = event.GetId();
962
963            wxWindow* focusWin = wxFindFocusDescendant(this);
964            if (focusWin && focusWin->ProcessEvent(event))
965            {
966                //s_command = NULL;
967                s_eventType = 0;
968                s_id = 0;
969                return true;
970            }
971
972            s_eventType = 0;
973            s_id = 0;
974        }
975        else
976        {
977            return false;
978        }
979    }
980
981    return wxFrame::ProcessEvent(event);
982}
983
984void MyFrame::OnOpen(wxCommandEvent& WXUNUSED(event))
985{
986    wxString path;
987    wxString filename;
988    wxArrayInt fileTypes;
989
990    wxString filter = wxRichTextBuffer::GetExtWildcard(false, false, & fileTypes);
991    if (!filter.empty())
992        filter += wxT("|");
993    filter += wxT("All files (*.*)|*.*");
994
995    wxFileDialog dialog(this,
996        _("Choose a filename"),
997        path,
998        filename,
999        filter,
1000        wxFD_OPEN);
1001
1002    if (dialog.ShowModal() == wxID_OK)
1003    {
1004        wxString path = dialog.GetPath();
1005
1006        if (!path.empty())
1007        {
1008            int filterIndex = dialog.GetFilterIndex();
1009            int fileType = (filterIndex < (int) fileTypes.GetCount())
1010                           ? fileTypes[filterIndex]
1011                           : wxRICHTEXT_TYPE_TEXT;
1012            m_richTextCtrl->LoadFile(path, fileType);
1013        }
1014    }
1015}
1016
1017void MyFrame::OnSave(wxCommandEvent& event)
1018{
1019    if (m_richTextCtrl->GetFilename().empty())
1020    {
1021        OnSaveAs(event);
1022        return;
1023    }
1024    m_richTextCtrl->SaveFile();
1025}
1026
1027void MyFrame::OnSaveAs(wxCommandEvent& WXUNUSED(event))
1028{
1029    wxString filter = wxRichTextBuffer::GetExtWildcard(false, true);
1030    wxString path;
1031    wxString filename;
1032
1033    wxFileDialog dialog(this,
1034        _("Choose a filename"),
1035        path,
1036        filename,
1037        filter,
1038        wxFD_SAVE);
1039
1040    if (dialog.ShowModal() == wxID_OK)
1041    {
1042        wxString path = dialog.GetPath();
1043
1044        if (!path.empty())
1045        {
1046            m_richTextCtrl->SaveFile(path);
1047        }
1048    }
1049}
1050
1051void MyFrame::OnBold(wxCommandEvent& WXUNUSED(event))
1052{
1053    m_richTextCtrl->ApplyBoldToSelection();
1054}
1055
1056void MyFrame::OnItalic(wxCommandEvent& WXUNUSED(event))
1057{
1058    m_richTextCtrl->ApplyItalicToSelection();
1059}
1060
1061void MyFrame::OnUnderline(wxCommandEvent& WXUNUSED(event))
1062{
1063    m_richTextCtrl->ApplyUnderlineToSelection();
1064}
1065
1066
1067void MyFrame::OnUpdateBold(wxUpdateUIEvent& event)
1068{
1069    event.Check(m_richTextCtrl->IsSelectionBold());
1070}
1071
1072void MyFrame::OnUpdateItalic(wxUpdateUIEvent& event)
1073{
1074    event.Check(m_richTextCtrl->IsSelectionItalics());
1075}
1076
1077void MyFrame::OnUpdateUnderline(wxUpdateUIEvent& event)
1078{
1079    event.Check(m_richTextCtrl->IsSelectionUnderlined());
1080}
1081
1082void MyFrame::OnAlignLeft(wxCommandEvent& WXUNUSED(event))
1083{
1084    m_richTextCtrl->ApplyAlignmentToSelection(wxTEXT_ALIGNMENT_LEFT);
1085}
1086
1087void MyFrame::OnAlignCentre(wxCommandEvent& WXUNUSED(event))
1088{
1089    m_richTextCtrl->ApplyAlignmentToSelection(wxTEXT_ALIGNMENT_CENTRE);
1090}
1091
1092void MyFrame::OnAlignRight(wxCommandEvent& WXUNUSED(event))
1093{
1094    m_richTextCtrl->ApplyAlignmentToSelection(wxTEXT_ALIGNMENT_RIGHT);
1095}
1096
1097void MyFrame::OnUpdateAlignLeft(wxUpdateUIEvent& event)
1098{
1099    event.Check(m_richTextCtrl->IsSelectionAligned(wxTEXT_ALIGNMENT_LEFT));
1100}
1101
1102void MyFrame::OnUpdateAlignCentre(wxUpdateUIEvent& event)
1103{
1104    event.Check(m_richTextCtrl->IsSelectionAligned(wxTEXT_ALIGNMENT_CENTRE));
1105}
1106
1107void MyFrame::OnUpdateAlignRight(wxUpdateUIEvent& event)
1108{
1109    event.Check(m_richTextCtrl->IsSelectionAligned(wxTEXT_ALIGNMENT_RIGHT));
1110}
1111
1112void MyFrame::OnFont(wxCommandEvent& WXUNUSED(event))
1113{
1114    wxRichTextRange range;
1115    if (m_richTextCtrl->HasSelection())
1116        range = m_richTextCtrl->GetSelectionRange();
1117    else
1118        range = wxRichTextRange(0, m_richTextCtrl->GetLastPosition()+1);
1119
1120    int pages = wxRICHTEXT_FORMAT_FONT;
1121
1122    wxRichTextFormattingDialog formatDlg(pages, this);
1123    formatDlg.GetStyle(m_richTextCtrl, range);
1124
1125    if (formatDlg.ShowModal() == wxID_OK)
1126    {
1127        formatDlg.ApplyStyle(m_richTextCtrl, range, wxRICHTEXT_SETSTYLE_WITH_UNDO|wxRICHTEXT_SETSTYLE_OPTIMIZE|wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY);
1128    }
1129
1130    // Old method using wxFontDialog
1131#if 0
1132    if (!m_richTextCtrl->HasSelection())
1133        return;
1134
1135    wxRichTextRange range = m_richTextCtrl->GetSelectionRange();
1136    wxFontData fontData;
1137
1138    wxTextAttrEx attr;
1139    attr.SetFlags(wxTEXT_ATTR_FONT);
1140
1141    if (m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr))
1142        fontData.SetInitialFont(attr.GetFont());
1143
1144    wxFontDialog dialog(this, fontData);
1145    if (dialog.ShowModal() == wxID_OK)
1146    {
1147        fontData = dialog.GetFontData();
1148        attr.SetFlags(wxTEXT_ATTR_FONT);
1149        attr.SetFont(fontData.GetChosenFont());
1150        if (attr.GetFont().Ok())
1151        {
1152            m_richTextCtrl->SetStyle(range, attr);
1153        }
1154    }
1155#endif
1156}
1157
1158void MyFrame::OnParagraph(wxCommandEvent& WXUNUSED(event))
1159{
1160    wxRichTextRange range;
1161    if (m_richTextCtrl->HasSelection())
1162        range = m_richTextCtrl->GetSelectionRange();
1163    else
1164        range = wxRichTextRange(0, m_richTextCtrl->GetLastPosition()+1);
1165
1166    int pages = wxRICHTEXT_FORMAT_INDENTS_SPACING|wxRICHTEXT_FORMAT_TABS|wxRICHTEXT_FORMAT_BULLETS;
1167
1168    wxRichTextFormattingDialog formatDlg(pages, this);
1169    formatDlg.GetStyle(m_richTextCtrl, range);
1170
1171    if (formatDlg.ShowModal() == wxID_OK)
1172    {
1173        formatDlg.ApplyStyle(m_richTextCtrl, range);
1174    }
1175}
1176
1177void MyFrame::OnFormat(wxCommandEvent& WXUNUSED(event))
1178{
1179    wxRichTextRange range;
1180    if (m_richTextCtrl->HasSelection())
1181        range = m_richTextCtrl->GetSelectionRange();
1182    else
1183        range = wxRichTextRange(0, m_richTextCtrl->GetLastPosition()+1);
1184
1185    int pages = wxRICHTEXT_FORMAT_FONT|wxRICHTEXT_FORMAT_INDENTS_SPACING|wxRICHTEXT_FORMAT_TABS|wxRICHTEXT_FORMAT_BULLETS;
1186
1187    wxRichTextFormattingDialog formatDlg(pages, this);
1188    formatDlg.GetStyle(m_richTextCtrl, range);
1189
1190    if (formatDlg.ShowModal() == wxID_OK)
1191    {
1192        formatDlg.ApplyStyle(m_richTextCtrl, range);
1193    }
1194}
1195
1196void MyFrame::OnUpdateFormat(wxUpdateUIEvent& event)
1197{
1198    event.Enable(m_richTextCtrl->HasSelection());
1199}
1200
1201void MyFrame::OnIndentMore(wxCommandEvent& WXUNUSED(event))
1202{
1203    wxTextAttrEx attr;
1204    attr.SetFlags(wxTEXT_ATTR_LEFT_INDENT);
1205
1206    if (m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr))
1207    {
1208        wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint());
1209        if (m_richTextCtrl->HasSelection())
1210            range = m_richTextCtrl->GetSelectionRange();
1211
1212        attr.SetLeftIndent(attr.GetLeftIndent() + 100);
1213
1214        attr.SetFlags(wxTEXT_ATTR_LEFT_INDENT);
1215        m_richTextCtrl->SetStyle(range, attr);
1216    }
1217}
1218
1219void MyFrame::OnIndentLess(wxCommandEvent& WXUNUSED(event))
1220{
1221    wxTextAttrEx attr;
1222    attr.SetFlags(wxTEXT_ATTR_LEFT_INDENT);
1223
1224    if (m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr))
1225    {
1226        wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint());
1227        if (m_richTextCtrl->HasSelection())
1228            range = m_richTextCtrl->GetSelectionRange();
1229
1230        if (attr.GetLeftIndent() > 0)
1231        {
1232            attr.SetLeftIndent(wxMax(0, attr.GetLeftIndent() - 100));
1233
1234            m_richTextCtrl->SetStyle(range, attr);
1235        }
1236    }
1237}
1238
1239void MyFrame::OnLineSpacingHalf(wxCommandEvent& WXUNUSED(event))
1240{
1241    wxTextAttrEx attr;
1242    attr.SetFlags(wxTEXT_ATTR_LINE_SPACING);
1243
1244    if (m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr))
1245    {
1246        wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint());
1247        if (m_richTextCtrl->HasSelection())
1248            range = m_richTextCtrl->GetSelectionRange();
1249
1250        attr.SetFlags(wxTEXT_ATTR_LINE_SPACING);
1251        attr.SetLineSpacing(15);
1252
1253        m_richTextCtrl->SetStyle(range, attr);
1254    }
1255}
1256
1257void MyFrame::OnLineSpacingDouble(wxCommandEvent& WXUNUSED(event))
1258{
1259    wxTextAttrEx attr;
1260    attr.SetFlags(wxTEXT_ATTR_LINE_SPACING);
1261
1262    if (m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr))
1263    {
1264        wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint());
1265        if (m_richTextCtrl->HasSelection())
1266            range = m_richTextCtrl->GetSelectionRange();
1267
1268        attr.SetFlags(wxTEXT_ATTR_LINE_SPACING);
1269        attr.SetLineSpacing(20);
1270
1271        m_richTextCtrl->SetStyle(range, attr);
1272    }
1273}
1274
1275void MyFrame::OnLineSpacingSingle(wxCommandEvent& WXUNUSED(event))
1276{
1277    wxTextAttrEx attr;
1278    attr.SetFlags(wxTEXT_ATTR_LINE_SPACING);
1279
1280    if (m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr))
1281    {
1282        wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint());
1283        if (m_richTextCtrl->HasSelection())
1284            range = m_richTextCtrl->GetSelectionRange();
1285
1286        attr.SetFlags(wxTEXT_ATTR_LINE_SPACING);
1287        attr.SetLineSpacing(0); // Can also use 10
1288
1289        m_richTextCtrl->SetStyle(range, attr);
1290    }
1291}
1292
1293void MyFrame::OnParagraphSpacingMore(wxCommandEvent& WXUNUSED(event))
1294{
1295    wxTextAttrEx attr;
1296    attr.SetFlags(wxTEXT_ATTR_PARA_SPACING_AFTER);
1297
1298    if (m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr))
1299    {
1300        wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint());
1301        if (m_richTextCtrl->HasSelection())
1302            range = m_richTextCtrl->GetSelectionRange();
1303
1304        attr.SetParagraphSpacingAfter(attr.GetParagraphSpacingAfter() + 20);
1305
1306        attr.SetFlags(wxTEXT_ATTR_PARA_SPACING_AFTER);
1307        m_richTextCtrl->SetStyle(range, attr);
1308    }
1309}
1310
1311void MyFrame::OnParagraphSpacingLess(wxCommandEvent& WXUNUSED(event))
1312{
1313    wxTextAttrEx attr;
1314    attr.SetFlags(wxTEXT_ATTR_PARA_SPACING_AFTER);
1315
1316    if (m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr))
1317    {
1318        wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint());
1319        if (m_richTextCtrl->HasSelection())
1320            range = m_richTextCtrl->GetSelectionRange();
1321
1322        if (attr.GetParagraphSpacingAfter() >= 20)
1323        {
1324            attr.SetParagraphSpacingAfter(attr.GetParagraphSpacingAfter() - 20);
1325
1326            attr.SetFlags(wxTEXT_ATTR_PARA_SPACING_AFTER);
1327            m_richTextCtrl->SetStyle(range, attr);
1328        }
1329    }
1330}
1331
1332void MyFrame::OnReload(wxCommandEvent& WXUNUSED(event))
1333{
1334    m_richTextCtrl->Clear();
1335    WriteInitialText();
1336}
1337
1338void MyFrame::OnViewHTML(wxCommandEvent& WXUNUSED(event))
1339{
1340    wxDialog dialog(this, wxID_ANY, _("HTML"), wxDefaultPosition, wxSize(500, 400), wxDEFAULT_DIALOG_STYLE);
1341
1342    wxBoxSizer* boxSizer = new wxBoxSizer(wxVERTICAL);
1343    dialog.SetSizer(boxSizer);
1344
1345    wxHtmlWindow* win = new wxHtmlWindow(& dialog, wxID_ANY, wxDefaultPosition, wxSize(500, 400), wxSUNKEN_BORDER);
1346    boxSizer->Add(win, 1, wxALL, 5);
1347
1348    wxButton* cancelButton = new wxButton(& dialog, wxID_CANCEL, wxT("&Close"));
1349    boxSizer->Add(cancelButton, 0, wxALL|wxCENTRE, 5);
1350
1351    wxString text;
1352    wxStringOutputStream strStream(& text);
1353
1354    wxRichTextHTMLHandler htmlHandler;
1355    htmlHandler.SetFlags(wxRICHTEXT_HANDLER_SAVE_IMAGES_TO_MEMORY);
1356
1357    wxArrayInt fontSizeMapping;
1358    fontSizeMapping.Add(7);
1359    fontSizeMapping.Add(9);
1360    fontSizeMapping.Add(11);
1361    fontSizeMapping.Add(12);
1362    fontSizeMapping.Add(14);
1363    fontSizeMapping.Add(22);
1364    fontSizeMapping.Add(100);
1365
1366    htmlHandler.SetFontSizeMapping(fontSizeMapping);
1367
1368    if (htmlHandler.SaveFile(& m_richTextCtrl->GetBuffer(), strStream))
1369    {
1370        win->SetPage(text);
1371    }
1372
1373    boxSizer->Fit(& dialog);
1374
1375    dialog.ShowModal();
1376
1377    // Now delete the temporary in-memory images
1378    htmlHandler.DeleteTemporaryImages();
1379}
1380
1381// Demonstrates how you can change the style sheets and have the changes
1382// reflected in the control content without wiping out character formatting.
1383
1384void MyFrame::OnSwitchStyleSheets(wxCommandEvent& WXUNUSED(event))
1385{
1386    static wxRichTextStyleSheet* gs_AlternateStyleSheet = NULL;
1387
1388    wxRichTextStyleListCtrl *styleList = (wxRichTextStyleListCtrl*) FindWindow(ID_RICHTEXT_STYLE_LIST);
1389    wxRichTextStyleComboCtrl* styleCombo = (wxRichTextStyleComboCtrl*) FindWindow(ID_RICHTEXT_STYLE_COMBO);
1390
1391    wxRichTextStyleSheet* sheet = m_richTextCtrl->GetStyleSheet();
1392
1393    // One-time creation of an alternate style sheet
1394    if (!gs_AlternateStyleSheet)
1395    {
1396        gs_AlternateStyleSheet = new wxRichTextStyleSheet(*sheet);
1397
1398        // Make some modifications
1399        for (int i = 0; i < (int) gs_AlternateStyleSheet->GetParagraphStyleCount(); i++)
1400        {
1401            wxRichTextParagraphStyleDefinition* def = gs_AlternateStyleSheet->GetParagraphStyle(i);
1402
1403            if (def->GetStyle().HasTextColour())
1404                def->GetStyle().SetTextColour(*wxBLUE);
1405
1406            if (def->GetStyle().HasAlignment())
1407            {
1408                if (def->GetStyle().GetAlignment() == wxTEXT_ALIGNMENT_CENTRE)
1409                    def->GetStyle().SetAlignment(wxTEXT_ALIGNMENT_RIGHT);
1410                else if (def->GetStyle().GetAlignment() == wxTEXT_ALIGNMENT_LEFT)
1411                    def->GetStyle().SetAlignment(wxTEXT_ALIGNMENT_CENTRE);
1412            }
1413            if (def->GetStyle().HasLeftIndent())
1414            {
1415                def->GetStyle().SetLeftIndent(def->GetStyle().GetLeftIndent() * 2);
1416            }
1417        }
1418    }
1419
1420    // Switch sheets
1421    wxRichTextStyleSheet* tmp = gs_AlternateStyleSheet;
1422    gs_AlternateStyleSheet = sheet;
1423    sheet = tmp;
1424
1425    m_richTextCtrl->SetStyleSheet(sheet);
1426    m_richTextCtrl->ApplyStyleSheet(sheet); // Makes the control reflect the new style definitions
1427
1428    styleList->SetStyleSheet(sheet);
1429    styleList->UpdateStyles();
1430
1431    styleCombo->SetStyleSheet(sheet);
1432    styleCombo->UpdateStyles();
1433}
1434
1435void MyFrame::OnManageStyles(wxCommandEvent& WXUNUSED(event))
1436{
1437    wxRichTextStyleSheet* sheet = m_richTextCtrl->GetStyleSheet();
1438
1439    int flags = wxRICHTEXT_ORGANISER_CREATE_STYLES|wxRICHTEXT_ORGANISER_EDIT_STYLES;
1440
1441    wxRichTextStyleOrganiserDialog dlg(flags, sheet, NULL, this, wxID_ANY, _("Style Manager"));
1442    dlg.ShowModal();
1443}
1444
1445void MyFrame::OnInsertSymbol(wxCommandEvent& WXUNUSED(event))
1446{
1447    wxTextAttrEx attr;
1448    attr.SetFlags(wxTEXT_ATTR_FONT);
1449    m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr);
1450
1451    wxString currentFontName;
1452    if (attr.HasFont() && attr.GetFont().Ok())
1453        currentFontName = attr.GetFont().GetFaceName();
1454
1455    // Don't set the initial font in the dialog (so the user is choosing
1456    // 'normal text', i.e. the current font) but do tell the dialog
1457    // what 'normal text' is.
1458
1459    wxSymbolPickerDialog dlg(wxT("*"), wxEmptyString, currentFontName, this);
1460
1461    if (dlg.ShowModal() == wxID_OK)
1462    {
1463        if (dlg.HasSelection())
1464        {
1465            long insertionPoint = m_richTextCtrl->GetInsertionPoint();
1466
1467            m_richTextCtrl->WriteText(dlg.GetSymbol());
1468
1469            if (!dlg.UseNormalFont())
1470            {
1471                wxFont font(attr.GetFont());
1472                font.SetFaceName(dlg.GetFontName());
1473                attr.SetFont(font);
1474                m_richTextCtrl->SetStyle(insertionPoint, insertionPoint+1, attr);
1475            }
1476        }
1477    }
1478}
1479
1480void MyFrame::OnNumberList(wxCommandEvent& WXUNUSED(event))
1481{
1482    if (m_richTextCtrl->HasSelection())
1483    {
1484        wxRichTextRange range = m_richTextCtrl->GetSelectionRange();
1485        m_richTextCtrl->SetListStyle(range, wxT("Numbered List 1"), wxRICHTEXT_SETSTYLE_WITH_UNDO|wxRICHTEXT_SETSTYLE_RENUMBER);
1486    }
1487}
1488
1489void MyFrame::OnBulletsAndNumbering(wxCommandEvent& WXUNUSED(event))
1490{
1491    wxRichTextStyleSheet* sheet = m_richTextCtrl->GetStyleSheet();
1492
1493    int flags = wxRICHTEXT_ORGANISER_BROWSE_NUMBERING;
1494
1495    wxRichTextStyleOrganiserDialog dlg(flags, sheet, m_richTextCtrl, this, wxID_ANY, _("Bullets and Numbering"));
1496    if (dlg.ShowModal() == wxID_OK)
1497    {
1498        if (dlg.GetSelectedStyleDefinition())
1499            dlg.ApplyStyle();
1500    }
1501}
1502
1503void MyFrame::OnItemizeList(wxCommandEvent& WXUNUSED(event))
1504{
1505    if (m_richTextCtrl->HasSelection())
1506    {
1507        wxRichTextRange range = m_richTextCtrl->GetSelectionRange();
1508        m_richTextCtrl->SetListStyle(range, wxT("Bullet List 1"));
1509    }
1510}
1511
1512void MyFrame::OnRenumberList(wxCommandEvent& WXUNUSED(event))
1513{
1514    if (m_richTextCtrl->HasSelection())
1515    {
1516        wxRichTextRange range = m_richTextCtrl->GetSelectionRange();
1517        m_richTextCtrl->NumberList(range, NULL, wxRICHTEXT_SETSTYLE_WITH_UNDO|wxRICHTEXT_SETSTYLE_RENUMBER);
1518    }
1519}
1520
1521void MyFrame::OnPromoteList(wxCommandEvent& WXUNUSED(event))
1522{
1523    if (m_richTextCtrl->HasSelection())
1524    {
1525        wxRichTextRange range = m_richTextCtrl->GetSelectionRange();
1526        m_richTextCtrl->PromoteList(1, range, NULL);
1527    }
1528}
1529
1530void MyFrame::OnDemoteList(wxCommandEvent& WXUNUSED(event))
1531{
1532    if (m_richTextCtrl->HasSelection())
1533    {
1534        wxRichTextRange range = m_richTextCtrl->GetSelectionRange();
1535        m_richTextCtrl->PromoteList(-1, range, NULL);
1536    }
1537}
1538
1539void MyFrame::OnClearList(wxCommandEvent& WXUNUSED(event))
1540{
1541    if (m_richTextCtrl->HasSelection())
1542    {
1543        wxRichTextRange range = m_richTextCtrl->GetSelectionRange();
1544        m_richTextCtrl->ClearListStyle(range);
1545    }
1546}
1547
1548void MyFrame::OnInsertURL(wxCommandEvent& WXUNUSED(event))
1549{
1550    wxString url = wxGetTextFromUser(_("URL:"), _("Insert URL"));
1551    if (!url.IsEmpty())
1552    {
1553        // Make a style suitable for showing a URL
1554        wxRichTextAttr urlStyle;
1555        urlStyle.SetTextColour(*wxBLUE);
1556        urlStyle.SetFontUnderlined(true);
1557
1558        m_richTextCtrl->BeginStyle(urlStyle);
1559        m_richTextCtrl->BeginURL(url);
1560        m_richTextCtrl->WriteText(url);
1561        m_richTextCtrl->EndURL();
1562        m_richTextCtrl->EndStyle();
1563    }
1564}
1565
1566void MyFrame::OnURL(wxTextUrlEvent& event)
1567{
1568    wxMessageBox(event.GetString());
1569}
1570
1571// Veto style sheet replace events when loading from XML, since we want
1572// to keep the original style sheet.
1573void MyFrame::OnStyleSheetReplacing(wxRichTextEvent& event)
1574{
1575    event.Veto();
1576}
1577
1578void MyFrame::OnPrint(wxCommandEvent& WXUNUSED(event))
1579{
1580    wxGetApp().GetPrinting()->PrintBuffer(m_richTextCtrl->GetBuffer());
1581}
1582
1583void MyFrame::OnPreview(wxCommandEvent& WXUNUSED(event))
1584{
1585    wxGetApp().GetPrinting()->PreviewBuffer(m_richTextCtrl->GetBuffer());
1586}
1587
1588void MyFrame::OnPageSetup(wxCommandEvent& WXUNUSED(event))
1589{
1590    wxGetApp().GetPrinting()->PageSetup();
1591}
1592