xref: /haiku/src/apps/debuganalyzer/gui/HeaderView.cpp (revision c97796c267850ae0d85d7487ab8275dfb936bab9)
1*c97796c2SIngo Weinhold /*
2*c97796c2SIngo Weinhold  * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3*c97796c2SIngo Weinhold  * Copyright 2009, Stephan Aßmus, superstippi@gmx.de.
4*c97796c2SIngo Weinhold  * Distributed under the terms of the MIT License.
5*c97796c2SIngo Weinhold  */
6*c97796c2SIngo Weinhold 
7*c97796c2SIngo Weinhold 
8*c97796c2SIngo Weinhold #include "HeaderView.h"
9*c97796c2SIngo Weinhold 
10*c97796c2SIngo Weinhold #include <stdio.h>
11*c97796c2SIngo Weinhold 
12*c97796c2SIngo Weinhold #include <algorithm>
13*c97796c2SIngo Weinhold #include <new>
14*c97796c2SIngo Weinhold 
15*c97796c2SIngo Weinhold #include <ControlLook.h>
16*c97796c2SIngo Weinhold #include <LayoutUtils.h>
17*c97796c2SIngo Weinhold 
18*c97796c2SIngo Weinhold 
19*c97796c2SIngo Weinhold // #pragma mark - HeaderRenderer
20*c97796c2SIngo Weinhold 
21*c97796c2SIngo Weinhold 
22*c97796c2SIngo Weinhold HeaderRenderer::~HeaderRenderer()
23*c97796c2SIngo Weinhold {
24*c97796c2SIngo Weinhold }
25*c97796c2SIngo Weinhold 
26*c97796c2SIngo Weinhold 
27*c97796c2SIngo Weinhold // #pragma mark - DefaultHeaderRenderer
28*c97796c2SIngo Weinhold 
29*c97796c2SIngo Weinhold 
30*c97796c2SIngo Weinhold DefaultHeaderRenderer::DefaultHeaderRenderer()
31*c97796c2SIngo Weinhold {
32*c97796c2SIngo Weinhold }
33*c97796c2SIngo Weinhold 
34*c97796c2SIngo Weinhold 
35*c97796c2SIngo Weinhold DefaultHeaderRenderer::~DefaultHeaderRenderer()
36*c97796c2SIngo Weinhold {
37*c97796c2SIngo Weinhold }
38*c97796c2SIngo Weinhold 
39*c97796c2SIngo Weinhold 
40*c97796c2SIngo Weinhold float
41*c97796c2SIngo Weinhold DefaultHeaderRenderer::HeaderHeight(BView* view, const Header* header)
42*c97796c2SIngo Weinhold {
43*c97796c2SIngo Weinhold 	BVariant value;
44*c97796c2SIngo Weinhold 	if (!header->GetValue(value))
45*c97796c2SIngo Weinhold 		return 0;
46*c97796c2SIngo Weinhold 
47*c97796c2SIngo Weinhold 	if (value.Type() == B_STRING_TYPE) {
48*c97796c2SIngo Weinhold 		return 15;
49*c97796c2SIngo Weinhold 			// TODO:...
50*c97796c2SIngo Weinhold 	} else
51*c97796c2SIngo Weinhold 		return 0;
52*c97796c2SIngo Weinhold }
53*c97796c2SIngo Weinhold 
54*c97796c2SIngo Weinhold 
55*c97796c2SIngo Weinhold void
56*c97796c2SIngo Weinhold DefaultHeaderRenderer::DrawHeader(BView* view, BRect frame, BRect updateRect,
57*c97796c2SIngo Weinhold 	const Header* header, uint32 flags)
58*c97796c2SIngo Weinhold {
59*c97796c2SIngo Weinhold printf("DefaultHeaderRenderer::DrawHeader(): frame: (%f, %f) - (%f, %f), header: %p\n",
60*c97796c2SIngo Weinhold frame.left, frame.top, frame.right, frame.bottom, header);
61*c97796c2SIngo Weinhold 	BVariant value;
62*c97796c2SIngo Weinhold 	if (!header->GetValue(value))
63*c97796c2SIngo Weinhold 		return;
64*c97796c2SIngo Weinhold 
65*c97796c2SIngo Weinhold 	if (value.Type() == B_STRING_TYPE) {
66*c97796c2SIngo Weinhold 		be_control_look->DrawLabel(view, value.ToString(), frame, updateRect,
67*c97796c2SIngo Weinhold 			view->LowColor(), 0);
68*c97796c2SIngo Weinhold 	}
69*c97796c2SIngo Weinhold }
70*c97796c2SIngo Weinhold 
71*c97796c2SIngo Weinhold 
72*c97796c2SIngo Weinhold // #pragma mark - HeaderListener
73*c97796c2SIngo Weinhold 
74*c97796c2SIngo Weinhold 
75*c97796c2SIngo Weinhold HeaderListener::~HeaderListener()
76*c97796c2SIngo Weinhold {
77*c97796c2SIngo Weinhold }
78*c97796c2SIngo Weinhold 
79*c97796c2SIngo Weinhold 
80*c97796c2SIngo Weinhold // #pragma mark - Header
81*c97796c2SIngo Weinhold 
82*c97796c2SIngo Weinhold 
83*c97796c2SIngo Weinhold Header::Header(int32 modelIndex)
84*c97796c2SIngo Weinhold 	:
85*c97796c2SIngo Weinhold 	fWidth(100),
86*c97796c2SIngo Weinhold 	fMinWidth(0),
87*c97796c2SIngo Weinhold 	fMaxWidth(10000),
88*c97796c2SIngo Weinhold 	fPreferredWidth(100),
89*c97796c2SIngo Weinhold 	fValue(),
90*c97796c2SIngo Weinhold 	fRenderer(NULL),
91*c97796c2SIngo Weinhold 	fModelIndex(modelIndex),
92*c97796c2SIngo Weinhold 	fResizable(true)
93*c97796c2SIngo Weinhold {
94*c97796c2SIngo Weinhold }
95*c97796c2SIngo Weinhold 
96*c97796c2SIngo Weinhold 
97*c97796c2SIngo Weinhold Header::Header(float width, float minWidth, float maxWidth,
98*c97796c2SIngo Weinhold 	float preferredWidth, int32 modelIndex)
99*c97796c2SIngo Weinhold 	:
100*c97796c2SIngo Weinhold 	fWidth(width),
101*c97796c2SIngo Weinhold 	fMinWidth(minWidth),
102*c97796c2SIngo Weinhold 	fMaxWidth(maxWidth),
103*c97796c2SIngo Weinhold 	fPreferredWidth(preferredWidth),
104*c97796c2SIngo Weinhold 	fValue(),
105*c97796c2SIngo Weinhold 	fRenderer(NULL),
106*c97796c2SIngo Weinhold 	fModelIndex(modelIndex),
107*c97796c2SIngo Weinhold 	fResizable(true)
108*c97796c2SIngo Weinhold {
109*c97796c2SIngo Weinhold }
110*c97796c2SIngo Weinhold 
111*c97796c2SIngo Weinhold 
112*c97796c2SIngo Weinhold float
113*c97796c2SIngo Weinhold Header::Width() const
114*c97796c2SIngo Weinhold {
115*c97796c2SIngo Weinhold 	return fWidth;
116*c97796c2SIngo Weinhold }
117*c97796c2SIngo Weinhold 
118*c97796c2SIngo Weinhold 
119*c97796c2SIngo Weinhold float
120*c97796c2SIngo Weinhold Header::MinWidth() const
121*c97796c2SIngo Weinhold {
122*c97796c2SIngo Weinhold 	return fMinWidth;
123*c97796c2SIngo Weinhold }
124*c97796c2SIngo Weinhold 
125*c97796c2SIngo Weinhold 
126*c97796c2SIngo Weinhold float
127*c97796c2SIngo Weinhold Header::MaxWidth() const
128*c97796c2SIngo Weinhold {
129*c97796c2SIngo Weinhold 	return fMaxWidth;
130*c97796c2SIngo Weinhold }
131*c97796c2SIngo Weinhold 
132*c97796c2SIngo Weinhold 
133*c97796c2SIngo Weinhold float
134*c97796c2SIngo Weinhold Header::PreferredWidth() const
135*c97796c2SIngo Weinhold {
136*c97796c2SIngo Weinhold 	return fPreferredWidth;
137*c97796c2SIngo Weinhold }
138*c97796c2SIngo Weinhold 
139*c97796c2SIngo Weinhold 
140*c97796c2SIngo Weinhold void
141*c97796c2SIngo Weinhold Header::SetWidth(float width)
142*c97796c2SIngo Weinhold {
143*c97796c2SIngo Weinhold 	if (width != fWidth) {
144*c97796c2SIngo Weinhold 		fWidth = width;
145*c97796c2SIngo Weinhold 		NotifyPropertiesChanged(true, true);
146*c97796c2SIngo Weinhold 	}
147*c97796c2SIngo Weinhold }
148*c97796c2SIngo Weinhold 
149*c97796c2SIngo Weinhold 
150*c97796c2SIngo Weinhold void
151*c97796c2SIngo Weinhold Header::SetMinWidth(float width)
152*c97796c2SIngo Weinhold {
153*c97796c2SIngo Weinhold 	if (width != fMinWidth) {
154*c97796c2SIngo Weinhold 		fMinWidth = width;
155*c97796c2SIngo Weinhold 		NotifyPropertiesChanged(false, false);
156*c97796c2SIngo Weinhold 	}
157*c97796c2SIngo Weinhold }
158*c97796c2SIngo Weinhold 
159*c97796c2SIngo Weinhold 
160*c97796c2SIngo Weinhold void
161*c97796c2SIngo Weinhold Header::SetMaxWidth(float width)
162*c97796c2SIngo Weinhold {
163*c97796c2SIngo Weinhold 	if (width != fMaxWidth) {
164*c97796c2SIngo Weinhold 		fMaxWidth = width;
165*c97796c2SIngo Weinhold 		NotifyPropertiesChanged(false, false);
166*c97796c2SIngo Weinhold 	}
167*c97796c2SIngo Weinhold }
168*c97796c2SIngo Weinhold 
169*c97796c2SIngo Weinhold 
170*c97796c2SIngo Weinhold void
171*c97796c2SIngo Weinhold Header::SetPreferredWidth(float width)
172*c97796c2SIngo Weinhold {
173*c97796c2SIngo Weinhold 	if (width != fPreferredWidth) {
174*c97796c2SIngo Weinhold 		fPreferredWidth = width;
175*c97796c2SIngo Weinhold 		NotifyPropertiesChanged(false, false);
176*c97796c2SIngo Weinhold 	}
177*c97796c2SIngo Weinhold }
178*c97796c2SIngo Weinhold 
179*c97796c2SIngo Weinhold 
180*c97796c2SIngo Weinhold bool
181*c97796c2SIngo Weinhold Header::IsResizable() const
182*c97796c2SIngo Weinhold {
183*c97796c2SIngo Weinhold 	return fResizable;
184*c97796c2SIngo Weinhold }
185*c97796c2SIngo Weinhold 
186*c97796c2SIngo Weinhold 
187*c97796c2SIngo Weinhold void
188*c97796c2SIngo Weinhold Header::SetResizable(bool resizable)
189*c97796c2SIngo Weinhold {
190*c97796c2SIngo Weinhold 	if (resizable != fResizable) {
191*c97796c2SIngo Weinhold 		fResizable = resizable;
192*c97796c2SIngo Weinhold 		NotifyPropertiesChanged(false, false);
193*c97796c2SIngo Weinhold 	}
194*c97796c2SIngo Weinhold }
195*c97796c2SIngo Weinhold 
196*c97796c2SIngo Weinhold 
197*c97796c2SIngo Weinhold bool
198*c97796c2SIngo Weinhold Header::GetValue(BVariant& _value) const
199*c97796c2SIngo Weinhold {
200*c97796c2SIngo Weinhold 	_value = fValue;
201*c97796c2SIngo Weinhold 	return true;
202*c97796c2SIngo Weinhold }
203*c97796c2SIngo Weinhold 
204*c97796c2SIngo Weinhold 
205*c97796c2SIngo Weinhold void
206*c97796c2SIngo Weinhold Header::SetValue(const BVariant& value)
207*c97796c2SIngo Weinhold {
208*c97796c2SIngo Weinhold 	fValue = value;
209*c97796c2SIngo Weinhold 	NotifyPropertiesChanged(true, false);
210*c97796c2SIngo Weinhold }
211*c97796c2SIngo Weinhold 
212*c97796c2SIngo Weinhold 
213*c97796c2SIngo Weinhold int32
214*c97796c2SIngo Weinhold Header::ModelIndex() const
215*c97796c2SIngo Weinhold {
216*c97796c2SIngo Weinhold 	return fModelIndex;
217*c97796c2SIngo Weinhold }
218*c97796c2SIngo Weinhold 
219*c97796c2SIngo Weinhold 
220*c97796c2SIngo Weinhold void
221*c97796c2SIngo Weinhold Header::SetModelIndex(int32 index)
222*c97796c2SIngo Weinhold {
223*c97796c2SIngo Weinhold 	if (index != fModelIndex) {
224*c97796c2SIngo Weinhold 		fModelIndex = index;
225*c97796c2SIngo Weinhold 		NotifyPropertiesChanged(true, false);
226*c97796c2SIngo Weinhold 	}
227*c97796c2SIngo Weinhold }
228*c97796c2SIngo Weinhold 
229*c97796c2SIngo Weinhold 
230*c97796c2SIngo Weinhold HeaderRenderer*
231*c97796c2SIngo Weinhold Header::GetHeaderRenderer() const
232*c97796c2SIngo Weinhold {
233*c97796c2SIngo Weinhold 	return fRenderer;
234*c97796c2SIngo Weinhold }
235*c97796c2SIngo Weinhold 
236*c97796c2SIngo Weinhold 
237*c97796c2SIngo Weinhold void
238*c97796c2SIngo Weinhold Header::SetHeaderRenderer(HeaderRenderer* renderer)
239*c97796c2SIngo Weinhold {
240*c97796c2SIngo Weinhold 	if (renderer != fRenderer) {
241*c97796c2SIngo Weinhold 		fRenderer = renderer;
242*c97796c2SIngo Weinhold 		NotifyPropertiesChanged(true, false);
243*c97796c2SIngo Weinhold 	}
244*c97796c2SIngo Weinhold }
245*c97796c2SIngo Weinhold 
246*c97796c2SIngo Weinhold 
247*c97796c2SIngo Weinhold void
248*c97796c2SIngo Weinhold Header::AddListener(HeaderListener* listener)
249*c97796c2SIngo Weinhold {
250*c97796c2SIngo Weinhold 	fListeners.AddItem(listener);
251*c97796c2SIngo Weinhold }
252*c97796c2SIngo Weinhold 
253*c97796c2SIngo Weinhold 
254*c97796c2SIngo Weinhold void
255*c97796c2SIngo Weinhold Header::RemoveListener(HeaderListener* listener)
256*c97796c2SIngo Weinhold {
257*c97796c2SIngo Weinhold 	fListeners.RemoveItem(listener);
258*c97796c2SIngo Weinhold }
259*c97796c2SIngo Weinhold 
260*c97796c2SIngo Weinhold 
261*c97796c2SIngo Weinhold void
262*c97796c2SIngo Weinhold Header::NotifyPropertiesChanged(bool redrawNeeded, bool relayoutNeeded)
263*c97796c2SIngo Weinhold {
264*c97796c2SIngo Weinhold 	for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) {
265*c97796c2SIngo Weinhold 		HeaderListener* listener = fListeners.ItemAt(i);
266*c97796c2SIngo Weinhold 		listener->HeaderPropertiesChanged(this, redrawNeeded, relayoutNeeded);
267*c97796c2SIngo Weinhold 	}
268*c97796c2SIngo Weinhold }
269*c97796c2SIngo Weinhold 
270*c97796c2SIngo Weinhold 
271*c97796c2SIngo Weinhold // #pragma mark - HeaderModelListener
272*c97796c2SIngo Weinhold 
273*c97796c2SIngo Weinhold 
274*c97796c2SIngo Weinhold HeaderModelListener::~HeaderModelListener()
275*c97796c2SIngo Weinhold {
276*c97796c2SIngo Weinhold }
277*c97796c2SIngo Weinhold 
278*c97796c2SIngo Weinhold 
279*c97796c2SIngo Weinhold void
280*c97796c2SIngo Weinhold HeaderModelListener::HeaderAdded(HeaderModel* model, int32 index)
281*c97796c2SIngo Weinhold {
282*c97796c2SIngo Weinhold }
283*c97796c2SIngo Weinhold 
284*c97796c2SIngo Weinhold 
285*c97796c2SIngo Weinhold void
286*c97796c2SIngo Weinhold HeaderModelListener::HeaderRemoved(HeaderModel* model, int32 index)
287*c97796c2SIngo Weinhold {
288*c97796c2SIngo Weinhold }
289*c97796c2SIngo Weinhold 
290*c97796c2SIngo Weinhold 
291*c97796c2SIngo Weinhold void
292*c97796c2SIngo Weinhold HeaderModelListener::HeaderMoved(HeaderModel* model, int32 fromIndex,
293*c97796c2SIngo Weinhold 	int32 toIndex)
294*c97796c2SIngo Weinhold {
295*c97796c2SIngo Weinhold }
296*c97796c2SIngo Weinhold 
297*c97796c2SIngo Weinhold 
298*c97796c2SIngo Weinhold // #pragma mark - HeaderModel
299*c97796c2SIngo Weinhold 
300*c97796c2SIngo Weinhold 
301*c97796c2SIngo Weinhold HeaderModel::HeaderModel()
302*c97796c2SIngo Weinhold {
303*c97796c2SIngo Weinhold }
304*c97796c2SIngo Weinhold 
305*c97796c2SIngo Weinhold 
306*c97796c2SIngo Weinhold HeaderModel::~HeaderModel()
307*c97796c2SIngo Weinhold {
308*c97796c2SIngo Weinhold }
309*c97796c2SIngo Weinhold 
310*c97796c2SIngo Weinhold 
311*c97796c2SIngo Weinhold int32
312*c97796c2SIngo Weinhold HeaderModel::CountHeaders() const
313*c97796c2SIngo Weinhold {
314*c97796c2SIngo Weinhold 	return fHeaders.CountItems();
315*c97796c2SIngo Weinhold }
316*c97796c2SIngo Weinhold 
317*c97796c2SIngo Weinhold 
318*c97796c2SIngo Weinhold Header*
319*c97796c2SIngo Weinhold HeaderModel::HeaderAt(int32 index) const
320*c97796c2SIngo Weinhold {
321*c97796c2SIngo Weinhold 	return fHeaders.ItemAt(index);
322*c97796c2SIngo Weinhold }
323*c97796c2SIngo Weinhold 
324*c97796c2SIngo Weinhold 
325*c97796c2SIngo Weinhold int32
326*c97796c2SIngo Weinhold HeaderModel::IndexOfHeader(Header* header) const
327*c97796c2SIngo Weinhold {
328*c97796c2SIngo Weinhold 	return fHeaders.IndexOf(header);
329*c97796c2SIngo Weinhold }
330*c97796c2SIngo Weinhold 
331*c97796c2SIngo Weinhold 
332*c97796c2SIngo Weinhold bool
333*c97796c2SIngo Weinhold HeaderModel::AddHeader(Header* header)
334*c97796c2SIngo Weinhold {
335*c97796c2SIngo Weinhold 	if (!fHeaders.AddItem(header))
336*c97796c2SIngo Weinhold 		return false;
337*c97796c2SIngo Weinhold 
338*c97796c2SIngo Weinhold 	NotifyHeaderAdded(fHeaders.CountItems() - 1);
339*c97796c2SIngo Weinhold 
340*c97796c2SIngo Weinhold 	return true;
341*c97796c2SIngo Weinhold }
342*c97796c2SIngo Weinhold 
343*c97796c2SIngo Weinhold 
344*c97796c2SIngo Weinhold Header*
345*c97796c2SIngo Weinhold HeaderModel::RemoveHeader(int32 index)
346*c97796c2SIngo Weinhold {
347*c97796c2SIngo Weinhold 	Header* header = fHeaders.RemoveItemAt(index);
348*c97796c2SIngo Weinhold 	if (header != NULL)
349*c97796c2SIngo Weinhold 		return NULL;
350*c97796c2SIngo Weinhold 
351*c97796c2SIngo Weinhold 	NotifyHeaderRemoved(index);
352*c97796c2SIngo Weinhold 
353*c97796c2SIngo Weinhold 	return header;
354*c97796c2SIngo Weinhold }
355*c97796c2SIngo Weinhold 
356*c97796c2SIngo Weinhold 
357*c97796c2SIngo Weinhold void
358*c97796c2SIngo Weinhold HeaderModel::RemoveHeader(Header* header)
359*c97796c2SIngo Weinhold {
360*c97796c2SIngo Weinhold 	RemoveHeader(fHeaders.IndexOf(header));
361*c97796c2SIngo Weinhold }
362*c97796c2SIngo Weinhold 
363*c97796c2SIngo Weinhold 
364*c97796c2SIngo Weinhold bool
365*c97796c2SIngo Weinhold HeaderModel::MoveHeader(int32 fromIndex, int32 toIndex)
366*c97796c2SIngo Weinhold {
367*c97796c2SIngo Weinhold 	int32 headerCount = fHeaders.CountItems();
368*c97796c2SIngo Weinhold 	if (fromIndex < 0 || fromIndex >= headerCount
369*c97796c2SIngo Weinhold 		|| toIndex < 0 || toIndex >= headerCount) {
370*c97796c2SIngo Weinhold 		return false;
371*c97796c2SIngo Weinhold 	}
372*c97796c2SIngo Weinhold 
373*c97796c2SIngo Weinhold 	if (fromIndex == toIndex)
374*c97796c2SIngo Weinhold 		return true;
375*c97796c2SIngo Weinhold 
376*c97796c2SIngo Weinhold 	Header* header = fHeaders.RemoveItemAt(fromIndex);
377*c97796c2SIngo Weinhold 	fHeaders.AddItem(header, toIndex);
378*c97796c2SIngo Weinhold 		// TODO: Might fail.
379*c97796c2SIngo Weinhold 
380*c97796c2SIngo Weinhold 	NotifyHeaderMoved(fromIndex, toIndex);
381*c97796c2SIngo Weinhold 
382*c97796c2SIngo Weinhold 	return true;
383*c97796c2SIngo Weinhold }
384*c97796c2SIngo Weinhold 
385*c97796c2SIngo Weinhold 
386*c97796c2SIngo Weinhold void
387*c97796c2SIngo Weinhold HeaderModel::AddListener(HeaderModelListener* listener)
388*c97796c2SIngo Weinhold {
389*c97796c2SIngo Weinhold 	fListeners.AddItem(listener);
390*c97796c2SIngo Weinhold }
391*c97796c2SIngo Weinhold 
392*c97796c2SIngo Weinhold 
393*c97796c2SIngo Weinhold void
394*c97796c2SIngo Weinhold HeaderModel::RemoveListener(HeaderModelListener* listener)
395*c97796c2SIngo Weinhold {
396*c97796c2SIngo Weinhold 	fListeners.RemoveItem(listener);
397*c97796c2SIngo Weinhold }
398*c97796c2SIngo Weinhold 
399*c97796c2SIngo Weinhold 
400*c97796c2SIngo Weinhold void
401*c97796c2SIngo Weinhold HeaderModel::NotifyHeaderAdded(int32 index)
402*c97796c2SIngo Weinhold {
403*c97796c2SIngo Weinhold 	for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) {
404*c97796c2SIngo Weinhold 		HeaderModelListener* listener = fListeners.ItemAt(i);
405*c97796c2SIngo Weinhold 		listener->HeaderAdded(this, index);
406*c97796c2SIngo Weinhold 	}
407*c97796c2SIngo Weinhold }
408*c97796c2SIngo Weinhold 
409*c97796c2SIngo Weinhold 
410*c97796c2SIngo Weinhold void
411*c97796c2SIngo Weinhold HeaderModel::NotifyHeaderRemoved(int32 index)
412*c97796c2SIngo Weinhold {
413*c97796c2SIngo Weinhold 	for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) {
414*c97796c2SIngo Weinhold 		HeaderModelListener* listener = fListeners.ItemAt(i);
415*c97796c2SIngo Weinhold 		listener->HeaderRemoved(this, index);
416*c97796c2SIngo Weinhold 	}
417*c97796c2SIngo Weinhold }
418*c97796c2SIngo Weinhold 
419*c97796c2SIngo Weinhold 
420*c97796c2SIngo Weinhold void
421*c97796c2SIngo Weinhold HeaderModel::NotifyHeaderMoved(int32 fromIndex, int32 toIndex)
422*c97796c2SIngo Weinhold {
423*c97796c2SIngo Weinhold 	for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) {
424*c97796c2SIngo Weinhold 		HeaderModelListener* listener = fListeners.ItemAt(i);
425*c97796c2SIngo Weinhold 		listener->HeaderMoved(this, fromIndex, toIndex);
426*c97796c2SIngo Weinhold 	}
427*c97796c2SIngo Weinhold }
428*c97796c2SIngo Weinhold 
429*c97796c2SIngo Weinhold 
430*c97796c2SIngo Weinhold // #pragma mark - HeaderEntry
431*c97796c2SIngo Weinhold 
432*c97796c2SIngo Weinhold 
433*c97796c2SIngo Weinhold struct HeaderView::HeaderEntry {
434*c97796c2SIngo Weinhold 	Header*	header;
435*c97796c2SIngo Weinhold 	float	position;
436*c97796c2SIngo Weinhold 	float	width;
437*c97796c2SIngo Weinhold 
438*c97796c2SIngo Weinhold 	HeaderEntry(Header* header)
439*c97796c2SIngo Weinhold 		:
440*c97796c2SIngo Weinhold 		header(header)
441*c97796c2SIngo Weinhold 	{
442*c97796c2SIngo Weinhold 	}
443*c97796c2SIngo Weinhold };
444*c97796c2SIngo Weinhold 
445*c97796c2SIngo Weinhold 
446*c97796c2SIngo Weinhold // #pragma mark - HeaderView
447*c97796c2SIngo Weinhold 
448*c97796c2SIngo Weinhold 
449*c97796c2SIngo Weinhold HeaderView::HeaderView()
450*c97796c2SIngo Weinhold  	:
451*c97796c2SIngo Weinhold  	BView("header view", B_WILL_DRAW),
452*c97796c2SIngo Weinhold  	fModel(NULL),
453*c97796c2SIngo Weinhold  	fHeaderEntries(10, true),
454*c97796c2SIngo Weinhold  	fLayoutValid(false)
455*c97796c2SIngo Weinhold {
456*c97796c2SIngo Weinhold  	HeaderModel* model = new(std::nothrow) HeaderModel;
457*c97796c2SIngo Weinhold  	Reference<HeaderModel> modelReference(model, true);
458*c97796c2SIngo Weinhold  	SetModel(model);
459*c97796c2SIngo Weinhold }
460*c97796c2SIngo Weinhold 
461*c97796c2SIngo Weinhold 
462*c97796c2SIngo Weinhold HeaderView::~HeaderView()
463*c97796c2SIngo Weinhold {
464*c97796c2SIngo Weinhold 	SetModel(NULL);
465*c97796c2SIngo Weinhold }
466*c97796c2SIngo Weinhold 
467*c97796c2SIngo Weinhold 
468*c97796c2SIngo Weinhold void
469*c97796c2SIngo Weinhold HeaderView::Draw(BRect updateRect)
470*c97796c2SIngo Weinhold {
471*c97796c2SIngo Weinhold 	if (fModel == NULL)
472*c97796c2SIngo Weinhold 		return;
473*c97796c2SIngo Weinhold 
474*c97796c2SIngo Weinhold 	_ValidateHeadersLayout();
475*c97796c2SIngo Weinhold 
476*c97796c2SIngo Weinhold 	DefaultHeaderRenderer defaultRenderer;
477*c97796c2SIngo Weinhold 	float bottom = Bounds().Height();
478*c97796c2SIngo Weinhold 
479*c97796c2SIngo Weinhold 	for (int32 i = 0; HeaderEntry* entry = fHeaderEntries.ItemAt(i); i++) {
480*c97796c2SIngo Weinhold 		if (Header* header = fModel->HeaderAt(i)) {
481*c97796c2SIngo Weinhold 			HeaderRenderer* renderer = header->GetHeaderRenderer();
482*c97796c2SIngo Weinhold 			if (renderer == NULL)
483*c97796c2SIngo Weinhold 				renderer = &defaultRenderer;
484*c97796c2SIngo Weinhold 
485*c97796c2SIngo Weinhold 			BRect frame(entry->position, 0, entry->position + entry->width - 1,
486*c97796c2SIngo Weinhold 				bottom);
487*c97796c2SIngo Weinhold 			renderer->DrawHeader(this, frame, updateRect, header, 0);
488*c97796c2SIngo Weinhold 				// TODO: flags!
489*c97796c2SIngo Weinhold 		}
490*c97796c2SIngo Weinhold 	}
491*c97796c2SIngo Weinhold }
492*c97796c2SIngo Weinhold 
493*c97796c2SIngo Weinhold 
494*c97796c2SIngo Weinhold BSize
495*c97796c2SIngo Weinhold HeaderView::MinSize()
496*c97796c2SIngo Weinhold {
497*c97796c2SIngo Weinhold 	_ValidateHeadersLayout();
498*c97796c2SIngo Weinhold 
499*c97796c2SIngo Weinhold 	return BLayoutUtils::ComposeSize(ExplicitMinSize(),
500*c97796c2SIngo Weinhold 		BSize(100, fPreferredHeight - 1));
501*c97796c2SIngo Weinhold }
502*c97796c2SIngo Weinhold 
503*c97796c2SIngo Weinhold 
504*c97796c2SIngo Weinhold BSize
505*c97796c2SIngo Weinhold HeaderView::MaxSize()
506*c97796c2SIngo Weinhold {
507*c97796c2SIngo Weinhold 	_ValidateHeadersLayout();
508*c97796c2SIngo Weinhold 
509*c97796c2SIngo Weinhold 	return BLayoutUtils::ComposeSize(ExplicitMaxSize(),
510*c97796c2SIngo Weinhold 		BSize(B_SIZE_UNLIMITED, fPreferredHeight - 1));
511*c97796c2SIngo Weinhold }
512*c97796c2SIngo Weinhold 
513*c97796c2SIngo Weinhold 
514*c97796c2SIngo Weinhold BSize
515*c97796c2SIngo Weinhold HeaderView::PreferredSize()
516*c97796c2SIngo Weinhold {
517*c97796c2SIngo Weinhold 	_ValidateHeadersLayout();
518*c97796c2SIngo Weinhold 
519*c97796c2SIngo Weinhold 	return BLayoutUtils::ComposeSize(ExplicitPreferredSize(),
520*c97796c2SIngo Weinhold 		BSize(fPreferredWidth - 1, fPreferredHeight - 1));
521*c97796c2SIngo Weinhold }
522*c97796c2SIngo Weinhold 
523*c97796c2SIngo Weinhold 
524*c97796c2SIngo Weinhold HeaderModel*
525*c97796c2SIngo Weinhold HeaderView::Model() const
526*c97796c2SIngo Weinhold {
527*c97796c2SIngo Weinhold 	return fModel;
528*c97796c2SIngo Weinhold }
529*c97796c2SIngo Weinhold 
530*c97796c2SIngo Weinhold 
531*c97796c2SIngo Weinhold status_t
532*c97796c2SIngo Weinhold HeaderView::SetModel(HeaderModel* model)
533*c97796c2SIngo Weinhold {
534*c97796c2SIngo Weinhold 	if (model == fModel)
535*c97796c2SIngo Weinhold 		return B_OK;
536*c97796c2SIngo Weinhold printf("HeaderView::SetModel(%p)\n", model);
537*c97796c2SIngo Weinhold 
538*c97796c2SIngo Weinhold 	if (fModel != NULL) {
539*c97796c2SIngo Weinhold 		// remove all headers
540*c97796c2SIngo Weinhold 		for (int32 i = 0; HeaderEntry* entry = fHeaderEntries.ItemAt(i); i++)
541*c97796c2SIngo Weinhold {
542*c97796c2SIngo Weinhold printf("  unsetting entry %p, header: %p\n", entry, entry->header);
543*c97796c2SIngo Weinhold 			entry->header->RemoveListener(this);
544*c97796c2SIngo Weinhold }
545*c97796c2SIngo Weinhold 		fHeaderEntries.MakeEmpty();
546*c97796c2SIngo Weinhold 
547*c97796c2SIngo Weinhold 		fModel->RemoveListener(this);
548*c97796c2SIngo Weinhold 		fModel->ReleaseReference();
549*c97796c2SIngo Weinhold 	}
550*c97796c2SIngo Weinhold 
551*c97796c2SIngo Weinhold 	fModel = model;
552*c97796c2SIngo Weinhold 
553*c97796c2SIngo Weinhold 	if (fModel != NULL) {
554*c97796c2SIngo Weinhold 		fModel->AcquireReference();
555*c97796c2SIngo Weinhold 		fModel->AddListener(this);
556*c97796c2SIngo Weinhold 
557*c97796c2SIngo Weinhold 		// create header entries
558*c97796c2SIngo Weinhold 		int32 headerCount = fModel->CountHeaders();
559*c97796c2SIngo Weinhold 		for (int32 i = 0; i < headerCount; i++) {
560*c97796c2SIngo Weinhold 			HeaderEntry* entry = new(std::nothrow) HeaderEntry(
561*c97796c2SIngo Weinhold 				fModel->HeaderAt(i));
562*c97796c2SIngo Weinhold 			if (entry == NULL || !fHeaderEntries.AddItem(entry)) {
563*c97796c2SIngo Weinhold 				delete entry;
564*c97796c2SIngo Weinhold 				return B_NO_MEMORY;
565*c97796c2SIngo Weinhold 			}
566*c97796c2SIngo Weinhold 
567*c97796c2SIngo Weinhold 			entry->header->AddListener(this);
568*c97796c2SIngo Weinhold 		}
569*c97796c2SIngo Weinhold 	}
570*c97796c2SIngo Weinhold 
571*c97796c2SIngo Weinhold 	_InvalidateHeadersLayout(0);
572*c97796c2SIngo Weinhold 	Invalidate();
573*c97796c2SIngo Weinhold 
574*c97796c2SIngo Weinhold 	return B_OK;
575*c97796c2SIngo Weinhold }
576*c97796c2SIngo Weinhold 
577*c97796c2SIngo Weinhold 
578*c97796c2SIngo Weinhold void
579*c97796c2SIngo Weinhold HeaderView::AddListener(HeaderViewListener* listener)
580*c97796c2SIngo Weinhold {
581*c97796c2SIngo Weinhold 	fListeners.AddItem(listener);
582*c97796c2SIngo Weinhold }
583*c97796c2SIngo Weinhold 
584*c97796c2SIngo Weinhold 
585*c97796c2SIngo Weinhold void
586*c97796c2SIngo Weinhold HeaderView::RemoveListener(HeaderViewListener* listener)
587*c97796c2SIngo Weinhold {
588*c97796c2SIngo Weinhold 	fListeners.RemoveItem(listener);
589*c97796c2SIngo Weinhold }
590*c97796c2SIngo Weinhold 
591*c97796c2SIngo Weinhold 
592*c97796c2SIngo Weinhold void
593*c97796c2SIngo Weinhold HeaderView::HeaderAdded(HeaderModel* model, int32 index)
594*c97796c2SIngo Weinhold {
595*c97796c2SIngo Weinhold 	if (Header* header = fModel->HeaderAt(index)) {
596*c97796c2SIngo Weinhold 		HeaderEntry* entry = new(std::nothrow) HeaderEntry(
597*c97796c2SIngo Weinhold 			fModel->HeaderAt(index));
598*c97796c2SIngo Weinhold printf("HeaderView::HeaderAdded(%p, %ld): header: %p, entry: %p\n", model, index, entry->header, entry);
599*c97796c2SIngo Weinhold 		if (entry == NULL || !fHeaderEntries.AddItem(entry)) {
600*c97796c2SIngo Weinhold 			delete entry;
601*c97796c2SIngo Weinhold 			return;
602*c97796c2SIngo Weinhold 		}
603*c97796c2SIngo Weinhold 
604*c97796c2SIngo Weinhold 		header->AddListener(this);
605*c97796c2SIngo Weinhold 		_InvalidateHeadersLayout(index);
606*c97796c2SIngo Weinhold 	}
607*c97796c2SIngo Weinhold }
608*c97796c2SIngo Weinhold 
609*c97796c2SIngo Weinhold 
610*c97796c2SIngo Weinhold void
611*c97796c2SIngo Weinhold HeaderView::HeaderRemoved(HeaderModel* model, int32 index)
612*c97796c2SIngo Weinhold {
613*c97796c2SIngo Weinhold 	if (HeaderEntry* entry = fHeaderEntries.RemoveItemAt(index)) {
614*c97796c2SIngo Weinhold 		entry->header->RemoveListener(this);
615*c97796c2SIngo Weinhold 		_InvalidateHeadersLayout(index);
616*c97796c2SIngo Weinhold 	}
617*c97796c2SIngo Weinhold }
618*c97796c2SIngo Weinhold 
619*c97796c2SIngo Weinhold 
620*c97796c2SIngo Weinhold void
621*c97796c2SIngo Weinhold HeaderView::HeaderMoved(HeaderModel* model, int32 fromIndex, int32 toIndex)
622*c97796c2SIngo Weinhold {
623*c97796c2SIngo Weinhold 	_InvalidateHeadersLayout(std::min(fromIndex, toIndex));
624*c97796c2SIngo Weinhold }
625*c97796c2SIngo Weinhold 
626*c97796c2SIngo Weinhold 
627*c97796c2SIngo Weinhold void
628*c97796c2SIngo Weinhold HeaderView::HeaderPropertiesChanged(Header* header, bool redrawNeeded,
629*c97796c2SIngo Weinhold 	bool relayoutNeeded)
630*c97796c2SIngo Weinhold {
631*c97796c2SIngo Weinhold 	if (!redrawNeeded && !relayoutNeeded)
632*c97796c2SIngo Weinhold 		return;
633*c97796c2SIngo Weinhold 
634*c97796c2SIngo Weinhold 	int32 index = fModel->IndexOfHeader(header);
635*c97796c2SIngo Weinhold 
636*c97796c2SIngo Weinhold 	if (relayoutNeeded)
637*c97796c2SIngo Weinhold 		_InvalidateHeadersLayout(index);
638*c97796c2SIngo Weinhold 	else if (redrawNeeded)
639*c97796c2SIngo Weinhold 		_InvalidateHeaders(index, index + 1);
640*c97796c2SIngo Weinhold }
641*c97796c2SIngo Weinhold 
642*c97796c2SIngo Weinhold 
643*c97796c2SIngo Weinhold void
644*c97796c2SIngo Weinhold HeaderView::_InvalidateHeadersLayout(int32 firstIndex)
645*c97796c2SIngo Weinhold {
646*c97796c2SIngo Weinhold 	if (!fLayoutValid)
647*c97796c2SIngo Weinhold 		return;
648*c97796c2SIngo Weinhold 
649*c97796c2SIngo Weinhold 	fLayoutValid = false;
650*c97796c2SIngo Weinhold 	InvalidateLayout();
651*c97796c2SIngo Weinhold 	Invalidate();
652*c97796c2SIngo Weinhold }
653*c97796c2SIngo Weinhold 
654*c97796c2SIngo Weinhold 
655*c97796c2SIngo Weinhold void
656*c97796c2SIngo Weinhold HeaderView::_InvalidateHeaders(int32 firstIndex, int32 endIndex)
657*c97796c2SIngo Weinhold {
658*c97796c2SIngo Weinhold 	Invalidate();
659*c97796c2SIngo Weinhold 		// TODO: Be less lazy!
660*c97796c2SIngo Weinhold }
661*c97796c2SIngo Weinhold 
662*c97796c2SIngo Weinhold 
663*c97796c2SIngo Weinhold void
664*c97796c2SIngo Weinhold HeaderView::_ValidateHeadersLayout()
665*c97796c2SIngo Weinhold {
666*c97796c2SIngo Weinhold 	if (fLayoutValid)
667*c97796c2SIngo Weinhold 		return;
668*c97796c2SIngo Weinhold 
669*c97796c2SIngo Weinhold 	DefaultHeaderRenderer defaultRenderer;
670*c97796c2SIngo Weinhold 
671*c97796c2SIngo Weinhold 	int32 headerCount = fHeaderEntries.CountItems();
672*c97796c2SIngo Weinhold 	float position = 0;
673*c97796c2SIngo Weinhold 	fPreferredWidth = 0;
674*c97796c2SIngo Weinhold 	fPreferredHeight = 0;
675*c97796c2SIngo Weinhold 
676*c97796c2SIngo Weinhold 	for (int32 i = 0; i < headerCount; i++) {
677*c97796c2SIngo Weinhold 		HeaderEntry* entry = fHeaderEntries.ItemAt(i);
678*c97796c2SIngo Weinhold 		entry->position = position;
679*c97796c2SIngo Weinhold 		if (Header* header = fModel->HeaderAt(i)) {
680*c97796c2SIngo Weinhold 			entry->width = header->Width();
681*c97796c2SIngo Weinhold 			fPreferredWidth += header->PreferredWidth();
682*c97796c2SIngo Weinhold 		} else
683*c97796c2SIngo Weinhold 			entry->width = 0;
684*c97796c2SIngo Weinhold 
685*c97796c2SIngo Weinhold 		position = entry->position + entry->width;
686*c97796c2SIngo Weinhold 
687*c97796c2SIngo Weinhold 		if (Header* header = fModel->HeaderAt(i)) {
688*c97796c2SIngo Weinhold 			HeaderRenderer* renderer = header->GetHeaderRenderer();
689*c97796c2SIngo Weinhold 			if (renderer == NULL)
690*c97796c2SIngo Weinhold 				renderer = &defaultRenderer;
691*c97796c2SIngo Weinhold 
692*c97796c2SIngo Weinhold 			float height = renderer->HeaderHeight(this, header);
693*c97796c2SIngo Weinhold 			if (height > fPreferredHeight)
694*c97796c2SIngo Weinhold 				fPreferredHeight = height;
695*c97796c2SIngo Weinhold 		}
696*c97796c2SIngo Weinhold 	}
697*c97796c2SIngo Weinhold 
698*c97796c2SIngo Weinhold 	fLayoutValid = true;
699*c97796c2SIngo Weinhold }
700*c97796c2SIngo Weinhold 
701*c97796c2SIngo Weinhold 
702*c97796c2SIngo Weinhold // #pragma mark - HeaderViewListener
703*c97796c2SIngo Weinhold 
704*c97796c2SIngo Weinhold 
705*c97796c2SIngo Weinhold HeaderViewListener::~HeaderViewListener()
706*c97796c2SIngo Weinhold {
707*c97796c2SIngo Weinhold }
708