1 /* 2 * Copyright 2010, Haiku Inc. 3 * Copyright 2006, Ingo Weinhold <bonefish@cs.tu-berlin.de>. 4 * All rights reserved. Distributed under the terms of the MIT License. 5 */ 6 7 8 #include <Layout.h> 9 10 #include <syslog.h> 11 #include <new> 12 13 #include <Message.h> 14 #include <View.h> 15 16 #include "ViewLayoutItem.h" 17 18 19 using std::nothrow; 20 21 22 namespace { 23 const char* const kLayoutItemField = "BLayout:items"; 24 } 25 26 27 BLayout::BLayout() 28 : 29 fView(NULL), 30 fItems(20) 31 { 32 } 33 34 35 BLayout::BLayout(BMessage* from) 36 : 37 BArchivable(BUnarchiver::PrepareArchive(from)), 38 fView(NULL), 39 fItems(20) 40 { 41 BUnarchiver unarchiver(from); 42 43 int32 i = 0; 44 while (unarchiver.EnsureUnarchived(kLayoutItemField, i++) == B_OK) 45 ; 46 } 47 48 49 BLayout::~BLayout() 50 { 51 // this deletes all items 52 SetView(NULL); 53 } 54 55 56 BView* 57 BLayout::View() const 58 { 59 return fView; 60 } 61 62 63 BLayoutItem* 64 BLayout::AddView(BView* child) 65 { 66 return AddView(-1, child); 67 } 68 69 70 BLayoutItem* 71 BLayout::AddView(int32 index, BView* child) 72 { 73 if (BViewLayoutItem* item = new(nothrow) BViewLayoutItem(child)) { 74 if (AddItem(index, item)) 75 return item; 76 delete item; 77 } 78 return NULL; 79 } 80 81 82 bool 83 BLayout::AddItem(BLayoutItem* item) 84 { 85 return AddItem(-1, item); 86 } 87 88 89 bool 90 BLayout::AddItem(int32 index, BLayoutItem* item) 91 { 92 if (!fView || !item || fItems.HasItem(item)) 93 return false; 94 95 // if the item refers to a BView, we make sure it is added to the parent 96 // view 97 bool addedView = false; 98 BView* view = item->View(); 99 if (view && view->fParent != fView 100 && !(addedView = fView->_AddChild(view, NULL))) 101 return false; 102 103 // validate the index 104 if (index < 0 || index > fItems.CountItems()) 105 index = fItems.CountItems(); 106 107 if (fItems.AddItem(item, index) && ItemAdded(item, index)) { 108 item->SetLayout(this); 109 InvalidateLayout(); 110 return true; 111 } else { 112 // this check is necessary so that if an addition somewhere other 113 // than the end of the list fails, we don't remove the wrong item 114 if (fItems.ItemAt(index) == item) 115 fItems.RemoveItem(index); 116 if (addedView) 117 view->_RemoveSelf(); 118 return false; 119 } 120 } 121 122 123 bool 124 BLayout::RemoveView(BView* child) 125 { 126 bool removed = false; 127 128 // a view can have any number of layout items - we need to remove them all 129 for (int32 i = fItems.CountItems(); i-- > 0;) { 130 BLayoutItem* item = ItemAt(i); 131 132 if (item->View() != child) 133 continue; 134 135 RemoveItem(i); 136 removed = true; 137 delete item; 138 } 139 140 return removed; 141 } 142 143 144 bool 145 BLayout::RemoveItem(BLayoutItem* item) 146 { 147 int32 index = IndexOfItem(item); 148 return (index >= 0 ? RemoveItem(index) : false); 149 } 150 151 152 BLayoutItem* 153 BLayout::RemoveItem(int32 index) 154 { 155 if (index < 0 || index >= fItems.CountItems()) 156 return NULL; 157 158 BLayoutItem* item = (BLayoutItem*)fItems.RemoveItem(index); 159 160 // if the item refers to a BView, we make sure, it is removed from the 161 // parent view 162 BView* view = item->View(); 163 if (view && view->fParent == fView) 164 view->_RemoveSelf(); 165 166 item->SetLayout(NULL); 167 ItemRemoved(item, index); 168 InvalidateLayout(); 169 170 return item; 171 } 172 173 174 BLayoutItem* 175 BLayout::ItemAt(int32 index) const 176 { 177 return (BLayoutItem*)fItems.ItemAt(index); 178 } 179 180 181 int32 182 BLayout::CountItems() const 183 { 184 return fItems.CountItems(); 185 } 186 187 188 int32 189 BLayout::IndexOfItem(const BLayoutItem* item) const 190 { 191 return fItems.IndexOf(item); 192 } 193 194 195 int32 196 BLayout::IndexOfView(BView* child) const 197 { 198 int itemCount = fItems.CountItems(); 199 for (int32 i = 0; i < itemCount; i++) { 200 BLayoutItem* item = (BLayoutItem*)fItems.ItemAt(i); 201 if (dynamic_cast<BViewLayoutItem*>(item) && item->View() == child) 202 return i; 203 } 204 205 return -1; 206 } 207 208 209 void 210 BLayout::InvalidateLayout() 211 { 212 if (fView) 213 fView->InvalidateLayout(); 214 } 215 216 217 status_t 218 BLayout::Archive(BMessage* into, bool deep) const 219 { 220 BArchiver archiver(into); 221 status_t err = BArchivable::Archive(into, deep); 222 223 if (deep) { 224 int32 count = CountItems(); 225 for (int32 i = 0; i < count && err == B_OK; i++) { 226 BLayoutItem* item = ItemAt(i); 227 err = archiver.AddArchivable(kLayoutItemField, item, deep); 228 229 if (err == B_OK) { 230 err = ItemArchived(into, item, i); 231 if (err != B_OK) 232 syslog(LOG_ERR, "ItemArchived() failed at index: %d.", i); 233 } 234 } 235 } 236 237 return archiver.Finish(err); 238 } 239 240 241 status_t 242 BLayout::AllUnarchived(const BMessage* from) 243 { 244 BUnarchiver unarchiver(from); 245 status_t err = BArchivable::AllUnarchived(from); 246 if (err != B_OK) 247 return err; 248 249 int32 itemCount; 250 unarchiver.ArchiveMessage()->GetInfo(kLayoutItemField, NULL, &itemCount); 251 for (int32 i = 0; i < itemCount && err == B_OK; i++) { 252 BLayoutItem* item; 253 err = unarchiver.FindObject(kLayoutItemField, 254 i, BUnarchiver::B_DONT_ASSUME_OWNERSHIP, item); 255 if (err != B_OK) 256 return err; 257 258 if (!fItems.AddItem(item, i) || !ItemAdded(item, i)) { 259 fItems.RemoveItem(i); 260 return B_ERROR; 261 } 262 263 err = ItemUnarchived(from, item, i); 264 if (err != B_OK) { 265 fItems.RemoveItem(i); 266 ItemRemoved(item, i); 267 return err; 268 } 269 270 item->SetLayout(this); 271 unarchiver.AssumeOwnership(item); 272 } 273 274 InvalidateLayout(); 275 return err; 276 } 277 278 279 status_t 280 BLayout::ItemArchived(BMessage* into, BLayoutItem* item, int32 index) const 281 { 282 return B_OK; 283 } 284 285 286 status_t 287 BLayout::ItemUnarchived(const BMessage* from, BLayoutItem* item, int32 index) 288 { 289 return B_OK; 290 } 291 292 293 bool 294 BLayout::ItemAdded(BLayoutItem* item, int32 atIndex) 295 { 296 return true; 297 } 298 299 300 void 301 BLayout::ItemRemoved(BLayoutItem* item, int32 fromIndex) 302 { 303 } 304 305 306 void 307 BLayout::SetView(BView* view) 308 { 309 if (view != fView) { 310 fView = NULL; 311 312 // remove and delete all items 313 for (int32 i = CountItems() - 1; i >= 0; i--) 314 delete RemoveItem(i); 315 316 fView = view; 317 318 InvalidateLayout(); 319 } 320 } 321