|
|
@@ -5,21 +5,180 @@
|
|
|
from PyQt5 import uic
|
|
|
from PyQt5.Qt import Qt, QEvent, QGraphicsScene, QPointF, QFileDialog, \
|
|
|
QApplication, QMessageBox, QTreeWidgetItem, \
|
|
|
- QGraphicsTextItem
|
|
|
+ QGraphicsTextItem, QGraphicsItem, QGraphicsRectItem, \
|
|
|
+ QBrush, QColor, QGraphicsLineItem, QLineF, \
|
|
|
+ QPen, QPainter, QSvgGenerator, QSize, QRect
|
|
|
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(QGraphicsTextItem):
|
|
|
- def __init__(self, obj, parent=None, scene=None):
|
|
|
+ items = []
|
|
|
+ def __init__(self, obj, parent=None):
|
|
|
+ super(GraphicsObject, self).__init__("", parent=parent)
|
|
|
self.obj = obj
|
|
|
- super(GraphicsObject, self).__init__("...", parent=parent)
|
|
|
- self.setHtml("<b>{}</b>".format(obj.nom))
|
|
|
- self.setTextWidth(200)
|
|
|
+ self._text = "[{}] <b>{}</b>".format(obj.type_, obj.nom)
|
|
|
+ self.links = []
|
|
|
+ self._x = 0
|
|
|
+ self._y = 0
|
|
|
+ self.setHtml(self._text)
|
|
|
+
|
|
|
+ self.setTextWidth(cell_width)
|
|
|
+ self.setFlag(QGraphicsItem.ItemIsMovable, True)
|
|
|
+ self.setFlag(QGraphicsItem.ItemIsSelectable, True)
|
|
|
+ self.setFlag(QGraphicsItem.ItemIsFocusable, True)
|
|
|
+
|
|
|
+ self._addRect()
|
|
|
+ self._addAnchors()
|
|
|
+ GraphicsObject.items.append(self)
|
|
|
+
|
|
|
+ def _addRect(self):
|
|
|
+ pen = QPen(palette[self.obj.type_])
|
|
|
+ self.rect = QGraphicsRectItem(self.boundingRect(), parent=self)
|
|
|
+ self.rect.setPen(pen)
|
|
|
+
|
|
|
+ def topAnchorCenter(self):
|
|
|
+ return self.mapToScene(QPointF((self.boundingRect().topLeft().x() + self.boundingRect().topRight().x() / 2), self.boundingRect().topLeft().y()))
|
|
|
+
|
|
|
+ def bottomAnchorCenter(self):
|
|
|
+ return self.mapToScene(QPointF((self.boundingRect().topLeft().x() + self.boundingRect().topRight().x() / 2), self.boundingRect().bottomLeft().y()))
|
|
|
+
|
|
|
+ def _addAnchors(self):
|
|
|
+ x = (self.boundingRect().topLeft().x() + self.boundingRect().topRight().x() / 2)
|
|
|
+ ytop = self.boundingRect().topLeft().y()
|
|
|
+ ybottom = self.boundingRect().bottomLeft().y()
|
|
|
+ self.top_anchor = QGraphicsRectItem(x - 3, ytop - 3, 6, 6, parent=self)
|
|
|
+ self.bottom_anchor = QGraphicsRectItem(x - 3, ybottom - 3, 6, 6, parent=self)
|
|
|
+ self.top_anchor.setBrush(QBrush(QColor(255, 153, 51)))
|
|
|
+ self.bottom_anchor.setBrush(QBrush(QColor(255, 153, 51)))
|
|
|
+
|
|
|
+ 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 = []
|
|
|
+
|
|
|
+ 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):
|
|
|
+ return sum([d.dep_emprise() for d in self.deps]) if self.deps else (cell_width + 2 * cell_spacing)
|
|
|
+
|
|
|
+ def ref_emprise(self):
|
|
|
+ return sum([r.ref_emprise() for r in self.refs]) if self.refs else (cell_width + 2 * cell_spacing)
|
|
|
+
|
|
|
+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
|
|
|
+
|
|
|
+ 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):
|
|
|
+ return sum([d.dep_emprise() for d in self.deps]) if self.deps else (cell_width + 2 * cell_spacing)
|
|
|
+
|
|
|
+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
|
|
|
+
|
|
|
+ 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):
|
|
|
+ return sum([d.ref_emprise() for d in self.refs]) if self.refs else (cell_width + 2 * cell_spacing)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+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):
|
|
|
@@ -36,28 +195,27 @@ class Viewer(QMainWindow):
|
|
|
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.treeWidget.itemClicked.connect(self.itemSelected)
|
|
|
+ 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.setDragMode(QGraphicsView.NoDrag)
|
|
|
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.ui.view.centerOn(QPointF(0, 0))
|
|
|
self.fit_in_view()
|
|
|
|
|
|
-
|
|
|
- def eventFilter(self, obj, event):
|
|
|
+ def eventFilter(self, _, event):
|
|
|
if event.type() == QEvent.Wheel:
|
|
|
if event.angleDelta().y() > 0:
|
|
|
self.zoom_plus()
|
|
|
@@ -75,6 +233,21 @@ class Viewer(QMainWindow):
|
|
|
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)
|
|
|
@@ -84,8 +257,8 @@ class Viewer(QMainWindow):
|
|
|
|
|
|
def run(self):
|
|
|
|
|
|
-# source_dir = QFileDialog.getExistingDirectory(self, "Sélectionner le répertoire des sources", "", QFileDialog.ShowDirsOnly)
|
|
|
- source_dir = r"C:\dev\access\AGRHum\source"
|
|
|
+ source_dir = QFileDialog.getExistingDirectory(self, "Sélectionner le répertoire des sources", "", QFileDialog.ShowDirsOnly)
|
|
|
+# source_dir = r"C:\dev\access\AGRHum\source"
|
|
|
|
|
|
self.ui.progressBar.setVisible(True)
|
|
|
self.ui.lbl_repertoire.setText(source_dir)
|
|
|
@@ -124,9 +297,74 @@ class Viewer(QMainWindow):
|
|
|
self.ui.treeWidget.setColumnHidden(1, True)
|
|
|
self.ui.treeWidget.expandToDepth(1)
|
|
|
|
|
|
- def itemSelected(self, item):
|
|
|
+ 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]
|
|
|
-
|
|
|
- go = GraphicsObject(obj)
|
|
|
- self._scene.addItem(go)
|
|
|
+ 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)
|