Commit 1afafa6b authored by Guillaume Sabbagh's avatar Guillaume Sabbagh
Browse files
parents d589263b d0d45491
...@@ -131,7 +131,6 @@ class Model: ...@@ -131,7 +131,6 @@ class Model:
""" """
def exporterGraphviz(self, uids): def exporterGraphviz(self, uids):
data=self.getObject(uids) data=self.getObject(uids)
with ThreadPoolExecutor(max_workers=len(data)) as executor: with ThreadPoolExecutor(max_workers=len(data)) as executor:
for index, row in data.iterrows(): for index, row in data.iterrows():
obj=row["object"] obj=row["object"]
...@@ -153,8 +152,7 @@ class Description: ...@@ -153,8 +152,7 @@ class Description:
return self._str return self._str
def generer(self): def generer(self):
mo=ModelObjects.get(self._obj) if issubclass(type(self._obj), Categorie):
if mo==ModelObjects.GC:
return self._genererDescriptionCategorie() return self._genererDescriptionCategorie()
else: else:
return str(self._obj) return str(self._obj)
...@@ -165,15 +163,15 @@ class Description: ...@@ -165,15 +163,15 @@ class Description:
`limite_fleches` est le nombre maximal de flèches entre deux objets qu'on s'autorise à afficher. `limite_fleches` est le nombre maximal de flèches entre deux objets qu'on s'autorise à afficher.
""" """
descr="" descr=""
if self._obj.nom:
descr+=self._obj.nom
# objets # objets
descr+=" {" descr+=" {"
print(self)
for o in self._obj.objets: for o in self._obj.objets:
descr+=str(o)+"," descr+=str(o)+","
descr=descr[:-1]+"}" if(len(self._obj.objets)>0):
descr=descr[:-1]+"}"
else:
descr+="}"
# flesches # flesches
fleches_elem = set(self._obj[self._obj.objets,self._obj.objets]) fleches_elem = set(self._obj[self._obj.objets,self._obj.objets])
...@@ -211,11 +209,18 @@ class Description: ...@@ -211,11 +209,18 @@ class Description:
if WARNING_LIMITE_FLECHES_ATTEINTE: if WARNING_LIMITE_FLECHES_ATTEINTE:
print("Warning : limite fleches entre "+str(source)+" et "+str(cible)+" atteinte.") print("Warning : limite fleches entre "+str(source)+" et "+str(cible)+" atteinte.")
break break
descr+=" flèches: " descr+=" {"
flag=False
for f in fleches_non_elementaires: for f in fleches_non_elementaires:
descr+=f descr+=f+","
flag=True
for f in fleches_elementaires: for f in fleches_elementaires:
descr+=f descr+=f+","
flag=True
if flag:
descr=descr[:-1]+"}"
else:
descr+="}"
return descr return descr
......
...@@ -4,20 +4,35 @@ ...@@ -4,20 +4,35 @@
class Parameters(): class Parameters():
"""
///////////////////// TK
"""
# Frames
FRAME_BD=2
# Section frame
SECTION_COLOR = "#649BB4" SECTION_COLOR = "#649BB4"
SECTION_RELIEF="groove" SECTION_RELIEF="groove"
SECTION_FONT_SIZE = 10 SECTION_FONT_SIZE = 10
SECTION_FONT_WEIGHT = 'bold' SECTION_FONT_WEIGHT = 'bold'
SECTION_FONT_UNDERLINE= 0 SECTION_FONT_UNDERLINE= 0
FRAME_BD=2 # Inform frame
INFORM_BG='#C0C0C0' INFORM_BG='#C0C0C0'
INFORM_FG='black' INFORM_FG='black'
# Export frame
ExportAsDialog_BG='white' ExportAsDialog_BG='white'
HIGHLIGHTCOLOR_BUTTON="#649BB4" HIGHLIGHTCOLOR_BUTTON="#649BB4"
"""
///////////////////// NetworkX
"""
# Graph
NODE_COLOR='#000000'
EDGE_ELEMENTARY_COLOR='#000000'
EDGE_NO_ELEMENTARY_COLOR='#0033FF'
parameters=Parameters() parameters=Parameters()
...@@ -3,9 +3,9 @@ ...@@ -3,9 +3,9 @@
from tkinter import Tk, YES, BOTH from tkinter import Tk, YES, BOTH
from tko.TkOglWin import TkOglWin from ogl.TkOglWin import TkOglWin
from oglWrap.ogl_hdr import GL_BLEND, GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, GL_DEPTH_TEST, \ from ogl.oglWrap.ogl_hdr import GL_BLEND, GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, GL_DEPTH_TEST, \
GL_MODELVIEW, GL_ONE_MINUS_SRC_ALPHA, GL_PROJECTION, GL_QUADS, GL_RENDERER, \ GL_MODELVIEW, GL_ONE_MINUS_SRC_ALPHA, GL_PROJECTION, GL_QUADS, GL_RENDERER, \
GL_SRC_ALPHA, GL_VENDOR, GL_VERSION, \ GL_SRC_ALPHA, GL_VENDOR, GL_VERSION, \
glBegin, glClear, glBlendFunc, glClearColor, \ glBegin, glClear, glBlendFunc, glClearColor, \
......
/* in MainWindow */
from ogl.AppOgl import AppOgl
_glFrame=None
...
def _initFrames(self):
...
# OGL frame
self._glFrame=Frame(self._frame)
self._glFrame.grid(row=0, column=0, sticky="nesw")
self.initGLApp()
...
def initGLApp(self):
self._glApp=AppOgl(self._glFrame, width=320, height=200)
self._glApp.pack(expand = YES, fill=BOTH)
\ No newline at end of file
...@@ -10,14 +10,14 @@ from tkinter import Frame ...@@ -10,14 +10,14 @@ from tkinter import Frame
import sys import sys
if sys.platform.startswith('win32'): if sys.platform.startswith('win32'):
from oglWrap.win32_gdi import PFD_DRAW_TO_WINDOW, PFD_SUPPORT_OPENGL, PFD_DOUBLEBUFFER, PFD_TYPE_RGBA, \ from ogl.oglWrap.win32_gdi import PFD_DRAW_TO_WINDOW, PFD_SUPPORT_OPENGL, PFD_DOUBLEBUFFER, PFD_TYPE_RGBA, \
PixelFormatDescriptor, get_dc, choose_pixel_format, set_pixel_format, \ PixelFormatDescriptor, get_dc, choose_pixel_format, set_pixel_format, \
get_pixel_format, swap_buffers get_pixel_format, swap_buffers
from oglWrap.ogl_hdr import wglCreateContext, wglMakeCurrent from ogl.oglWrap.ogl_hdr import wglCreateContext, wglMakeCurrent
elif sys.platform.startswith('linux'): elif sys.platform.startswith('linux'):
from oglWrap.x11_gdi import X11_None, x_open_display from ogl.oglWrap.x11_gdi import X11_None, x_open_display
from oglWrap.ogl_hdr import PGLint, GLX_RGBA, GLX_DEPTH_SIZE, GLX_DOUBLEBUFFER, GL_TRUE, \ from ogl.oglWrap.ogl_hdr import PGLint, GLX_RGBA, GLX_DEPTH_SIZE, GLX_DOUBLEBUFFER, GL_TRUE, \
GLX_BLUE_SIZE, GLX_GREEN_SIZE, GLX_RED_SIZE, \ GLX_BLUE_SIZE, GLX_GREEN_SIZE, GLX_RED_SIZE, \
glXChooseVisual, glXCreateContext, glXMakeCurrent, glXSwapBuffers glXChooseVisual, glXCreateContext, glXMakeCurrent, glXSwapBuffers
......
"""entry point for Tkinter Window with OpenGL]
"""
from itertools import product
from tkinter import TOP, X, YES, BOTH, \
Frame, Label
from Categorie import Categorie
from tk.Factory import *
from Parameters import parameters
import matplotlib.pyplot as plt
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
import networkx as nx
class PlotFrame(Frame):
_controller=None
_plot=None
_canvas=None
def __init__(self, parent, controller, *args, **kwargs):
assert controller
Frame.__init__(self, parent, *args, **kwargs)
self._controller=controller
self.columnconfigure(0, weight=1, minsize=200)
self.rowconfigure(0, minsize=20)
self.rowconfigure(1, weight=1, minsize=100)
self._initFrame()
def _initFrame(self):
factory.buildSectionLabel(self,"Visualisation NetworkX").grid(row=0, column=0, sticky="nwe")
G = nx.fast_gnp_random_graph(n=10, p=0.5,directed=True)
# draw
f = Figure(figsize=(5,5), dpi=100)
self._plot=f.add_subplot(111)
self._plot.cla()
nx.draw_networkx(G, ax=self._plot, pos=nx.random_layout(G), node_color='r', edge_color='b')
self._canvas = FigureCanvasTkAgg(f, master=self)
self._canvas.draw()
toolbar = NavigationToolbar2Tk(self._canvas, self, pack_toolbar=False)
toolbar.update()
toolbar.grid(row=2, column=0, sticky="nswe")
self._canvas.get_tk_widget().grid(row=1, column=0, sticky="nswe")
def setGraph(self, graph:nx.Graph):
self._plot.cla()
if callable(getattr(graph,"check_planarity",None)) and graph.check_planarity()[0]:
nx.draw_networkx(graph, ax=self._plot, pos=nx.planar_layout(graph))
else:
nx.draw_networkx(graph, ax=self._plot, pos=nx.random_layout(graph))
self._canvas.draw()
class GraphGenerator:
"""
Static
Construit le nx.Graph associé à un objet par la fonction 'give(object)'
"""
def give(obj) -> nx.Graph:
if issubclass(type(obj), Categorie):
return GraphGenerator._genererGrapheCategorie(obj)
else:
print(f"Impossible de générer le graphe de l'objet: {obj}")
"""
GENERATEURS PAR CLASSE
"""
def _genererGrapheCategorie(cat,
afficher_identites:bool = True,
complet:bool = True,
limite_fleches:int = 30)-> nx.Graph:
"""
@param complet: - si True affiche toutes les flèches;
- si False affiche seulement les flèches élémentaires.
@param limite_fleches: nombre maximal de flèches entre deux objets.
"""
G = nx.MultiDiGraph()
G.add_nodes_from(cat.objets, color=parameters.NODE_COLOR)
#pos = nx.spring_layout(G)
# flesches
fleches_elem = set(cat[cat.objets,cat.objets])
if complet:
func = lambda x,y : cat({x},{y})
else:
func = lambda x,y : cat[{x},{y}]
for source,cible in product(cat.objets,repeat=2):
nb_fleches = 0
for fleche in func(source,cible):
if afficher_identites or not fleche.is_identite:
if fleche.source not in cat.objets:
raise Exception("Source d'une fleche pas dans les objets de la categorie.")
if fleche.cible not in cat.objets:
raise Exception("Source d'une fleche pas dans les objets de la categorie.")
if len({obj for obj in cat.objets if obj == fleche.source}) > 1:
raise Exception("Plus d'un objet de la catégorie est source de la fleche.")
if len({obj for obj in cat.objets if obj == fleche.cible}) > 1:
raise Exception("Plus d'un objet de la catégorie est cible de la fleche.")
#permet d'avoir toujours un objet de la catégorie comme source
source = {obj for obj in cat.objets if obj == fleche.source}.pop()
#permet d'avoir toujours un objet de la catégorie comme cible
cible = {obj for obj in cat.objets if obj == fleche.cible}.pop()
# descriptions
if fleche in fleches_elem:
G.add_edge(str(source),str(cible),
color=parameters.EDGE_ELEMENTARY_COLOR,
label=str(fleche))
else:
G.add_edge(str(source),str(cible),
color=parameters.EDGE_NO_ELEMENTARY_COLOR,
label=str(fleche))
nb_fleches += 1
if nb_fleches > limite_fleches:
if WARNING_LIMITE_FLECHES_ATTEINTE:
print("Warning : limite fleches entre "+str(source)+" et "+str(cible)+" atteinte.")
break
return G
\ No newline at end of file
...@@ -4,9 +4,9 @@ from tkinter import TOP, YES, BOTH, X, \ ...@@ -4,9 +4,9 @@ from tkinter import TOP, YES, BOTH, X, \
filedialog, messagebox filedialog, messagebox
from Parameters import parameters from Parameters import parameters
from tko.AppOgl import AppOgl
from tk.OutilsFrame import OutilsFrame from tk.OutilsFrame import OutilsFrame
from tk.ObjetsFrame import ObjetsFrame from tk.ObjetsFrame import ObjetsFrame
from plot.PlotFrame import PlotFrame
class MainWindow: class MainWindow:
...@@ -16,9 +16,10 @@ class MainWindow: ...@@ -16,9 +16,10 @@ class MainWindow:
def getRoot(self): return self._root def getRoot(self): return self._root
_frame=None _frame=None
_glFrame=None _plotFrame=None
_outFrame=None _outFrame=None
_objFrame=None _objFrame=None
def getPlotFrame(self): return self._plotFrame
_glApp=None _glApp=None
_menu=None _menu=None
...@@ -46,11 +47,6 @@ class MainWindow: ...@@ -46,11 +47,6 @@ class MainWindow:
self._root.config(bg = "#787878") self._root.config(bg = "#787878")
def _initFrames(self): def _initFrames(self):
# main frame
#test
#b=Button(self._root, text="test", command=lambda:self._controller.test(self._root))
#b.pack(fill=X)
# Frame # Frame
self._frame = Frame(self._root) self._frame = Frame(self._root)
self._frame.pack(expand=YES, fill=BOTH) self._frame.pack(expand=YES, fill=BOTH)
...@@ -59,24 +55,19 @@ class MainWindow: ...@@ -59,24 +55,19 @@ class MainWindow:
self._frame.columnconfigure(2, weight=2, minsize=200) self._frame.columnconfigure(2, weight=2, minsize=200)
self._frame.rowconfigure(0, weight=1, minsize=300) self._frame.rowconfigure(0, weight=1, minsize=300)
# OGL frame # Plot frame
self._glFrame=Frame(self._frame) self._plotFrame=PlotFrame(self._frame, self._controller)
self._glFrame.grid(row=0, column=0, sticky="nesw") self._plotFrame.grid(row=0, column=0, sticky="nesw")
self.initGLApp()
# Outils frame # Outils frame
self._outFrame = OutilsFrame(self._frame, self._controller) self._outFrame = OutilsFrame(self._frame, self._controller)
self._outFrame.grid(row=0, column=1, sticky="nesw") self._outFrame.grid(row=0, column=1, sticky="nesw")
# Objets frame # Objets frame
self._objFrame = ObjetsFrame(self._frame, self._controller) self._objFrame = ObjetsFrame(self._frame, self._controller, self)
self._objFrame.grid(row=0, column=2, sticky="nesw") self._objFrame.grid(row=0, column=2, sticky="nesw")
def initGLApp(self):
self._glApp=AppOgl(self._glFrame, width=320, height=200)
self._glApp.pack(expand = YES, fill=BOTH)
def _initMenu(self): def _initMenu(self):
self._menu=Menu() self._menu=Menu()
...@@ -137,7 +128,31 @@ class MainWindow: ...@@ -137,7 +128,31 @@ class MainWindow:
uids=self._objFrame.getSelectedObjects() uids=self._objFrame.getSelectedObjects()
self._controller.getModel().exporterGraphviz(uids) self._controller.getModel().exporterGraphviz(uids)
def exportObjectsGraphviz(self, uids):
print(f"ddz{uids}")
self._controller.getModel().exporterGraphviz(uids)
"""
EXPORTS DIALOG CLASS
"""
class ExportAsDialog(Toplevel): class ExportAsDialog(Toplevel):
_registered=None _registered=None
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
""" """
from pandas import DataFrame from pandas import DataFrame
from tkinter import TOP, X, NO, W, Y, YES, BOTH, RIGHT, VERTICAL, \ from tkinter import TOP, X, NO, W, Y, YES, BOTH, RIGHT, VERTICAL, \
Frame, Label Frame, Label, Menu
from tkinter.ttk import Treeview, Style, Scrollbar from tkinter.ttk import Treeview, Style, Scrollbar
from ModelCallable import ModelCallable from ModelCallable import ModelCallable
...@@ -12,23 +12,30 @@ from Model import Description ...@@ -12,23 +12,30 @@ from Model import Description
from tk.InformFrame import InformFrame from tk.InformFrame import InformFrame
from tk.Factory import * from tk.Factory import *
from plot.PlotFrame import GraphGenerator
class ObjetsFrame(Frame, ModelCallable): class ObjetsFrame(Frame, ModelCallable):
_controller=None _controller=None
_mainWindow=None
_tree=None _tree=None
_scrollbarY=None _scrollbarY=None
_informFrame=None _informFrame=None
_popupMenu=None
_popupObjectIid=None
_folders={} _folders={}
def __init__(self, parent, controller, *args, **kwargs): def __init__(self, parent, controller, mainWindow, *args, **kwargs):
assert controller assert controller and mainWindow
Frame.__init__(self, parent, *args, **kwargs) Frame.__init__(self, parent, *args, **kwargs)
self._controller=controller self._controller=controller
self._controller.getModel().registerModelCallable(self) self._controller.getModel().registerModelCallable(self)
self._mainWindow=mainWindow
self.columnconfigure(0, weight=1, minsize=100) self.columnconfigure(0, weight=1, minsize=100)
self.columnconfigure(1, minsize=16)#default value of scrollbar width self.columnconfigure(1, minsize=16)#default value of scrollbar width
...@@ -54,7 +61,7 @@ class ObjetsFrame(Frame, ModelCallable): ...@@ -54,7 +61,7 @@ class ObjetsFrame(Frame, ModelCallable):
self._tree["columns"]=("class","description") self._tree["columns"]=("class","description")
self._tree.column("#0", width=100, minwidth=15, stretch=False) self._tree.column("#0", width=100, minwidth=15, stretch=False)
self._tree.column("class", width=50, stretch=False) self._tree.column("class", width=15, stretch=False)
self._tree.column("description", width=200, minwidth=80, stretch=True) self._tree.column("description", width=200, minwidth=80, stretch=True)
self._tree.heading("#0",text="UID",anchor=W) self._tree.heading("#0",text="UID",anchor=W)
...@@ -64,9 +71,19 @@ class ObjetsFrame(Frame, ModelCallable): ...@@ -64,9 +71,19 @@ class ObjetsFrame(Frame, ModelCallable):
self._tree.bind("<<TreeviewSelect>>", self.objectSelection) self._tree.bind("<<TreeviewSelect>>", self.objectSelection)
self._tree.bind("<Delete>", self.objectSelection) self._tree.bind("<Delete>", self.objectSelection)
# popup tree menu
self._popupMenu = Menu(self._tree, tearoff=0)
self._popupMenu.add_command(label="NetworkX",
command=self.toNetworkX)
self._popupMenu.add_command(label="Graphviz",
command=self.toGraphviz)
self._tree.bind("<Button-3>", self.popup) # Button-2 on Aqua
# INFORM # INFORM
self._informFrame=InformFrame(self) self._informFrame=InformFrame(self)
self._informFrame.grid(row=2, columnspan = 2, column=0, sticky="nesw") self._informFrame.grid(row=2, columnspan = 2, column=0, sticky="nesw")
""" """
GETTERS GETTERS
""" """
...@@ -132,7 +149,7 @@ class ObjetsFrame(Frame, ModelCallable): ...@@ -132,7 +149,7 @@ class ObjetsFrame(Frame, ModelCallable):
""" """
BIND FUNCTIONS BIND FUNCTIONS/MENU FUNCTIONS
""" """
def objectSelection(self, event): def objectSelection(self, event):
curItems = self._tree.selection() curItems = self._tree.selection()
...@@ -147,7 +164,30 @@ class ObjetsFrame(Frame, ModelCallable): ...@@ -147,7 +164,30 @@ class ObjetsFrame(Frame, ModelCallable):
self._informFrame.setText(text) self._informFrame.setText(text)
def objectDelete(self, event): def objectDelete(self, event):
print(self._tree.focus()) pass
def popup(self, event):
try:
iid = self._tree.identify_row(event.y)
if iid:
self._popupMenu.tk_popup(event.x_root, event.y_root, 0)
if self._tree.parent(iid):
self._popupObjectIid=int(iid)
else:
pass
finally:
self._popupMenu.grab_release()
def toNetworkX(self):
if self._popupObjectIid is not None:
self._mainWindow.getPlotFrame().setGraph(GraphGenerator.give(self._controller.getModel().