diff --git a/src/apps/debuganalyzer/gui/HeaderView.cpp b/src/apps/debuganalyzer/gui/HeaderView.cpp new file mode 100644 index 0000000000..ba28818d8c --- /dev/null +++ b/src/apps/debuganalyzer/gui/HeaderView.cpp @@ -0,0 +1,707 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2009, Stephan Aßmus, superstippi@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "HeaderView.h" + +#include + +#include +#include + +#include +#include + + +// #pragma mark - HeaderRenderer + + +HeaderRenderer::~HeaderRenderer() +{ +} + + +// #pragma mark - DefaultHeaderRenderer + + +DefaultHeaderRenderer::DefaultHeaderRenderer() +{ +} + + +DefaultHeaderRenderer::~DefaultHeaderRenderer() +{ +} + + +float +DefaultHeaderRenderer::HeaderHeight(BView* view, const Header* header) +{ + BVariant value; + if (!header->GetValue(value)) + return 0; + + if (value.Type() == B_STRING_TYPE) { + return 15; + // TODO:... + } else + return 0; +} + + +void +DefaultHeaderRenderer::DrawHeader(BView* view, BRect frame, BRect updateRect, + const Header* header, uint32 flags) +{ +printf("DefaultHeaderRenderer::DrawHeader(): frame: (%f, %f) - (%f, %f), header: %p\n", +frame.left, frame.top, frame.right, frame.bottom, header); + BVariant value; + if (!header->GetValue(value)) + return; + + if (value.Type() == B_STRING_TYPE) { + be_control_look->DrawLabel(view, value.ToString(), frame, updateRect, + view->LowColor(), 0); + } +} + + +// #pragma mark - HeaderListener + + +HeaderListener::~HeaderListener() +{ +} + + +// #pragma mark - Header + + +Header::Header(int32 modelIndex) + : + fWidth(100), + fMinWidth(0), + fMaxWidth(10000), + fPreferredWidth(100), + fValue(), + fRenderer(NULL), + fModelIndex(modelIndex), + fResizable(true) +{ +} + + +Header::Header(float width, float minWidth, float maxWidth, + float preferredWidth, int32 modelIndex) + : + fWidth(width), + fMinWidth(minWidth), + fMaxWidth(maxWidth), + fPreferredWidth(preferredWidth), + fValue(), + fRenderer(NULL), + fModelIndex(modelIndex), + fResizable(true) +{ +} + + +float +Header::Width() const +{ + return fWidth; +} + + +float +Header::MinWidth() const +{ + return fMinWidth; +} + + +float +Header::MaxWidth() const +{ + return fMaxWidth; +} + + +float +Header::PreferredWidth() const +{ + return fPreferredWidth; +} + + +void +Header::SetWidth(float width) +{ + if (width != fWidth) { + fWidth = width; + NotifyPropertiesChanged(true, true); + } +} + + +void +Header::SetMinWidth(float width) +{ + if (width != fMinWidth) { + fMinWidth = width; + NotifyPropertiesChanged(false, false); + } +} + + +void +Header::SetMaxWidth(float width) +{ + if (width != fMaxWidth) { + fMaxWidth = width; + NotifyPropertiesChanged(false, false); + } +} + + +void +Header::SetPreferredWidth(float width) +{ + if (width != fPreferredWidth) { + fPreferredWidth = width; + NotifyPropertiesChanged(false, false); + } +} + + +bool +Header::IsResizable() const +{ + return fResizable; +} + + +void +Header::SetResizable(bool resizable) +{ + if (resizable != fResizable) { + fResizable = resizable; + NotifyPropertiesChanged(false, false); + } +} + + +bool +Header::GetValue(BVariant& _value) const +{ + _value = fValue; + return true; +} + + +void +Header::SetValue(const BVariant& value) +{ + fValue = value; + NotifyPropertiesChanged(true, false); +} + + +int32 +Header::ModelIndex() const +{ + return fModelIndex; +} + + +void +Header::SetModelIndex(int32 index) +{ + if (index != fModelIndex) { + fModelIndex = index; + NotifyPropertiesChanged(true, false); + } +} + + +HeaderRenderer* +Header::GetHeaderRenderer() const +{ + return fRenderer; +} + + +void +Header::SetHeaderRenderer(HeaderRenderer* renderer) +{ + if (renderer != fRenderer) { + fRenderer = renderer; + NotifyPropertiesChanged(true, false); + } +} + + +void +Header::AddListener(HeaderListener* listener) +{ + fListeners.AddItem(listener); +} + + +void +Header::RemoveListener(HeaderListener* listener) +{ + fListeners.RemoveItem(listener); +} + + +void +Header::NotifyPropertiesChanged(bool redrawNeeded, bool relayoutNeeded) +{ + for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) { + HeaderListener* listener = fListeners.ItemAt(i); + listener->HeaderPropertiesChanged(this, redrawNeeded, relayoutNeeded); + } +} + + +// #pragma mark - HeaderModelListener + + +HeaderModelListener::~HeaderModelListener() +{ +} + + +void +HeaderModelListener::HeaderAdded(HeaderModel* model, int32 index) +{ +} + + +void +HeaderModelListener::HeaderRemoved(HeaderModel* model, int32 index) +{ +} + + +void +HeaderModelListener::HeaderMoved(HeaderModel* model, int32 fromIndex, + int32 toIndex) +{ +} + + +// #pragma mark - HeaderModel + + +HeaderModel::HeaderModel() +{ +} + + +HeaderModel::~HeaderModel() +{ +} + + +int32 +HeaderModel::CountHeaders() const +{ + return fHeaders.CountItems(); +} + + +Header* +HeaderModel::HeaderAt(int32 index) const +{ + return fHeaders.ItemAt(index); +} + + +int32 +HeaderModel::IndexOfHeader(Header* header) const +{ + return fHeaders.IndexOf(header); +} + + +bool +HeaderModel::AddHeader(Header* header) +{ + if (!fHeaders.AddItem(header)) + return false; + + NotifyHeaderAdded(fHeaders.CountItems() - 1); + + return true; +} + + +Header* +HeaderModel::RemoveHeader(int32 index) +{ + Header* header = fHeaders.RemoveItemAt(index); + if (header != NULL) + return NULL; + + NotifyHeaderRemoved(index); + + return header; +} + + +void +HeaderModel::RemoveHeader(Header* header) +{ + RemoveHeader(fHeaders.IndexOf(header)); +} + + +bool +HeaderModel::MoveHeader(int32 fromIndex, int32 toIndex) +{ + int32 headerCount = fHeaders.CountItems(); + if (fromIndex < 0 || fromIndex >= headerCount + || toIndex < 0 || toIndex >= headerCount) { + return false; + } + + if (fromIndex == toIndex) + return true; + + Header* header = fHeaders.RemoveItemAt(fromIndex); + fHeaders.AddItem(header, toIndex); + // TODO: Might fail. + + NotifyHeaderMoved(fromIndex, toIndex); + + return true; +} + + +void +HeaderModel::AddListener(HeaderModelListener* listener) +{ + fListeners.AddItem(listener); +} + + +void +HeaderModel::RemoveListener(HeaderModelListener* listener) +{ + fListeners.RemoveItem(listener); +} + + +void +HeaderModel::NotifyHeaderAdded(int32 index) +{ + for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) { + HeaderModelListener* listener = fListeners.ItemAt(i); + listener->HeaderAdded(this, index); + } +} + + +void +HeaderModel::NotifyHeaderRemoved(int32 index) +{ + for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) { + HeaderModelListener* listener = fListeners.ItemAt(i); + listener->HeaderRemoved(this, index); + } +} + + +void +HeaderModel::NotifyHeaderMoved(int32 fromIndex, int32 toIndex) +{ + for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) { + HeaderModelListener* listener = fListeners.ItemAt(i); + listener->HeaderMoved(this, fromIndex, toIndex); + } +} + + +// #pragma mark - HeaderEntry + + +struct HeaderView::HeaderEntry { + Header* header; + float position; + float width; + + HeaderEntry(Header* header) + : + header(header) + { + } +}; + + +// #pragma mark - HeaderView + + +HeaderView::HeaderView() + : + BView("header view", B_WILL_DRAW), + fModel(NULL), + fHeaderEntries(10, true), + fLayoutValid(false) +{ + HeaderModel* model = new(std::nothrow) HeaderModel; + Reference modelReference(model, true); + SetModel(model); +} + + +HeaderView::~HeaderView() +{ + SetModel(NULL); +} + + +void +HeaderView::Draw(BRect updateRect) +{ + if (fModel == NULL) + return; + + _ValidateHeadersLayout(); + + DefaultHeaderRenderer defaultRenderer; + float bottom = Bounds().Height(); + + for (int32 i = 0; HeaderEntry* entry = fHeaderEntries.ItemAt(i); i++) { + if (Header* header = fModel->HeaderAt(i)) { + HeaderRenderer* renderer = header->GetHeaderRenderer(); + if (renderer == NULL) + renderer = &defaultRenderer; + + BRect frame(entry->position, 0, entry->position + entry->width - 1, + bottom); + renderer->DrawHeader(this, frame, updateRect, header, 0); + // TODO: flags! + } + } +} + + +BSize +HeaderView::MinSize() +{ + _ValidateHeadersLayout(); + + return BLayoutUtils::ComposeSize(ExplicitMinSize(), + BSize(100, fPreferredHeight - 1)); +} + + +BSize +HeaderView::MaxSize() +{ + _ValidateHeadersLayout(); + + return BLayoutUtils::ComposeSize(ExplicitMaxSize(), + BSize(B_SIZE_UNLIMITED, fPreferredHeight - 1)); +} + + +BSize +HeaderView::PreferredSize() +{ + _ValidateHeadersLayout(); + + return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), + BSize(fPreferredWidth - 1, fPreferredHeight - 1)); +} + + +HeaderModel* +HeaderView::Model() const +{ + return fModel; +} + + +status_t +HeaderView::SetModel(HeaderModel* model) +{ + if (model == fModel) + return B_OK; +printf("HeaderView::SetModel(%p)\n", model); + + if (fModel != NULL) { + // remove all headers + for (int32 i = 0; HeaderEntry* entry = fHeaderEntries.ItemAt(i); i++) +{ +printf(" unsetting entry %p, header: %p\n", entry, entry->header); + entry->header->RemoveListener(this); +} + fHeaderEntries.MakeEmpty(); + + fModel->RemoveListener(this); + fModel->ReleaseReference(); + } + + fModel = model; + + if (fModel != NULL) { + fModel->AcquireReference(); + fModel->AddListener(this); + + // create header entries + int32 headerCount = fModel->CountHeaders(); + for (int32 i = 0; i < headerCount; i++) { + HeaderEntry* entry = new(std::nothrow) HeaderEntry( + fModel->HeaderAt(i)); + if (entry == NULL || !fHeaderEntries.AddItem(entry)) { + delete entry; + return B_NO_MEMORY; + } + + entry->header->AddListener(this); + } + } + + _InvalidateHeadersLayout(0); + Invalidate(); + + return B_OK; +} + + +void +HeaderView::AddListener(HeaderViewListener* listener) +{ + fListeners.AddItem(listener); +} + + +void +HeaderView::RemoveListener(HeaderViewListener* listener) +{ + fListeners.RemoveItem(listener); +} + + +void +HeaderView::HeaderAdded(HeaderModel* model, int32 index) +{ + if (Header* header = fModel->HeaderAt(index)) { + HeaderEntry* entry = new(std::nothrow) HeaderEntry( + fModel->HeaderAt(index)); +printf("HeaderView::HeaderAdded(%p, %ld): header: %p, entry: %p\n", model, index, entry->header, entry); + if (entry == NULL || !fHeaderEntries.AddItem(entry)) { + delete entry; + return; + } + + header->AddListener(this); + _InvalidateHeadersLayout(index); + } +} + + +void +HeaderView::HeaderRemoved(HeaderModel* model, int32 index) +{ + if (HeaderEntry* entry = fHeaderEntries.RemoveItemAt(index)) { + entry->header->RemoveListener(this); + _InvalidateHeadersLayout(index); + } +} + + +void +HeaderView::HeaderMoved(HeaderModel* model, int32 fromIndex, int32 toIndex) +{ + _InvalidateHeadersLayout(std::min(fromIndex, toIndex)); +} + + +void +HeaderView::HeaderPropertiesChanged(Header* header, bool redrawNeeded, + bool relayoutNeeded) +{ + if (!redrawNeeded && !relayoutNeeded) + return; + + int32 index = fModel->IndexOfHeader(header); + + if (relayoutNeeded) + _InvalidateHeadersLayout(index); + else if (redrawNeeded) + _InvalidateHeaders(index, index + 1); +} + + +void +HeaderView::_InvalidateHeadersLayout(int32 firstIndex) +{ + if (!fLayoutValid) + return; + + fLayoutValid = false; + InvalidateLayout(); + Invalidate(); +} + + +void +HeaderView::_InvalidateHeaders(int32 firstIndex, int32 endIndex) +{ + Invalidate(); + // TODO: Be less lazy! +} + + +void +HeaderView::_ValidateHeadersLayout() +{ + if (fLayoutValid) + return; + + DefaultHeaderRenderer defaultRenderer; + + int32 headerCount = fHeaderEntries.CountItems(); + float position = 0; + fPreferredWidth = 0; + fPreferredHeight = 0; + + for (int32 i = 0; i < headerCount; i++) { + HeaderEntry* entry = fHeaderEntries.ItemAt(i); + entry->position = position; + if (Header* header = fModel->HeaderAt(i)) { + entry->width = header->Width(); + fPreferredWidth += header->PreferredWidth(); + } else + entry->width = 0; + + position = entry->position + entry->width; + + if (Header* header = fModel->HeaderAt(i)) { + HeaderRenderer* renderer = header->GetHeaderRenderer(); + if (renderer == NULL) + renderer = &defaultRenderer; + + float height = renderer->HeaderHeight(this, header); + if (height > fPreferredHeight) + fPreferredHeight = height; + } + } + + fLayoutValid = true; +} + + +// #pragma mark - HeaderViewListener + + +HeaderViewListener::~HeaderViewListener() +{ +} diff --git a/src/apps/debuganalyzer/gui/HeaderView.h b/src/apps/debuganalyzer/gui/HeaderView.h new file mode 100644 index 0000000000..edfc3740b7 --- /dev/null +++ b/src/apps/debuganalyzer/gui/HeaderView.h @@ -0,0 +1,207 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2009, Stephan Aßmus, superstippi@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef HEADER_VIEW_H +#define HEADER_VIEW_H + + +#include + +#include +#include +#include + + +class Header; +class HeaderModel; +class HeaderViewListener; + + +class HeaderRenderer { +public: + virtual ~HeaderRenderer(); + + virtual float HeaderHeight(BView* view, const Header* header) + = 0; + virtual void DrawHeader(BView* view, BRect frame, + BRect updateRect, const Header* header, + uint32 flags) = 0; +}; + + +class DefaultHeaderRenderer : public HeaderRenderer { +public: + DefaultHeaderRenderer(); + virtual ~DefaultHeaderRenderer(); + + virtual float HeaderHeight(BView* view, const Header* header); + virtual void DrawHeader(BView* view, BRect frame, + BRect updateRect, const Header* header, + uint32 flags); +}; + + +class HeaderListener { +public: + virtual ~HeaderListener(); + + virtual void HeaderPropertiesChanged(Header* header, + bool redrawNeeded, bool relayoutNeeded) = 0; +}; + + +class Header { +public: + Header(int32 modelIndex = 0); + Header(float width, float minWidth, + float maxWidth, float preferredWidth, + int32 modelIndex = 0); + + float Width() const; + float MinWidth() const; + float MaxWidth() const; + float PreferredWidth() const; + + void SetWidth(float width); + void SetMinWidth(float width); + void SetMaxWidth(float width); + void SetPreferredWidth(float width); + + bool IsResizable() const; + void SetResizable(bool resizable); + + bool GetValue(BVariant& _value) const; + void SetValue(const BVariant& value); + + int32 ModelIndex() const; + void SetModelIndex(int32 index); + + HeaderRenderer* GetHeaderRenderer() const; + void SetHeaderRenderer(HeaderRenderer* renderer); + + void AddListener(HeaderListener* listener); + void RemoveListener(HeaderListener* listener); + +protected: + void NotifyPropertiesChanged(bool redrawNeeded, + bool relayoutNeeded); + +private: + typedef BObjectList ListenerList; + +private: + float fWidth; + float fMinWidth; + float fMaxWidth; + float fPreferredWidth; + BVariant fValue; + HeaderRenderer* fRenderer; + int32 fModelIndex; + bool fResizable; + ListenerList fListeners; +}; + + +class HeaderModelListener { +public: + virtual ~HeaderModelListener(); + + virtual void HeaderAdded(HeaderModel* model, int32 index); + virtual void HeaderRemoved(HeaderModel* model, int32 index); + virtual void HeaderMoved(HeaderModel* model, + int32 fromIndex, int32 toIndex); +}; + + +class HeaderModel : public BReferenceable { +public: + HeaderModel(); + virtual ~HeaderModel(); + + virtual int32 CountHeaders() const; + virtual Header* HeaderAt(int32 index) const; + virtual int32 IndexOfHeader(Header* header) const; + + virtual bool AddHeader(Header* header); + virtual Header* RemoveHeader(int32 index); + virtual void RemoveHeader(Header* header); + virtual bool MoveHeader(int32 fromIndex, int32 toIndex); + + virtual void AddListener(HeaderModelListener* listener); + virtual void RemoveListener(HeaderModelListener* listener); + +protected: + void NotifyHeaderAdded(int32 index); + void NotifyHeaderRemoved(int32 index); + void NotifyHeaderMoved(int32 fromIndex, + int32 toIndex); + +private: + typedef BObjectList
HeaderList; + typedef BObjectList ListenerList; + +private: + HeaderList fHeaders; + ListenerList fListeners; +}; + + +class HeaderView : public BView, private HeaderModelListener, + private HeaderListener { +public: + HeaderView(); + virtual ~HeaderView(); + + virtual void Draw(BRect updateRect); + + virtual BSize MinSize(); + virtual BSize MaxSize(); + virtual BSize PreferredSize(); + + HeaderModel* Model() const; + status_t SetModel(HeaderModel* model); + + void AddListener(HeaderViewListener* listener); + void RemoveListener(HeaderViewListener* listener); + +private: + struct HeaderEntry; + + typedef BObjectList HeaderEntryList; + typedef BObjectList ListenerList; + +private: + // HeaderModelListener + virtual void HeaderAdded(HeaderModel* model, int32 index); + virtual void HeaderRemoved(HeaderModel* model, int32 index); + virtual void HeaderMoved(HeaderModel* model, + int32 fromIndex, int32 toIndex); + + // HeaderListener + virtual void HeaderPropertiesChanged(Header* header, + bool redrawNeeded, bool relayoutNeeded); + + void _InvalidateHeadersLayout(int32 firstIndex); + void _InvalidateHeaders(int32 firstIndex, + int32 endIndex); + void _ValidateHeadersLayout(); + +private: + HeaderModel* fModel; + HeaderEntryList fHeaderEntries; + float fPreferredWidth; + float fPreferredHeight; + bool fLayoutValid; + ListenerList fListeners; +}; + + +class HeaderViewListener { +public: + virtual ~HeaderViewListener(); +}; + + +#endif // HEADER_VIEW_H diff --git a/src/apps/debuganalyzer/gui/Jamfile b/src/apps/debuganalyzer/gui/Jamfile index 8033297e8c..98b6dafda5 100644 --- a/src/apps/debuganalyzer/gui/Jamfile +++ b/src/apps/debuganalyzer/gui/Jamfile @@ -5,11 +5,14 @@ UsePrivateSystemHeaders ; UseHeaders $(HAIKU_DEBUG_ANALYZER_HEADERS) ; +CCFLAGS += -Werror ; +C++FLAGS += -Werror ; MergeObject DebugAnalyzer_gui.o : AbstractGeneralPage.cpp ColorCheckBox.cpp + HeaderView.cpp SubWindow.cpp SubWindowManager.cpp :