diff --git a/src/Mod/Spreadsheet/App/SheetPy.xml b/src/Mod/Spreadsheet/App/SheetPy.xml
index d968809ea7..f9a8348812 100644
--- a/src/Mod/Spreadsheet/App/SheetPy.xml
+++ b/src/Mod/Spreadsheet/App/SheetPy.xml
@@ -180,5 +180,26 @@ following dependency order.
+
+
+
+
+getUsedCells()
+
+Get a list of the names of all cells that are marked as used. These cells may
+or may not have a non-empty string content.
+
+
+
+
+
+
+
+getNonEmptyCells()
+
+Get a list of the names of all cells with data in them.
+
+
+
diff --git a/src/Mod/Spreadsheet/App/SheetPyImp.cpp b/src/Mod/Spreadsheet/App/SheetPyImp.cpp
index c330453b01..415be1afd7 100644
--- a/src/Mod/Spreadsheet/App/SheetPyImp.cpp
+++ b/src/Mod/Spreadsheet/App/SheetPyImp.cpp
@@ -980,6 +980,27 @@ PyObject *SheetPy::recomputeCells(PyObject *args) {
}PY_CATCH;
}
+PyObject *SheetPy::getUsedCells(PyObject *args)
+{
+ auto usedCells = getSheetPtr()->getCells()->getUsedCells();
+ Py::List pyCellList;
+ for (const auto &cell : usedCells) {
+ pyCellList.append(Py::String(cell.toString()));
+ }
+ return Py::new_reference_to(pyCellList);
+}
+
+PyObject *SheetPy::getNonEmptyCells(PyObject *args)
+{
+ auto usedCells = getSheetPtr()->getCells()->getNonEmptyCells();
+ Py::List pyCellList;
+ for (const auto &cell : usedCells) {
+ pyCellList.append(Py::String(cell.toString()));
+ }
+ return Py::new_reference_to(pyCellList);
+}
+
+
// +++ custom attributes implementer ++++++++++++++++++++++++++++++++++++++++
PyObject *SheetPy::getCustomAttributes(const char*) const
diff --git a/src/Mod/Spreadsheet/TestSpreadsheet.py b/src/Mod/Spreadsheet/TestSpreadsheet.py
index 353e494537..743d5c72c7 100644
--- a/src/Mod/Spreadsheet/TestSpreadsheet.py
+++ b/src/Mod/Spreadsheet/TestSpreadsheet.py
@@ -1345,6 +1345,40 @@ class SpreadsheetCases(unittest.TestCase):
with self.assertRaises(AttributeError):
self.assertEqual(ss1.B1, "fail")
+ def testGetUsedCells(self):
+ sheet = self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
+ test_cells = ['B13','C14','D15']
+ for i,cell in enumerate(test_cells):
+ sheet.set(cell,str(i))
+
+ used_cells = sheet.getUsedCells()
+ self.assertEqual(len(used_cells), len(test_cells))
+ for cell in test_cells:
+ self.assertTrue(cell in used_cells)
+
+ for cell in test_cells:
+ sheet.set(cell,"")
+ sheet.setAlignment(cell,"center")
+ non_empty_cells = sheet.getUsedCells()
+ self.assertEqual(len(non_empty_cells), len(test_cells)) # Alignment counts as "used"
+
+ def testGetNonEmptyCells(self):
+ sheet = self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
+ test_cells = ['B13','C14','D15']
+ for i,cell in enumerate(test_cells):
+ sheet.set(cell,str(i))
+
+ non_empty_cells = sheet.getNonEmptyCells()
+ self.assertEqual(len(non_empty_cells), len(test_cells))
+ for cell in test_cells:
+ self.assertTrue(cell in non_empty_cells)
+
+ for cell in test_cells:
+ sheet.set(cell,"")
+ sheet.setAlignment(cell,"center")
+ non_empty_cells = sheet.getNonEmptyCells()
+ self.assertEqual(len(non_empty_cells), 0) # Alignment does not count as "non-empty"
+
def tearDown(self):
#closing doc
FreeCAD.closeDocument(self.doc.Name)