'''
'''
from PyQt5 import uic
from PyQt5.Qt import Qt, QEvent, QGraphicsScene, QPointF, QFileDialog, \
QApplication, QMessageBox, QTreeWidgetItem, \
QGraphicsTextItem, QGraphicsItem, QGraphicsRectItem, \
QBrush, QColor, QGraphicsLineItem, QLineF, \
QPen, QPainter, QSvgGenerator, QSize, QRect, QGraphicsItemGroup
from PyQt5.QtWidgets import QMainWindow, QGraphicsView
from path import Path
from core import AccessObject
import core
Ui_window, _ = uic.loadUiType(Path(__file__).parent / 'qt_viewer.ui')
palette = {
"tables": QColor(240, 240, 20),
"queries": QColor(210, 50, 210),
"modules": QColor(220, 10, 33),
"relations": QColor(122, 50, 209),
"reports": QColor(25, 10, 220),
"forms": QColor(10, 180, 220),
"scripts": QColor(40, 220, 10),
}
v_spacing = 120
cell_width = 150
cell_spacing = 25
class GraphicsObject(QGraphicsItemGroup):
items = []
def __init__(self, obj, parent=None):
super(GraphicsObject, self).__init__(parent=parent)
self.obj = obj
self._text = "[{}]
{}".format(obj.type_, obj.nom)
self.links = []
self._x = 0
self._y = 0
self.setFlag(QGraphicsItem.ItemIsMovable, True)
self.setFlag(QGraphicsItem.ItemIsSelectable, True)
self.setFlag(QGraphicsItem.ItemIsFocusable, True)
self.label = QGraphicsTextItem()
self.label.setHtml(self._text)
self.label.setTextWidth(cell_width)
self.label.setZValue(2)
self.addToGroup(self.label)
pen = QPen(palette[self.obj.type_].darker(150))
pen.setWidth(2)
self.rect = QGraphicsRectItem(self.label.boundingRect())
self.rect.setPen(pen)
self.rect.setBrush(palette[self.obj.type_].lighter(150))
self.rect.setZValue(0)
self.addToGroup(self.rect)
self.topAnchorCoords = ((self.boundingRect().topLeft().x() + self.boundingRect().topRight().x() / 2), self.boundingRect().topLeft().y())
self.bottomAnchorCoords = ((self.boundingRect().topLeft().x() + self.boundingRect().topRight().x() / 2), self.boundingRect().bottomLeft().y())
self.top_anchor = QGraphicsRectItem(self.topAnchorCoords[0] - 3, self.topAnchorCoords[1] - 3, 6, 6)
self.bottom_anchor = QGraphicsRectItem(self.bottomAnchorCoords[0] - 3, self.bottomAnchorCoords[1] - 3, 6, 6)
for anchor in (self.top_anchor, self.bottom_anchor):
anchor.setBrush(QBrush(QColor(255, 153, 51)))
anchor.setZValue(1)
self.addToGroup(anchor)
GraphicsObject.items.append(self)
def topAnchorCenter(self):
return self.mapToScene(QPointF(*self.topAnchorCoords))
def bottomAnchorCenter(self):
return self.mapToScene(QPointF(*self.bottomAnchorCoords))
def update(self):
if self.pos() is not QPointF(self._x, self._y):
self.setPos(QPointF(self._x, self._y))
for l in self.links:
l.update()
def paint(self, *args, **kwargs):
super(GraphicsObject, self).paint(*args, **kwargs)
self._x, self._y = self.pos().x(), self.pos().y()
self.update()
class GraphicsRootObject(GraphicsObject):
def __init__(self, obj, parent=None):
super(GraphicsRootObject, self).__init__(obj, parent=parent)
self.level = 0
self.deps = []
self.refs = []
self._dep_emprise = 0
self._ref_emprise = 0
def xleft(self):
return 0
# def compute_coords(self):
# return 0, 0
def compute_coords(self):
return (0.5 * self.emprise() - (cell_width / 2 + cell_spacing)), 0
def emprise(self):
return max([self.dep_emprise(), self.ref_emprise()])
def dep_emprise(self):
if not self._dep_emprise:
self._dep_emprise = sum([d.dep_emprise() for d in self.deps]) if self.deps else (cell_width + 2 * cell_spacing)
return self._dep_emprise
def ref_emprise(self):
if not self._ref_emprise:
self._ref_emprise = sum([r.ref_emprise() for r in self.refs]) if self.refs else (cell_width + 2 * cell_spacing)
return self._ref_emprise
class GraphicsDepObject(GraphicsObject):
def __init__(self, obj, parentItem, parent=None):
super(GraphicsDepObject, self).__init__(obj, parent=parent)
self.deps = []
self.parentItem = parentItem
if parentItem:
parentItem.deps.append(self)
self.level = parentItem.level + 1
self._dep_emprise = 0
def xleft(self):
x0 = sum([n.dep_emprise() for n in self.parentItem.deps[0:self.parentItem.deps.index(self)]])
return self.parentItem.xleft() + x0
def compute_coords(self):
x0 = sum([n.dep_emprise() for n in self.parentItem.deps[0:self.parentItem.deps.index(self)]])
x = self.parentItem.xleft() + (0.5 * self.dep_emprise() - (cell_width / 2 + cell_spacing)) + x0
y = v_spacing * self.level
return x, y
def dep_emprise(self):
if not self._dep_emprise:
self._dep_emprise = sum([d.dep_emprise() for d in self.deps]) if self.deps else (cell_width + 2 * cell_spacing)
return self._dep_emprise
class GraphicsRefObject(GraphicsObject):
def __init__(self, obj, childItem, parent=None):
super(GraphicsRefObject, self).__init__(obj, parent=parent)
self.refs = []
self.childItem = childItem
if childItem:
childItem.refs.append(self)
self.level = childItem.level - 1
self._ref_emprise = 0
def xleft(self):
x0 = sum([n.ref_emprise() for n in self.childItem.refs[0:self.childItem.refs.index(self)]])
return self.childItem.xleft() + x0
def compute_coords(self):
x0 = sum([n.ref_emprise() for n in self.childItem.refs[0:self.childItem.refs.index(self)]])
return self.childItem.xleft() + (0.5 * self.ref_emprise() - (cell_width / 2 + cell_spacing)) + x0, v_spacing * self.level
def ref_emprise(self):
if not self._ref_emprise:
self._ref_emprise = sum([d.ref_emprise() for d in self.refs]) if self.refs else (cell_width + 2 * cell_spacing)
return self._ref_emprise
class GraphicsLink(QGraphicsLineItem):
items = []
def __init__(self, topGraphicsObject, bottomGraphicsObject, parent=None):
self.topGraphicsObject = topGraphicsObject
self.topGraphicsObject.links.append(self)
self.bottomGraphicsObject = bottomGraphicsObject
self.bottomGraphicsObject.links.append(self)
super(QGraphicsLineItem, self).__init__(parent=parent)
self.update()
def update(self):
line = QLineF(self.mapToScene(self.topGraphicsObject.bottomAnchorCenter()), self.mapToScene(self.bottomGraphicsObject.topAnchorCenter()))
self.setLine(line)
def select(self, active):
pen = QPen()
if active:
pen.setColor(QColor("blue"))
pen.setWidth(2)
else:
pen.setColor(QColor("black"))
pen.setWidth(1)
self.setPen(pen)
class Viewer(QMainWindow):
def __init__(self):
super (Viewer, self).__init__()
self.createWidgets()
# ## UI related methods
def createWidgets(self):
self.ui = Ui_window()
self.ui.setupUi(self)
self.ui.progressBar.setVisible(False)
self.ui.stackedWidget.setCurrentIndex(0)
self.ui.btn_test.clicked.connect(self.test)
self.ui.btn_select.clicked.connect(self.run)
self.ui.btn_zoom_plus.clicked.connect(self.zoom_plus)
self.ui.btn_zoom_minus.clicked.connect(self.zoom_minus)
self.ui.btn_zoom_view.clicked.connect(self.fit_in_view)
self.ui.btn_save.clicked.connect(self.save_to_png)
self.ui.treeWidget.itemClicked.connect(self.treeItemSelected)
core.Analyse.report = self.update_progression
self.ui.view.setViewportUpdateMode(QGraphicsView.BoundingRectViewportUpdate)
self.ui.view.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
self.ui.view.viewport().installEventFilter(self)
self._scene = QGraphicsScene()
self._scene.setItemIndexMethod(QGraphicsScene.BspTreeIndex)
self.ui.view.setScene(self._scene)
self.fit_in_view()
def eventFilter(self, _, event):
if event.type() == QEvent.Wheel:
if event.angleDelta().y() > 0:
self.zoom_plus()
elif event.angleDelta().y() < 0:
self.zoom_minus()
return True
return False
def fit_in_view(self):
self.ui.view.fitInView(self._scene.sceneRect(), Qt.KeepAspectRatio)
def zoom_plus(self):
self.ui.view.scale(1.2, 1.2)
def zoom_minus(self):
self.ui.view.scale(0.8, 0.8)
def save_to_png(self):
fileName, _ = QFileDialog.getSaveFileName(self, "Save File", "", "Svg File (*.svg)")
if not fileName:
return
gen = QSvgGenerator()
gen.setFileName(fileName)
gen.setSize(QSize(1000, 1000))
gen.setViewBox(QRect(0, 0, 1000, 1000))
gen.setTitle("SVG Generator Example Drawing")
gen.setDescription("An SVG drawing created by the SVG Generator "
"Example provided with Qt.")
painter = QPainter(gen)
self._scene.render(painter)
painter.end()
def update_progression(self, i, total, msg=""):
self.ui.progressBar.setMaximum(total)
self.ui.progressBar.setValue(i)
if msg:
self.ui.txtPanel.append(msg)
QApplication.processEvents()
def run(self):
source_dir = QFileDialog.getExistingDirectory(self, "Sélectionner le répertoire des sources", "", QFileDialog.ShowDirsOnly)
self.ui.progressBar.setVisible(True)
self.ui.lbl_repertoire.setText(source_dir)
self.ui.txtPanel.clear()
self.ui.treeWidget.clear()
QApplication.setOverrideCursor(Qt.WaitCursor)
core.Analyse.run(source_dir)
QApplication.restoreOverrideCursor()
QMessageBox.information(self, "test", "{} objets chargés".format(len(core.Analyse.objects)))
self.ui.progressBar.setVisible(False)
self.ui.stackedWidget.setCurrentIndex(1)
self.ui.txtPanel.clear()
topitem = QTreeWidgetItem()
topitem.setText(0, "Objets")
self.ui.treeWidget.addTopLevelItem(topitem)
groupes = {}
for index, obj in enumerate(core.Analyse.objects):
if not obj.type_ in groupes:
item = QTreeWidgetItem()
item.setText(0, obj.type_)
groupes[obj.type_] = item
topitem.addChild(item)
item = QTreeWidgetItem()
item.setText(0, obj.nom)
item.setData(1, 0, index)
groupes[obj.type_].addChild(item)
self.ui.treeWidget.setColumnHidden(1, True)
self.ui.treeWidget.expandToDepth(1)
def clear_scene(self):
self._scene.clear()
GraphicsObject.items = []
def maj_scene_with(self, root_object):
self.clear_scene()
root = GraphicsRootObject(root_object)
self._scene.addItem(root)
def _addDeps(go):
for dep in go.obj.deps:
if dep in [go.obj for go in GraphicsObject.items]:
print("ref circulaire: {}".format(dep))
continue
gdep = GraphicsDepObject(dep, go)
self._scene.addItem(gdep)
link = GraphicsLink(go, gdep)
self._scene.addItem(link)
if dep.deps:
_addDeps(gdep)
_addDeps(root)
def _addRefs(go):
for ref in go.obj.refs:
if ref in [go.obj for go in GraphicsObject.items]:
print("ref circulaire: {}".format(ref))
continue
gref = GraphicsRefObject(ref, go)
self._scene.addItem(gref)
link = GraphicsLink(gref, go)
self._scene.addItem(link)
if ref.refs:
_addRefs(gref)
_addRefs(root)
for item in GraphicsObject.items:
item._x, item._y = item.compute_coords()
item.update()
self.ui.btn_save.setEnabled(True)
self.fit_in_view()
def treeItemSelected(self, item):
index = item.data(1, 0)
obj = core.Analyse.objects[index]
self.maj_scene_with(obj)
def test(self):
a = AccessObject("queries", "testA_", "")
b = AccessObject("queries", "testB", "")
c = AccessObject("tables", "testC", "")
d = AccessObject("tables", "testD", "")
e = AccessObject("modules", "testE", "")
f = AccessObject("relations", "testF", "")
g = AccessObject("reports", "testG", "")
h = AccessObject("forms", "testH", "")
i = AccessObject("scripts", "testI", "")
j = AccessObject("reports", "testJ", "")
k = AccessObject("forms", "testK", "")
l = AccessObject("scripts", "testL", "")
b.deps = [e, f, g]
c.deps = [h, i]
a.deps = [b, c, d]
j.refs = [k, l]
a.refs = [j]
self.maj_scene_with(a)
def keyPressEvent(self, e):
if e.key() == Qt.Key_Control:
self.ui.view.setDragMode(QGraphicsView.ScrollHandDrag)
e.accept()
def keyReleaseEvent(self, e):
if e.key() == Qt.Key_Control:
self.ui.view.setDragMode(QGraphicsView.RubberBandDrag)