1/* 2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2011-2016, Rene Gollent, rene@gollent.com. 4 * Distributed under the terms of the MIT License. 5 */ 6 7#include "ImageListView.h" 8 9#include <stdio.h> 10 11#include <new> 12 13#include <Looper.h> 14#include <Message.h> 15 16#include <AutoLocker.h> 17#include <ObjectList.h> 18 19#include "GuiSettingsUtils.h" 20#include "table/TableColumns.h" 21#include "TargetAddressTableColumn.h" 22#include "Tracing.h" 23 24 25enum { 26 MSG_SYNC_IMAGE_LIST = 'sytl' 27}; 28 29 30// #pragma mark - ImagesTableModel 31 32 33class ImageListView::ImagesTableModel : public TableModel { 34public: 35 ImagesTableModel(Team* team) 36 : 37 fTeam(team) 38 { 39 Update(); 40 } 41 42 ~ImagesTableModel() 43 { 44 fTeam = NULL; 45 Update(); 46 } 47 48 bool Update() 49 { 50 if (fTeam == NULL) { 51 for (int32 i = 0; Image* image = fImages.ItemAt(i); i++) 52 image->ReleaseReference(); 53 fImages.MakeEmpty(); 54 55 return true; 56 } 57 58 AutoLocker<Team> locker(fTeam); 59 60 ImageList::ConstIterator it = fTeam->Images().GetIterator(); 61 Image* newImage = it.Next(); 62 int32 index = 0; 63 64 // remove no longer existing images 65 while (Image* oldImage = fImages.ItemAt(index)) { 66 if (oldImage == newImage) { 67 index++; 68 newImage = it.Next(); 69 } else { 70 // TODO: Not particularly efficient! 71 fImages.RemoveItemAt(index); 72 oldImage->ReleaseReference(); 73 NotifyRowsRemoved(index, 1); 74 } 75 } 76 77 // add new images 78 int32 countBefore = fImages.CountItems(); 79 while (newImage != NULL) { 80 if (!fImages.AddItem(newImage)) 81 return false; 82 83 newImage->AcquireReference(); 84 newImage = it.Next(); 85 } 86 87 int32 count = fImages.CountItems(); 88 if (count > countBefore) 89 NotifyRowsAdded(countBefore, count - countBefore); 90 91 return true; 92 } 93 94 virtual int32 CountColumns() const 95 { 96 return 6; 97 } 98 99 virtual int32 CountRows() const 100 { 101 return fImages.CountItems(); 102 } 103 104 virtual bool GetValueAt(int32 rowIndex, int32 columnIndex, BVariant& value) 105 { 106 Image* image = fImages.ItemAt(rowIndex); 107 if (image == NULL) 108 return false; 109 110 const ImageInfo& info = image->Info(); 111 switch (columnIndex) { 112 case 0: 113 value.SetTo(image->ID()); 114 return true; 115 case 1: 116 value.SetTo(image->Name(), B_VARIANT_DONT_COPY_DATA); 117 return true; 118 case 2: 119 value.SetTo(info.TextBase()); 120 return true; 121 case 3: 122 value.SetTo(info.TextBase() + info.TextSize()); 123 return true; 124 case 4: 125 value.SetTo(info.DataBase()); 126 return true; 127 case 5: 128 value.SetTo(info.DataBase() + info.DataSize()); 129 return true; 130 default: 131 return false; 132 } 133 } 134 135 Image* ImageAt(int32 index) const 136 { 137 return fImages.ItemAt(index); 138 } 139 140private: 141 Team* fTeam; 142 BObjectList<Image> fImages; 143}; 144 145 146// #pragma mark - ImageListView 147 148 149ImageListView::ImageListView(Team* team, Listener* listener) 150 : 151 BGroupView(B_VERTICAL), 152 fTeam(team), 153 fImage(NULL), 154 fImagesTable(NULL), 155 fImagesTableModel(NULL), 156 fListener(listener) 157{ 158 SetName("Images"); 159 160 fTeam->AddListener(this); 161} 162 163 164ImageListView::~ImageListView() 165{ 166 SetImage(NULL); 167 fTeam->RemoveListener(this); 168 fImagesTable->SetTableModel(NULL); 169 delete fImagesTableModel; 170} 171 172 173/*static*/ ImageListView* 174ImageListView::Create(Team* team, Listener* listener) 175{ 176 ImageListView* self = new ImageListView(team, listener); 177 178 try { 179 self->_Init(); 180 } catch (...) { 181 delete self; 182 throw; 183 } 184 185 return self; 186} 187 188 189void 190ImageListView::UnsetListener() 191{ 192 fListener = NULL; 193} 194 195 196void 197ImageListView::SetImage(Image* image) 198{ 199 if (image == fImage) 200 return; 201 202 TRACE_GUI("ImageListView::SetImage(%p)\n", image); 203 204 if (fImage != NULL) 205 fImage->ReleaseReference(); 206 207 fImage = image; 208 209 if (fImage != NULL) { 210 fImage->AcquireReference(); 211 212 for (int32 i = 0; Image* other = fImagesTableModel->ImageAt(i); i++) { 213 if (fImage == other) { 214 fImagesTable->SelectRow(i, false); 215 216 TRACE_GUI("ImageListView::SetImage() done\n"); 217 return; 218 } 219 } 220 } 221 222 fImagesTable->DeselectAllRows(); 223 224 TRACE_GUI("ImageListView::SetImage() done\n"); 225} 226 227 228void 229ImageListView::MessageReceived(BMessage* message) 230{ 231 switch (message->what) { 232 case MSG_SYNC_IMAGE_LIST: 233 if (fImagesTableModel != NULL) 234 fImagesTableModel->Update(); 235 break; 236 default: 237 BGroupView::MessageReceived(message); 238 break; 239 } 240} 241 242 243void 244ImageListView::LoadSettings(const BMessage& settings) 245{ 246 BMessage tableSettings; 247 if (settings.FindMessage("imagesTable", &tableSettings) == B_OK) { 248 GuiSettingsUtils::UnarchiveTableSettings(tableSettings, 249 fImagesTable); 250 } 251} 252 253 254status_t 255ImageListView::SaveSettings(BMessage& settings) 256{ 257 settings.MakeEmpty(); 258 259 BMessage tableSettings; 260 status_t result = GuiSettingsUtils::ArchiveTableSettings(tableSettings, 261 fImagesTable); 262 if (result == B_OK) 263 result = settings.AddMessage("imagesTable", &tableSettings); 264 265 return result; 266} 267 268 269void 270ImageListView::ImageAdded(const Team::ImageEvent& event) 271{ 272 Looper()->PostMessage(MSG_SYNC_IMAGE_LIST, this); 273} 274 275 276void 277ImageListView::ImageRemoved(const Team::ImageEvent& event) 278{ 279 Looper()->PostMessage(MSG_SYNC_IMAGE_LIST, this); 280} 281 282 283void 284ImageListView::TableSelectionChanged(Table* table) 285{ 286 if (fListener == NULL) 287 return; 288 289 Image* image = NULL; 290 if (fImagesTableModel != NULL) { 291 TableSelectionModel* selectionModel = table->SelectionModel(); 292 image = fImagesTableModel->ImageAt(selectionModel->RowAt(0)); 293 } 294 295 fListener->ImageSelectionChanged(image); 296} 297 298 299void 300ImageListView::_Init() 301{ 302 fImagesTable = new Table("images list", 0, B_FANCY_BORDER); 303 fImagesTable->SetFont(B_FONT_ROW, be_fixed_font); 304 AddChild(fImagesTable->ToView()); 305 306 // columns 307 fImagesTable->AddColumn(new Int32TableColumn(0, "ID", 40, 20, 1000, 308 B_TRUNCATE_MIDDLE, B_ALIGN_RIGHT)); 309 fImagesTable->AddColumn(new StringTableColumn(1, "Name", 80, 40, 1000, 310 B_TRUNCATE_BEGINNING, B_ALIGN_LEFT)); 311 fImagesTable->AddColumn(new TargetAddressTableColumn(2, "Text Base", 80, 312 40, 1000, B_TRUNCATE_MIDDLE, B_ALIGN_RIGHT)); 313 fImagesTable->AddColumn(new TargetAddressTableColumn(3, "Text End", 80, 40, 314 1000, B_TRUNCATE_MIDDLE, B_ALIGN_RIGHT)); 315 fImagesTable->AddColumn(new TargetAddressTableColumn(4, "Data Base", 80, 316 40, 1000, B_TRUNCATE_MIDDLE, B_ALIGN_RIGHT)); 317 fImagesTable->AddColumn(new TargetAddressTableColumn(5, "Data End", 80, 40, 318 1000, B_TRUNCATE_MIDDLE, B_ALIGN_RIGHT)); 319 320 fImagesTable->AddTableListener(this); 321 322 fImagesTableModel = new ImagesTableModel(fTeam); 323 fImagesTable->SetTableModel(fImagesTableModel); 324 fImagesTable->ResizeAllColumnsToPreferred(); 325} 326 327 328// #pragma mark - Listener 329 330 331ImageListView::Listener::~Listener() 332{ 333} 334