Turned the spreadsheet into a FreeCAD object

This commit is contained in:
Yorik van Havre 2013-08-03 14:14:49 -03:00
parent 3a64a9db8a
commit 7f1044a9bb
2 changed files with 209 additions and 37 deletions

View File

@ -20,6 +20,56 @@
#* *
#***************************************************************************
import Spreadsheet_rc
class SpreadsheetWorkbench(Workbench):
"Spreadsheet workbench object"
Icon = """
/* XPM */
static char * Spreadsheet_xpm[] = {
"16 16 5 1",
" c None",
". c #151614",
"+ c #575956",
"@ c #969895",
"# c #F7F9F6",
" ",
" ",
" ...............",
".@##@+########@.",
".+@@+.@@@@@@@@+.",
"..+++.+++++++++.",
".@##@+########@.",
".+@@+.@@@@@@@@+.",
"..+++.+++++++++.",
".@##@+########@.",
".+@@+.@@@@@@@@+.",
"..+++.+++++++++.",
".@##@+########@.",
"..+++.+++++++++.",
" ",
" "};"""
MenuText = "Spreadsheet"
ToolTip = "Spreadsheet workbench"
def Initialize(self):
import Spreadsheet,Spreadsheet_rc
from DraftTools import translate
commands = ["Spreadsheet_Create"]
self.appendToolbar(str(translate("Spreadsheet","Spreadsheet tools")),commands)
self.appendMenu(str(translate("Spreadsheet","&Spreadsheet")),commands)
FreeCADGui.addIconPath(":/icons")
FreeCADGui.addLanguagePath(":/translations")
Log ('Loading Spreadsheet module... done\n')
def Activated(self):
Msg("Spreadsheet workbench activated\n")
def Deactivated(self):
Msg("Spreadsheet workbench deactivated\n")
def GetClassName(self):
return "Gui::PythonWorkbench"
FreeCADGui.addWorkbench(SpreadsheetWorkbench)

View File

