* Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2011-2013, Rene Gollent, rene@gollent.com.
* Distributed under the terms of the MIT License.
*/
#include "StackTraceView.h"
#include <stdio.h>
#include <new>
#include <ControlLook.h>
#include <Window.h>
#include "table/TableColumns.h"
#include "FunctionInstance.h"
#include "GuiSettingsUtils.h"
#include "Image.h"
#include "StackTrace.h"
#include "TargetAddressTableColumn.h"
#include "UiUtils.h"
class StackTraceView::FramesTableModel : public TableModel {
public:
FramesTableModel()
:
fStackTrace(NULL)
{
}
~FramesTableModel()
{
SetStackTrace(NULL);
}
void SetStackTrace(StackTrace* stackTrace)
{
if (fStackTrace != NULL && fStackTrace->CountFrames())
NotifyRowsRemoved(0, fStackTrace->CountFrames());
fStackTrace = stackTrace;
if (fStackTrace != NULL && fStackTrace->CountFrames() > 0)
NotifyRowsAdded(0, fStackTrace->CountFrames());
}
virtual int32 CountColumns() const
{
return 3;
}
virtual int32 CountRows() const
{
return fStackTrace != NULL ? fStackTrace->CountFrames() : 0;
}
virtual bool GetValueAt(int32 rowIndex, int32 columnIndex, BVariant& value)
{
StackFrame* frame
= fStackTrace != NULL ? fStackTrace->FrameAt(rowIndex) : NULL;
if (frame == NULL)
return false;
switch (columnIndex) {
case 0:
value.SetTo(frame->FrameAddress());
return true;
case 1:
value.SetTo(frame->InstructionPointer());
return true;
case 2:
{
char buffer[512];
value.SetTo(UiUtils::FunctionNameForFrame(frame, buffer,
sizeof(buffer)));
return true;
}
default:
return false;
}
}
StackFrame* FrameAt(int32 index) const
{
return fStackTrace != NULL ? fStackTrace->FrameAt(index) : NULL;
}
private:
StackTrace* fStackTrace;
};
StackTraceView::StackTraceView(Listener* listener)
:
BGroupView(B_VERTICAL),
fStackTrace(NULL),
fFramesTable(NULL),
fFramesTableModel(NULL),
fTraceClearPending(false),
fListener(listener)
{
SetName("Stack Trace");
}
StackTraceView::~StackTraceView()
{
SetStackTrace(NULL);
fFramesTable->SetTableModel(NULL);
delete fFramesTableModel;
}
StackTraceView*
StackTraceView::Create(Listener* listener)
{
StackTraceView* self = new StackTraceView(listener);
try {
self->_Init();
} catch (...) {
delete self;
throw;
}
return self;
}
void
StackTraceView::UnsetListener()
{
fListener = NULL;
}
void
StackTraceView::SetStackTrace(StackTrace* stackTrace)
{
fTraceClearPending = false;
if (stackTrace == fStackTrace)
return;
if (fStackTrace != NULL)
fStackTrace->ReleaseReference();
fStackTrace = stackTrace;
if (fStackTrace != NULL)
fStackTrace->AcquireReference();
fFramesTableModel->SetStackTrace(fStackTrace);
}
void
StackTraceView::SetStackFrame(StackFrame* stackFrame)
{
if (fStackTrace != NULL && stackFrame != NULL) {
for (int32 i = 0; StackFrame* other = fStackTrace->FrameAt(i); i++) {
if (stackFrame == other) {
fFramesTable->SelectRow(i, false);
return;
}
}
}
fFramesTable->DeselectAllRows();
}
void
StackTraceView::LoadSettings(const BMessage& settings)
{
BMessage tableSettings;
if (settings.FindMessage("framesTable", &tableSettings) == B_OK) {
GuiSettingsUtils::UnarchiveTableSettings(tableSettings,
fFramesTable);
}
}
status_t
StackTraceView::SaveSettings(BMessage& settings)
{
settings.MakeEmpty();
BMessage tableSettings;
status_t result = GuiSettingsUtils::ArchiveTableSettings(tableSettings,
fFramesTable);
if (result == B_OK)
result = settings.AddMessage("framesTable", &tableSettings);
return result;
}
void
StackTraceView::SetStackTraceClearPending()
{
fTraceClearPending = true;
}
void
StackTraceView::TableSelectionChanged(Table* table)
{
if (fListener == NULL || fTraceClearPending)
return;
StackFrame* frame
= fFramesTableModel->FrameAt(table->SelectionModel()->RowAt(0));
fListener->StackFrameSelectionChanged(frame);
}
void
StackTraceView::_Init()
{
fFramesTable = new Table("stack trace", 0, B_FANCY_BORDER);
fFramesTable->SetFont(B_FONT_ROW, be_fixed_font);
AddChild(fFramesTable->ToView());
fFramesTable->SetSortingEnabled(false);
float addressWidth = be_fixed_font->StringWidth("0xffffffff00000000")
+ be_control_look->DefaultLabelSpacing();
fFramesTable->AddColumn(new TargetAddressTableColumn(0, "Frame",
addressWidth, 40, 1000, B_TRUNCATE_END, B_ALIGN_RIGHT));
fFramesTable->AddColumn(new TargetAddressTableColumn(1, "IP", addressWidth,
40, 1000, B_TRUNCATE_END, B_ALIGN_RIGHT));
fFramesTable->AddColumn(new StringTableColumn(2, "Function", 300, 100, 1000,
B_TRUNCATE_END, B_ALIGN_LEFT));
fFramesTableModel = new FramesTableModel();
fFramesTable->SetTableModel(fFramesTableModel);
fFramesTable->SetSelectionMode(B_SINGLE_SELECTION_LIST);
fFramesTable->AddTableListener(this);
}
StackTraceView::Listener::~Listener()
{
}