olivier.massot преди 7 години
ревизия
d6c8d244fa
променени са 7 файла, в които са добавени 654 реда и са изтрити 0 реда
  1. 5 0
      .gitignore
  2. 2 0
      .settings/org.eclipse.core.resources.prefs
  3. 132 0
      Viewer.py
  4. 133 0
      core.py
  5. BIN
      dossier_32.png
  6. 27 0
      main.py
  7. 355 0
      qt_viewer.ui

+ 5 - 0
.gitignore

@@ -0,0 +1,5 @@
+*.pyc
+.project
+.pydevproject
+Output/
+htmlcov/

+ 2 - 0
.settings/org.eclipse.core.resources.prefs

@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8

+ 132 - 0
Viewer.py

@@ -0,0 +1,132 @@
+'''
+
+'''
+
+from PyQt5 import uic
+from PyQt5.Qt import Qt, QEvent, QGraphicsScene, QPointF, QFileDialog, \
+    QApplication, QMessageBox, QTreeWidgetItem, \
+    QGraphicsTextItem
+from PyQt5.QtWidgets import QMainWindow, QGraphicsView
+from path import Path
+
+import core
+
+
+Ui_window, _ = uic.loadUiType(Path(__file__).parent / 'qt_viewer.ui')
+
+class GraphicsObject(QGraphicsTextItem):
+    def __init__(self, obj, parent=None, scene=None):
+        self.obj = obj
+        super(GraphicsObject, self).__init__("...", parent=parent)
+        self.setHtml("<b>{}</b>".format(obj.nom))
+        self.setTextWidth(200)
+
+
+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_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)
+
+        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):
+        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 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)
+        source_dir = r"C:\dev\access\AGRHum\source"
+
+        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 itemSelected(self, item):
+        index = item.data(1, 0)
+        obj = core.Analyse.objects[index]
+
+        go = GraphicsObject(obj)
+        self._scene.addItem(go)

+ 133 - 0
core.py

@@ -0,0 +1,133 @@
+'''
+
+@author: olivier.massot
+'''
+import re
+
+from path import Path
+
+objects = []
+
+
+SUBSTR = {92: "\\", 47: "/", 58: ":", 42: "*", 63:"?", 34:"\"", 60:"<", 62:">", 124:"|" }
+def path_to_name(path):
+    name_ = path.name.stripext()
+    for ascii_code, char in SUBSTR.items():
+        name_ = name_.replace("[{}]".format(ascii_code), char)
+    return name_
+
+
+RXS = {}
+def getrx(nom):
+    try:
+        return RXS[nom]
+    except KeyError:
+        rx = re.compile(r"(?:^|\W)({})(?:$|\W)".format(nom))
+        RXS[nom] = rx
+        return rx
+
+def recurse(acc_obj):
+    deptree = []
+    for dep in acc_obj.deps:
+        deptree.append(dep)
+        if dep.deps:
+            deptree += recurse(dep)
+    return deptree
+
+class AccessObject():
+    def __init__(self, type_, nom, sourcefile):
+        self.nom = nom
+        self.type_ = type_
+        self.functions = []
+        self.sourcefile = sourcefile
+        self.deps = []
+
+    def __repr__(self):
+        return "<{}: {}>".format(self.type_, self.nom)
+
+    def add_dep(self, obj):
+        if not obj in self.deps:
+            self.deps.append(obj)
+
+    def to_json(self):
+        pass
+
+class Analyse():
+    objects = []
+
+    def __enter__(self):
+        pass
+
+    @staticmethod
+    def report(current, total, msg=""):
+        pass
+
+    @staticmethod
+    def ended():
+        pass
+
+    @classmethod
+    def run(cls, source_dir):
+        source_dir = Path(source_dir)
+
+        cls.objects = []
+
+        # Liste les objets à partir de l'arborescence du repertoire des sources
+        cls.report(0, 100, "Analyse du répertoire")
+
+        for folder in ["queries", "forms", "relations", "reports", "scripts"]:
+            for file in Path(source_dir / folder).files("*.bas"):
+                cls.objects.append(AccessObject(folder, path_to_name(file), file))
+        for file in Path(source_dir / "tables").files("*.xml") + Path(source_dir / "tables").files("*.lnkd"):
+            cls.objects.append(AccessObject("tables", path_to_name(file), file))
+
+        rx = re.compile(r"Sub|Function ([^(]+)\(")
+        for file in Path(source_dir / "modules").files("*.bas"):
+            obj = AccessObject("modules", path_to_name(file), file)
+            obj.functions = [fname for fname in rx.findall(file.text()) if fname]
+            cls.objects.append(obj)
+
+        total = len(cls.objects)
+        cls.report(0, total, "> {} objets trouvés".format(total))
+
+        # met à jour les dependances en listant les noms d'objets mentionnés dans le fichier subject
+        for i, subject in enumerate(cls.objects):
+            cls.report(i, total, "* {}".format(subject.nom))
+
+            source = subject.sourcefile.text()
+            for object_ in cls.objects:
+                if object_ is subject:
+                    continue
+                if getrx(object_.nom).search(source):
+                    subject.add_dep(object_)
+                    continue
+                for fname in object_.functions:
+                    if getrx(fname).search(source):
+                        subject.add_dep(object_)
+                        break
+
+        cls.report(total, total, "Analyse terminée")
+        cls.ended()
+        return cls.objects
+
+
+if __name__ == "__main__":
+    source_dir = Path(r"c:\dev\access\Analytique\source")
+
+    here = Path(__file__).parent.abspath()
+    datafile = here / "access_data.txt"
+    datafile.remove_p()
+
+    def main_report(i, total, msg=""):
+        print(msg)
+    Analyse.report = main_report
+
+    Analyse.run(source_dir)
+
+    with open("data.txt", "w+") as f:
+        for o in Analyse.objects:
+            f.write("* {} - {}{}\n\tdeps > {}\n".format(o.type_,
+                                                        o.nom,
+                                                        "\n\tfunctions > ".format(", ".join(o.functions)) if o.functions else "",
+                                                        o.deps))
+    print("# Terminé")

