xref: /haiku/src/apps/debuganalyzer/gui/HeaderView.cpp (revision cbe0a0c436162d78cc3f92a305b64918c839d079)
1 /*
2  * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2009, Stephan Aßmus, superstippi@gmx.de.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include "HeaderView.h"
9 
10 #include <stdio.h>
11 
12 #include <algorithm>
13 #include <new>
14 
15 #include <ControlLook.h>
16 #include <LayoutUtils.h>
17 #include <Looper.h>
18 
19 
20 // #pragma mark - HeaderRenderer
21 
22 
23 HeaderRenderer::~HeaderRenderer()
24 {
25 }
26 
27 
28 void
29 HeaderRenderer::DrawHeaderBackground(BView* view, BRect frame, BRect updateRect,
30 	uint32 flags)
31 {
32 	BRect bgRect = frame;
33 
34 	rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
35 	view->SetHighColor(tint_color(base, B_DARKEN_2_TINT));
36 	view->StrokeLine(bgRect.LeftBottom(), bgRect.RightBottom());
37 
38 	bgRect.bottom--;
39 	bgRect.right--;
40 
41 //	if ((flags & CLICKED) != 0)
42 //		base = tint_color(base, B_DARKEN_1_TINT);
43 
44 	be_control_look->DrawButtonBackground(view, bgRect, updateRect, base, 0,
45 		BControlLook::B_TOP_BORDER | BControlLook::B_BOTTOM_BORDER);
46 
47 	view->StrokeLine(frame.RightTop(), frame.RightBottom());
48 }
49 
50 
51 // #pragma mark - DefaultHeaderRenderer
52 
53 
54 DefaultHeaderRenderer::DefaultHeaderRenderer()
55 {
56 }
57 
58 
59 DefaultHeaderRenderer::~DefaultHeaderRenderer()
60 {
61 }
62 
63 
64 float
65 DefaultHeaderRenderer::HeaderHeight(BView* view, const Header* header)
66 {
67 	BVariant value;
68 	if (!header->GetValue(value))
69 		return 0;
70 
71 	if (value.Type() == B_STRING_TYPE) {
72 		font_height fontHeight;
73 		view->GetFontHeight(&fontHeight);
74 		return ceilf((fontHeight.ascent + fontHeight.descent) * 1.2f) + 2.0f;
75 	} else {
76 		// TODO: Support more value types.
77 		return 0;
78 	}
79 }
80 
81 
82 float
83 DefaultHeaderRenderer::PreferredHeaderWidth(BView* view, const Header* header)
84 {
85 	BVariant value;
86 	if (!header->GetValue(value))
87 		return 0;
88 
89 	if (value.Type() == B_STRING_TYPE) {
90 		float width = view->StringWidth(value.ToString());
91 		return width + be_control_look->DefaultLabelSpacing() * 2.0f;
92 	} else {
93 		// TODO: Support more value types.
94 		return 0;
95 	}
96 }
97 
98 
99 void
100 DefaultHeaderRenderer::DrawHeader(BView* view, BRect frame, BRect updateRect,
101 	const Header* header, uint32 flags)
102 {
103 	DrawHeaderBackground(view, frame, updateRect, flags);
104 
105 	BVariant value;
106 	if (!header->GetValue(value))
107 		return;
108 
109 	frame.InsetBy(be_control_look->DefaultLabelSpacing(), 0);
110 
111 	if (value.Type() == B_STRING_TYPE) {
112 		be_control_look->DrawLabel(view, value.ToString(), frame, updateRect,
113 			view->LowColor(), 0);
114 	}
115 }
116 
117 
118 // #pragma mark - HeaderListener
119 
120 
121 HeaderListener::~HeaderListener()
122 {
123 }
124 
125 
126 void
127 HeaderListener::HeaderWidthChanged(Header* header)
128 {
129 }
130 
131 
132 void
133 HeaderListener::HeaderWidthRestrictionsChanged(Header* header)
134 {
135 }
136 
137 
138 void
139 HeaderListener::HeaderValueChanged(Header* header)
140 {
141 }
142 
143 
144 void
145 HeaderListener::HeaderRendererChanged(Header* header)
146 {
147 }
148 
149 
150 // #pragma mark - Header
151 
152 
153 Header::Header(int32 modelIndex)
154 	:
155 	fWidth(100),
156 	fMinWidth(0),
157 	fMaxWidth(10000),
158 	fPreferredWidth(100),
159 	fValue(),
160 	fRenderer(NULL),
161 	fModelIndex(modelIndex),
162 	fResizable(true)
163 {
164 }
165 
166 
167 Header::Header(float width, float minWidth, float maxWidth,
168 	float preferredWidth, int32 modelIndex)
169 	:
170 	fWidth(width),
171 	fMinWidth(minWidth),
172 	fMaxWidth(maxWidth),
173 	fPreferredWidth(preferredWidth),
174 	fValue(),
175 	fRenderer(NULL),
176 	fModelIndex(modelIndex),
177 	fResizable(true)
178 {
179 }
180 
181 
182 float
183 Header::Width() const
184 {
185 	return fWidth;
186 }
187 
188 
189 float
190 Header::MinWidth() const
191 {
192 	return fMinWidth;
193 }
194 
195 
196 float
197 Header::MaxWidth() const
198 {
199 	return fMaxWidth;
200 }
201 
202 
203 float
204 Header::PreferredWidth() const
205 {
206 	return fPreferredWidth;
207 }
208 
209 
210 void
211 Header::SetWidth(float width)
212 {
213 	if (width != fWidth) {
214 		fWidth = width;
215 		NotifyWidthChanged();
216 	}
217 }
218 
219 
220 void
221 Header::SetMinWidth(float width)
222 {
223 	if (width != fMinWidth) {
224 		fMinWidth = width;
225 		NotifyWidthRestrictionsChanged();
226 	}
227 }
228 
229 
230 void
231 Header::SetMaxWidth(float width)
232 {
233 	if (width != fMaxWidth) {
234 		fMaxWidth = width;
235 		NotifyWidthRestrictionsChanged();
236 	}
237 }
238 
239 
240 void
241 Header::SetPreferredWidth(float width)
242 {
243 	if (width != fPreferredWidth) {
244 		fPreferredWidth = width;
245 		NotifyWidthRestrictionsChanged();
246 	}
247 }
248 
249 
250 bool
251 Header::IsResizable() const
252 {
253 	return fResizable;
254 }
255 
256 
257 void
258 Header::SetResizable(bool resizable)
259 {
260 	if (resizable != fResizable) {
261 		fResizable = resizable;
262 		NotifyWidthRestrictionsChanged();
263 	}
264 }
265 
266 
267 bool
268 Header::GetValue(BVariant& _value) const
269 {
270 	_value = fValue;
271 	return true;
272 }
273 
274 
275 void
276 Header::SetValue(const BVariant& value)
277 {
278 	fValue = value;
279 	NotifyValueChanged();
280 }
281 
282 
283 int32
284 Header::ModelIndex() const
285 {
286 	return fModelIndex;
287 }
288 
289 
290 void
291 Header::SetModelIndex(int32 index)
292 {
293 	fModelIndex = index;
294 }
295 
296 
297 HeaderRenderer*
298 Header::GetHeaderRenderer() const
299 {
300 	return fRenderer;
301 }
302 
303 
304 void
305 Header::SetHeaderRenderer(HeaderRenderer* renderer)
306 {
307 	if (renderer != fRenderer) {
308 		fRenderer = renderer;
309 		NotifyRendererChanged();
310 	}
311 }
312 
313 
314 void
315 Header::AddListener(HeaderListener* listener)
316 {
317 	fListeners.AddItem(listener);
318 }
319 
320 
321 void
322 Header::RemoveListener(HeaderListener* listener)
323 {
324 	fListeners.RemoveItem(listener);
325 }
326 
327 
328 void
329 Header::NotifyWidthChanged()
330 {
331 	for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) {
332 		HeaderListener* listener = fListeners.ItemAt(i);
333 		listener->HeaderWidthChanged(this);
334 	}
335 }
336 
337 
338 void
339 Header::NotifyWidthRestrictionsChanged()
340 {
341 	for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) {
342 		HeaderListener* listener = fListeners.ItemAt(i);
343 		listener->HeaderWidthRestrictionsChanged(this);
344 	}
345 }
346 
347 
348 void
349 Header::NotifyValueChanged()
350 {
351 	for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) {
352 		HeaderListener* listener = fListeners.ItemAt(i);
353 		listener->HeaderValueChanged(this);
354 	}
355 }
356 
357 
358 void
359 Header::NotifyRendererChanged()
360 {
361 	for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) {
362 		HeaderListener* listener = fListeners.ItemAt(i);
363 		listener->HeaderRendererChanged(this);
364 	}
365 }
366 
367 
368 // #pragma mark - HeaderModelListener
369 
370 
371 HeaderModelListener::~HeaderModelListener()
372 {
373 }
374 
375 
376 void
377 HeaderModelListener::HeaderAdded(HeaderModel* model, int32 index)
378 {
379 }
380 
381 
382 void
383 HeaderModelListener::HeaderRemoved(HeaderModel* model, int32 index)
384 {
385 }
386 
387 
388 void
389 HeaderModelListener::HeaderMoved(HeaderModel* model, int32 fromIndex,
390 	int32 toIndex)
391 {
392 }
393 
394 
395 // #pragma mark - HeaderModel
396 
397 
398 HeaderModel::HeaderModel()
399 {
400 }
401 
402 
403 HeaderModel::~HeaderModel()
404 {
405 }
406 
407 
408 int32
409 HeaderModel::CountHeaders() const
410 {
411 	return fHeaders.CountItems();
412 }
413 
414 
415 Header*
416 HeaderModel::HeaderAt(int32 index) const
417 {
418 	return fHeaders.ItemAt(index);
419 }
420 
421 
422 int32
423 HeaderModel::IndexOfHeader(Header* header) const
424 {
425 	return fHeaders.IndexOf(header);
426 }
427 
428 
429 bool
430 HeaderModel::AddHeader(Header* header)
431 {
432 	if (!fHeaders.AddItem(header))
433 		return false;
434 
435 	NotifyHeaderAdded(fHeaders.CountItems() - 1);
436 
437 	return true;
438 }
439 
440 
441 Header*
442 HeaderModel::RemoveHeader(int32 index)
443 {
444 	Header* header = fHeaders.RemoveItemAt(index);
445 	if (header != NULL)
446 		return NULL;
447 
448 	NotifyHeaderRemoved(index);
449 
450 	return header;
451 }
452 
453 
454 void
455 HeaderModel::RemoveHeader(Header* header)
456 {
457 	RemoveHeader(fHeaders.IndexOf(header));
458 }
459 
460 
461 bool
462 HeaderModel::MoveHeader(int32 fromIndex, int32 toIndex)
463 {
464 	int32 headerCount = fHeaders.CountItems();
465 	if (fromIndex < 0 || fromIndex >= headerCount
466 		|| toIndex < 0 || toIndex >= headerCount) {
467 		return false;
468 	}
469 
470 	if (fromIndex == toIndex)
471 		return true;
472 
473 	Header* header = fHeaders.RemoveItemAt(fromIndex);
474 	fHeaders.AddItem(header, toIndex);
475 		// TODO: Might fail.
476 
477 	NotifyHeaderMoved(fromIndex, toIndex);
478 
479 	return true;
480 }
481 
482 
483 void
484 HeaderModel::AddListener(HeaderModelListener* listener)
485 {
486 	fListeners.AddItem(listener);
487 }
488 
489 
490 void
491 HeaderModel::RemoveListener(HeaderModelListener* listener)
492 {
493 	fListeners.RemoveItem(listener);
494 }
495 
496 
497 void
498 HeaderModel::NotifyHeaderAdded(int32 index)
499 {
500 	for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) {
501 		HeaderModelListener* listener = fListeners.ItemAt(i);
502 		listener->HeaderAdded(this, index);
503 	}
504 }
505 
506 
507 void
508 HeaderModel::NotifyHeaderRemoved(int32 index)
509 {
510 	for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) {
511 		HeaderModelListener* listener = fListeners.ItemAt(i);
512 		listener->HeaderRemoved(this, index);
513 	}
514 }
515 
516 
517 void
518 HeaderModel::NotifyHeaderMoved(int32 fromIndex, int32 toIndex)
519 {
520 	for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) {
521 		HeaderModelListener* listener = fListeners.ItemAt(i);
522 		listener->HeaderMoved(this, fromIndex, toIndex);
523 	}
524 }
525 
526 
527 // #pragma mark - HeaderEntry
528 
529 
530 struct HeaderView::HeaderEntry {
531 	Header*	header;
532 	float	position;
533 	float	width;
534 
535 	HeaderEntry(Header* header)
536 		:
537 		header(header)
538 	{
539 	}
540 };
541 
542 
543 // #pragma mark - States
544 
545 
546 class HeaderView::State {
547 public:
548 	State(HeaderView* parent)
549 		:
550 		fParent(parent)
551 	{
552 	}
553 
554 	virtual ~State()
555 	{
556 	}
557 
558 	virtual void Entering(State* previousState)
559 	{
560 	}
561 
562 	virtual void Leaving(State* nextState)
563 	{
564 	}
565 
566 	virtual void MouseDown(BPoint where, uint32 buttons, uint32 modifiers)
567 	{
568 	}
569 
570 	virtual void MouseUp(BPoint where, uint32 buttons, uint32 modifiers)
571 	{
572 	}
573 
574 	virtual void MouseMoved(BPoint where, uint32 transit,
575 		const BMessage* dragMessage)
576 	{
577 	}
578 
579 protected:
580 	HeaderView*	fParent;
581 };
582 
583 
584 class HeaderView::DefaultState : public State {
585 public:
586 								DefaultState(HeaderView* parent);
587 
588 	virtual	void				MouseDown(BPoint where, uint32 buttons,
589 									uint32 modifiers);
590 	virtual	void				MouseMoved(BPoint where, uint32 transit,
591 									const BMessage* dragMessage);
592 };
593 
594 
595 class HeaderView::ResizeState : public State {
596 public:
597 	virtual	void				Entering(State* previousState);
598 	virtual	void				Leaving(State* nextState);
599 
600 								ResizeState(HeaderView* parent,
601 									int32 headerIndex, BPoint startPoint);
602 
603 	virtual	void				MouseUp(BPoint where, uint32 buttons,
604 									uint32 modifiers);
605 	virtual	void				MouseMoved(BPoint where, uint32 transit,
606 									const BMessage* dragMessage);
607 
608 private:
609 			Header*				fHeader;
610 			float				fStartX;
611 			float				fStartWidth;
612 };
613 
614 
615 // #pragma mark - DefaultState
616 
617 
618 HeaderView::DefaultState::DefaultState(HeaderView* parent)
619 	:
620 	State(parent)
621 {
622 }
623 
624 
625 void
626 HeaderView::DefaultState::MouseDown(BPoint where, uint32 buttons,
627 	uint32 modifiers)
628 {
629 	HeaderModel* model = fParent->Model();
630 	if (model == NULL)
631 		return;
632 
633 	if ((buttons & B_PRIMARY_MOUSE_BUTTON) == 0)
634 		return;
635 
636 	int32 headerIndex = fParent->HeaderIndexAt(where);
637 	if (headerIndex < 0) {
638 		int32 headerCount = model->CountHeaders();
639 		if (headerCount == 0)
640 			return;
641 
642 		headerIndex = headerCount - 1;
643 	}
644 
645 	// Check whether the mouse is close to the left or the right side of the
646 	// header.
647 	BRect headerFrame = fParent->HeaderFrame(headerIndex);
648 	if (fabs(headerFrame.left - where.x) <= 3) {
649 		if (headerIndex == 0)
650 			return;
651 		headerIndex--;
652 	} else if (fabs(headerFrame.right + 1 - where.x) > 3)
653 		return;
654 
655 	// start resizing the header
656 	fParent->_SwitchState(new ResizeState(fParent, headerIndex, where));
657 }
658 
659 
660 void
661 HeaderView::DefaultState::MouseMoved(BPoint where, uint32 transit,
662 	const BMessage* dragMessage)
663 {
664 }
665 
666 
667 // #pragma mark - ResizeState
668 
669 
670 void
671 HeaderView::ResizeState::Entering(State* previousState)
672 {
673 	fParent->SetEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
674 }
675 
676 
677 void
678 HeaderView::ResizeState::Leaving(State* nextState)
679 {
680 	fParent->SetEventMask(0, 0);
681 }
682 
683 
684 HeaderView::ResizeState::ResizeState(HeaderView* parent, int32 headerIndex,
685 	BPoint startPoint)
686 	:
687 	State(parent),
688 	fHeader(parent->Model()->HeaderAt(headerIndex)),
689 	fStartX(startPoint.x),
690 	fStartWidth(fHeader->Width())
691 {
692 }
693 
694 
695 void
696 HeaderView::ResizeState::MouseUp(BPoint where, uint32 buttons,
697 	uint32 modifiers)
698 {
699 	if ((buttons & B_PRIMARY_MOUSE_BUTTON) == 0)
700 		fParent->_SwitchState(NULL);
701 }
702 
703 
704 void
705 HeaderView::ResizeState::MouseMoved(BPoint where, uint32 transit,
706 	const BMessage* dragMessage)
707 {
708 	float width = fStartWidth + where.x - fStartX;
709 	width = std::max(width, fHeader->MinWidth());
710 	width = std::min(width, fHeader->MaxWidth());
711 	fHeader->SetWidth(width);
712 }
713 
714 
715 // #pragma mark - HeaderView
716 
717 
718 HeaderView::HeaderView()
719  	:
720  	BView("header view", B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
721  	fModel(NULL),
722  	fHeaderEntries(10, true),
723  	fLayoutValid(false),
724  	fDefaultState(new DefaultState(this)),
725  	fState(fDefaultState)
726 {
727  	HeaderModel* model = new(std::nothrow) HeaderModel;
728  	BReference<HeaderModel> modelReference(model, true);
729  	SetModel(model);
730 
731 	SetViewColor(B_TRANSPARENT_32_BIT);
732 }
733 
734 
735 HeaderView::~HeaderView()
736 {
737 	SetModel(NULL);
738 
739 	_SwitchState(NULL);
740 	delete fDefaultState;
741 }
742 
743 
744 void
745 HeaderView::Draw(BRect updateRect)
746 {
747 	if (fModel == NULL)
748 		return;
749 
750 	_ValidateHeadersLayout();
751 
752 	DefaultHeaderRenderer defaultRenderer;
753 	float bottom = Bounds().Height();
754 	float left = 0.0f;
755 
756 	for (int32 i = 0; HeaderEntry* entry = fHeaderEntries.ItemAt(i); i++) {
757 		if (Header* header = fModel->HeaderAt(i)) {
758 			HeaderRenderer* renderer = header->GetHeaderRenderer();
759 			if (renderer == NULL)
760 				renderer = &defaultRenderer;
761 
762 			BRect frame(entry->position, 0, entry->position + entry->width - 1,
763 				bottom);
764 			renderer->DrawHeader(this, frame, updateRect, header, 0);
765 				// TODO: flags!
766 
767 			left = entry->position + entry->width;
768 		}
769 	}
770 
771 	// TODO: We are not using any custom renderer here.
772 	defaultRenderer.DrawHeaderBackground(this,
773 		BRect(left, 0, Bounds().right + 1, bottom), updateRect, 0);
774 }
775 
776 
777 BSize
778 HeaderView::MinSize()
779 {
780 	_ValidateHeadersLayout();
781 
782 	return BLayoutUtils::ComposeSize(ExplicitMinSize(),
783 		BSize(100, fPreferredHeight - 1));
784 }
785 
786 
787 BSize
788 HeaderView::MaxSize()
789 {
790 	_ValidateHeadersLayout();
791 
792 	return BLayoutUtils::ComposeSize(ExplicitMaxSize(),
793 		BSize(B_SIZE_UNLIMITED, fPreferredHeight - 1));
794 }
795 
796 
797 BSize
798 HeaderView::PreferredSize()
799 {
800 	_ValidateHeadersLayout();
801 
802 	return BLayoutUtils::ComposeSize(ExplicitPreferredSize(),
803 		BSize(fPreferredWidth - 1, fPreferredHeight - 1));
804 }
805 
806 
807 HeaderModel*
808 HeaderView::Model() const
809 {
810 	return fModel;
811 }
812 
813 
814 void
815 HeaderView::MouseDown(BPoint where)
816 {
817 	// get buttons and modifiers
818 	BMessage* message = Looper()->CurrentMessage();
819 	int32 buttons;
820 	if (message == NULL || message->FindInt32("buttons", &buttons) != B_OK)
821 		buttons = 0;
822 	int32 modifiers;
823 	if (message == NULL || message->FindInt32("modifiers", &modifiers) != B_OK)
824 		modifiers = 0;
825 
826 	fState->MouseDown(where, buttons, modifiers);
827 }
828 
829 
830 void
831 HeaderView::MouseUp(BPoint where)
832 {
833 	// get buttons and modifiers
834 	BMessage* message = Looper()->CurrentMessage();
835 	int32 buttons;
836 	if (message == NULL || message->FindInt32("buttons", &buttons) != B_OK)
837 		buttons = 0;
838 	int32 modifiers;
839 	if (message == NULL || message->FindInt32("modifiers", &modifiers) != B_OK)
840 		modifiers = 0;
841 
842 	fState->MouseUp(where, buttons, modifiers);
843 }
844 
845 
846 void
847 HeaderView::MouseMoved(BPoint where, uint32 transit,
848 	const BMessage* dragMessage)
849 {
850 	fState->MouseMoved(where, transit, dragMessage);
851 }
852 
853 
854 status_t
855 HeaderView::SetModel(HeaderModel* model)
856 {
857 	if (model == fModel)
858 		return B_OK;
859 
860 	_SwitchState(NULL);
861 
862 	if (fModel != NULL) {
863 		// remove all headers
864 		for (int32 i = 0; HeaderEntry* entry = fHeaderEntries.ItemAt(i); i++)
865 			entry->header->RemoveListener(this);
866 		fHeaderEntries.MakeEmpty();
867 
868 		fModel->RemoveListener(this);
869 		fModel->ReleaseReference();
870 	}
871 
872 	fModel = model;
873 
874 	if (fModel != NULL) {
875 		fModel->AcquireReference();
876 		fModel->AddListener(this);
877 
878 		// create header entries
879 		int32 headerCount = fModel->CountHeaders();
880 		for (int32 i = 0; i < headerCount; i++) {
881 			HeaderEntry* entry = new(std::nothrow) HeaderEntry(
882 				fModel->HeaderAt(i));
883 			if (entry == NULL || !fHeaderEntries.AddItem(entry)) {
884 				delete entry;
885 				return B_NO_MEMORY;
886 			}
887 
888 			entry->header->AddListener(this);
889 		}
890 	}
891 
892 	_InvalidateHeadersLayout(0);
893 	Invalidate();
894 
895 	return B_OK;
896 }
897 
898 
899 BRect
900 HeaderView::HeaderFrame(int32 index) const
901 {
902 	float bottom = Bounds().Height();
903 
904 	if (HeaderEntry* entry = fHeaderEntries.ItemAt(index)) {
905 		return BRect(entry->position, 0, entry->position + entry->width - 1,
906 			bottom);
907 	}
908 
909 	return BRect();
910 }
911 
912 
913 int32
914 HeaderView::HeaderIndexAt(BPoint point) const
915 {
916 	float x = point.x;
917 
918 	for (int32 i = 0; HeaderEntry* entry = fHeaderEntries.ItemAt(i); i++) {
919 		if (x >= entry->position && x < entry->position + entry->width)
920 			return i;
921 	}
922 
923 	return -1;
924 }
925 
926 
927 void
928 HeaderView::AddListener(HeaderViewListener* listener)
929 {
930 	fListeners.AddItem(listener);
931 }
932 
933 
934 void
935 HeaderView::RemoveListener(HeaderViewListener* listener)
936 {
937 	fListeners.RemoveItem(listener);
938 }
939 
940 
941 void
942 HeaderView::HeaderAdded(HeaderModel* model, int32 index)
943 {
944 	if (Header* header = fModel->HeaderAt(index)) {
945 		HeaderEntry* entry = new(std::nothrow) HeaderEntry(
946 			fModel->HeaderAt(index));
947 		if (entry == NULL || !fHeaderEntries.AddItem(entry)) {
948 			delete entry;
949 			return;
950 		}
951 
952 		header->AddListener(this);
953 		_InvalidateHeadersLayout(index);
954 	}
955 }
956 
957 
958 void
959 HeaderView::HeaderRemoved(HeaderModel* model, int32 index)
960 {
961 	if (HeaderEntry* entry = fHeaderEntries.RemoveItemAt(index)) {
962 		entry->header->RemoveListener(this);
963 		_InvalidateHeadersLayout(index);
964 	}
965 }
966 
967 
968 void
969 HeaderView::HeaderMoved(HeaderModel* model, int32 fromIndex, int32 toIndex)
970 {
971 	_InvalidateHeadersLayout(std::min(fromIndex, toIndex));
972 }
973 
974 
975 void
976 HeaderView::HeaderWidthChanged(Header* header)
977 {
978 	_HeaderPropertiesChanged(header, true, true);
979 }
980 
981 
982 void
983 HeaderView::HeaderWidthRestrictionsChanged(Header* header)
984 {
985 	// TODO:...
986 }
987 
988 
989 void
990 HeaderView::HeaderValueChanged(Header* header)
991 {
992 	_HeaderPropertiesChanged(header, true, false);
993 }
994 
995 
996 void
997 HeaderView::HeaderRendererChanged(Header* header)
998 {
999 	_HeaderPropertiesChanged(header, true, true);
1000 }
1001 
1002 
1003 void
1004 HeaderView::_HeaderPropertiesChanged(Header* header, bool redrawNeeded,
1005 	bool relayoutNeeded)
1006 {
1007 	if (!redrawNeeded && !relayoutNeeded)
1008 		return;
1009 
1010 	int32 index = fModel->IndexOfHeader(header);
1011 
1012 	if (relayoutNeeded)
1013 		_InvalidateHeadersLayout(index);
1014 	else if (redrawNeeded)
1015 		_InvalidateHeaders(index, index + 1);
1016 }
1017 
1018 
1019 void
1020 HeaderView::_InvalidateHeadersLayout(int32 firstIndex)
1021 {
1022 	if (!fLayoutValid)
1023 		return;
1024 
1025 	fLayoutValid = false;
1026 	InvalidateLayout();
1027 	Invalidate();
1028 }
1029 
1030 
1031 void
1032 HeaderView::_InvalidateHeaders(int32 firstIndex, int32 endIndex)
1033 {
1034 	Invalidate();
1035 		// TODO: Be less lazy!
1036 }
1037 
1038 
1039 void
1040 HeaderView::_ValidateHeadersLayout()
1041 {
1042 	if (fLayoutValid)
1043 		return;
1044 
1045 	DefaultHeaderRenderer defaultRenderer;
1046 
1047 	int32 headerCount = fHeaderEntries.CountItems();
1048 	float position = 0;
1049 	fPreferredWidth = 0;
1050 	fPreferredHeight = 0;
1051 
1052 	for (int32 i = 0; i < headerCount; i++) {
1053 		HeaderEntry* entry = fHeaderEntries.ItemAt(i);
1054 		entry->position = position;
1055 		if (Header* header = fModel->HeaderAt(i)) {
1056 			entry->width = header->Width();
1057 			fPreferredWidth += header->PreferredWidth();
1058 		} else
1059 			entry->width = 0;
1060 
1061 		position = entry->position + entry->width;
1062 
1063 		if (Header* header = fModel->HeaderAt(i)) {
1064 			HeaderRenderer* renderer = header->GetHeaderRenderer();
1065 			if (renderer == NULL)
1066 				renderer = &defaultRenderer;
1067 
1068 			float height = renderer->HeaderHeight(this, header);
1069 			if (height > fPreferredHeight)
1070 				fPreferredHeight = height;
1071 		}
1072 	}
1073 
1074 	fLayoutValid = true;
1075 }
1076 
1077 
1078 void
1079 HeaderView::_SwitchState(State* newState)
1080 {
1081 	if (newState == NULL)
1082 		newState = fDefaultState;
1083 
1084 	fState->Leaving(newState);
1085 	newState->Entering(fState);
1086 
1087 	if (fState != fDefaultState)
1088 		delete fState;
1089 
1090 	fState = newState;
1091 }
1092 
1093 
1094 // #pragma mark - HeaderViewListener
1095 
1096 
1097 HeaderViewListener::~HeaderViewListener()
1098 {
1099 }
1100