
| Current Path : /home/cgabriel/20_dev/12_procpy/dataninja/ |
Linux ift1.ift-informatik.de 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64 |
| Current File : //home/cgabriel/20_dev/12_procpy/dataninja/graphreport.py |
# coding: utf8
import os,re,sys,time,functools,math,tkinter,codecs,procpy
# import procpy.procobj
try:
import tkinter.ttk,Pmw,xmltodict,json,svgwrite # ,tkintertable
except:
import pip
pip.main(["install","pyttk"])
pip.main(["install","Pmw"])
# pip.main(["install","tkintertable"])
pip.main(["install","xmltodict"])
pip.main(["install","json"])
pip.main(["install","svgwrite"])
import tkinter.ttk,Pmw,xmltodict,json,svgwrite # ,tkintertable
import tkinter.filedialog
import procpy.viewobj
#**************************************************************************
class Graphreport (tkinter.Frame):
def __init__ (self,graphproc,*pars,**args):
tkinter.Frame.__init__(self,*pars,**args)
self.config(background="white")
self.header = tkinter.Canvas(self,height=30,borderwidth=0)
self.report = tkinter.Canvas(self,borderwidth=0)
self.header.config(background="white")
self.report.config(background="white")
self.header_comboboxes = []
self.actual_report_columns = []
self.col_width = [160] * 100
self.row_elements = []
self.graphproc = graphproc
self.sort_klicks = {}
self.sort_fields = []
self.last_click = 0
self.xmax = 0
self.ymax = 0
self.report.rf_show = None # the highlighted element in the reporting section
self.report.rf_col = None # the column in which the first element will be highlighted
self.clicked11 = False # helpder variable for distinguishing normal and simple clicks
self.old_columns = []
self.style = tkinter.ttk.Style()
self.style.configure('Yellow.TCombobox',background="yellow")
self.style.configure('White.TCombobox', background="white")
self.header.pack(side=tkinter.TOP, fill=tkinter.X)
self.report.pack(side=tkinter.BOTTOM,fill=tkinter.BOTH,expand=tkinter.TRUE)
self.draw_report_headers()
#**************************************************************************
def config (self,*pars,**args): # additional configurations
for par in ["dbh"]:
if par in args:
vars(self)[par] = args[par]
del args[par]
tkinter.Frame.config(self,*pars,**args)
#**************************************************************************
def clear (self):
self.report.delete("allx")
self.header.delete("sortmarker")
#**************************************************************************
def load (self,text):
self.actual_report_columns = []
m = re.search(r"COLUMNS\: +(.*)",text)
if m:
for col in m.group(1).split(","):
if not col == "":
print(col)
self.header_comboboxes[-1][0].set(col)
self.draw_report_headers()
# self.actual_report_columns.append(col)
self.sort_fields = []
self.sort_klicks = {}
m = re.search("SORTFIELDS\: +(.*)",text)
if m:
self.sort_fields = m.group(1).split(",")
self.sort_klicks = list(zip(self.sort_fields,[0]*len(self.sort_fields)))
self.sort_klicks = {}
m = re.search("SORTKLICKS\: +(.*)",text)
if m:
for o in m.group(1).split(","):
m1 = re.search(r"^(.*)\.(.*)$",o)
if m1:
self.sort_klicks[m1.group(1)] = int(m1.group(2))
#**************************************************************************
def save (self):
text = "COLUMNS: " + ",".join(self.actual_report_columns) + "\n"
text = text + "SORTFIELDS: " + ",".join(self.sort_fields) + "\n"
text = text + "SORTKLICKS: " + ",".join( [x+"."+str(self.sort_klicks[x]) for x in self.sort_klicks] ) + "\n"
return(text)
#**************************************************************************
def update_combo_selection (self):
names = [""]
# print self.graphproc.storeproc.store.list_of_variables
for name in self.graphproc.storeproc.store.list_of_variables:
if not name[0] == "_":
names.append(name)
names.sort()
self.report.rf_show = None
self.report.rf_col = None
# self.sort_fields = []
# self.header.delete("sortmarker")
self.graphproc.graphmodel.hide(0)
for combobox in self.header_comboboxes:
text = combobox[0].get().strip()
aggr = ""
m = re.search(r"(\S+)\((\S+)\)",text)
if m:
text = m.group(2)
aggr = m.group(1)
names1 = names[:]
if not text == "":
aggr_set = self.graphproc.storeproc.store.list_of_variables[text][:]
aggr_set.append("COUNT")
combobox[1] = text
names1.remove(text)
names1.insert(1,text)
split_index = names1.index(text) + 1
# split_index = 1
names2 = names1[:split_index]
for aggr1 in aggr_set:
names2.append(" - " + aggr1)
names1 = names2 + names1[split_index:]
combobox[0].config(values=names1)
#**************************************************************************
def draw_report_headers (self,event=None,clicked_col=9999):
new_columns = []
for header_combobox in self.header_comboboxes: # collect the actual values in the comboboxes
header_text = header_combobox[0].get()
if header_text[0:3] == " - ":
header_text = header_text[3:] + "(" + header_combobox[1] + ")"
header_combobox[0].set(header_text)
new_columns.append(header_text)
if "(" in header_text or header_text == "":
header_combobox[0].config(style="White.TCombobox",font="Arial 8")
else:
header_combobox[0].config(style="Yellow.TCombobox",font="Arial 8") # bold italic")
if len(new_columns) == clicked_col and not header_text == "":
m = re.search(r"^.*?\((.*)\)$",header_text)
if not m or not m.group(1) == self.old_columns[clicked_col-1]:
new_columns.append(self.old_columns[clicked_col-1])
while new_columns.count("") > 0:
new_columns.remove("")
new_columns.append("")
zaehler = 0
for col in new_columns:
try:
self.header_comboboxes[zaehler][0].set(col)
except:
break
zaehler = zaehler + 1
self.old_columns = new_columns
if not self.actual_report_columns == new_columns: # the comboboxes have to be re-build
o1 = len(self.actual_report_columns)
o2 = len(new_columns)
if not o2 == o1:
if o2 < o1:
while o2 < len(self.header_comboboxes):
self.header_comboboxes[-1][0].destroy()
del self.header_comboboxes[-1]
else:
newcombo = tkinter.ttk.Combobox(self.header,width=21,font=("Arial",8),style="White.TCombobox")
self.header.create_window( sum(self.col_width[:o2-1])+5,5,anchor=tkinter.NW,window=newcombo)
newcombo.config(postcommand=self.update_combo_selection)
exec('self.func_exec = lambda event: self.draw_report_headers(event,'+str(o2)+')', vars())
# print (ff)
# print (777)
newcombo.bind("<<ComboboxSelected>>", self.func_exec)
self.header_comboboxes.append([newcombo,None,None])
self.actual_report_columns = new_columns
self.report_positions = []
zaehler = 0
for col in self.actual_report_columns:
if not col == "":
self.report_positions.append( (zaehler,0,sum(self.col_width[:zaehler])+3,self.col_width[zaehler],col) )
zaehler = zaehler + 1
self.xmax = sum(self.col_width[:zaehler])+10
self.graphproc.storeproc.mark_end()
xdim = self.header.winfo_width()
ydim = self.header.winfo_height()
self.header.config(scrollregion=(0,0,max(xdim,self.xmax),max(ydim,self.ymax)))
ydim = self.report.winfo_height()
self.report.config(scrollregion=(0,0,max(xdim,self.xmax),max(ydim,self.ymax)))
#**************************************************************************
def draw_report (self,cursor,sort_col=""):
if cursor == None:
return(0)
gesamt_val = {}
self.report_rows = []
self.header_options = []
self.ymax = 0
self.header.delete("sortmarker")
while (0 == 0):
report_row = procpy.objpickle.read_obj(cursor)
if not report_row:
break
self.report_rows.append({})
zaehler1 = 0
sort_position = None
if not self.sort_fields:
sort_position = -100
for (nrx,nry,x_pos,x_width,fieldname) in self.report_positions:
if sort_position == None:
zaehler1 = zaehler1 + 1
if self.sort_fields[0] == fieldname:
sort_position = sum(self.col_width[:zaehler1-1])
richtung = (self.sort_klicks[fieldname] % 2) * 14 + 3
self.header.create_oval(sort_position,richtung,sort_position+4,richtung+4,fill="red",tag="sortmarker")
fieldname1 = fieldname
function1 = ""
if fieldname in report_row:
val = report_row[fieldname1]
else:
m = re.search(r"^(\S+?)\((\S+?)\)",fieldname)
if m:
function1 = m.group(1)
fieldname1 = m.group(2)
val = report_row[fieldname1]
if fieldname1 in procpy.config.VIEWOBJ:
self.report_rows[-1][fieldname] = procpy.config.VIEWOBJ[fieldname1](
self.report,self.graphproc.graphmodel,val,function1 )
elif type(val) in (type(1.1),type(1),type(""),type(""),type(None),type([])):
self.report_rows[-1][fieldname] = procpy.config.VIEWOBJ['SCALAR'](
self.report,self.graphproc.graphmodel,val,function1 )
else:
self.report_rows[-1][fieldname] = procpy.config.VIEWOBJ[val.__class__.__name__](
self.report,self.graphproc.graphmodel,val,function1 )
if not fieldname in gesamt_val:
gesamt_val[fieldname] = []
self.report_rows[-1][fieldname].evaluate_type(nrx,nry,x_pos,x_width)
self.report_rows[-1][fieldname].make_gesamt_val( gesamt_val[fieldname] ) # ,len(self.report_rows) )
zaehler = -1
y_offset = 10
# Sortieren. Die Spalten, die in der SQL-Clause zu sortieren gingen, sind schon sortiert.
# Es macht aber nichts, ggfs. doppelt zu sortieren, wenn schon sortiert ist.
def sort_fields_by_value (a,b):
for fieldname in self.sort_fields:
try:
erg = a[fieldname].val - b[fieldname].val
except:
erg = 0
if not erg == 0:
if self.sort_klicks[fieldname] % 2 == 0:
erg = -erg
return( {True:1,False:-1}[erg > 0] )
return(0)
self.report_rows.sort(key=functools.cmp_to_key(sort_fields_by_value))
rf_show = None
for report_row in self.report_rows: # zweiter Durchgang
y_pos = [0.0]
zaehler = zaehler + 1
row_tag = "arow" + ("%06u"%zaehler)
self.report.delete(row_tag)
for fieldname in report_row:
rf = report_row[fieldname]
while len(y_pos) <= rf.nrx:
y_pos.append(0.0)
rf.positioning(rf.x_width,rf.x_pos,y_offset+y_pos[rf.nrx],(row_tag,fieldname,row_tag+"."+fieldname))
y_pos[rf.nrx] = y_pos[rf.nrx] + rf.height
rf.post_fit(gesamt_val[fieldname])
if rf_show == None and fieldname == self.report.rf_col:
rf_show = rf
y_offset = y_offset + max(y_pos)
self.ymax = y_offset
if rf_show and self.report.rf_show and not self.report.rf_show.val == rf_show.val:
if rf_show:
rf_show.press()
self.report.rf_show = rf_show
else:
self.graphproc.graphmodel.hide(0)
self.report.delete("allx")
for fieldname in gesamt_val:
exec('self.func_exec = lambda event: self.sort_field(event,11,"'+fieldname+'")', vars())
self.report.tag_bind(fieldname,'<ButtonPress-1>',self.func_exec)
# exec 'func = lambda event: self.sort_field(event,12,"'+fieldname+'")' in vars()
# self.report.tag_bind(fieldname,'<Double-Button-1>',func)
self.report.addtag_withtag("allx",fieldname)
xdim = self.report.winfo_width()
ydim = self.report.winfo_height()
self.report.config(scrollregion=(0,0,max(xdim,self.xmax),max(ydim,self.ymax+10)))
#**************************************************************************
def xxprepare_view_object (self,obj):
if type(obj) in (type(1.1),type(1),type(""),type("")):
return(procpy.viewobj.Scalar(obj))
#**************************************************************************
def sort_field (self,event,clicktype,fieldname):
self.report.rf_col = fieldname
if clicktype == 11: # Single Klick
if self.clicked11:
self.clicked11 = False # to avoid get fired event by Double Klick
else:
self.after(400,self.sort_field,event,1,fieldname)
self.clicked11 = True
elif clicktype == 1:
if self.clicked11:
self.clicked11 = False
if len(self.sort_fields) > 0 and self.sort_fields[0] == fieldname:
self.sort_klicks[fieldname] = self.sort_klicks[fieldname] + 1
else:
if fieldname in self.sort_fields:
self.sort_fields.remove(fieldname)
self.sort_fields.insert(0,fieldname)
self.sort_klicks[fieldname] = 0
self.graphproc.storeproc.mark_end()
#**************************************************************************