1/* 2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2011, Rene Gollent, rene@gollent.com. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8#include "BreakpointListView.h" 9 10#include <stdio.h> 11 12#include <new> 13 14#include <AutoLocker.h> 15#include <ObjectList.h> 16 17#include "FunctionID.h" 18#include "GuiSettingsUtils.h" 19#include "LocatableFile.h" 20#include "table/TableColumns.h" 21#include "TargetAddressTableColumn.h" 22#include "Team.h" 23#include "UserBreakpoint.h" 24#include "Watchpoint.h" 25 26 27// #pragma mark - BreakpointsTableModel 28 29 30class BreakpointListView::BreakpointsTableModel : public TableModel { 31public: 32 BreakpointsTableModel(Team* team) 33 : 34 fTeam(team) 35 { 36 UpdateBreakpoint(NULL); 37 UpdateWatchpoint(NULL); 38 } 39 40 ~BreakpointsTableModel() 41 { 42 fTeam = NULL; 43 UpdateBreakpoint(NULL); 44 UpdateWatchpoint(NULL); 45 } 46 47 bool UpdateBreakpoint(UserBreakpoint* changedBreakpoint) 48 { 49 if (fTeam == NULL) { 50 for (int32 i = 0; 51 UserBreakpoint* breakpoint = fBreakpoints.ItemAt(i); 52 i++) { 53 breakpoint->ReleaseReference(); 54 } 55 fBreakpoints.MakeEmpty(); 56 57 return true; 58 } 59 60 AutoLocker<Team> locker(fTeam); 61 62 UserBreakpointList::ConstIterator it 63 = fTeam->UserBreakpoints().GetIterator(); 64 UserBreakpoint* newBreakpoint = it.Next(); 65 int32 index = 0; 66 67 // remove no longer existing breakpoints 68 while (UserBreakpoint* oldBreakpoint = fBreakpoints.ItemAt(index)) { 69 if (oldBreakpoint == newBreakpoint) { 70 if (oldBreakpoint == changedBreakpoint) 71 NotifyRowsChanged(index, 1); 72 index++; 73 newBreakpoint = it.Next(); 74 } else { 75 // TODO: Not particularly efficient! 76 fBreakpoints.RemoveItemAt(index); 77 oldBreakpoint->ReleaseReference(); 78 NotifyRowsRemoved(index, 1); 79 } 80 } 81 82 // add new breakpoints 83 int32 countBefore = fBreakpoints.CountItems(); 84 while (newBreakpoint != NULL) { 85 if (!fBreakpoints.AddItem(newBreakpoint)) 86 return false; 87 88 newBreakpoint->AcquireReference(); 89 newBreakpoint = it.Next(); 90 } 91 92 int32 count = fBreakpoints.CountItems(); 93 if (count > countBefore) 94 NotifyRowsAdded(countBefore, count - countBefore); 95 96 return true; 97 } 98 99 bool UpdateWatchpoint(Watchpoint* changedWatchpoint) 100 { 101 if (fTeam == NULL) { 102 for (int32 i = 0; 103 Watchpoint* watchpoint = fWatchpoints.ItemAt(i); 104 i++) { 105 watchpoint->ReleaseReference(); 106 } 107 fWatchpoints.MakeEmpty(); 108 109 return true; 110 } 111 112 AutoLocker<Team> locker(fTeam); 113 114 int32 breakpointCount = fBreakpoints.CountItems(); 115 int32 index = 0; 116 int32 teamIndex = 0; 117 Watchpoint* newWatchpoint = fTeam->WatchpointAt(teamIndex); 118 // remove no longer existing breakpoints 119 while (Watchpoint* oldWatchpoint = fWatchpoints.ItemAt(index)) { 120 if (oldWatchpoint == newWatchpoint) { 121 if (oldWatchpoint == changedWatchpoint) 122 NotifyRowsChanged(index + breakpointCount, 1); 123 index++; 124 teamIndex++; 125 newWatchpoint = fTeam->WatchpointAt(teamIndex); 126 } else { 127 // TODO: Not particularly efficient! 128 fWatchpoints.RemoveItemAt(index); 129 oldWatchpoint->ReleaseReference(); 130 NotifyRowsRemoved(index + breakpointCount, 1); 131 } 132 } 133 134 // add new breakpoints 135 int32 countBefore = fWatchpoints.CountItems(); 136 while (newWatchpoint != NULL) { 137 if (!fWatchpoints.AddItem(newWatchpoint)) 138 return false; 139 140 newWatchpoint->AcquireReference(); 141 teamIndex++; 142 newWatchpoint = fTeam->WatchpointAt(teamIndex); 143 } 144 145 int32 count = fWatchpoints.CountItems(); 146 if (count > countBefore) 147 NotifyRowsAdded(countBefore + breakpointCount, count - countBefore); 148 149 return true; 150 } 151 152 virtual int32 CountColumns() const 153 { 154 return 5; 155 } 156 157 virtual int32 CountRows() const 158 { 159 return fBreakpoints.CountItems() + fWatchpoints.CountItems(); 160 } 161 162 virtual bool GetValueAt(int32 rowIndex, int32 columnIndex, BVariant& value) 163 { 164 int32 breakpointCount = fBreakpoints.CountItems(); 165 if (rowIndex < breakpointCount) 166 return _GetBreakpointValueAt(rowIndex, columnIndex, value); 167 168 return _GetWatchpointValueAt(rowIndex - breakpointCount, columnIndex, 169 value); 170 } 171 172 UserBreakpoint* BreakpointAt(int32 index) const 173 { 174 return fBreakpoints.ItemAt(index); 175 } 176 177 Watchpoint* WatchpointAt(int32 index) const 178 { 179 return fWatchpoints.ItemAt(index - fBreakpoints.CountItems()); 180 } 181 182private: 183 184 bool _GetBreakpointValueAt(int32 rowIndex, int32 columnIndex, 185 BVariant &value) 186 { 187 UserBreakpoint* breakpoint = fBreakpoints.ItemAt(rowIndex); 188 if (breakpoint == NULL) 189 return false; 190 const UserBreakpointLocation& location = breakpoint->Location(); 191 192 switch (columnIndex) { 193 case 0: 194 value.SetTo((int32)breakpoint->IsEnabled()); 195 return true; 196 case 1: 197 value.SetTo(location.GetFunctionID()->FunctionName(), 198 B_VARIANT_DONT_COPY_DATA); 199 return true; 200 case 2: 201 if (LocatableFile* sourceFile = location.SourceFile()) { 202 value.SetTo(sourceFile->Name(), B_VARIANT_DONT_COPY_DATA); 203 return true; 204 } 205 return false; 206 case 3: 207 if (location.SourceFile() != NULL) { 208 value.SetTo(location.GetSourceLocation().Line() + 1); 209 return true; 210 } 211 return false; 212 case 4: 213 if (location.SourceFile() == NULL) { 214 AutoLocker<Team> teamLocker(fTeam); 215 if (UserBreakpointInstance* instance 216 = breakpoint->InstanceAt(0)) { 217 value.SetTo(instance->Address()); 218 return true; 219 } 220 } 221 return false; 222 default: 223 return false; 224 } 225 } 226 227 bool _GetWatchpointValueAt(int32 rowIndex, int32 columnIndex, 228 BVariant& value) 229 { 230 Watchpoint* watchpoint = fWatchpoints.ItemAt(rowIndex); 231 if (watchpoint == NULL) 232 return false; 233 234 switch (columnIndex) { 235 case 0: 236 value.SetTo((int32)watchpoint->IsEnabled()); 237 return true; 238 case 1: 239 value.SetTo("Watchpoint"); 240 return true; 241 case 2: 242 return false; 243 case 3: 244 return false; 245 case 4: 246 value.SetTo(watchpoint->Address()); 247 return true; 248 default: 249 return false; 250 } 251 } 252 253private: 254 Team* fTeam; 255 BObjectList<UserBreakpoint> fBreakpoints; 256 BObjectList<Watchpoint> fWatchpoints; 257}; 258 259 260// #pragma mark - BreakpointListView 261 262 263BreakpointListView::BreakpointListView(Team* team, Listener* listener) 264 : 265 BGroupView(B_VERTICAL), 266 fTeam(team), 267 fBreakpoint(NULL), 268 fBreakpointsTable(NULL), 269 fBreakpointsTableModel(NULL), 270 fListener(listener) 271{ 272} 273 274 275BreakpointListView::~BreakpointListView() 276{ 277 fBreakpointsTable->SetTableModel(NULL); 278 delete fBreakpointsTableModel; 279} 280 281 282/*static*/ BreakpointListView* 283BreakpointListView::Create(Team* team, Listener* listener) 284{ 285 BreakpointListView* self = new BreakpointListView(team, listener); 286 287 try { 288 self->_Init(); 289 } catch (...) { 290 delete self; 291 throw; 292 } 293 294 return self; 295} 296 297 298void 299BreakpointListView::UnsetListener() 300{ 301 fListener = NULL; 302} 303 304 305void 306BreakpointListView::SetBreakpoint(UserBreakpoint* breakpoint, 307 Watchpoint* watchpoint) 308{ 309 if (breakpoint == fBreakpoint) 310 return; 311 312 if (fBreakpoint != NULL) 313 fBreakpoint->ReleaseReference(); 314 315 fBreakpoint = breakpoint; 316 317 if (fBreakpoint != NULL) { 318 fBreakpoint->AcquireReference(); 319 320 for (int32 i = 0; 321 UserBreakpoint* other = fBreakpointsTableModel->BreakpointAt(i); 322 i++) { 323 if (fBreakpoint == other) { 324 fBreakpointsTable->SelectRow(i, false); 325 return; 326 } 327 } 328 } 329 330 fBreakpointsTable->DeselectAllRows(); 331} 332 333 334void 335BreakpointListView::UserBreakpointChanged(UserBreakpoint* breakpoint) 336{ 337 fBreakpointsTableModel->UpdateBreakpoint(breakpoint); 338} 339 340 341void 342BreakpointListView::WatchpointChanged(Watchpoint* watchpoint) 343{ 344 fBreakpointsTableModel->UpdateWatchpoint(watchpoint); 345} 346 347 348void 349BreakpointListView::LoadSettings(const BMessage& settings) 350{ 351 BMessage tableSettings; 352 if (settings.FindMessage("breakpointsTable", &tableSettings) == B_OK) { 353 GuiSettingsUtils::UnarchiveTableSettings(tableSettings, 354 fBreakpointsTable); 355 } 356} 357 358 359status_t 360BreakpointListView::SaveSettings(BMessage& settings) 361{ 362 settings.MakeEmpty(); 363 364 BMessage tableSettings; 365 status_t result = GuiSettingsUtils::ArchiveTableSettings(tableSettings, 366 fBreakpointsTable); 367 if (result == B_OK) 368 result = settings.AddMessage("breakpointsTable", &tableSettings); 369 370 return result; 371} 372 373 374void 375BreakpointListView::TableSelectionChanged(Table* table) 376{ 377 if (fListener == NULL) 378 return; 379 380 TableSelectionModel* selectionModel = table->SelectionModel(); 381 UserBreakpoint* breakpoint = fBreakpointsTableModel->BreakpointAt( 382 selectionModel->RowAt(0)); 383 if (breakpoint != NULL) 384 fListener->BreakpointSelectionChanged(breakpoint); 385 else { 386 Watchpoint* watchpoint = fBreakpointsTableModel->WatchpointAt( 387 selectionModel->RowAt(0)); 388 fListener->WatchpointSelectionChanged(watchpoint); 389 } 390} 391 392 393void 394BreakpointListView::_Init() 395{ 396 fBreakpointsTable = new Table("breakpoints list", 0, B_FANCY_BORDER); 397 AddChild(fBreakpointsTable->ToView()); 398 399 // columns 400 fBreakpointsTable->AddColumn(new BoolStringTableColumn(0, "State", 70, 20, 401 1000, "Enabled", "Disabled")); 402 fBreakpointsTable->AddColumn(new StringTableColumn(1, "Function", 250, 40, 403 1000, B_TRUNCATE_END, B_ALIGN_LEFT)); 404 fBreakpointsTable->AddColumn(new StringTableColumn(2, "File", 250, 40, 405 1000, B_TRUNCATE_END, B_ALIGN_LEFT)); 406 fBreakpointsTable->AddColumn(new Int32TableColumn(3, "Line", 60, 20, 407 1000, B_TRUNCATE_END, B_ALIGN_RIGHT)); 408 fBreakpointsTable->AddColumn(new TargetAddressTableColumn(4, "Address", 100, 409 20, 1000, B_TRUNCATE_END, B_ALIGN_RIGHT)); 410 411 fBreakpointsTable->SetSelectionMode(B_SINGLE_SELECTION_LIST); 412 fBreakpointsTable->AddTableListener(this); 413 414 fBreakpointsTableModel = new BreakpointsTableModel(fTeam); 415 fBreakpointsTable->SetTableModel(fBreakpointsTableModel); 416} 417 418 419// #pragma mark - Listener 420 421 422BreakpointListView::Listener::~Listener() 423{ 424} 425