@ -20,36 +20,33 @@
#* *
#***************************************************************************
import re, math
import re, math, FreeCAD, FreeCADGui
from PyQt4 import QtCore,QtGui
from DraftTools import translate
class Spreadsheet(object):
"A spreadsheet object"
"""An object representing a spreadsheet. Can be used as a
FreeCAD object or as a standalone python object.
Cells of the spreadsheet can be got/set as arguments, as:
myspreadsheet.a1 = 54
print(myspreadsheet.a1)
myspreadsheet.a2 = "My text"
myspreadsheet.b1 = "=a1*3"
print(myspreadsheet.a3)
Functions usable in formulae are limited to the contents of
the math module."""
def __init__(self):
def __init__(self,obj=None):
if obj:
obj.Proxy = self
self._cells = {}
# a list of safe functions to allow
safe_list = ['acos', 'asin', 'atan', 'atan2', 'ceil',
'cos', 'cosh', 'e', 'exp', 'fabs',
'floor', 'fmod', 'frexp', 'hypot', 'ldexp', 'log',
'log10', 'modf', 'pi', 'pow', 'radians', 'sin',
'sinh', 'sqrt', 'tan', 'tanh']
self._tools = dict((k, getattr(math, k)) for k in safe_list)
# adding abs
self._tools["abs"] = abs
# removing all builtins from allowed functions
self._tools["__builtins__"] = None
self._relations = {}
self.cols = []
self.rows = []
def __repr__(self):
return "Spreadsheet object containing " + str(len(self._cells)) + " cells"
def allowedFunctions(self):
"returns a list of allowed functions in cells"
return self.tools.keys()
def __setattr__(self, key, value):
#print "setting key:",key," to value:",value
@ -58,7 +55,7 @@ class Spreadsheet(object):
if value:
if self.isFunction(value):
self._updateDependencies(key,value)
c,r = splitKey(key)
c,r = self.splitKey(key)
if not c in self.cols:
self.cols.append(c)
self.cols.sort()
@ -67,17 +64,42 @@ class Spreadsheet(object):
self.rows.sort()
else:
self.__dict__.__setitem__(key,value)
def __getattr__(self, key):
if key in self._cells:
if self.isFunction(self._cells[key]):
#print "result = ",self.getFunction(key)
return eval(self._format(key),self._tools,{"self":self})
# building a list of safe functions allowed in eval
safe_list = ['acos', 'asin', 'atan', 'atan2', 'ceil',
'cos', 'cosh', 'e', 'exp', 'fabs',
'floor', 'fmod', 'frexp', 'hypot', 'ldexp', 'log',
'log10', 'modf', 'pi', 'pow', 'radians', 'sin',
'sinh', 'sqrt', 'tan', 'tanh']
tools = dict((k, getattr(math, k)) for k in safe_list)
# adding abs
tools["abs"] = abs
# removing all builtins from allowed functions
tools["__builtins__"] = None
try:
e = eval(self._format(key),tools,{"self":self})
except:
print "Error evaluating formula"
return self._cells[key]
else:
return e
else:
return self._cells[key]
else:
return None
def __getstate__(self):
return self._cells
def __setstate__(self,state):
if state:
self._cells = state
# TODO rebuild rows, cols and _relations
def _format(self,key):
"formats all cellnames in the function a the given cell"
elts = re.split(r'(\W+)',self._cells[key][1:])
@ -102,7 +124,10 @@ class Spreadsheet(object):
self._relations[a].append(key)
else:
self._relations[a] = [key]
def execute(self,obj=None):
pass
def isFunction(self,key):
"isFunction(cell): returns True if the given cell or value is a function"
if key in self._cells:
@ -138,7 +163,7 @@ class Spreadsheet(object):
if not nu:
return False
return True
def splitKey(self,key):
"splitKey(cell): splits a key between column and row"
c = ''
@ -149,18 +174,18 @@ class Spreadsheet(object):
else:
r += ch
return c,r
def getFunction(self,key):
"getFunction(cell): returns the function contained in the given cell, instead of the value"
if key in self._cells:
return self._cells[key]
else:
return None
def getSize(self):
"getSize(): returns a tuple with number of columns and rows of this spreadsheet"
return (len(self.columns),len(self.rows))
def getCells(self,index):
"getCells(index): returns the cells from the given column of row number"
cells = {}
@ -169,34 +194,106 @@ class Spreadsheet(object):
if index in [c,r]:
cells[k] = self._cells[k]
return cells
class ViewProviderSpreadsheet(object):
def __init__(self, vobj):
vobj.Proxy = self
def getIcon(self):
import Spreadsheet_rc
return ":/icons/Spreadsheet.svg"
def __getstate__(self):
return None
def __setstate__(self,state):
return None
def getDisplayModes(self,vobj):
return ["None"]
def getDefaultDisplayMode(self):
return "None"
def setDisplayMode(self,mode):
return mode
def setEdit(self,vobj,mode):
if hasattr(self,"editor"):
pass
else:
#FreeCADGui.Control.showDialog(SpreadsheetTaskPanel())
self.editor = SpreadsheetView(vobj.Object)
addSpreadsheetView(self.editor)
return True
def unsetEdit(self,vobj,mode):
#FreeCADGui.Control.closeDialog()
return False
class SpreadsheetView(QtGui.QWidget):
"A spreadsheet viewer for FreeCAD"
def __init__(self):
def __init__(self,spreadsheet=None):
from DraftTools import translate
QtGui.QWidget.__init__(self)
self.setWindowIcon(QtGui.QIcon(":/icons/Spreadsheet.svg"))
self.setWindowTitle(str(translate("Spreadsheet","Spreadsheet")))
self.setObjectName("Spreadsheet viewer")
self.verticalLayout = QtGui.QVBoxLayout(self)
# add editor line
self.horizontalLayout = QtGui.QHBoxLayout()
self.label = QtGui.QLabel(self)
self.label.setMinimumSize(QtCore.QSize(82, 0))
self.label.setText(str(translate("Spreadsheet","Cell"))+":")
self.horizontalLayout.addWidget(self.label)
self.lineEdit = QtGui.QLineEdit(self)
self.horizontalLayout.addWidget(self.lineEdit)
self.verticalLayout.addLayout(self.horizontalLayout)
# add table
self.table = QtGui.QTableWidget(30,26,self)
for i in range(26):
ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i]
self.table.setHorizontalHeaderItem(i, QtGui.QTableWidgetItem(ch))
self.verticalLayout.addWidget(self.table)
self.spreadsheet = None
self.spreadsheet = spreadsheet
self.update()
QtCore.QObject.connect(self.table, QtCore.SIGNAL("cellChanged(int,int)"), self.changeCell)
QtCore.QObject.connect(self.table, QtCore.SIGNAL("currentCellChanged(int,int,int,int)"), self.activeCell)
def __del__(self):
if self.spreadsheet:
if hasattr(self.spreadsheet,"ViewObject"):
if self.spreadsheet.ViewObject:
if hasattr(self.spreadsheet.ViewObject,"editor"):
del self.spreadsheet.ViewObject.editor
def update(self):
"fills the cells with the contents of the spreadsheet"
if self.spreadsheet:
for cell in self.spreadsheet.Proxy._cells.keys():
c,r = self.spreadsheet.Proxy.splitKey(cell)
c = "abcdefghijklmnopqrstuvwxyz".index(c)
r = r-1
self.table.item(r,c).setText(getattr(self.spreadsheet.Proxy,cell))
def changeCell(self,r,c):
"changes the contens of a cell"
key = "abcdefghijklmnopqrstuvwxyz"[c]+str(r+1)
value = self.table.item(r,c).text()
print "Changing "+key+" to "+value
if self.spreadsheet:
setattr(self.spreadsheet,key,value)
setattr(self.spreadsheet.Proxy,key,value)
def activeCell(self,r,c,or,oc):
"sets the contents of the active cell to the header"
print "setting cell ",r,c
def clear(self):
"clears the spreadsheet"
for r in range(self.table.columnCount):
@ -204,10 +301,35 @@ class SpreadsheetView(QtGui.QWidget):
self.table.item(r,c).setText("")
class _CommandSpreadsheet:
"the Spreadsheet FreeCAD command"
def GetResources(self):
return {'Pixmap' : 'Spreadsheet',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Spreadsheet_Create","Spreadsheet"),
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Spreadsheet_Create","Adds a spreadsheet object to the active document")}
def Activated(self):
from DraftTools import translate
FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Create Spreadsheet")))
FreeCADGui.doCommand("import Spreadsheet")
FreeCADGui.doCommand("Spreadsheet.makeSpreadsheet()")
FreeCAD.ActiveDocument.commitTransaction()
def makeSpreadsheet():
"makeSpreadsheet(): adds a spreadsheet object to the active document"
obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython","Spreadsheet")
Spreadsheet(obj)
if FreeCAD.GuiUp:
ViewProviderSpreadsheet(obj.ViewObject)
return obj
def addSpreadsheetView(view):
"addSpreadsheetView(view): adds the given spreadsheet view to the FreeCAD MDI area"
import FreeCAD
if FreeCAD.GuiUp:
import FreeCADGui,Spreadsheet_rc
import Spreadsheet_rc
mdi = FreeCADGui.getMainWindow().findChild(QtGui.QMdiArea)
mdi.addSubWindow(view)
FreeCADGui.addCommand('Spreadsheet_Create',_CommandSpreadsheet())