BIN
dossier_32.png


+ 27 - 0
main.py

@@ -0,0 +1,27 @@
+'''
+Created on 13 mars 2017
+
+@author: olinox
+'''
+import sys
+
+from PyQt5.Qt import QApplication, QMessageBox
+from Viewer import Viewer
+
+# import ipdb
+
+if __name__ == '__main__':
+    app = QApplication(sys.argv)
+    iface = Viewer()
+
+    iface.show()
+
+    SYS_HOOK = sys.excepthook
+    def error_handler(typ, value, trace):
+        QApplication.restoreOverrideCursor()
+        QMessageBox.critical(iface, typ.__name__, "{}".format(value))
+        SYS_HOOK(typ, value, trace)
+    sys.excepthook = error_handler
+
+    r = app.exec_()
+    sys.exit(r)

+ 355 - 0
qt_viewer.ui

@@ -0,0 +1,355 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>window</class>
+ <widget class="QMainWindow" name="window">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>994</width>
+    <height>658</height>
+   </rect>
+  </property>
+  <property name="font">
+   <font>
+    <family>Verdana</family>
+    <pointsize>8</pointsize>
+   </font>
+  </property>
+  <property name="windowTitle">
+   <string>GridViewer</string>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <layout class="QHBoxLayout" name="horizontalLayout" stretch="2">
+    <property name="spacing">
+     <number>3</number>
+    </property>
+    <property name="leftMargin">
+     <number>3</number>
+    </property>
+    <property name="topMargin">
+     <number>3</number>
+    </property>
+    <property name="rightMargin">
+     <number>3</number>
+    </property>
+    <property name="bottomMargin">
+     <number>3</number>
+    </property>
+    <item>
+     <layout class="QVBoxLayout" name="verticalLayout">
+      <property name="spacing">
+       <number>3</number>
+      </property>
+      <item>
+       <widget class="QLabel" name="lbl_title">
+        <property name="font">
+         <font>
+          <weight>75</weight>
+          <bold>true</bold>
+         </font>
+        </property>
+        <property name="focusPolicy">
+         <enum>Qt::StrongFocus</enum>
+        </property>
+        <property name="text">
+         <string>Viewer</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QFrame" name="frame_tools">
+        <property name="minimumSize">
+         <size>
+          <width>0</width>
+          <height>30</height>
+         </size>
+        </property>
+        <property name="frameShape">
+         <enum>QFrame::StyledPanel</enum>
+        </property>
+        <property name="frameShadow">
+         <enum>QFrame::Raised</enum>
+        </property>
+        <layout class="QHBoxLayout" name="horizontalLayout_2">
+         <property name="spacing">
+          <number>3</number>
+         </property>
+         <property name="leftMargin">
+          <number>3</number>
+         </property>
+         <property name="topMargin">
+          <number>3</number>
+         </property>
+         <property name="rightMargin">
+          <number>3</number>
+         </property>
+         <property name="bottomMargin">
+          <number>3</number>
+         </property>
+         <item>
+          <widget class="QPushButton" name="btn_select">
+           <property name="text">
+            <string/>
+           </property>
+           <property name="icon">
+            <iconset>
+             <normaloff>dossier_32.png</normaloff>dossier_32.png</iconset>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QLabel" name="lbl_repertoire">
+           <property name="font">
+            <font>
+             <pointsize>8</pointsize>
+             <italic>true</italic>
+            </font>
+           </property>
+           <property name="text">
+            <string>Veuillez sélectionner le répertoire des sources à analyser</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="horizontalSpacer_3">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item>
+          <widget class="QProgressBar" name="progressBar">
+           <property name="value">
+            <number>24</number>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout_5">
+        <item>
+         <widget class="QGraphicsView" name="view">
+          <property name="font">
+           <font>
+            <stylestrategy>PreferAntialias</stylestrategy>
+           </font>
+          </property>
+          <property name="verticalScrollBarPolicy">
+           <enum>Qt::ScrollBarAsNeeded</enum>
+          </property>
+          <property name="horizontalScrollBarPolicy">
+           <enum>Qt::ScrollBarAsNeeded</enum>
+          </property>
+          <property name="transformationAnchor">
+           <enum>QGraphicsView::AnchorUnderMouse</enum>
+          </property>
+          <property name="resizeAnchor">
+           <enum>QGraphicsView::AnchorUnderMouse</enum>
+          </property>
+          <property name="viewportUpdateMode">
+           <enum>QGraphicsView::BoundingRectViewportUpdate</enum>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QFrame" name="pannel">
+          <property name="minimumSize">
+           <size>
+            <width>300</width>
+            <height>0</height>
+           </size>
+          </property>
+          <property name="maximumSize">
+           <size>
+            <width>300</width>
+            <height>16777215</height>
+           </size>
+          </property>
+          <property name="frameShape">
+           <enum>QFrame::StyledPanel</enum>
+          </property>
+          <property name="frameShadow">
+           <enum>QFrame::Raised</enum>
+          </property>
+          <layout class="QVBoxLayout" name="verticalLayout_2">
+           <property name="leftMargin">
+            <number>3</number>
+           </property>
+           <property name="topMargin">
+            <number>3</number>
+           </property>
+           <property name="rightMargin">
+            <number>3</number>
+           </property>
+           <property name="bottomMargin">
+            <number>3</number>
+           </property>
+           <item>
+            <widget class="QStackedWidget" name="stackedWidget">
+             <property name="currentIndex">
+              <number>1</number>
+             </property>
+             <widget class="QWidget" name="page">
+              <layout class="QVBoxLayout" name="verticalLayout_3">
+               <property name="spacing">
+                <number>0</number>
+               </property>
+               <property name="leftMargin">
+                <number>0</number>
+               </property>
+               <property name="topMargin">
+                <number>0</number>
+               </property>
+               <property name="rightMargin">
+                <number>0</number>
+               </property>
+               <property name="bottomMargin">
+                <number>0</number>
+               </property>
+               <item>
+                <widget class="QTextEdit" name="txtPanel">
+                 <property name="minimumSize">
+                  <size>
+                   <width>0</width>
+                   <height>0</height>
+                  </size>
+                 </property>
+                 <property name="maximumSize">
+                  <size>
+                   <width>16777215</width>
+                   <height>16777215</height>
+                  </size>
+                 </property>
+                 <property name="frameShape">
+                  <enum>QFrame::Box</enum>
+                 </property>
+                 <property name="frameShadow">
+                  <enum>QFrame::Sunken</enum>
+                 </property>
+                </widget>
+               </item>
+              </layout>
+             </widget>
+             <widget class="QWidget" name="page_2">
+              <layout class="QVBoxLayout" name="verticalLayout_4">
+               <property name="spacing">
+                <number>0</number>
+               </property>
+               <property name="leftMargin">
+                <number>0</number>
+               </property>
+               <property name="topMargin">
+                <number>0</number>
+               </property>
+               <property name="rightMargin">
+                <number>0</number>
+               </property>
+               <property name="bottomMargin">
+                <number>0</number>
+               </property>
+               <item>
+                <widget class="QTreeWidget" name="treeWidget">
+                 <attribute name="headerVisible">
+                  <bool>false</bool>
+                 </attribute>
+                 <attribute name="headerCascadingSectionResizes">
+                  <bool>false</bool>
+                 </attribute>
+                 <attribute name="headerDefaultSectionSize">
+                  <number>40</number>
+                 </attribute>
+                 <column>
+                  <property name="text">
+                   <string notr="true">1</string>
+                  </property>
+                 </column>
+                </widget>
+               </item>
+              </layout>
+             </widget>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout_4">
+        <property name="topMargin">
+         <number>0</number>
+        </property>
+        <item>
+         <widget class="QLabel" name="label_3">
+          <property name="text">
+           <string>Zoom</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QToolButton" name="btn_zoom_plus">
+          <property name="text">
+           <string>+</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QToolButton" name="btn_zoom_view">
+          <property name="text">
+           <string>X</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QToolButton" name="btn_zoom_minus">
+          <property name="text">
+           <string>-</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <spacer name="horizontalSpacer_2">
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>40</width>
+            <height>20</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QStatusBar" name="statusbar"/>
+  <action name="actionQuitter">
+   <property name="text">
+    <string>Quitter</string>
+   </property>
+  </action>
+ </widget>
+ <tabstops>
+  <tabstop>btn_zoom_plus</tabstop>
+  <tabstop>btn_zoom_minus</tabstop>
+  <tabstop>lbl_title</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>