]> git.saurik.com Git - wxWidgets.git/blob - src/common/statbar.cpp
fixing overrelease and out-of-bounds write, fixes #13725
[wxWidgets.git] / src / common / statbar.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/statbar.cpp
3 // Purpose: wxStatusBarBase implementation
4 // Author: Vadim Zeitlin
5 // Modified by: Francesco Montorsi
6 // Created: 14.10.01
7 // RCS-ID: $Id$
8 // Copyright: (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #if wxUSE_STATUSBAR
28
29 #include "wx/statusbr.h"
30
31 #ifndef WX_PRECOMP
32 #include "wx/frame.h"
33 #endif //WX_PRECOMP
34
35 const char wxStatusBarNameStr[] = "statusBar";
36
37 // ============================================================================
38 // wxStatusBarPane implementation
39 // ============================================================================
40
41 bool wxStatusBarPane::SetText(const wxString& text)
42 {
43 if ( text == m_text )
44 return false;
45
46 /*
47 If we have a message to restore on the stack, we update it to
48 correspond to the current one so that a sequence of calls such as
49
50 1. SetStatusText("foo")
51 2. PushStatusText("bar")
52 3. SetStatusText("new foo")
53 4. PopStatusText()
54
55 doesn't overwrite the "new foo" which should be shown at the end with
56 the old value "foo". This would be unexpected and hard to avoid,
57 especially when PushStatusText() is used internally by wxWidgets
58 without knowledge of the user program, as it is for showing the menu
59 and toolbar help strings.
60
61 By updating the top of the stack we ensure that the next call to
62 PopStatusText() basically becomes a NOP without breaking the balance
63 between the calls to push and pop as we would have done if we really
64 called PopStatusText() here.
65 */
66 if ( !m_arrStack.empty() )
67 {
68 m_arrStack.back() = text;
69 }
70
71 m_text = text;
72
73 return true;
74 }
75
76 bool wxStatusBarPane::PushText(const wxString& text)
77 {
78 // save the currently shown text
79 m_arrStack.push_back(m_text);
80
81 // and update the new one if necessary
82 if ( text == m_text )
83 return false;
84
85 m_text = text;
86
87 return true;
88 }
89
90 bool wxStatusBarPane::PopText()
91 {
92 wxCHECK_MSG( !m_arrStack.empty(), false, "no status message to pop" );
93
94 const wxString text = m_arrStack.back();
95
96 m_arrStack.pop_back();
97
98 if ( text == m_text )
99 return false;
100
101 m_text = text;
102
103 return true;
104 }
105
106 // ============================================================================
107 // wxStatusBarBase implementation
108 // ============================================================================
109
110 IMPLEMENT_DYNAMIC_CLASS(wxStatusBar, wxWindow)
111
112 #include "wx/arrimpl.cpp" // This is a magic incantation which must be done!
113 WX_DEFINE_EXPORTED_OBJARRAY(wxStatusBarPaneArray)
114
115
116 // ----------------------------------------------------------------------------
117 // ctor/dtor
118 // ----------------------------------------------------------------------------
119
120 wxStatusBarBase::wxStatusBarBase()
121 {
122 m_bSameWidthForAllPanes = true;
123 }
124
125 wxStatusBarBase::~wxStatusBarBase()
126 {
127 // notify the frame that it doesn't have a status bar any longer to avoid
128 // dangling pointers
129 wxFrame *frame = wxDynamicCast(GetParent(), wxFrame);
130 if ( frame && frame->GetStatusBar() == this )
131 frame->SetStatusBar(NULL);
132 }
133
134 // ----------------------------------------------------------------------------
135 // field widths
136 // ----------------------------------------------------------------------------
137
138 void wxStatusBarBase::SetFieldsCount(int number, const int *widths)
139 {
140 wxCHECK_RET( number > 0, wxT("invalid field number in SetFieldsCount") );
141
142 if ( (size_t)number > m_panes.GetCount() )
143 {
144 wxStatusBarPane newPane;
145
146 // add more entries with the default style and zero width
147 // (this will be set later)
148 for (size_t i = m_panes.GetCount(); i < (size_t)number; ++i)
149 m_panes.Add(newPane);
150 }
151 else if ( (size_t)number < m_panes.GetCount() )
152 {
153 // remove entries in excess
154 m_panes.RemoveAt(number, m_panes.GetCount()-number);
155 }
156
157 // SetStatusWidths will automatically refresh
158 SetStatusWidths(number, widths);
159 }
160
161 void wxStatusBarBase::SetStatusWidths(int WXUNUSED_UNLESS_DEBUG(n),
162 const int widths[])
163 {
164 wxASSERT_MSG( (size_t)n == m_panes.GetCount(), wxT("field number mismatch") );
165
166 if (widths == NULL)
167 {
168 // special value meaning: override explicit pane widths and make them all
169 // of the same size
170 m_bSameWidthForAllPanes = true;
171 }
172 else
173 {
174 for ( size_t i = 0; i < m_panes.GetCount(); i++ )
175 m_panes[i].SetWidth(widths[i]);
176
177 m_bSameWidthForAllPanes = false;
178 }
179
180 // update the display after the widths changed
181 Refresh();
182 }
183
184 void wxStatusBarBase::SetStatusStyles(int WXUNUSED_UNLESS_DEBUG(n),
185 const int styles[])
186 {
187 wxCHECK_RET( styles, wxT("NULL pointer in SetStatusStyles") );
188
189 wxASSERT_MSG( (size_t)n == m_panes.GetCount(), wxT("field number mismatch") );
190
191 for ( size_t i = 0; i < m_panes.GetCount(); i++ )
192 m_panes[i].SetStyle(styles[i]);
193
194 // update the display after the widths changed
195 Refresh();
196 }
197
198 wxArrayInt wxStatusBarBase::CalculateAbsWidths(wxCoord widthTotal) const
199 {
200 wxArrayInt widths;
201
202 if ( m_bSameWidthForAllPanes )
203 {
204 // Default: all fields have the same width. This is not always
205 // possible to do exactly (if widthTotal is not divisible by
206 // m_panes.GetCount()) - if that happens, we distribute the extra
207 // pixels among all fields:
208 int widthToUse = widthTotal;
209
210 for ( size_t i = m_panes.GetCount(); i > 0; i-- )
211 {
212 // divide the unassigned width evently between the
213 // not yet processed fields:
214 int w = widthToUse / i;
215 widths.Add(w);
216 widthToUse -= w;
217 }
218 }
219 else // do not override explicit pane widths
220 {
221 // calculate the total width of all the fixed width fields and the
222 // total number of var field widths counting with multiplicity
223 size_t nTotalWidth = 0,
224 nVarCount = 0,
225 i;
226
227 for ( i = 0; i < m_panes.GetCount(); i++ )
228 {
229 if ( m_panes[i].GetWidth() >= 0 )
230 nTotalWidth += m_panes[i].GetWidth();
231 else
232 nVarCount += -m_panes[i].GetWidth();
233 }
234
235 // the amount of extra width we have per each var width field
236 int widthExtra = widthTotal - nTotalWidth;
237
238 // do fill the array
239 for ( i = 0; i < m_panes.GetCount(); i++ )
240 {
241 if ( m_panes[i].GetWidth() >= 0 )
242 widths.Add(m_panes[i].GetWidth());
243 else
244 {
245 int nVarWidth = widthExtra > 0 ? (widthExtra * (-m_panes[i].GetWidth())) / nVarCount : 0;
246 nVarCount += m_panes[i].GetWidth();
247 widthExtra -= nVarWidth;
248 widths.Add(nVarWidth);
249 }
250 }
251 }
252
253 return widths;
254 }
255
256 // ----------------------------------------------------------------------------
257 // setting/getting status text
258 // ----------------------------------------------------------------------------
259
260 void wxStatusBarBase::SetStatusText(const wxString& text, int number)
261 {
262 wxCHECK_RET( (unsigned)number < m_panes.size(),
263 "invalid status bar field index" );
264
265 if ( m_panes[number].SetText(text) )
266 DoUpdateStatusText(number);
267 }
268
269 wxString wxStatusBarBase::GetStatusText(int number) const
270 {
271 wxCHECK_MSG( (unsigned)number < m_panes.size(), wxString(),
272 "invalid status bar field index" );
273
274 return m_panes[number].GetText();
275 }
276
277 void wxStatusBarBase::SetEllipsizedFlag(int number, bool isEllipsized)
278 {
279 wxCHECK_RET( (unsigned)number < m_panes.size(),
280 "invalid status bar field index" );
281
282 m_panes[number].SetIsEllipsized(isEllipsized);
283 }
284
285 // ----------------------------------------------------------------------------
286 // pushing/popping status text
287 // ----------------------------------------------------------------------------
288
289 void wxStatusBarBase::PushStatusText(const wxString& text, int number)
290 {
291 wxCHECK_RET( (unsigned)number < m_panes.size(),
292 "invalid status bar field index" );
293
294 if ( m_panes[number].PushText(text) )
295 DoUpdateStatusText(number);
296 }
297
298 void wxStatusBarBase::PopStatusText(int number)
299 {
300 wxCHECK_RET( (unsigned)number < m_panes.size(),
301 "invalid status bar field index" );
302
303 if ( m_panes[number].PopText() )
304 DoUpdateStatusText(number);
305 }
306
307 #endif // wxUSE_STATUSBAR