1 /* 2 Copyright (C) 2010-2014 Kristian Duske 3 4 This file is part of TrenchBroom. 5 6 TrenchBroom is free software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 TrenchBroom is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with TrenchBroom. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "EntityAttributeGridTable.h" 21 22 #include "Assets/AttributeDefinition.h" 23 #include "Assets/EntityDefinition.h" 24 #include "Model/AttributableNode.h" 25 #include "Model/Entity.h" 26 #include "Model/EntityAttributes.h" 27 #include "View/MapDocument.h" 28 #include "View/ViewUtils.h" 29 30 #include <wx/msgdlg.h> 31 32 namespace TrenchBroom { 33 namespace View { AttributeRow()34 EntityAttributeGridTable::AttributeRow::AttributeRow() : 35 m_nameMutable(false), 36 m_valueMutable(false), 37 m_default(false), 38 m_maxCount(0), 39 m_count(0), 40 m_multi(false) {} 41 AttributeRow(const String & name,const String & value,const bool nameMutable,const bool valueMutable,const String & tooltip,const bool i_default,const size_t maxCount)42 EntityAttributeGridTable::AttributeRow::AttributeRow(const String& name, const String& value, const bool nameMutable, const bool valueMutable, const String& tooltip, const bool i_default, const size_t maxCount) : 43 m_name(name), 44 m_value(value), 45 m_nameMutable(nameMutable), 46 m_valueMutable(valueMutable), 47 m_tooltip(tooltip), 48 m_default(i_default), 49 m_maxCount(maxCount), 50 m_count(1), 51 m_multi(false) { 52 assert(!m_default || m_valueMutable); 53 } 54 name() const55 const String& EntityAttributeGridTable::AttributeRow::name() const { 56 return m_name; 57 } 58 value() const59 const String& EntityAttributeGridTable::AttributeRow::value() const { 60 return m_value; 61 } 62 nameMutable() const63 bool EntityAttributeGridTable::AttributeRow::nameMutable() const { 64 return m_nameMutable; 65 } 66 valueMutable() const67 bool EntityAttributeGridTable::AttributeRow::valueMutable() const { 68 return m_valueMutable; 69 } 70 tooltip() const71 const String& EntityAttributeGridTable::AttributeRow::tooltip() const { 72 return m_multi ? EmptyString : m_tooltip; 73 } 74 isDefault() const75 bool EntityAttributeGridTable::AttributeRow::isDefault() const { 76 return m_default; 77 } 78 merge(const String & i_value,const bool nameMutable,const bool valueMutable)79 void EntityAttributeGridTable::AttributeRow::merge(const String& i_value, const bool nameMutable, const bool valueMutable) { 80 m_multi |= (m_value != i_value); 81 m_nameMutable &= nameMutable; 82 m_valueMutable &= valueMutable; 83 m_default = false; 84 ++m_count; 85 } 86 multi() const87 bool EntityAttributeGridTable::AttributeRow::multi() const { 88 return m_multi; 89 } 90 subset() const91 bool EntityAttributeGridTable::AttributeRow::subset() const { 92 return m_count < m_maxCount; 93 } 94 reset()95 void EntityAttributeGridTable::AttributeRow::reset() { 96 m_count = m_maxCount; 97 m_multi = false; 98 } 99 totalRowCount() const100 size_t EntityAttributeGridTable::RowManager::totalRowCount() const { 101 return m_rows.size(); 102 } 103 defaultRowCount() const104 size_t EntityAttributeGridTable::RowManager::defaultRowCount() const { 105 return m_defaultRowCount; 106 } 107 attributeRowCount() const108 size_t EntityAttributeGridTable::RowManager::attributeRowCount() const { 109 return totalRowCount() - defaultRowCount(); 110 } 111 isAttributeRow(const size_t rowIndex) const112 bool EntityAttributeGridTable::RowManager::isAttributeRow(const size_t rowIndex) const { 113 return !isDefaultRow(rowIndex); 114 } 115 isDefaultRow(const size_t rowIndex) const116 bool EntityAttributeGridTable::RowManager::isDefaultRow(const size_t rowIndex) const { 117 assert(rowIndex < totalRowCount()); 118 return m_rows[rowIndex].isDefault(); 119 } 120 indexOf(const String & name) const121 size_t EntityAttributeGridTable::RowManager::indexOf(const String& name) const { 122 AttributeRow::List::const_iterator propIt = findRow(m_rows, name); 123 if (propIt != m_rows.end()) 124 return static_cast<size_t>(std::distance(m_rows.begin(), propIt)); 125 return totalRowCount(); 126 } 127 name(const size_t rowIndex) const128 const String& EntityAttributeGridTable::RowManager::name(const size_t rowIndex) const { 129 assert(rowIndex < totalRowCount()); 130 return m_rows[rowIndex].name(); 131 } 132 value(const size_t rowIndex) const133 const String& EntityAttributeGridTable::RowManager::value(const size_t rowIndex) const { 134 assert(rowIndex < totalRowCount()); 135 const AttributeRow& row = m_rows[rowIndex]; 136 return row.multi() ? EmptyString : row.value(); 137 } 138 nameMutable(const size_t rowIndex) const139 bool EntityAttributeGridTable::RowManager::nameMutable(const size_t rowIndex) const { 140 assert(rowIndex < totalRowCount()); 141 return m_rows[rowIndex].nameMutable(); 142 } 143 valueMutable(const size_t rowIndex) const144 bool EntityAttributeGridTable::RowManager::valueMutable(const size_t rowIndex) const { 145 assert(rowIndex < totalRowCount()); 146 return m_rows[rowIndex].valueMutable(); 147 } 148 tooltip(const size_t rowIndex) const149 const String& EntityAttributeGridTable::RowManager::tooltip(const size_t rowIndex) const { 150 assert(rowIndex < totalRowCount()); 151 return m_rows[rowIndex].tooltip(); 152 } 153 multi(const size_t rowIndex) const154 bool EntityAttributeGridTable::RowManager::multi(const size_t rowIndex) const { 155 assert(rowIndex < totalRowCount()); 156 return m_rows[rowIndex].multi(); 157 } 158 subset(const size_t rowIndex) const159 bool EntityAttributeGridTable::RowManager::subset(const size_t rowIndex) const { 160 assert(rowIndex < totalRowCount()); 161 return m_rows[rowIndex].subset(); 162 } 163 names(const size_t rowIndex,const size_t count) const164 const StringList EntityAttributeGridTable::RowManager::names(const size_t rowIndex, const size_t count) const { 165 assert(rowIndex + count <= totalRowCount()); 166 167 StringList result(count); 168 for (size_t i = 0; i < count; ++i) 169 result[i] = m_rows[rowIndex + i].name(); 170 return result; 171 } 172 updateRows(const Model::AttributableNodeList & attributables,const bool showDefaultRows)173 void EntityAttributeGridTable::RowManager::updateRows(const Model::AttributableNodeList& attributables, const bool showDefaultRows) { 174 m_rows.clear(); 175 m_defaultRowCount = 0; 176 177 Model::AttributableNodeList::const_iterator attriutableIt, attributableEnd; 178 Model::EntityAttribute::List::const_iterator attributeIt, attributeEnd; 179 180 for (attriutableIt = attributables.begin(), 181 attributableEnd = attributables.end(); 182 attriutableIt != attributableEnd; 183 ++attriutableIt) { 184 185 const Model::AttributableNode* attributable = *attriutableIt; 186 const Model::EntityAttribute::List& attributes = attributable->attributes(); 187 for (attributeIt = attributes.begin(), 188 attributeEnd = attributes.end(); 189 attributeIt != attributeEnd; 190 ++attributeIt) { 191 192 const Model::EntityAttribute& attribute = *attributeIt; 193 const Assets::AttributeDefinition* attributeDefinition = attribute.definition(); 194 195 const bool nameMutable = attributable->isAttributeNameMutable(attribute.name()); 196 const bool valueMutable = attributable->isAttributeValueMutable(attribute.value()); 197 198 AttributeRow::List::iterator rowIt = findRow(m_rows, attribute.name()); 199 if (rowIt != m_rows.end()) { 200 rowIt->merge(attribute.value(), nameMutable, valueMutable); 201 } else { 202 const String tooltip = Assets::AttributeDefinition::safeFullDescription(attributeDefinition); 203 m_rows.push_back(AttributeRow(attribute.name(), attribute.value(), 204 nameMutable, valueMutable, 205 tooltip, false, attributables.size())); 206 } 207 } 208 } 209 210 if (showDefaultRows) { 211 const Assets::EntityDefinition* definition = Model::AttributableNode::selectEntityDefinition(attributables); 212 if (definition != NULL) { 213 const Assets::AttributeDefinitionList& attributeDefs = definition->attributeDefinitions(); 214 Assets::AttributeDefinitionList::const_iterator definitionIt, definitionEnd; 215 for (definitionIt = attributeDefs.begin(), 216 definitionEnd = attributeDefs.end(); 217 definitionIt != definitionEnd; 218 ++definitionIt) { 219 220 const Assets::AttributeDefinitionPtr propertyDef = *definitionIt; 221 const String& name = propertyDef->name(); 222 223 if (findRow(m_rows, name) != m_rows.end()) 224 continue; 225 226 const String value = Assets::AttributeDefinition::defaultValue(*propertyDef); 227 const String tooltip = Assets::AttributeDefinition::safeFullDescription(propertyDef.get()); 228 m_rows.push_back(AttributeRow(name, value, false, true, tooltip, true, attributables.size())); 229 ++m_defaultRowCount; 230 } 231 } 232 } 233 } 234 insertRows(const size_t rowIndex,const size_t count,const Model::AttributableNodeList & attributables)235 StringList EntityAttributeGridTable::RowManager::insertRows(const size_t rowIndex, const size_t count, const Model::AttributableNodeList& attributables) { 236 assert(rowIndex <= attributeRowCount()); 237 238 const StringList attributeNames = newAttributeNames(count, attributables); 239 assert(attributeNames.size() == count); 240 241 AttributeRow::List::iterator entryIt = m_rows.begin(); 242 std::advance(entryIt, rowIndex); 243 for (size_t i = 0; i < count; i++) { 244 entryIt = m_rows.insert(entryIt, AttributeRow(attributeNames[i], "", true, true, "", false, attributables.size())); 245 entryIt->reset(); 246 std::advance(entryIt, 1); 247 } 248 249 return attributeNames; 250 } 251 deleteRows(const size_t rowIndex,const size_t count)252 void EntityAttributeGridTable::RowManager::deleteRows(const size_t rowIndex, const size_t count) { 253 assert(rowIndex + count <= attributeRowCount()); 254 255 AttributeRow::List::iterator first = m_rows.begin(); 256 AttributeRow::List::iterator last = first; 257 std::advance(first, rowIndex); 258 std::advance(last, rowIndex + count); 259 m_rows.erase(first, last); 260 } 261 findRow(AttributeRow::List & rows,const String & name)262 EntityAttributeGridTable::AttributeRow::List::iterator EntityAttributeGridTable::RowManager::findRow(AttributeRow::List& rows, const String& name) { 263 AttributeRow::List::iterator it, end; 264 for (it = rows.begin(), end = rows.end(); it != end; ++it) { 265 const AttributeRow& row = *it; 266 if (row.name() == name) 267 return it; 268 } 269 return end; 270 } 271 findRow(const AttributeRow::List & rows,const String & name)272 EntityAttributeGridTable::AttributeRow::List::const_iterator EntityAttributeGridTable::RowManager::findRow(const AttributeRow::List& rows, const String& name) { 273 AttributeRow::List::const_iterator it, end; 274 for (it = rows.begin(), end = rows.end(); it != end; ++it) { 275 const AttributeRow& row = *it; 276 if (row.name() == name) 277 return it; 278 } 279 return end; 280 } 281 newAttributeNames(const size_t count,const Model::AttributableNodeList & attributables) const282 StringList EntityAttributeGridTable::RowManager::newAttributeNames(const size_t count, const Model::AttributableNodeList& attributables) const { 283 StringList result; 284 result.reserve(count); 285 286 size_t index = 1; 287 for (size_t i = 0; i < count; ++i) { 288 while (true) { 289 StringStream nameStream; 290 nameStream << "property " << index; 291 292 bool indexIsFree = true; 293 Model::AttributableNodeList::const_iterator it, end; 294 for (it = attributables.begin(), end = attributables.end(); it != end && indexIsFree; ++it) { 295 const Model::AttributableNode& attributable = **it; 296 indexIsFree = !attributable.hasAttribute(nameStream.str()); 297 } 298 299 if (indexIsFree) { 300 result.push_back(nameStream.str()); 301 break; 302 } 303 304 ++index; 305 } 306 } 307 return result; 308 } 309 EntityAttributeGridTable(MapDocumentWPtr document)310 EntityAttributeGridTable::EntityAttributeGridTable(MapDocumentWPtr document) : 311 m_document(document), 312 m_rows(), 313 m_ignoreUpdates(false), 314 m_showDefaultRows(true), 315 m_readonlyCellColor(wxColor(224, 224, 224)), 316 m_specialCellColor(wxColor(128, 128, 128)) {} 317 GetNumberRows()318 int EntityAttributeGridTable::GetNumberRows() { 319 return static_cast<int>(m_rows.totalRowCount()); 320 } 321 GetNumberAttributeRows() const322 int EntityAttributeGridTable::GetNumberAttributeRows() const { 323 return static_cast<int>(m_rows.attributeRowCount()); 324 } 325 GetNumberCols()326 int EntityAttributeGridTable::GetNumberCols() { 327 return 2; 328 } 329 GetValue(const int row,const int col)330 wxString EntityAttributeGridTable::GetValue(const int row, const int col) { 331 // Fixes a problem when the user deselects everything while editing an entity property. 332 if (row < 0 || col < 0) 333 return wxEmptyString; 334 335 assert(row >= 0 && row < GetRowsCount()); 336 assert(col >= 0 && col < GetColsCount()); 337 338 const size_t rowIndex = static_cast<size_t>(row); 339 if (col == 0) 340 return m_rows.name(rowIndex); 341 return m_rows.value(rowIndex); 342 } 343 SetValue(const int row,const int col,const wxString & value)344 void EntityAttributeGridTable::SetValue(const int row, const int col, const wxString& value) { 345 assert(row >= 0 && row < GetRowsCount()); 346 assert(col >= 0 && col < GetColsCount()); 347 348 MapDocumentSPtr document = lock(m_document); 349 350 const size_t rowIndex = static_cast<size_t>(row); 351 const Model::AttributableNodeList attributables = document->allSelectedAttributableNodes(); 352 assert(!attributables.empty()); 353 354 // Ignoring the updates here fails if the user changes the entity classname because in that 355 // case, we must really refresh everything from the entity. 356 // const SetBool ignoreUpdates(m_ignoreUpdates); 357 if (col == 0) 358 renameAttribute(rowIndex, value.ToStdString(), attributables); 359 else 360 updateAttribute(rowIndex, value.ToStdString(), attributables); 361 } 362 Clear()363 void EntityAttributeGridTable::Clear() { 364 DeleteRows(0, m_rows.totalRowCount()); 365 } 366 InsertRows(const size_t pos,const size_t numRows)367 bool EntityAttributeGridTable::InsertRows(const size_t pos, const size_t numRows) { 368 assert(pos <= m_rows.totalRowCount()); 369 370 MapDocumentSPtr document = lock(m_document); 371 372 const Model::AttributableNodeList attributables = document->allSelectedAttributableNodes(); 373 assert(!attributables.empty()); 374 375 const StringList newKeys = m_rows.insertRows(pos, numRows, attributables); 376 377 const SetBool ignoreUpdates(m_ignoreUpdates); 378 379 const Transaction transaction(document); 380 StringList::const_iterator it, end; 381 for (it = newKeys.begin(), end = newKeys.end(); it != end; ++it) { 382 const String& name = *it; 383 document->setAttribute(name, ""); 384 } 385 386 notifyRowsInserted(pos, numRows); 387 388 return true; 389 } 390 AppendRows(const size_t numRows)391 bool EntityAttributeGridTable::AppendRows(const size_t numRows) { 392 return InsertRows(m_rows.totalRowCount(), numRows); 393 } 394 DeleteRows(const size_t pos,size_t numRows)395 bool EntityAttributeGridTable::DeleteRows(const size_t pos, size_t numRows) { 396 // TODO: when deleting a property that has a default value in the property definition, re-add it to the list 397 // of default properties... 398 399 if (pos >= m_rows.totalRowCount()) 400 return false; 401 402 numRows = std::min(m_rows.totalRowCount() - pos, numRows); 403 assert(pos + numRows <= m_rows.totalRowCount()); 404 405 MapDocumentSPtr document = lock(m_document); 406 407 const Model::AttributableNodeList attributables = document->allSelectedAttributableNodes(); 408 assert(!attributables.empty()); 409 410 const StringList names = m_rows.names(pos, numRows); 411 assert(names.size() == numRows); 412 413 const SetBool ignoreUpdates(m_ignoreUpdates); 414 415 Transaction transaction(document, StringUtils::safePlural(numRows, "Remove Attribute", "Remove Attributes")); 416 417 bool success = true; 418 for (size_t i = 0; i < numRows && success; i++) 419 success = document->removeAttribute(names[i]); 420 421 if (!success) { 422 transaction.rollback(); 423 return false; 424 } 425 426 m_rows.deleteRows(pos, numRows); 427 notifyRowsDeleted(pos, numRows); 428 return true; 429 } 430 GetColLabelValue(const int col)431 wxString EntityAttributeGridTable::GetColLabelValue(const int col) { 432 assert(col >= 0 && col < GetColsCount()); 433 if (col == 0) 434 return "Key"; 435 return "Value"; 436 } 437 GetAttr(const int row,const int col,const wxGridCellAttr::wxAttrKind kind)438 wxGridCellAttr* EntityAttributeGridTable::GetAttr(const int row, const int col, const wxGridCellAttr::wxAttrKind kind) { 439 if (row < 0 || row >= GetRowsCount() || 440 col < 0 || col >= GetColsCount()) 441 return NULL; 442 443 const size_t rowIndex = static_cast<size_t>(row); 444 wxGridCellAttr* attr = wxGridTableBase::GetAttr(row, col, kind); 445 if (attr == NULL) 446 attr = new wxGridCellAttr(); 447 448 if (col == 0) { 449 if (m_rows.isDefaultRow(rowIndex)) { 450 attr->SetFont(GetView()->GetFont().MakeItalic()); 451 attr->SetReadOnly(); 452 } else { 453 attr->SetFont(GetView()->GetFont()); 454 455 if (!m_rows.nameMutable(rowIndex)) { 456 attr->SetReadOnly(true); 457 attr->SetBackgroundColour(m_readonlyCellColor); 458 } else if (m_rows.subset(rowIndex)) { 459 attr->SetTextColour(m_specialCellColor); 460 } 461 } 462 } else if (col == 1) { 463 if (m_rows.isDefaultRow(rowIndex)) { 464 attr->SetFont(GetView()->GetFont().MakeItalic()); 465 } else { 466 attr->SetFont(GetView()->GetFont()); 467 468 if (!m_rows.valueMutable(rowIndex)) { 469 attr->SetReadOnly(true); 470 attr->SetBackgroundColour(m_readonlyCellColor); 471 } 472 if (m_rows.multi(rowIndex)) 473 attr->SetTextColour(m_specialCellColor); 474 } 475 } 476 return attr; 477 } 478 update()479 void EntityAttributeGridTable::update() { 480 if (m_ignoreUpdates) 481 return; 482 483 MapDocumentSPtr document = lock(m_document); 484 const size_t oldRowCount = m_rows.totalRowCount(); 485 m_rows.updateRows(document->allSelectedAttributableNodes(), m_showDefaultRows); 486 const size_t newRowCount = m_rows.totalRowCount(); 487 488 if (oldRowCount < newRowCount) 489 notifyRowsAppended(newRowCount - oldRowCount); 490 else if (oldRowCount > newRowCount) 491 notifyRowsDeleted(oldRowCount - 1, oldRowCount - newRowCount); 492 notifyRowsUpdated(0, newRowCount); 493 } 494 tooltip(const wxGridCellCoords cellCoords) const495 String EntityAttributeGridTable::tooltip(const wxGridCellCoords cellCoords) const { 496 if (cellCoords.GetRow() < 0 || cellCoords.GetRow() >= GetRowsCount()) 497 return ""; 498 499 const size_t rowIndex = static_cast<size_t>(cellCoords.GetRow()); 500 return m_rows.tooltip(rowIndex); 501 } 502 attributeName(const int row) const503 Model::AttributeName EntityAttributeGridTable::attributeName(const int row) const { 504 if (row < 0 || row >= static_cast<int>(m_rows.totalRowCount())) 505 return ""; 506 return m_rows.name(static_cast<size_t>(row)); 507 } 508 rowForName(const Model::AttributeName & name) const509 int EntityAttributeGridTable::rowForName(const Model::AttributeName& name) const { 510 const size_t index = m_rows.indexOf(name); 511 if (index >= m_rows.totalRowCount()) 512 return -1; 513 return static_cast<int>(index); 514 } 515 canRemove(const int row)516 bool EntityAttributeGridTable::canRemove(const int row) { 517 if (row < 0 || row >= GetNumberAttributeRows()) 518 return false; 519 const size_t index = static_cast<size_t>(row); 520 return m_rows.nameMutable(index) && m_rows.valueMutable(index); 521 } 522 showDefaultRows() const523 bool EntityAttributeGridTable::showDefaultRows() const { 524 return m_showDefaultRows; 525 } 526 setShowDefaultRows(const bool showDefaultRows)527 void EntityAttributeGridTable::setShowDefaultRows(const bool showDefaultRows) { 528 if (showDefaultRows == m_showDefaultRows) 529 return; 530 m_showDefaultRows = showDefaultRows; 531 update(); 532 } 533 renameAttribute(const size_t rowIndex,const String & newName,const Model::AttributableNodeList & attributables)534 void EntityAttributeGridTable::renameAttribute(const size_t rowIndex, const String& newName, const Model::AttributableNodeList& attributables) { 535 assert(rowIndex < m_rows.attributeRowCount()); 536 537 const String& oldName = m_rows.name(rowIndex); 538 if (!m_rows.nameMutable(rowIndex)) { 539 wxString msg; 540 msg << "Cannot rename attribute '" << oldName << "' to '" << newName << "'"; 541 wxMessageBox(msg, "Error", wxOK | wxICON_ERROR | wxCENTRE, GetView()); 542 return; 543 } 544 545 MapDocumentSPtr document = lock(m_document); 546 if (document->renameAttribute(oldName, newName)) { 547 m_rows.updateRows(attributables, m_showDefaultRows); 548 notifyRowsUpdated(0, m_rows.totalRowCount()); 549 } 550 } 551 updateAttribute(const size_t rowIndex,const String & newValue,const Model::AttributableNodeList & attributables)552 void EntityAttributeGridTable::updateAttribute(const size_t rowIndex, const String& newValue, const Model::AttributableNodeList& attributables) { 553 assert(rowIndex < m_rows.totalRowCount()); 554 555 const String& name = m_rows.name(rowIndex); 556 Model::AttributableNodeList::const_iterator it, end; 557 for (it = attributables.begin(), end = attributables.end(); it != end; ++it) { 558 const Model::AttributableNode* attributable = *it; 559 if (attributable->hasAttribute(name)) { 560 if (!attributable->canAddOrUpdateAttribute(name, newValue)) { 561 const Model::AttributeValue& oldValue = attributable->attribute(name); 562 wxString msg; 563 msg << "Cannot change property value '" << oldValue << "' to '" << newValue << "'"; 564 wxMessageBox(msg, "Error", wxOK | wxICON_ERROR | wxCENTRE, GetView()); 565 return; 566 } 567 } 568 } 569 570 MapDocumentSPtr document = lock(m_document); 571 if (document->setAttribute(name, newValue)) { 572 m_rows.updateRows(attributables, m_showDefaultRows); 573 notifyRowsUpdated(0, m_rows.totalRowCount()); 574 } 575 } 576 notifyRowsUpdated(size_t pos,size_t numRows)577 void EntityAttributeGridTable::notifyRowsUpdated(size_t pos, size_t numRows) { 578 if (GetView() != NULL) { 579 wxGridTableMessage message(this, wxGRIDTABLE_REQUEST_VIEW_GET_VALUES, 580 static_cast<int>(pos), 581 static_cast<int>(numRows)); 582 GetView()->ProcessTableMessage(message); 583 } 584 } 585 notifyRowsInserted(size_t pos,size_t numRows)586 void EntityAttributeGridTable::notifyRowsInserted(size_t pos, size_t numRows) { 587 if (GetView() != NULL) { 588 wxGridTableMessage message(this, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, 589 static_cast<int>(pos), 590 static_cast<int>(numRows)); 591 GetView()->ProcessTableMessage(message); 592 } 593 } 594 notifyRowsAppended(size_t numRows)595 void EntityAttributeGridTable::notifyRowsAppended(size_t numRows) { 596 if (GetView() != NULL) { 597 wxGridTableMessage message(this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 598 static_cast<int>(numRows)); 599 GetView()->ProcessTableMessage(message); 600 } 601 } 602 notifyRowsDeleted(size_t pos,size_t numRows)603 void EntityAttributeGridTable::notifyRowsDeleted(size_t pos, size_t numRows) { 604 if (GetView() != NULL) { 605 wxGridTableMessage message(this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 606 static_cast<int>(pos), 607 static_cast<int>(numRows)); 608 GetView()->ProcessTableMessage(message); 609 } 610 } 611 } 612 } 613