1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/richtext/richtextstyles.cpp
3 // Purpose:     Style management for wxRichTextCtrl
4 // Author:      Julian Smart
5 // Modified by:
6 // Created:     2005-09-30
7 // RCS-ID:      $Id: richtextstyles.cpp 67222 2011-03-17 09:23:18Z JS $
8 // Copyright:   (c) Julian Smart
9 // Licence:     wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11 
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14 
15 #ifdef __BORLANDC__
16   #pragma hdrstop
17 #endif
18 
19 #if wxUSE_RICHTEXT
20 
21 #include "wx/richtext/richtextstyles.h"
22 
23 #ifndef WX_PRECOMP
24   #include "wx/wx.h"
25 #endif
26 
27 #include "wx/filename.h"
28 #include "wx/clipbrd.h"
29 #include "wx/wfstream.h"
30 #include "wx/settings.h"
31 
32 #include "wx/richtext/richtextctrl.h"
33 
IMPLEMENT_CLASS(wxRichTextStyleDefinition,wxObject)34 IMPLEMENT_CLASS(wxRichTextStyleDefinition, wxObject)
35 IMPLEMENT_CLASS(wxRichTextCharacterStyleDefinition, wxRichTextStyleDefinition)
36 IMPLEMENT_CLASS(wxRichTextParagraphStyleDefinition, wxRichTextStyleDefinition)
37 IMPLEMENT_CLASS(wxRichTextListStyleDefinition, wxRichTextParagraphStyleDefinition)
38 
39 /*!
40  * A definition
41  */
42 
43 void wxRichTextStyleDefinition::Copy(const wxRichTextStyleDefinition& def)
44 {
45     m_name = def.m_name;
46     m_baseStyle = def.m_baseStyle;
47     m_style = def.m_style;
48     m_description = def.m_description;
49 }
50 
Eq(const wxRichTextStyleDefinition & def) const51 bool wxRichTextStyleDefinition::Eq(const wxRichTextStyleDefinition& def) const
52 {
53     return (m_name == def.m_name && m_baseStyle == def.m_baseStyle && m_style == def.m_style);
54 }
55 
56 /// Gets the style combined with the base style
GetStyleMergedWithBase(const wxRichTextStyleSheet * sheet) const57 wxRichTextAttr wxRichTextStyleDefinition::GetStyleMergedWithBase(const wxRichTextStyleSheet* sheet) const
58 {
59     if (m_baseStyle.IsEmpty())
60         return m_style;
61 
62     bool isParaStyle = IsKindOf(CLASSINFO(wxRichTextParagraphStyleDefinition));
63     bool isCharStyle = IsKindOf(CLASSINFO(wxRichTextCharacterStyleDefinition));
64     bool isListStyle = IsKindOf(CLASSINFO(wxRichTextListStyleDefinition));
65 
66     // Collect the styles, detecting loops
67     wxArrayString styleNames;
68     wxList styles;
69     const wxRichTextStyleDefinition* def = this;
70     while (def)
71     {
72         styles.Insert((wxObject*) def);
73         styleNames.Add(def->GetName());
74 
75         wxString baseStyleName = def->GetBaseStyle();
76         if (!baseStyleName.IsEmpty() && styleNames.Index(baseStyleName) == wxNOT_FOUND)
77         {
78             if (isParaStyle)
79                 def = sheet->FindParagraphStyle(baseStyleName);
80             else if (isCharStyle)
81                 def = sheet->FindCharacterStyle(baseStyleName);
82             else if (isListStyle)
83                 def = sheet->FindListStyle(baseStyleName);
84             else
85                 def = sheet->FindStyle(baseStyleName);
86         }
87         else
88             def = NULL;
89     }
90 
91     wxRichTextAttr attr;
92     wxList::compatibility_iterator node = styles.GetFirst();
93     while (node)
94     {
95         wxRichTextStyleDefinition* def = (wxRichTextStyleDefinition*) node->GetData();
96         attr.Apply(def->GetStyle(), NULL);
97         node = node->GetNext();
98     }
99 
100     return attr;
101 }
102 
103 /*!
104  * Paragraph style definition
105  */
106 
Copy(const wxRichTextParagraphStyleDefinition & def)107 void wxRichTextParagraphStyleDefinition::Copy(const wxRichTextParagraphStyleDefinition& def)
108 {
109     wxRichTextStyleDefinition::Copy(def);
110 
111     m_nextStyle = def.m_nextStyle;
112 }
113 
operator ==(const wxRichTextParagraphStyleDefinition & def) const114 bool wxRichTextParagraphStyleDefinition::operator ==(const wxRichTextParagraphStyleDefinition& def) const
115 {
116     return (Eq(def) && m_nextStyle == def.m_nextStyle);
117 }
118 
119 /*!
120  * List style definition
121  */
122 
Copy(const wxRichTextListStyleDefinition & def)123 void wxRichTextListStyleDefinition::Copy(const wxRichTextListStyleDefinition& def)
124 {
125     wxRichTextParagraphStyleDefinition::Copy(def);
126 
127     int i;
128     for (i = 0; i < 10; i++)
129         m_levelStyles[i] = def.m_levelStyles[i];
130 }
131 
operator ==(const wxRichTextListStyleDefinition & def) const132 bool wxRichTextListStyleDefinition::operator ==(const wxRichTextListStyleDefinition& def) const
133 {
134     if (!Eq(def))
135         return false;
136     int i;
137     for (i = 0; i < 10; i++)
138         if (!(m_levelStyles[i] == def.m_levelStyles[i]))
139             return false;
140 
141     return true;
142 }
143 
144 /// Sets/gets the attributes for the given level
SetLevelAttributes(int i,const wxRichTextAttr & attr)145 void wxRichTextListStyleDefinition::SetLevelAttributes(int i, const wxRichTextAttr& attr)
146 {
147     wxASSERT( (i >= 0 && i < 10) );
148     if (i >= 0 && i < 10)
149         m_levelStyles[i] = attr;
150 }
151 
GetLevelAttributes(int i) const152 const wxRichTextAttr* wxRichTextListStyleDefinition::GetLevelAttributes(int i) const
153 {
154     wxASSERT( (i >= 0 && i < 10) );
155     if (i >= 0 && i < 10)
156         return & m_levelStyles[i];
157     else
158         return NULL;
159 }
160 
GetLevelAttributes(int i)161 wxRichTextAttr* wxRichTextListStyleDefinition::GetLevelAttributes(int i)
162 {
163     wxASSERT( (i >= 0 && i < 10) );
164     if (i >= 0 && i < 10)
165         return & m_levelStyles[i];
166     else
167         return NULL;
168 }
169 
170 /// Convenience function for setting the major attributes for a list level specification
SetAttributes(int i,int leftIndent,int leftSubIndent,int bulletStyle,const wxString & bulletSymbol)171 void wxRichTextListStyleDefinition::SetAttributes(int i, int leftIndent, int leftSubIndent, int bulletStyle, const wxString& bulletSymbol)
172 {
173     wxASSERT( (i >= 0 && i < 10) );
174     if (i >= 0 && i < 10)
175     {
176         wxRichTextAttr attr;
177 
178         attr.SetBulletStyle(bulletStyle);
179         attr.SetLeftIndent(leftIndent, leftSubIndent);
180 
181         if (!bulletSymbol.IsEmpty())
182         {
183             if (bulletStyle & wxTEXT_ATTR_BULLET_STYLE_SYMBOL)
184                 attr.SetBulletText(bulletSymbol);
185             else
186                 attr.SetBulletName(bulletSymbol);
187         }
188 
189         m_levelStyles[i] = attr;
190     }
191 }
192 
193 /// Finds the level corresponding to the given indentation
FindLevelForIndent(int indent) const194 int wxRichTextListStyleDefinition::FindLevelForIndent(int indent) const
195 {
196     int i;
197     for (i = 0; i < 10; i++)
198     {
199         if (indent < m_levelStyles[i].GetLeftIndent())
200         {
201             if (i > 0)
202                 return i - 1;
203             else
204                 return 0;
205         }
206     }
207     return 9;
208 }
209 
210 /// Combine the list style with a paragraph style, using the given indent (from which
211 /// an appropriate level is found)
CombineWithParagraphStyle(int indent,const wxRichTextAttr & paraStyle,wxRichTextStyleSheet * styleSheet)212 wxRichTextAttr wxRichTextListStyleDefinition::CombineWithParagraphStyle(int indent, const wxRichTextAttr& paraStyle, wxRichTextStyleSheet* styleSheet)
213 {
214     int listLevel = FindLevelForIndent(indent);
215 
216     wxRichTextAttr attr(*GetLevelAttributes(listLevel));
217     int oldLeftIndent = attr.GetLeftIndent();
218     int oldLeftSubIndent = attr.GetLeftSubIndent();
219 
220     // First apply the overall paragraph style, if any
221     if (styleSheet)
222         attr.Apply(GetStyleMergedWithBase(styleSheet));
223     else
224         attr.Apply(GetStyle());
225 
226     // Then apply paragraph style, e.g. from paragraph style definition
227     attr.Apply(paraStyle);
228 
229     // We override the indents according to the list definition
230     attr.SetLeftIndent(oldLeftIndent, oldLeftSubIndent);
231 
232     return attr;
233 }
234 
235 /// Combine the base and list style, using the given indent (from which
236 /// an appropriate level is found)
GetCombinedStyle(int indent,wxRichTextStyleSheet * styleSheet)237 wxRichTextAttr wxRichTextListStyleDefinition::GetCombinedStyle(int indent, wxRichTextStyleSheet* styleSheet)
238 {
239     int listLevel = FindLevelForIndent(indent);
240     return GetCombinedStyleForLevel(listLevel, styleSheet);
241 }
242 
243 /// Combine the base and list style, using the given indent (from which
244 /// an appropriate level is found)
GetCombinedStyleForLevel(int listLevel,wxRichTextStyleSheet * styleSheet)245 wxRichTextAttr wxRichTextListStyleDefinition::GetCombinedStyleForLevel(int listLevel, wxRichTextStyleSheet* styleSheet)
246 {
247     wxRichTextAttr attr(*GetLevelAttributes(listLevel));
248     int oldLeftIndent = attr.GetLeftIndent();
249     int oldLeftSubIndent = attr.GetLeftSubIndent();
250 
251     // Apply the overall paragraph style, if any
252     if (styleSheet)
253         attr.Apply(GetStyleMergedWithBase(styleSheet));
254     else
255         attr.Apply(GetStyle());
256 
257     // We override the indents according to the list definition
258     attr.SetLeftIndent(oldLeftIndent, oldLeftSubIndent);
259 
260     return attr;
261 }
262 
263 /// Is this a numbered list?
IsNumbered(int i) const264 bool wxRichTextListStyleDefinition::IsNumbered(int i) const
265 {
266     return (0 != (GetLevelAttributes(i)->GetFlags() &
267                    (wxTEXT_ATTR_BULLET_STYLE_ARABIC|wxTEXT_ATTR_BULLET_STYLE_LETTERS_UPPER|wxTEXT_ATTR_BULLET_STYLE_LETTERS_LOWER|
268                     wxTEXT_ATTR_BULLET_STYLE_ROMAN_UPPER|wxTEXT_ATTR_BULLET_STYLE_ROMAN_LOWER)));
269 }
270 
271 /*!
272  * The style manager
273  */
274 
IMPLEMENT_CLASS(wxRichTextStyleSheet,wxObject)275 IMPLEMENT_CLASS(wxRichTextStyleSheet, wxObject)
276 
277 wxRichTextStyleSheet::~wxRichTextStyleSheet()
278 {
279     DeleteStyles();
280 
281     if (m_nextSheet)
282         m_nextSheet->m_previousSheet = m_previousSheet;
283 
284     if (m_previousSheet)
285         m_previousSheet->m_nextSheet = m_nextSheet;
286 
287     m_previousSheet = NULL;
288     m_nextSheet = NULL;
289 }
290 
291 /// Initialisation
Init()292 void wxRichTextStyleSheet::Init()
293 {
294     m_previousSheet = NULL;
295     m_nextSheet = NULL;
296 }
297 
298 /// Add a definition to one of the style lists
AddStyle(wxList & list,wxRichTextStyleDefinition * def)299 bool wxRichTextStyleSheet::AddStyle(wxList& list, wxRichTextStyleDefinition* def)
300 {
301     if (!list.Find(def))
302         list.Append(def);
303     return true;
304 }
305 
306 /// Remove a style
RemoveStyle(wxList & list,wxRichTextStyleDefinition * def,bool deleteStyle)307 bool wxRichTextStyleSheet::RemoveStyle(wxList& list, wxRichTextStyleDefinition* def, bool deleteStyle)
308 {
309     wxList::compatibility_iterator node = list.Find(def);
310     if (node)
311     {
312         wxRichTextStyleDefinition* def = (wxRichTextStyleDefinition*) node->GetData();
313         list.Erase(node);
314         if (deleteStyle)
315             delete def;
316         return true;
317     }
318     else
319         return false;
320 }
321 
322 /// Remove a style
RemoveStyle(wxRichTextStyleDefinition * def,bool deleteStyle)323 bool wxRichTextStyleSheet::RemoveStyle(wxRichTextStyleDefinition* def, bool deleteStyle)
324 {
325     if (RemoveParagraphStyle(def, deleteStyle))
326         return true;
327     if (RemoveCharacterStyle(def, deleteStyle))
328         return true;
329     if (RemoveListStyle(def, deleteStyle))
330         return true;
331     return false;
332 }
333 
334 /// Find a definition by name
FindStyle(const wxList & list,const wxString & name,bool recurse) const335 wxRichTextStyleDefinition* wxRichTextStyleSheet::FindStyle(const wxList& list, const wxString& name, bool recurse) const
336 {
337     for (wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext())
338     {
339         wxRichTextStyleDefinition* def = (wxRichTextStyleDefinition*) node->GetData();
340         if (def->GetName().Lower() == name.Lower())
341             return def;
342     }
343 
344     if (m_nextSheet && recurse)
345         return m_nextSheet->FindStyle(list, name, recurse);
346 
347     return NULL;
348 }
349 
350 /// Delete all styles
DeleteStyles()351 void wxRichTextStyleSheet::DeleteStyles()
352 {
353     WX_CLEAR_LIST(wxList, m_characterStyleDefinitions);
354     WX_CLEAR_LIST(wxList, m_paragraphStyleDefinitions);
355     WX_CLEAR_LIST(wxList, m_listStyleDefinitions);
356 }
357 
358 /// Insert into list of style sheets
InsertSheet(wxRichTextStyleSheet * before)359 bool wxRichTextStyleSheet::InsertSheet(wxRichTextStyleSheet* before)
360 {
361     m_previousSheet = before->m_previousSheet;
362     m_nextSheet = before;
363 
364     before->m_previousSheet = this;
365     return true;
366 }
367 
368 /// Append to list of style sheets
AppendSheet(wxRichTextStyleSheet * after)369 bool wxRichTextStyleSheet::AppendSheet(wxRichTextStyleSheet* after)
370 {
371     wxRichTextStyleSheet* last = after;
372     while (last && last->m_nextSheet)
373     {
374         last = last->m_nextSheet;
375     }
376 
377     if (last)
378     {
379         m_previousSheet = last;
380         last->m_nextSheet = this;
381 
382         return true;
383     }
384     else
385         return false;
386 }
387 
388 /// Unlink from the list of style sheets
Unlink()389 void wxRichTextStyleSheet::Unlink()
390 {
391     if (m_previousSheet)
392         m_previousSheet->m_nextSheet = m_nextSheet;
393     if (m_nextSheet)
394         m_nextSheet->m_previousSheet = m_previousSheet;
395 
396     m_previousSheet = NULL;
397     m_nextSheet = NULL;
398 }
399 
400 /// Add a definition to the character style list
AddCharacterStyle(wxRichTextCharacterStyleDefinition * def)401 bool wxRichTextStyleSheet::AddCharacterStyle(wxRichTextCharacterStyleDefinition* def)
402 {
403     def->GetStyle().SetCharacterStyleName(def->GetName());
404     return AddStyle(m_characterStyleDefinitions, def);
405 }
406 
407 /// Add a definition to the paragraph style list
AddParagraphStyle(wxRichTextParagraphStyleDefinition * def)408 bool wxRichTextStyleSheet::AddParagraphStyle(wxRichTextParagraphStyleDefinition* def)
409 {
410     def->GetStyle().SetParagraphStyleName(def->GetName());
411     return AddStyle(m_paragraphStyleDefinitions, def);
412 }
413 
414 /// Add a definition to the list style list
AddListStyle(wxRichTextListStyleDefinition * def)415 bool wxRichTextStyleSheet::AddListStyle(wxRichTextListStyleDefinition* def)
416 {
417     def->GetStyle().SetListStyleName(def->GetName());
418     return AddStyle(m_listStyleDefinitions, def);
419 }
420 
421 /// Add a definition to the appropriate style list
AddStyle(wxRichTextStyleDefinition * def)422 bool wxRichTextStyleSheet::AddStyle(wxRichTextStyleDefinition* def)
423 {
424     wxRichTextListStyleDefinition* listDef = wxDynamicCast(def, wxRichTextListStyleDefinition);
425     if (listDef)
426         return AddListStyle(listDef);
427 
428     wxRichTextParagraphStyleDefinition* paraDef = wxDynamicCast(def, wxRichTextParagraphStyleDefinition);
429     if (paraDef)
430         return AddParagraphStyle(paraDef);
431 
432     wxRichTextCharacterStyleDefinition* charDef = wxDynamicCast(def, wxRichTextCharacterStyleDefinition);
433     if (charDef)
434         return AddCharacterStyle(charDef);
435 
436     return false;
437 }
438 
439 /// Find any definition by name
FindStyle(const wxString & name,bool recurse) const440 wxRichTextStyleDefinition* wxRichTextStyleSheet::FindStyle(const wxString& name, bool recurse) const
441 {
442     wxRichTextListStyleDefinition* listDef = FindListStyle(name, recurse);
443     if (listDef)
444         return listDef;
445 
446     wxRichTextParagraphStyleDefinition* paraDef = FindParagraphStyle(name, recurse);
447     if (paraDef)
448         return paraDef;
449 
450     wxRichTextCharacterStyleDefinition* charDef = FindCharacterStyle(name, recurse);
451     if (charDef)
452         return charDef;
453 
454     return NULL;
455 }
456 
457 /// Copy
Copy(const wxRichTextStyleSheet & sheet)458 void wxRichTextStyleSheet::Copy(const wxRichTextStyleSheet& sheet)
459 {
460     DeleteStyles();
461 
462     wxList::compatibility_iterator node;
463 
464     for (node = sheet.m_characterStyleDefinitions.GetFirst(); node; node = node->GetNext())
465     {
466         wxRichTextCharacterStyleDefinition* def = (wxRichTextCharacterStyleDefinition*) node->GetData();
467         AddCharacterStyle(new wxRichTextCharacterStyleDefinition(*def));
468     }
469 
470     for (node = sheet.m_paragraphStyleDefinitions.GetFirst(); node; node = node->GetNext())
471     {
472         wxRichTextParagraphStyleDefinition* def = (wxRichTextParagraphStyleDefinition*) node->GetData();
473         AddParagraphStyle(new wxRichTextParagraphStyleDefinition(*def));
474     }
475 
476     for (node = sheet.m_listStyleDefinitions.GetFirst(); node; node = node->GetNext())
477     {
478         wxRichTextListStyleDefinition* def = (wxRichTextListStyleDefinition*) node->GetData();
479         AddListStyle(new wxRichTextListStyleDefinition(*def));
480     }
481 
482     SetName(sheet.GetName());
483     SetDescription(sheet.GetDescription());
484 }
485 
486 /// Equality
operator ==(const wxRichTextStyleSheet & WXUNUSED (sheet)) const487 bool wxRichTextStyleSheet::operator==(const wxRichTextStyleSheet& WXUNUSED(sheet)) const
488 {
489     // TODO
490     return false;
491 }
492 
493 
494 #if wxUSE_HTML
495 
496 // Functions for dealing with clashing names for different kinds of style.
497 // Returns "P", "C", or "L" (paragraph, character, list) for
498 // style name | type.
wxGetRichTextStyleType(const wxString & style)499 static wxString wxGetRichTextStyleType(const wxString& style)
500 {
501     return style.AfterLast(wxT('|'));
502 }
503 
wxGetRichTextStyle(const wxString & style)504 static wxString wxGetRichTextStyle(const wxString& style)
505 {
506     return style.BeforeLast(wxT('|'));
507 }
508 
509 /*!
510  * wxRichTextStyleListBox: a listbox to display styles.
511  */
512 
IMPLEMENT_CLASS(wxRichTextStyleListBox,wxHtmlListBox)513 IMPLEMENT_CLASS(wxRichTextStyleListBox, wxHtmlListBox)
514 
515 BEGIN_EVENT_TABLE(wxRichTextStyleListBox, wxHtmlListBox)
516     EVT_LEFT_DOWN(wxRichTextStyleListBox::OnLeftDown)
517     EVT_LEFT_DCLICK(wxRichTextStyleListBox::OnLeftDoubleClick)
518     EVT_IDLE(wxRichTextStyleListBox::OnIdle)
519 END_EVENT_TABLE()
520 
521 wxRichTextStyleListBox::wxRichTextStyleListBox(wxWindow* parent, wxWindowID id, const wxPoint& pos,
522     const wxSize& size, long style)
523 {
524     Init();
525     Create(parent, id, pos, size, style);
526 }
527 
Create(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style)528 bool wxRichTextStyleListBox::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos,
529         const wxSize& size, long style)
530 {
531     return wxHtmlListBox::Create(parent, id, pos, size, style);
532 }
533 
~wxRichTextStyleListBox()534 wxRichTextStyleListBox::~wxRichTextStyleListBox()
535 {
536 }
537 
538 /// Returns the HTML for this item
OnGetItem(size_t n) const539 wxString wxRichTextStyleListBox::OnGetItem(size_t n) const
540 {
541     if (!GetStyleSheet())
542         return wxEmptyString;
543 
544     wxRichTextStyleDefinition* def = GetStyle(n);
545     if (def)
546         return CreateHTML(def);
547 
548     return wxEmptyString;
549 }
550 
551 // Get style for index
GetStyle(size_t i) const552 wxRichTextStyleDefinition* wxRichTextStyleListBox::GetStyle(size_t i) const
553 {
554     if (!GetStyleSheet())
555         return NULL;
556 
557     if (i >= m_styleNames.GetCount() /* || i < 0 */ )
558         return NULL;
559 
560     wxString styleType = wxGetRichTextStyleType(m_styleNames[i]);
561     wxString style = wxGetRichTextStyle(m_styleNames[i]);
562     if (styleType == wxT("P"))
563         return GetStyleSheet()->FindParagraphStyle(style);
564     else if (styleType == wxT("C"))
565         return GetStyleSheet()->FindCharacterStyle(style);
566     else if (styleType == wxT("L"))
567         return GetStyleSheet()->FindListStyle(style);
568     else
569         return GetStyleSheet()->FindStyle(style);
570 }
571 
572 /// Updates the list
UpdateStyles()573 void wxRichTextStyleListBox::UpdateStyles()
574 {
575     if (GetStyleSheet())
576     {
577         int oldSel = GetSelection();
578 
579         SetSelection(wxNOT_FOUND);
580 
581         m_styleNames.Clear();
582 
583         size_t i;
584         if (GetStyleType() == wxRICHTEXT_STYLE_ALL || GetStyleType() == wxRICHTEXT_STYLE_PARAGRAPH)
585         {
586             for (i = 0; i < GetStyleSheet()->GetParagraphStyleCount(); i++)
587                 m_styleNames.Add(GetStyleSheet()->GetParagraphStyle(i)->GetName() + wxT("|P"));
588         }
589         if (GetStyleType() == wxRICHTEXT_STYLE_ALL || GetStyleType() == wxRICHTEXT_STYLE_CHARACTER)
590         {
591             for (i = 0; i < GetStyleSheet()->GetCharacterStyleCount(); i++)
592                 m_styleNames.Add(GetStyleSheet()->GetCharacterStyle(i)->GetName() + wxT("|C"));
593         }
594         if (GetStyleType() == wxRICHTEXT_STYLE_ALL || GetStyleType() == wxRICHTEXT_STYLE_LIST)
595         {
596             for (i = 0; i < GetStyleSheet()->GetListStyleCount(); i++)
597                 m_styleNames.Add(GetStyleSheet()->GetListStyle(i)->GetName() + wxT("|L"));
598         }
599 
600         m_styleNames.Sort();
601         SetItemCount(m_styleNames.GetCount());
602 
603         Refresh();
604 
605         int newSel = -1;
606         if (oldSel >= 0 && oldSel < (int) GetItemCount())
607             newSel = oldSel;
608         else if (GetItemCount() > 0)
609             newSel = 0;
610 
611         if (newSel >= 0)
612         {
613             SetSelection(newSel);
614             SendSelectedEvent();
615         }
616     }
617 }
618 
619 // Get index for style name
GetIndexForStyle(const wxString & name) const620 int wxRichTextStyleListBox::GetIndexForStyle(const wxString& name) const
621 {
622     wxString s(name);
623     if (GetStyleType() == wxRICHTEXT_STYLE_PARAGRAPH)
624         s += wxT("|P");
625     else if (GetStyleType() == wxRICHTEXT_STYLE_CHARACTER)
626         s += wxT("|C");
627     else if (GetStyleType() == wxRICHTEXT_STYLE_LIST)
628         s += wxT("|L");
629     else
630     {
631         if (m_styleNames.Index(s + wxT("|P")) != wxNOT_FOUND)
632             s += wxT("|P");
633         else if (m_styleNames.Index(s + wxT("|C")) != wxNOT_FOUND)
634             s += wxT("|C");
635         else if (m_styleNames.Index(s + wxT("|L")) != wxNOT_FOUND)
636             s += wxT("|L");
637     }
638     return m_styleNames.Index(s);
639 }
640 
641 /// Set selection for string
SetStyleSelection(const wxString & name)642 int wxRichTextStyleListBox::SetStyleSelection(const wxString& name)
643 {
644     int i = GetIndexForStyle(name);
645     if (i > -1)
646         SetSelection(i);
647     return i;
648 }
649 
650 // Convert a colour to a 6-digit hex string
ColourToHexString(const wxColour & col)651 static wxString ColourToHexString(const wxColour& col)
652 {
653     wxString hex;
654 
655     hex += wxDecToHex(col.Red());
656     hex += wxDecToHex(col.Green());
657     hex += wxDecToHex(col.Blue());
658 
659     return hex;
660 }
661 
662 /// Creates a suitable HTML fragment for a definition
CreateHTML(wxRichTextStyleDefinition * def) const663 wxString wxRichTextStyleListBox::CreateHTML(wxRichTextStyleDefinition* def) const
664 {
665     // TODO: indicate list format for list style types
666 
667     wxString str;
668 
669     bool isCentred = false;
670 
671     wxRichTextAttr attr(def->GetStyleMergedWithBase(GetStyleSheet()));
672 
673     if (attr.HasAlignment() && attr.GetAlignment() == wxTEXT_ALIGNMENT_CENTRE)
674         isCentred = true;
675 
676     if (isCentred)
677         str << wxT("<center>");
678 
679 
680     str << wxT("<table><tr>");
681 
682     if (attr.GetLeftIndent() > 0)
683     {
684         wxClientDC dc((wxWindow*) this);
685 
686         str << wxT("<td width=") << wxMin(50, (ConvertTenthsMMToPixels(dc, attr.GetLeftIndent())/2)) << wxT("></td>");
687     }
688 
689     if (isCentred)
690         str << wxT("<td nowrap align=\"center\">");
691     else
692         str << wxT("<td nowrap>");
693 
694 #ifdef __WXMSW__
695     int size = 2;
696 #else
697     int size = 3;
698 #endif
699 
700     // Guess a standard font size
701     int stdFontSize = 0;
702 
703     // First see if we have a default/normal style to base the size on
704     wxString normalTranslated(_("normal"));
705     wxString defaultTranslated(_("default"));
706     size_t i;
707     for (i = 0; i < GetStyleSheet()->GetParagraphStyleCount(); i++)
708     {
709         wxRichTextStyleDefinition* d = GetStyleSheet()->GetParagraphStyle(i);
710         wxString name = d->GetName().Lower();
711         if (name.Find(wxT("normal")) != wxNOT_FOUND || name.Find(normalTranslated) != wxNOT_FOUND ||
712             name.Find(wxT("default")) != wxNOT_FOUND || name.Find(defaultTranslated) != wxNOT_FOUND)
713         {
714             wxRichTextAttr attr2(d->GetStyleMergedWithBase(GetStyleSheet()));
715             if (attr2.HasFontSize())
716             {
717                 stdFontSize = attr2.GetFontSize();
718                 break;
719             }
720         }
721     }
722 
723     if (stdFontSize == 0)
724     {
725         // Look at sizes up to 20 points, and see which is the most common
726         wxArrayInt sizes;
727         size_t maxSize = 20;
728         for (i = 0; i <= maxSize; i++)
729             sizes.Add(0);
730         for (i = 0; i < m_styleNames.GetCount(); i++)
731         {
732             wxRichTextStyleDefinition* d = GetStyle(i);
733             if (d)
734             {
735                 wxRichTextAttr attr2(d->GetStyleMergedWithBase(GetStyleSheet()));
736                 if (attr2.HasFontSize())
737                 {
738                     if (attr2.GetFontSize() <= (int) maxSize)
739                         sizes[attr2.GetFontSize()] ++;
740                 }
741             }
742         }
743         int mostCommonSize = 0;
744         for (i = 0; i <= maxSize; i++)
745         {
746             if (sizes[i] > mostCommonSize)
747                 mostCommonSize = i;
748         }
749         if (mostCommonSize > 0)
750             stdFontSize = mostCommonSize;
751     }
752 
753     if (stdFontSize == 0)
754         stdFontSize = 12;
755 
756     int thisFontSize = ((attr.GetFlags() & wxTEXT_ATTR_FONT_SIZE) != 0) ? attr.GetFontSize() : stdFontSize;
757 
758     if (thisFontSize < stdFontSize)
759         size --;
760     else if (thisFontSize > stdFontSize)
761         size ++;
762 
763     str += wxT("<font");
764 
765     str << wxT(" size=") << size;
766 
767     if (!attr.GetFontFaceName().IsEmpty())
768         str << wxT(" face=\"") << attr.GetFontFaceName() << wxT("\"");
769 
770     if (attr.GetTextColour().Ok())
771         str << wxT(" color=\"#") << ColourToHexString(attr.GetTextColour()) << wxT("\"");
772 
773     str << wxT(">");
774 
775     bool hasBold = false;
776     bool hasItalic = false;
777     bool hasUnderline = false;
778 
779     if (attr.GetFontWeight() == wxBOLD)
780         hasBold = true;
781     if (attr.GetFontStyle() == wxITALIC)
782         hasItalic = true;
783     if (attr.GetFontUnderlined())
784         hasUnderline = true;
785 
786     if (hasBold)
787         str << wxT("<b>");
788     if (hasItalic)
789         str << wxT("<i>");
790     if (hasUnderline)
791         str << wxT("<u>");
792 
793     str += def->GetName();
794 
795     if (hasUnderline)
796         str << wxT("</u>");
797     if (hasItalic)
798         str << wxT("</i>");
799     if (hasBold)
800         str << wxT("</b>");
801 
802     if (isCentred)
803         str << wxT("</centre>");
804 
805     str << wxT("</font>");
806 
807     str << wxT("</td></tr></table>");
808 
809     if (isCentred)
810         str << wxT("</center>");
811 
812     return str;
813 }
814 
815 // Convert units in tends of a millimetre to device units
ConvertTenthsMMToPixels(wxDC & dc,int units) const816 int wxRichTextStyleListBox::ConvertTenthsMMToPixels(wxDC& dc, int units) const
817 {
818     int ppi = dc.GetPPI().x;
819 
820     // There are ppi pixels in 254.1 "1/10 mm"
821 
822     double pixels = ((double) units * (double)ppi) / 254.1;
823 
824     return (int) pixels;
825 }
826 
OnLeftDown(wxMouseEvent & event)827 void wxRichTextStyleListBox::OnLeftDown(wxMouseEvent& event)
828 {
829     wxVListBox::OnLeftDown(event);
830 
831     int item = HitTest(event.GetPosition());
832     if (item != wxNOT_FOUND && GetApplyOnSelection())
833         ApplyStyle(item);
834 }
835 
OnLeftDoubleClick(wxMouseEvent & event)836 void wxRichTextStyleListBox::OnLeftDoubleClick(wxMouseEvent& event)
837 {
838     wxVListBox::OnLeftDown(event);
839 
840     int item = HitTest(event.GetPosition());
841     if (item != wxNOT_FOUND && !GetApplyOnSelection())
842         ApplyStyle(item);
843 }
844 
845 /// Helper for listbox and combo control
GetStyleToShowInIdleTime(wxRichTextCtrl * ctrl,wxRichTextStyleType styleType)846 wxString wxRichTextStyleListBox::GetStyleToShowInIdleTime(wxRichTextCtrl* ctrl, wxRichTextStyleType styleType)
847 {
848     int adjustedCaretPos = ctrl->GetAdjustedCaretPosition(ctrl->GetCaretPosition());
849 
850     wxString styleName;
851 
852     wxTextAttrEx attr;
853     ctrl->GetStyle(adjustedCaretPos, attr);
854 
855     // Take into account current default style just chosen by user
856     if (ctrl->IsDefaultStyleShowing())
857     {
858         wxRichTextApplyStyle(attr, ctrl->GetDefaultStyleEx());
859 
860         if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_CHARACTER) &&
861                           !attr.GetCharacterStyleName().IsEmpty())
862             styleName = attr.GetCharacterStyleName();
863         else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_PARAGRAPH) &&
864                           !attr.GetParagraphStyleName().IsEmpty())
865             styleName = attr.GetParagraphStyleName();
866         else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_LIST) &&
867                           !attr.GetListStyleName().IsEmpty())
868             styleName = attr.GetListStyleName();
869     }
870     else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_CHARACTER) &&
871              !attr.GetCharacterStyleName().IsEmpty())
872     {
873         styleName = attr.GetCharacterStyleName();
874     }
875     else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_PARAGRAPH) &&
876              !attr.GetParagraphStyleName().IsEmpty())
877     {
878         styleName = attr.GetParagraphStyleName();
879     }
880     else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_LIST) &&
881              !attr.GetListStyleName().IsEmpty())
882     {
883         styleName = attr.GetListStyleName();
884     }
885 
886     return styleName;
887 }
888 
889 /// Auto-select from style under caret in idle time
OnIdle(wxIdleEvent & event)890 void wxRichTextStyleListBox::OnIdle(wxIdleEvent& event)
891 {
892     if (CanAutoSetSelection() && GetRichTextCtrl() && IsShownOnScreen() && wxWindow::FindFocus() != this)
893     {
894         wxString styleName = GetStyleToShowInIdleTime(GetRichTextCtrl(), GetStyleType());
895 
896         int sel = GetSelection();
897         if (!styleName.IsEmpty())
898         {
899             // Don't do the selection if it's already set
900             if (sel == GetIndexForStyle(styleName))
901                 return;
902 
903             SetStyleSelection(styleName);
904         }
905         else if (sel != -1)
906             SetSelection(-1);
907     }
908     event.Skip();
909 }
910 
911 /// Do selection
ApplyStyle(int item)912 void wxRichTextStyleListBox::ApplyStyle(int item)
913 {
914     if ( item != wxNOT_FOUND )
915     {
916         wxRichTextStyleDefinition* def = GetStyle(item);
917         if (def && GetRichTextCtrl())
918         {
919             GetRichTextCtrl()->ApplyStyle(def);
920             GetRichTextCtrl()->SetFocus();
921         }
922     }
923 }
924 
925 /*!
926  * wxRichTextStyleListCtrl class: manages a listbox and a choice control to
927  * switch shown style types
928  */
929 
IMPLEMENT_CLASS(wxRichTextStyleListCtrl,wxControl)930 IMPLEMENT_CLASS(wxRichTextStyleListCtrl, wxControl)
931 
932 BEGIN_EVENT_TABLE(wxRichTextStyleListCtrl, wxControl)
933     EVT_CHOICE(wxID_ANY, wxRichTextStyleListCtrl::OnChooseType)
934     EVT_SIZE(wxRichTextStyleListCtrl::OnSize)
935 END_EVENT_TABLE()
936 
937 wxRichTextStyleListCtrl::wxRichTextStyleListCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos,
938     const wxSize& size, long style)
939 {
940     Init();
941     Create(parent, id, pos, size, style);
942 }
943 
Create(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style)944 bool wxRichTextStyleListCtrl::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos,
945         const wxSize& size, long style)
946 {
947     if ((style & wxBORDER_MASK) == wxBORDER_DEFAULT)
948 #ifdef __WXMSW__
949         style |= GetThemedBorderStyle();
950 #else
951         style |= wxBORDER_SUNKEN;
952 #endif
953 
954     wxControl::Create(parent, id, pos, size, style);
955 
956     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
957     if (size != wxDefaultSize)
958         SetInitialSize(size);
959 
960     bool showSelector = ((style & wxRICHTEXTSTYLELIST_HIDE_TYPE_SELECTOR) == 0);
961 
962     wxBorder listBoxStyle;
963     if (showSelector)
964     {
965 #ifdef __WXMSW__
966         listBoxStyle = GetThemedBorderStyle();
967 #else
968         listBoxStyle = wxBORDER_SUNKEN;
969 #endif
970     }
971     else
972         listBoxStyle = wxBORDER_NONE;
973 
974     m_styleListBox = new wxRichTextStyleListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, listBoxStyle);
975 
976     wxBoxSizer* boxSizer = new wxBoxSizer(wxVERTICAL);
977 
978     if (showSelector)
979     {
980         wxArrayString choices;
981         choices.Add(_("All styles"));
982         choices.Add(_("Paragraph styles"));
983         choices.Add(_("Character styles"));
984         choices.Add(_("List styles"));
985 
986         m_styleChoice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, choices);
987 
988         boxSizer->Add(m_styleListBox, 1, wxALL|wxEXPAND, 5);
989         boxSizer->Add(m_styleChoice, 0, wxALL|wxEXPAND, 5);
990     }
991     else
992     {
993         boxSizer->Add(m_styleListBox, 1, wxALL|wxEXPAND, 0);
994     }
995 
996     SetSizer(boxSizer);
997     Layout();
998 
999     m_dontUpdate = true;
1000 
1001     if (m_styleChoice)
1002     {
1003         int i = StyleTypeToIndex(m_styleListBox->GetStyleType());
1004         m_styleChoice->SetSelection(i);
1005     }
1006 
1007     m_dontUpdate = false;
1008 
1009     return true;
1010 }
1011 
~wxRichTextStyleListCtrl()1012 wxRichTextStyleListCtrl::~wxRichTextStyleListCtrl()
1013 {
1014 
1015 }
1016 
1017 /// React to style type choice
OnChooseType(wxCommandEvent & event)1018 void wxRichTextStyleListCtrl::OnChooseType(wxCommandEvent& event)
1019 {
1020     if (event.GetEventObject() != m_styleChoice)
1021         event.Skip();
1022     else
1023     {
1024         if (m_dontUpdate)
1025             return;
1026 
1027         wxRichTextStyleListBox::wxRichTextStyleType styleType = StyleIndexToType(event.GetSelection());
1028         m_styleListBox->SetSelection(-1);
1029         m_styleListBox->SetStyleType(styleType);
1030     }
1031 }
1032 
1033 /// Lay out the controls
OnSize(wxSizeEvent & WXUNUSED (event))1034 void wxRichTextStyleListCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
1035 {
1036     if (GetAutoLayout())
1037         Layout();
1038 }
1039 
1040 /// Get the choice index for style type
StyleTypeToIndex(wxRichTextStyleListBox::wxRichTextStyleType styleType)1041 int wxRichTextStyleListCtrl::StyleTypeToIndex(wxRichTextStyleListBox::wxRichTextStyleType styleType)
1042 {
1043     if (styleType == wxRichTextStyleListBox::wxRICHTEXT_STYLE_ALL)
1044     {
1045         return 0;
1046     }
1047     else if (styleType == wxRichTextStyleListBox::wxRICHTEXT_STYLE_PARAGRAPH)
1048     {
1049         return 1;
1050     }
1051     else if (styleType == wxRichTextStyleListBox::wxRICHTEXT_STYLE_CHARACTER)
1052     {
1053         return 2;
1054     }
1055     else if (styleType == wxRichTextStyleListBox::wxRICHTEXT_STYLE_LIST)
1056     {
1057         return 3;
1058     }
1059     return 0;
1060 }
1061 
1062 /// Get the style type for choice index
StyleIndexToType(int i)1063 wxRichTextStyleListBox::wxRichTextStyleType wxRichTextStyleListCtrl::StyleIndexToType(int i)
1064 {
1065     if (i == 1)
1066         return wxRichTextStyleListBox::wxRICHTEXT_STYLE_PARAGRAPH;
1067     else if (i == 2)
1068         return wxRichTextStyleListBox::wxRICHTEXT_STYLE_CHARACTER;
1069     else if (i == 3)
1070         return wxRichTextStyleListBox::wxRICHTEXT_STYLE_LIST;
1071 
1072     return wxRichTextStyleListBox::wxRICHTEXT_STYLE_ALL;
1073 }
1074 
1075 /// Associates the control with a style manager
SetStyleSheet(wxRichTextStyleSheet * styleSheet)1076 void wxRichTextStyleListCtrl::SetStyleSheet(wxRichTextStyleSheet* styleSheet)
1077 {
1078     if (m_styleListBox)
1079         m_styleListBox->SetStyleSheet(styleSheet);
1080 }
1081 
GetStyleSheet() const1082 wxRichTextStyleSheet* wxRichTextStyleListCtrl::GetStyleSheet() const
1083 {
1084     if (m_styleListBox)
1085         return m_styleListBox->GetStyleSheet();
1086     else
1087         return NULL;
1088 }
1089 
1090 /// Associates the control with a wxRichTextCtrl
SetRichTextCtrl(wxRichTextCtrl * ctrl)1091 void wxRichTextStyleListCtrl::SetRichTextCtrl(wxRichTextCtrl* ctrl)
1092 {
1093     if (m_styleListBox)
1094         m_styleListBox->SetRichTextCtrl(ctrl);
1095 }
1096 
GetRichTextCtrl() const1097 wxRichTextCtrl* wxRichTextStyleListCtrl::GetRichTextCtrl() const
1098 {
1099     if (m_styleListBox)
1100         return m_styleListBox->GetRichTextCtrl();
1101     else
1102         return NULL;
1103 }
1104 
1105 /// Set/get the style type to display
SetStyleType(wxRichTextStyleListBox::wxRichTextStyleType styleType)1106 void wxRichTextStyleListCtrl::SetStyleType(wxRichTextStyleListBox::wxRichTextStyleType styleType)
1107 {
1108     if (m_styleListBox)
1109         m_styleListBox->SetStyleType(styleType);
1110 
1111     m_dontUpdate = true;
1112 
1113     if (m_styleChoice)
1114     {
1115         int i = StyleTypeToIndex(m_styleListBox->GetStyleType());
1116         m_styleChoice->SetSelection(i);
1117     }
1118 
1119     m_dontUpdate = false;
1120 }
1121 
GetStyleType() const1122 wxRichTextStyleListBox::wxRichTextStyleType wxRichTextStyleListCtrl::GetStyleType() const
1123 {
1124     if (m_styleListBox)
1125         return m_styleListBox->GetStyleType();
1126     else
1127         return wxRichTextStyleListBox::wxRICHTEXT_STYLE_ALL;
1128 }
1129 
1130 /// Updates the style list box
UpdateStyles()1131 void wxRichTextStyleListCtrl::UpdateStyles()
1132 {
1133     if (m_styleListBox)
1134         m_styleListBox->UpdateStyles();
1135 }
1136 
1137 #if wxUSE_COMBOCTRL
1138 
1139 /*!
1140  * Style drop-down for a wxComboCtrl
1141  */
1142 
1143 
BEGIN_EVENT_TABLE(wxRichTextStyleComboPopup,wxRichTextStyleListBox)1144 BEGIN_EVENT_TABLE(wxRichTextStyleComboPopup, wxRichTextStyleListBox)
1145     EVT_MOTION(wxRichTextStyleComboPopup::OnMouseMove)
1146     EVT_LEFT_DOWN(wxRichTextStyleComboPopup::OnMouseClick)
1147 END_EVENT_TABLE()
1148 
1149 void wxRichTextStyleComboPopup::SetStringValue( const wxString& s )
1150 {
1151     m_value = SetStyleSelection(s);
1152 }
1153 
GetStringValue() const1154 wxString wxRichTextStyleComboPopup::GetStringValue() const
1155 {
1156     int sel = m_value;
1157     if (sel > -1)
1158     {
1159         wxRichTextStyleDefinition* def = GetStyle(sel);
1160         if (def)
1161             return def->GetName();
1162     }
1163     return wxEmptyString;
1164 }
1165 
1166 //
1167 // Popup event handlers
1168 //
1169 
1170 // Mouse hot-tracking
OnMouseMove(wxMouseEvent & event)1171 void wxRichTextStyleComboPopup::OnMouseMove(wxMouseEvent& event)
1172 {
1173     // Move selection to cursor if it is inside the popup
1174 
1175     int itemHere = wxRichTextStyleListBox::HitTest(event.GetPosition());
1176     if ( itemHere >= 0 )
1177     {
1178         wxRichTextStyleListBox::SetSelection(itemHere);
1179         m_itemHere = itemHere;
1180     }
1181     event.Skip();
1182 }
1183 
1184 // On mouse left, set the value and close the popup
OnMouseClick(wxMouseEvent & WXUNUSED (event))1185 void wxRichTextStyleComboPopup::OnMouseClick(wxMouseEvent& WXUNUSED(event))
1186 {
1187     if (m_itemHere >= 0)
1188         m_value = m_itemHere;
1189 
1190     // Ordering is important, so we don't dismiss this popup accidentally
1191     // by setting the focus elsewhere e.g. in ApplyStyle
1192     Dismiss();
1193 
1194     if (m_itemHere >= 0)
1195         wxRichTextStyleListBox::ApplyStyle(m_itemHere);
1196 }
1197 
1198 /*!
1199  * wxRichTextStyleComboCtrl
1200  * A combo for applying styles.
1201  */
1202 
IMPLEMENT_CLASS(wxRichTextStyleComboCtrl,wxComboCtrl)1203 IMPLEMENT_CLASS(wxRichTextStyleComboCtrl, wxComboCtrl)
1204 
1205 BEGIN_EVENT_TABLE(wxRichTextStyleComboCtrl, wxComboCtrl)
1206     EVT_IDLE(wxRichTextStyleComboCtrl::OnIdle)
1207 END_EVENT_TABLE()
1208 
1209 bool wxRichTextStyleComboCtrl::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos,
1210         const wxSize& size, long style)
1211 {
1212     if (!wxComboCtrl::Create(parent, id, wxEmptyString, pos, size, style))
1213         return false;
1214 
1215     SetPopupMaxHeight(400);
1216 
1217     m_stylePopup = new wxRichTextStyleComboPopup;
1218 
1219     SetPopupControl(m_stylePopup);
1220 
1221     return true;
1222 }
1223 
1224 /// Auto-select from style under caret in idle time
1225 
1226 // TODO: must be able to show italic, bold, combinations
1227 // in style box. Do we have a concept of automatic, temporary
1228 // styles that are added whenever we wish to show a style
1229 // that doesn't exist already? E.g. "Bold, Italic, Underline".
1230 // Word seems to generate these things on the fly.
1231 // If there's a named style already, it uses e.g. Heading1 + Bold, Italic
1232 // If you unembolden text in a style that has bold, it uses the
1233 // term "Not bold".
1234 // TODO: order styles alphabetically. This means indexes can change,
1235 // so need a different way to specify selections, i.e. by name.
1236 
OnIdle(wxIdleEvent & event)1237 void wxRichTextStyleComboCtrl::OnIdle(wxIdleEvent& event)
1238 {
1239     if (GetRichTextCtrl() && !IsPopupShown() && m_stylePopup && IsShownOnScreen() && wxWindow::FindFocus() != this)
1240     {
1241         wxString styleName = wxRichTextStyleListBox::GetStyleToShowInIdleTime(GetRichTextCtrl(), m_stylePopup->GetStyleType());
1242 
1243         wxString currentValue = GetValue();
1244         if (!styleName.IsEmpty())
1245         {
1246             // Don't do the selection if it's already set
1247             if (currentValue == styleName)
1248                 return;
1249 
1250             SetValue(styleName);
1251         }
1252         else if (!currentValue.IsEmpty())
1253             SetValue(wxEmptyString);
1254     }
1255     event.Skip();
1256 }
1257 
1258 #endif
1259     // wxUSE_COMBOCTRL
1260 
1261 #endif
1262     // wxUSE_HTML
1263 
1264 #endif
1265     // wxUSE_RICHTEXT
1266