/*************************************************************************** * Copyright (c) Eivind Kvedalen (eivind@kvedalen.name) 2015 * * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2010 * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ #include "PreCompiled.h" #include #include #include #include #include "Utils.h" #include "Range.h" // inclusion of the generated files (generated out of SheetPy.xml) #include "SheetPy.h" #include "SheetPy.cpp" using namespace Spreadsheet; using namespace App; // returns a string which represents the object e.g. when printed in python std::string SheetPy::representation(void) const { return std::string(""); } PyObject *SheetPy::PyMake(struct _typeobject *, PyObject *, PyObject *) // Python wrapper { // create a new instance of SheetPy and the Twin object return new SheetPy(new Sheet()); } // constructor method int SheetPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/) { return 0; } // +++ methodes implementer ++++++++++++++++++++++++++++++++++++++++++++++++ PyObject* SheetPy::set(PyObject *args) { char *address; char *contents; if (!PyArg_ParseTuple(args, "ss:set", &address, &contents)) return 0; try { Range rangeIter(address); do { getSheetPtr()->setCell(rangeIter.address().c_str(), contents); } while (rangeIter.next()); } catch (const Base::Exception & e) { PyErr_SetString(PyExc_ValueError, e.what()); return 0; } Py_Return; } PyObject* SheetPy::get(PyObject *args) { char *address; if (!PyArg_ParseTuple(args, "s:get", &address)) return 0; App::Property * prop = this->getSheetPtr()->getPropertyByName(address); if (prop == 0) { PyErr_SetString(PyExc_ValueError, "Invalid address or property."); return 0; } return prop->getPyObject(); } PyObject* SheetPy::getContents(PyObject *args) { char *strAddress; CellAddress address; if (!PyArg_ParseTuple(args, "s:getContents", &strAddress)) return 0; try { address = stringToAddress(strAddress); } catch (const Base::Exception & e) { PyErr_SetString(PyExc_ValueError, e.what()); return 0; } std::string contents; const Cell * cell = this->getSheetPtr()->getCell(address); if (cell) cell->getStringContent( contents ); return Py::new_reference_to( Py::String( contents ) ); } PyObject* SheetPy::clear(PyObject *args) { const char * strAddress; int all = 1; if (!PyArg_ParseTuple(args, "s|p:clear", &strAddress, &all)) return 0; try { Range rangeIter(strAddress); do { this->getSheetPtr()->clear(*rangeIter, all); } while (rangeIter.next()); } catch (const Base::Exception & e) { PyErr_SetString(PyExc_ValueError, e.what()); return 0; } Py_Return; } PyObject* SheetPy::clearAll(PyObject *args) { this->getSheetPtr()->clearAll(); Py_Return; } PyObject* SheetPy::importFile(PyObject *args) { const char * filename; const char * delimiter = "\t"; const char * quoteChar = "\""; const char * escapeChar = "\\"; if (!PyArg_ParseTuple(args, "s|sss:importFile", &filename, &delimiter, "eChar, &escapeChar)) return 0; if (getSheetPtr()->importFromFile(filename, delimiter[0], quoteChar[0], escapeChar[0])) return Py::new_reference_to( Py::Boolean(true) ); else return Py::new_reference_to( Py::Boolean(false) ); } PyObject* SheetPy::exportFile(PyObject *args) { const char * filename; const char * delimiter = "\t"; const char * quoteChar = "\""; const char * escapeChar = "\\"; if (!PyArg_ParseTuple(args, "s|sss:exportFile", &filename, &delimiter, "eChar, &escapeChar)) return 0; if (getSheetPtr()->exportToFile(filename, delimiter[0], quoteChar[0], escapeChar[0])) return Py::new_reference_to( Py::Boolean(true) ); else return Py::new_reference_to( Py::Boolean(false) ); } PyObject* SheetPy::mergeCells(PyObject *args) { const char * range; if (!PyArg_ParseTuple(args, "s:mergeCells", &range)) return 0; getSheetPtr()->mergeCells(Range(range)); Py_Return; } PyObject* SheetPy::splitCell(PyObject *args) { const char * strAddress; if (!PyArg_ParseTuple(args, "s:splitCell", &strAddress)) return 0; CellAddress address; try { address = stringToAddress(strAddress); } catch (const Base::Exception & e) { PyErr_SetString(PyExc_ValueError, e.what()); return 0; } getSheetPtr()->splitCell(address); Py_Return; } PyObject* SheetPy::insertColumns(PyObject *args) { const char * column; int count; if (!PyArg_ParseTuple(args, "si:insertColumns", &column, &count)) return 0; getSheetPtr()->insertColumns(decodeColumn(column), count); Py_Return; } PyObject* SheetPy::removeColumns(PyObject *args) { const char * column; int count; if (!PyArg_ParseTuple(args, "si:removeColumns", &column, &count)) return 0; getSheetPtr()->removeColumns(decodeColumn(column), count); Py_Return; } PyObject* SheetPy::insertRows(PyObject *args) { const char * row; int count; if (!PyArg_ParseTuple(args, "si:insertRows", &row, &count)) return 0; getSheetPtr()->insertRows(decodeRow(std::string(row)), count); Py_Return; } PyObject* SheetPy::removeRows(PyObject *args) { const char * row; int count; if (!PyArg_ParseTuple(args, "si:removeRows", &row, &count)) return 0; getSheetPtr()->removeRows(decodeRow(std::string(row)), count); Py_Return; } PyObject* SheetPy::setStyle(PyObject *args) { const char * cell; PyObject * value; std::set style; const char * options = "replace"; if (!PyArg_ParseTuple(args, "sO|s:setStyle", &cell, &value, &options)) return 0; if (PySet_Check(value)) { PyObject * copy = PySet_New(value); while (PySet_Size(copy) > 0) { PyObject * item = PySet_Pop(copy); // check on the key: if (PyString_Check(item)) style.insert(PyString_AsString(item)); else { std::string error = std::string("type of the set need to be a string, not ") + item->ob_type->tp_name; PyErr_SetString(PyExc_TypeError, error.c_str()); Py_DECREF(copy); return 0; } } Py_DECREF(copy); } else if (PyString_Check(value)) { using namespace boost; escaped_list_separator e('\0', '|', '\0'); std::string line = PyString_AsString(value); tokenizer > tok(line, e); for(tokenizer >::iterator i = tok.begin(); i != tok.end();++i) style.insert(*i); } else { std::string error = std::string("style must be either set or string, not ") + value->ob_type->tp_name; PyErr_SetString(PyExc_TypeError, error.c_str()); return 0; } if (strcmp(options, "replace") == 0) { Range rangeIter(cell); do { getSheetPtr()->setStyle(*rangeIter, style); } while (rangeIter.next()); } else if (strcmp(options, "add") == 0) { Range rangeIter(cell); do { std::set oldStyle; const Cell * cell = getSheetPtr()->getCell(*rangeIter); // Get old styles first if (cell) cell->getStyle(oldStyle); for (std::set::const_iterator it = oldStyle.begin(); it != oldStyle.end(); ++it) style.insert(*it); // Set new style getSheetPtr()->setStyle(*rangeIter, style); } while (rangeIter.next()); } else if (strcmp(options, "remove") == 0) { Range rangeIter(cell); do { std::set oldStyle; const Cell * cell = getSheetPtr()->getCell(*rangeIter); // Get old styles first if (cell) cell->getStyle(oldStyle); for (std::set::const_iterator it = style.begin(); it != style.end(); ++it) oldStyle.erase(*it); // Set new style getSheetPtr()->setStyle(*rangeIter, oldStyle); } while (rangeIter.next()); } else if (strcmp(options, "invert") == 0) { Range rangeIter(cell); do { std::set oldStyle; std::set newStyle; const Cell * cell = getSheetPtr()->getCell(*rangeIter); // Get old styles first if (cell) { cell->getStyle(oldStyle); newStyle = oldStyle; } for (std::set::const_iterator i = style.begin(); i != style.end(); ++i) { if (oldStyle.find(*i) == oldStyle.end()) // Not found in oldstyle; add it to newStyle newStyle.insert(*i); else // Found in oldStyle, remove it from newStyle newStyle.erase(*i); } // Set new style getSheetPtr()->setStyle(*rangeIter, newStyle); } while (rangeIter.next()); } else { PyErr_SetString(PyExc_ValueError, "Optional parameter must be either 'replace', 'add', 'remove', or 'invert'"); return 0; } Py_Return; } PyObject* SheetPy::getStyle(PyObject *args) { const char * strAddress; CellAddress address; if (!PyArg_ParseTuple(args, "s:getStyle", &strAddress)) return 0; try { address = stringToAddress(strAddress); } catch (const Base::Exception & e) { PyErr_SetString(PyExc_ValueError, e.what()); return 0; } std::set style; const Cell * cell = getSheetPtr()->getCell(address); if (cell && cell->getStyle(style)) { PyObject * s = PySet_New(NULL); for (std::set::const_iterator i = style.begin(); i != style.end(); ++i) PySet_Add(s, PyString_FromString((*i).c_str())); return s; } else { Py_INCREF(Py_None); return Py_None; } } PyObject* SheetPy::setDisplayUnit(PyObject *args) { const char * cell; const char * value; if (!PyArg_ParseTuple(args, "ss:setDisplayUnit", &cell, &value)) return 0; try { Range rangeIter(cell); do { getSheetPtr()->setDisplayUnit(*rangeIter, value); } while (rangeIter.next()); } catch (const Base::Exception & e) { PyErr_SetString(PyExc_ValueError, e.what()); return 0; } Py_Return; } PyObject* SheetPy::setAlias(PyObject *args) { CellAddress address; const char * strAddress; const char * value; if (!PyArg_ParseTuple(args, "ss:setAlias", &strAddress, &value)) return 0; try { address = stringToAddress(strAddress); getSheetPtr()->setAlias(address, value); Py_Return; } catch (const Base::Exception & e) { PyErr_SetString(PyExc_ValueError, e.what()); return 0; } } PyObject* SheetPy::getCellFromAlias(PyObject *args) { const char * alias; if (!PyArg_ParseTuple(args, "s:getAlias", &alias)) return 0; try { std::string address = getSheetPtr()->getAddressFromAlias(alias); if (address.size() > 0) return Py::new_reference_to( Py::String( address ) ); else { Py_INCREF(Py_None); return Py_None; } } catch (const Base::Exception & e) { PyErr_SetString(PyExc_ValueError, e.what()); return 0; } } PyObject* SheetPy::getDisplayUnit(PyObject *args) { const char * strAddress; CellAddress address; if (!PyArg_ParseTuple(args, "s:getDisplayUnit", &strAddress)) return 0; try { address = stringToAddress(strAddress); Spreadsheet::DisplayUnit unit; const Cell * cell = getSheetPtr()->getCell(address); if ( cell && cell->getDisplayUnit(unit) ) return Py::new_reference_to( Py::String( unit.stringRep ) ); else Py_Return; } catch (const Base::Exception & e) { PyErr_SetString(PyExc_ValueError, e.what()); return 0; } } PyObject* SheetPy::setAlignment(PyObject *args) { const char * cell; PyObject * value; int alignment = 0; const char * options = "replace"; if (!PyArg_ParseTuple(args, "sO|s:setAlignment", &cell, &value, &options)) return 0; if (PySet_Check(value)) { // Argument is a set of strings PyObject * copy = PySet_New(value); int n = PySet_Size(copy); while (n-- > 0) { PyObject * item = PySet_Pop(copy); if (PyString_Check(item)) alignment = Cell::decodeAlignment(PyString_AsString(item), alignment); else { std::string error = std::string("type of the key need to be a string, not") + item->ob_type->tp_name; PyErr_SetString(PyExc_TypeError, error.c_str()); Py_DECREF(copy); return 0; } } Py_DECREF(copy); } else if (PyString_Check(value)) { // Argument is a string, combination of alignments, separated by the pipe character using namespace boost; escaped_list_separator e('\0', '|', '\0'); std::string line = PyString_AsString(value); tokenizer > tok(line, e); for(tokenizer >::iterator i = tok.begin(); i != tok.end();++i) alignment = Cell::decodeAlignment(*i, alignment); } else { std::string error = std::string("style must be either set or string, not ") + value->ob_type->tp_name; PyErr_SetString(PyExc_TypeError, error.c_str()); return 0; } // Set alignment depending on 'options' variable if (strcmp(options, "replace") == 0) { Range rangeIter(cell); do { getSheetPtr()->setAlignment(*rangeIter, alignment); } while (rangeIter.next()); } else if (strcmp(options, "keep") == 0) { Range rangeIter(cell); do { int oldAlignment = 0; const Cell * cell = getSheetPtr()->getCell(*rangeIter); if (cell) cell->getAlignment(oldAlignment); if (alignment & Cell::ALIGNMENT_VERTICAL) oldAlignment &= ~Cell::ALIGNMENT_VERTICAL; if (alignment & Cell::ALIGNMENT_HORIZONTAL) oldAlignment &= ~Cell::ALIGNMENT_HORIZONTAL; getSheetPtr()->setAlignment(*rangeIter, alignment | oldAlignment); } while (rangeIter.next()); } else { PyErr_SetString(PyExc_ValueError, "Optional parameter must be either 'replace' or 'keep'"); return 0; } Py_Return; } PyObject* SheetPy::getAlignment(PyObject *args) { const char * strAddress; CellAddress address; if (!PyArg_ParseTuple(args, "s:getAlignment", &strAddress)) return 0; try { address = stringToAddress(strAddress); } catch (const Base::Exception & e) { PyErr_SetString(PyExc_ValueError, e.what()); return 0; } int alignment; const Cell * cell = getSheetPtr()->getCell(address); if (cell && cell->getAlignment(alignment)) { PyObject * s = PySet_New(NULL); if (alignment & Cell::ALIGNMENT_LEFT) PySet_Add(s, PyString_FromString("left")); if (alignment & Cell::ALIGNMENT_HCENTER) PySet_Add(s, PyString_FromString("center")); if (alignment & Cell::ALIGNMENT_RIGHT) PySet_Add(s, PyString_FromString("right")); if (alignment & Cell::ALIGNMENT_TOP) PySet_Add(s, PyString_FromString("top")); if (alignment & Cell::ALIGNMENT_VCENTER) PySet_Add(s, PyString_FromString("vcenter")); if (alignment & Cell::ALIGNMENT_BOTTOM) PySet_Add(s, PyString_FromString("bottom")); return s; } else { Py_INCREF(Py_None); return Py_None; } } static float decodeFloat(const PyObject * obj) { if (PyFloat_Check(obj)) return PyFloat_AsDouble((PyObject *)obj); else if (PyInt_Check(obj)) return PyInt_AsLong((PyObject *)obj); throw Base::TypeError("Float or integer expected"); } static void decodeColor(PyObject * value, Color & c) { if (PyTuple_Check(value)) { if (PyTuple_Size(value) < 3 || PyTuple_Size(value) > 4) throw Base::TypeError("Tuple must be either of 3 or 4 floats/ints."); c.r = decodeFloat(PyTuple_GetItem(value, 0)); c.g = decodeFloat(PyTuple_GetItem(value, 1)); c.b = decodeFloat(PyTuple_GetItem(value, 2)); if (PyTuple_Size(value) == 4) { c.a = decodeFloat(PyTuple_GetItem(value, 3)); return; } else c.a = 1.0; } else throw Base::TypeError("Tuple required."); } PyObject* SheetPy::setForeground(PyObject *args) { try { const char * range; PyObject * value; Color c; if (!PyArg_ParseTuple(args, "sO:setForeground", &range, &value)) return 0; decodeColor(value, c); Range rangeIter(range); do { getSheetPtr()->setForeground(*rangeIter, c); } while (rangeIter.next()); Py_Return; } catch (const Base::TypeError & e) { PyErr_SetString(PyExc_TypeError, e.what()); return 0; } catch (const Base::Exception & e) { PyErr_SetString(PyExc_ValueError, e.what()); return 0; } } PyObject* SheetPy::getForeground(PyObject *args) { const char * strAddress; CellAddress address; if (!PyArg_ParseTuple(args, "s:getForeground", &strAddress)) return 0; try { address = stringToAddress(strAddress); } catch (const Base::Exception & e) { PyErr_SetString(PyExc_ValueError, e.what()); return 0; } Color c; const Cell * cell = getSheetPtr()->getCell(address); if (cell && cell->getForeground(c)) { PyObject * t = PyTuple_New(4); PyTuple_SetItem(t, 0, Py::new_reference_to( Py::Float(c.r) )); PyTuple_SetItem(t, 1, Py::new_reference_to( Py::Float(c.g) )); PyTuple_SetItem(t, 2, Py::new_reference_to( Py::Float(c.b) )); PyTuple_SetItem(t, 3, Py::new_reference_to( Py::Float(c.a) )); return t; } else { Py_INCREF(Py_None); return Py_None; } } PyObject* SheetPy::setBackground(PyObject *args) { try { const char * strAddress; PyObject * value; Color c; if (!PyArg_ParseTuple(args, "sO:setBackground", &strAddress, &value)) return 0; decodeColor(value, c); Range rangeIter(strAddress); do { getSheetPtr()->setBackground(*rangeIter, c); } while (rangeIter.next()); Py_Return; } catch (const Base::TypeError & e) { PyErr_SetString(PyExc_TypeError, e.what()); return 0; } catch (const Base::Exception & e) { PyErr_SetString(PyExc_ValueError, e.what()); return 0; } } PyObject* SheetPy::getBackground(PyObject *args) { const char * strAddress; CellAddress address; if (!PyArg_ParseTuple(args, "s:setStyle", &strAddress)) return 0; try { address = stringToAddress(strAddress); } catch (const Base::Exception & e) { PyErr_SetString(PyExc_ValueError, e.what()); return 0; } Color c; const Cell * cell = getSheetPtr()->getCell(address); if (cell && cell->getBackground(c)) { PyObject * t = PyTuple_New(4); PyTuple_SetItem(t, 0, Py::new_reference_to( Py::Float(c.r) )); PyTuple_SetItem(t, 1, Py::new_reference_to( Py::Float(c.g) )); PyTuple_SetItem(t, 2, Py::new_reference_to( Py::Float(c.b) )); PyTuple_SetItem(t, 3, Py::new_reference_to( Py::Float(c.a) )); return t; } else { Py_INCREF(Py_None); return Py_None; } } PyObject* SheetPy::setColumnWidth(PyObject *args) { const char * columnStr; int width; CellAddress address; if (!PyArg_ParseTuple(args, "si:setColumnWidth", &columnStr, &width)) return 0; try { std::string cellAddr = std::string(columnStr) + "1"; address = stringToAddress(cellAddr.c_str()); getSheetPtr()->setColumnWidth(address.col(), width); Py_Return; } catch (const Base::Exception & e) { PyErr_SetString(PyExc_ValueError, e.what()); return 0; } } PyObject* SheetPy::getColumnWidth(PyObject *args) { const char * columnStr; if (!PyArg_ParseTuple(args, "s:getColumnWidth", &columnStr)) return 0; try { CellAddress address(std::string(columnStr) + "1"); return Py::new_reference_to( Py::Int( getSheetPtr()->getColumnWidth(address.col()) ) ); } catch (const Base::Exception & e) { PyErr_SetString(PyExc_ValueError, e.what()); return 0; } } PyObject* SheetPy::setRowHeight(PyObject *args) { const char * rowStr; int height; if (!PyArg_ParseTuple(args, "si:setRowHeight", &rowStr, &height)) return 0; try { CellAddress address("A" + std::string(rowStr)); getSheetPtr()->setRowHeight(address.row(), height); Py_Return; } catch (const Base::Exception & e) { PyErr_SetString(PyExc_ValueError, e.what()); return 0; } } PyObject* SheetPy::getRowHeight(PyObject *args) { const char * rowStr; if (!PyArg_ParseTuple(args, "s:getRowHeight", &rowStr)) return 0; try { CellAddress address("A" + std::string(rowStr)); return Py::new_reference_to( Py::Int( getSheetPtr()->getRowHeight(address.row()) ) ); } catch (const Base::Exception & e) { PyErr_SetString(PyExc_ValueError, e.what()); return 0; } } // +++ custom attributes implementer ++++++++++++++++++++++++++++++++++++++++ PyObject *SheetPy::getCustomAttributes(const char* attr) const { App::Property * prop = this->getSheetPtr()->getPropertyByName(attr); if (prop == 0) return 0; return prop->getPyObject(); } int SheetPy::setCustomAttributes(const char* attr, PyObject* obj) { return 0; }