diff --git a/src/Wt/WTable.C b/src/Wt/WTable.C index 4d10062c6b..375a2986ff 100644 --- a/src/Wt/WTable.C +++ b/src/Wt/WTable.C @@ -102,7 +102,11 @@ WTableRow* WTable::insertRow(int row, std::unique_ptr tableRow) for (auto &cell : tableRow->cells_) { widgetAdded(cell.get()); } + + int old_end = rows_.size(); rows_.insert(rows_.begin() + row, std::move(tableRow)); + updateRowNumbers(std::min(old_end, row), rowCount() - 1); + rows_[row].get()->expand(columnCount()); repaint(RepaintFlag::SizeAffected); @@ -143,6 +147,8 @@ std::unique_ptr WTable::removeRow(int row) std::unique_ptr result = std::move(rows_[row]); rows_.erase(rows_.begin() + row); + updateRowNumbers(row, rowCount() - 1); + result->setTable(nullptr); for (auto &cell : result->cells_) @@ -408,6 +414,7 @@ void WTable::moveRow(int from, int to) if (to > (int)rows_.size()) rowAt(to); rows_.insert(rows_.begin() + to, std::move(from_tr)); + updateRowNumbers(std::min(from, to), std::max(from, to)); // make sure spans don't cause segmentation faults during rendering auto& cells = rows_[to]->cells_; @@ -451,6 +458,16 @@ void WTable::moveColumn(int from, int to) repaint(RepaintFlag::SizeAffected); } +void WTable::updateRowNumbers(int begin, int end) { + if (begin < 0 || begin >= rowCount() || end < 0 || end >= rowCount()) { + return; + } + + for (size_t i = begin; i <= end; ++i) { + rows_[i]->rowNumber_ = i; + } +} + void WTable::iterateChildren(const HandleWidgetMethod &method) const { for (const auto &row : rows_) { diff --git a/src/Wt/WTable.h b/src/Wt/WTable.h index bca35f33ea..714d84f977 100644 --- a/src/Wt/WTable.h +++ b/src/Wt/WTable.h @@ -197,6 +197,7 @@ class WT_API WTable : public WInteractWidget void expand(int row, int column, int rowSpan, int columnSpan); WTableCell *itemAt(int row, int column); void setItemAt(int row, int column, std::unique_ptr cell); + void updateRowNumbers(int begin, int end); void repaintRow(WTableRow *row); void repaintColumn(WTableColumn *col); diff --git a/src/Wt/WTableRow.C b/src/Wt/WTableRow.C index d6981618cf..bf0c521cf1 100644 --- a/src/Wt/WTableRow.C +++ b/src/Wt/WTableRow.C @@ -17,8 +17,9 @@ namespace Wt { WTableRow::WTableRow() : hidden_(false), - hiddenChanged_(false) -{ + hiddenChanged_(false), + rowNumber_(-1) +{ implementStateless(&WTableRow::hide, &WTableRow::undoHide); implementStateless(&WTableRow::show, &WTableRow::undoHide); } @@ -87,6 +88,7 @@ WTableCell *WTableRow::elementAt(int column) int WTableRow::rowNum() const { if (table_) + if (rowNumber_ != -1) return rowNumber_; for (unsigned i = 0; i < table_->rows_.size(); ++i) if (table_->rows_[i].get() == this) return i; diff --git a/src/Wt/WTableRow.h b/src/Wt/WTableRow.h index e8884553dc..92a0e2a087 100644 --- a/src/Wt/WTableRow.h +++ b/src/Wt/WTableRow.h @@ -148,6 +148,7 @@ class WT_API WTableRow : public WObject std::string id_; WT_USTRING styleClass_; bool hidden_, hiddenChanged_, wasHidden_; + size_t rowNumber_; void updateDom(DomElement& element, bool all); void setTable(WTable *table); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4275330af0..97dcbe5c55 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -32,6 +32,7 @@ IF(ENABLE_LIBWTTEST) utils/Base64Test.C utils/EraseWord.C utils/ParseNumber.C + widgets/WTableTest.C widgets/WSpinBoxTest.C length/WLengthTest.C color/WColorTest.C diff --git a/test/widgets/WTableTest.C b/test/widgets/WTableTest.C new file mode 100644 index 0000000000..214d135673 --- /dev/null +++ b/test/widgets/WTableTest.C @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2010 Emweb bvba, Kessel-Lo, Belgium. + * + * See the LICENSE file for terms of use. + */ +#include + +#include +#include +#include + +using namespace Wt; + +namespace { +Wt::Test::WTestEnvironment environment; +Wt::WApplication testApp(environment); + +void CheckRowNumbers(WTable* table) +{ + for (auto i = 0; i < table->rowCount(); ++i) { + BOOST_REQUIRE_EQUAL(table->rowAt(i)->rowNum(), i); + } +} +void CheckColumnNumbers(WTable* table) +{ + for (auto i = 0; i < table->columnCount(); ++i) { + BOOST_REQUIRE_EQUAL(table->columnAt(i)->columnNum(), i); + } +} +} + +BOOST_AUTO_TEST_SUITE( WTableTest ) + +BOOST_AUTO_TEST_CASE( elementAt1 ) +{ + auto table = cpp14::make_unique(); + BOOST_REQUIRE_NO_THROW(table->elementAt(5, 1)); + + auto rowCount = table->rowCount(); + + BOOST_REQUIRE_EQUAL(rowCount, 6); + CheckRowNumbers(table.get()); +} + +BOOST_AUTO_TEST_CASE( elementAt2 ) +{ + auto table = cpp14::make_unique(); + BOOST_REQUIRE_NO_THROW(table->elementAt(1, 5)); + + auto columnCount = table->columnCount(); + + BOOST_REQUIRE_EQUAL(columnCount, 6); + CheckColumnNumbers(table.get()); +} + +BOOST_AUTO_TEST_CASE( elementAt3 ) +{ + auto table = cpp14::make_unique(); + BOOST_REQUIRE_NO_THROW(table->elementAt(5, 4)); + + auto rowCount = table->rowCount(); + auto columnCount = table->columnCount(); + + BOOST_REQUIRE_EQUAL(rowCount, 6); + BOOST_REQUIRE_EQUAL(columnCount, 5); + CheckRowNumbers(table.get()); + CheckColumnNumbers(table.get()); +} + +BOOST_AUTO_TEST_CASE( rowAt ) +{ + auto table = cpp14::make_unique(); + BOOST_REQUIRE_NO_THROW(table->rowAt(5)); + + auto rowCount = table->rowCount(); + + BOOST_REQUIRE_EQUAL(rowCount, 6); + CheckRowNumbers(table.get()); +} + +BOOST_AUTO_TEST_CASE( columnAt ) +{ + auto table = cpp14::make_unique(); + BOOST_REQUIRE_NO_THROW(table->columnAt(5)); + + auto columnCount = table->columnCount(); + + BOOST_REQUIRE_EQUAL(columnCount, 6); + CheckColumnNumbers(table.get()); +} + +BOOST_AUTO_TEST_CASE( insertRow1 ) +{ + auto table = cpp14::make_unique(); + table->rowAt(2); + BOOST_REQUIRE_NO_THROW(table->insertRow(1)); + + auto rowCount = table->rowCount(); + + BOOST_REQUIRE_EQUAL(rowCount, 4); + CheckRowNumbers(table.get()); +} + +BOOST_AUTO_TEST_CASE( insertRow2 ) +{ + auto table = cpp14::make_unique(); + table->rowAt(2); + BOOST_REQUIRE_NO_THROW(table->insertRow(3)); + + auto rowCount = table->rowCount(); + + BOOST_REQUIRE_EQUAL(rowCount, 4); + CheckRowNumbers(table.get()); +} + +BOOST_AUTO_TEST_CASE( insertRow3 ) +{ + auto table = cpp14::make_unique(); + BOOST_REQUIRE_NO_THROW(table->insertRow(0)); +} + +BOOST_AUTO_TEST_CASE( insertColumn1 ) +{ + auto table = cpp14::make_unique(); + table->columnAt(2); + BOOST_REQUIRE_NO_THROW(table->insertColumn(1)); + + auto columnCount = table->columnCount(); + + BOOST_REQUIRE_EQUAL(columnCount, 4); + CheckColumnNumbers(table.get()); +} + +BOOST_AUTO_TEST_CASE( insertColumn2 ) +{ + auto table = cpp14::make_unique(); + table->columnAt(2); + BOOST_REQUIRE_NO_THROW(table->insertColumn(3)); + + auto columnCount = table->columnCount(); + + BOOST_REQUIRE_EQUAL(columnCount, 4); + CheckColumnNumbers(table.get()); +} + +BOOST_AUTO_TEST_CASE( insertColumn3 ) +{ + auto table = cpp14::make_unique(); + BOOST_REQUIRE_NO_THROW(table->insertColumn(0)); +} + +BOOST_AUTO_TEST_CASE( removeRow1 ) +{ + auto table = cpp14::make_unique(); + table->rowAt(5); + BOOST_REQUIRE_NO_THROW(table->removeRow(2)); + + auto rowCount = table->rowCount(); + + BOOST_REQUIRE_EQUAL(rowCount, 5); + CheckRowNumbers(table.get()); +} + +BOOST_AUTO_TEST_CASE( removeRow2 ) +{ + auto table = cpp14::make_unique(); + table->rowAt(0); + BOOST_REQUIRE_NO_THROW(table->removeRow(0)); +} + +BOOST_AUTO_TEST_CASE( removeColumn1 ) +{ + auto table = cpp14::make_unique(); + table->columnAt(5); + BOOST_REQUIRE_NO_THROW(table->removeColumn(2)); + + auto columnCount = table->columnCount(); + + BOOST_REQUIRE_EQUAL(columnCount, 5); + CheckColumnNumbers(table.get()); +} + +BOOST_AUTO_TEST_CASE( removeColumn2 ) +{ + auto table = cpp14::make_unique(); + table->columnAt(0); + BOOST_REQUIRE_NO_THROW(table->removeColumn(0)); +} + +BOOST_AUTO_TEST_CASE( moveRow1 ) +{ + auto table = cpp14::make_unique(); + table->rowAt(5); + + WTableCell* cell2 = table->elementAt(2, 0); + WTableCell* cell0 = table->elementAt(0, 0); + + BOOST_REQUIRE_NO_THROW(table->moveRow(2, 0)); + + BOOST_REQUIRE_EQUAL(table->elementAt(0, 0), cell2); + BOOST_REQUIRE_EQUAL(table->elementAt(1, 0), cell0); + BOOST_REQUIRE_NE(table->elementAt(2, 0), cell2); + + BOOST_REQUIRE_EQUAL(table->rowCount(), 6); + CheckRowNumbers(table.get()); +} + +BOOST_AUTO_TEST_CASE( moveRow2, * boost::unit_test::disabled() ) +{ + auto table = cpp14::make_unique(); + table->rowAt(5); + + WTableCell* cell2 = table->elementAt(2, 0); + + BOOST_REQUIRE_NO_THROW(table->moveRow(2, 7)); + + BOOST_REQUIRE_NE(table->elementAt(2, 0), cell2); + BOOST_REQUIRE_EQUAL(table->elementAt(7, 0), cell2); + + BOOST_REQUIRE_EQUAL(table->rowCount(), 8); + CheckRowNumbers(table.get()); +} + +BOOST_AUTO_TEST_CASE( moveColumn1 ) +{ + auto table = cpp14::make_unique(); + table->columnAt(5); + + WTableCell* cell2 = table->elementAt(0, 2); + WTableCell* cell0 = table->elementAt(0, 0); + + BOOST_REQUIRE_NO_THROW(table->moveColumn(2, 0)); + + BOOST_REQUIRE_EQUAL(table->elementAt(0, 0), cell2); + BOOST_REQUIRE_EQUAL(table->elementAt(0, 1), cell0); + BOOST_REQUIRE_NE(table->elementAt(0, 2), cell2); + + BOOST_REQUIRE_EQUAL(table->columnCount(), 6); + CheckColumnNumbers(table.get()); +} + +BOOST_AUTO_TEST_CASE( moveColumn2, * boost::unit_test::disabled() ) +{ + auto table = cpp14::make_unique(); + table->columnAt(5); + + WTableCell* cell2 = table->elementAt(0, 2); + + BOOST_REQUIRE_NO_THROW(table->moveColumn(2, 7)); + + BOOST_REQUIRE_EQUAL(table->elementAt(0, 7), cell2); + BOOST_REQUIRE_NE(table->elementAt(0, 2), cell2); + + BOOST_REQUIRE_EQUAL(table->columnCount(), 8); + CheckColumnNumbers(table.get()); +} + +BOOST_AUTO_TEST_CASE( clear ) +{ + auto table = cpp14::make_unique(); + table->elementAt(4, 4); + + BOOST_REQUIRE_NO_THROW(table->clear()); + + BOOST_REQUIRE_EQUAL(table->rowCount(), 0); + BOOST_REQUIRE_EQUAL(table->columnCount(), 0); +} + +BOOST_AUTO_TEST_SUITE_END()