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