Explorar o código

Dialogue Details: CRUD ok

olivier.massot %!s(int64=7) %!d(string=hai) anos
pai
achega
0b0a2aa211
Modificáronse 10 ficheiros con 299 adicións e 21 borrados
  1. 99 8
      Viewer.py
  2. 20 5
      core.py
  3. 2 5
      qt_details.ui
  4. 101 0
      qt_select_object.ui
  5. BIN=BIN
      rsc/search.png
  6. BIN=BIN
      rsc/warning_16.png
  7. 74 0
      test/source/forms/Chevaliers.bas
  8. 2 2
      test/source/tables/Chevaliers.xml
  9. 1 1
      test/source/tables/tblChateaux.xml
  10. BIN=BIN
      test/test.zip

+ 99 - 8
Viewer.py

@@ -8,15 +8,18 @@ from PyQt5.Qt import Qt, QEvent, QGraphicsScene, QPointF, QFileDialog, \
     QGraphicsTextItem, QGraphicsItem, QGraphicsRectItem, \
     QBrush, QColor, QGraphicsLineItem, QLineF, \
     QPen, QPainter, QSvgGenerator, QSize, QRect, QGraphicsItemGroup, \
-    QGraphicsColorizeEffect, QFont, QDialog, QTableWidgetItem
+    QGraphicsColorizeEffect, QFont, QDialog, QTableWidgetItem, QAbstractItemView, \
+    QListWidgetItem, QFrame, QInputDialog, QIcon, QPixmap
 from PyQt5.QtWidgets import QMainWindow, QGraphicsView
 from path import Path
 
+from core import Mention
 import core
 
 
 Ui_window, _ = uic.loadUiType(Path(__file__).parent / 'qt_viewer.ui')
 Ui_details, _ = uic.loadUiType(Path(__file__).parent / 'qt_details.ui')
+Ui_select, _ = uic.loadUiType(Path(__file__).parent / 'qt_select_object.ui')
 
 palette = {
             "Table": QColor(240, 240, 20),
@@ -503,8 +506,9 @@ class DetailsDialog(QDialog):
 
         self.ui.tbl_mentions.hideColumn(0)
         self.ui.tbl_mentions.setColumnWidth(1, 50)
-        self.ui.tbl_mentions.setColumnWidth(2, 200)
-        self.ui.tbl_mentions.setColumnWidth(3, 70)
+        self.ui.tbl_mentions.setColumnWidth(2, 70)
+        self.ui.tbl_mentions.setColumnWidth(3, 150)
+
 
         self.load_table()
 
@@ -515,6 +519,12 @@ class DetailsDialog(QDialog):
 
         for index, mention in enumerate(self.obj.mentions):
 
+            item = QTableWidgetItem("")
+            if mention.warning:
+                item.setIcon(QIcon(QPixmap(core.here / "rsc\\warning_16.png")))
+                item.setToolTip(mention.warning)
+            self.ui.tbl_mentions.setVerticalHeaderItem(index, item)
+
             item = QTableWidgetItem("")
             item.setData(0, index)
             self.ui.tbl_mentions.setItem(index, 0, item)
@@ -522,10 +532,10 @@ class DetailsDialog(QDialog):
             item = QTableWidgetItem("{}".format(mention.line))
             self.ui.tbl_mentions.setItem(index, 1, item)
 
-            item = QTableWidgetItem("{}".format(mention.objname))
+            item = QTableWidgetItem("{}".format(mention.obj.type_))
             self.ui.tbl_mentions.setItem(index, 2, item)
 
-            item = QTableWidgetItem("{}".format(mention.obj.type_))
+            item = QTableWidgetItem("{}".format(mention.objname))
             self.ui.tbl_mentions.setItem(index, 3, item)
 
             item = QTableWidgetItem("{}".format(mention.quote))
@@ -539,13 +549,50 @@ class DetailsDialog(QDialog):
         self.ui.btn_del.setEnabled(True)
 
     def add_mention(self):
-        pass
+        dlg = ObjectSelectorDialog(parent=self)
+        dlg.show()
+        r = dlg.exec_()
+        if not r:
+            return
+        mention = Mention(0, dlg.obj.name_, "(ajouté manuellement)", dlg.obj)
+
+        linenum, _ = QInputDialog.getInt(self, "Ligne", "Numéro de ligne correspondant dans le code-source? (facultatif)", 0)
+        if linenum > 0:
+            mention.line = linenum
+            try:
+                with open(self.obj.sourcefile, "r", encoding='utf-8') as f:
+                    mention.quote = next((line.strip() for i, line in enumerate(f) if i == linenum - 1)).strip()
+            except FileNotFoundError:
+                pass
+
+        self.obj.mentions.append(mention)
+        self.load_table()
 
     def selected_index(self):
-        return self.ui.tbl_mentions.item(self.ui.tbl_mentions.currentRow(), 0).data(0)
+        row = self.ui.tbl_mentions.currentRow()
+        if row < 0:
+            return None
+        return self.ui.tbl_mentions.item(row, 0).data(0)
 
     def edit_mention(self):
-        pass
+        row = self.ui.tbl_mentions.currentRow()
+        if row < 0:
+            return
+
+        item = QTableWidgetItem("")
+        item.setIcon(QIcon(QPixmap(core.here / "rsc\\edit_16.png")))
+        self.ui.tbl_mentions.setVerticalHeaderItem(row, item)
+
+        index = self.ui.tbl_mentions.item(row, 0).data(0)
+        mention = self.obj.mentions[index]
+
+        dlg = ObjectSelectorDialog(filterStr=mention.objname, parent=self)
+        dlg.show()
+        r = dlg.exec_()
+        if r:
+            mention.obj = dlg.obj
+            mention.warning = ""
+        self.load_table()
 
     def del_mention(self):
         index = self.selected_index()
@@ -557,3 +604,47 @@ class DetailsDialog(QDialog):
     def ok(self):
         self.done(1)
 
+
+class ObjectSelectorDialog(QDialog):
+
+    def __init__(self, filterStr="", parent=None):
+        self.obj = None
+        super (ObjectSelectorDialog, self).__init__(parent)
+        self.createWidgets()
+        self.ui.searchBox.setText(filterStr)
+
+    def createWidgets(self):
+        self.ui = Ui_select()
+        self.ui.setupUi(self)
+
+        for obj in core.Analyse.objects:
+            item = QListWidgetItem("{} - {}".format(obj.type_, obj.name_))
+            item.obj = obj
+            self.ui.listWidget.addItem(item)
+
+        self.ui.searchBox.textChanged.connect(self.filter)
+        self.ui.listWidget.itemClicked.connect(self.itemClicked)
+        self.ui.listWidget.itemDoubleClicked.connect(self.itemDoubleClicked)
+        self.ui.btn_ok.clicked.connect(self.ok)
+
+    def itemClicked(self, item):
+        self.obj = item.obj
+        self.ui.btn_ok.setEnabled(True)
+
+    def itemDoubleClicked(self, item):
+        self.itemClicked(item)
+        self.ok()
+
+    def filter(self, filterStr):
+        for i in range(self.ui.listWidget.count()):
+            item = self.ui.listWidget.item(i)
+            item.setHidden(filterStr.lower() not in item.text().lower())
+
+    def ok(self):
+        self.done(1)
+
+    def done(self, status):
+        if not status:
+            self.obj = None
+        super(ObjectSelectorDialog, self).done(status)
+

+ 20 - 5
core.py

@@ -16,6 +16,9 @@ from path import Path
 # TODO: Stocker un aperçu du contexte de la ou des références dans le code source, pour contrôle ultérieur
 # TODO: Permettre de supprimer / ajouter des réferences
 # TODO: Verifier que la recherche puisse être Case sensitive?
+
+here = Path(__file__).parent.abspath()
+
 def recurse(acc_obj):
     deptree = []
     for dep in acc_obj.deps:
@@ -28,15 +31,17 @@ class InvalidFileExt(IOError):
     pass
 
 class Mention():
-    def __init__(self, line, objname, quote, obj):
+    def __init__(self, line, objname, quote, obj, warning=""):
         self.line = line
         self.objname = objname
         self.quote = quote
         self.obj = obj
+        self.warning = warning
 
 class AccessObject():
     type_ = "<unknown>"
     _valid_file_exts = (".bas")
+    _order = 0
 
     def __init__(self, name_):
         self.name_ = name_
@@ -79,21 +84,27 @@ class AccessObject():
 class TableObject(AccessObject):
     type_ = "Table"
     _valid_file_exts = (".xml", ".lnkd")
+    _order = 10
 
 class QueryObject(AccessObject):
     type_ = "Query"
+    _order = 30
 
 class FormObject(AccessObject):
     type_ = "Form"
+    _order = 40
 
 class ReportObject(AccessObject):
     type_ = "Report"
+    _order = 50
 
 class MacroObject(AccessObject):
     type_ = "Macro"
+    _order = 60
 
 class ModuleObject(AccessObject):
     type_ = "Module"
+    _order = 70
 
     @classmethod
     def from_file(cls, file):
@@ -105,6 +116,7 @@ class ModuleObject(AccessObject):
 class RelationObject(AccessObject):
     type_ = "Relation"
     _valid_file_exts = (".txt")
+    _order = 20
 
 class Analyse():
     objects = []
@@ -155,6 +167,9 @@ class Analyse():
                 except InvalidFileExt:
                     print("Ignored unrecognized file: {}".format(file))
 
+        cls.objects.sort(key=lambda x: (x._order, x.name_))
+
+
     @classmethod
     def parse_source(cls, subject):
 
@@ -167,6 +182,7 @@ class Analyse():
 
         # Indexe la position des lignes
         line_ends = [m.end() for m in re.finditer('.*\n', subject.sourcecode)]
+        warning = ""
 
         for match in rx.finditer(subject.sourcecode):
             line = next(i for i in range(len(line_ends)) if line_ends[i] > match.start(1)) + 1
@@ -176,14 +192,14 @@ class Analyse():
                 obj = cls.index[objname][0]
             else:
                 # plusieurs objets portent le même nom
-                # si l'objet mentionné porte le même nom que le sujet, on part du principe qu'il se mentione lui-même
+                warning = "Plusieurs objets portant ce nom ont été trouvés, vérifiez qu'il s'agit bien de l'objet ci-contre."
                 if objname == subject.name_:
+                    # si l'objet mentionné porte le même nom que le sujet, on part du principe qu'il se mentione lui-même
                     obj = subject
                 else:
                     obj = cls.index[objname][0]
 
-            subject.mentions.append(Mention(line, objname, quote, obj))
-
+            subject.mentions.append(Mention(line, objname, quote, obj, warning))
 
     @classmethod
     def parse_all(cls):
@@ -239,7 +255,6 @@ class Analyse():
 
 if __name__ == "__main__":
 
-    here = Path(__file__).parent.abspath()
     source_dir = here / r"test\source"
     resultfile = here / r"test\analyse.txt"
     resultfile.remove_p()

+ 2 - 5
qt_details.ui

@@ -209,9 +209,6 @@
      <attribute name="horizontalHeaderStretchLastSection">
       <bool>true</bool>
      </attribute>
-     <attribute name="verticalHeaderVisible">
-      <bool>false</bool>
-     </attribute>
      <column>
       <property name="text">
        <string>index</string>
@@ -224,12 +221,12 @@
      </column>
      <column>
       <property name="text">
-       <string>Nom</string>
+       <string>Type</string>
       </property>
      </column>
      <column>
       <property name="text">
-       <string>Type</string>
+       <string>Nom</string>
       </property>
      </column>
      <column>

+ 101 - 0
qt_select_object.ui

@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Dialog</class>
+ <widget class="QDialog" name="Dialog">
+  <property name="windowModality">
+   <enum>Qt::ApplicationModal</enum>
+  </property>
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>275</width>
+    <height>297</height>
+   </rect>
+  </property>
+  <property name="minimumSize">
+   <size>
+    <width>261</width>
+    <height>184</height>
+   </size>
+  </property>
+  <property name="maximumSize">
+   <size>
+    <width>782</width>
+    <height>758</height>
+   </size>
+  </property>
+  <property name="windowTitle">
+   <string>Sélectionner un objet</string>
+  </property>
+  <property name="windowIcon">
+   <iconset>
+    <normaloff>rsc/icon.svg</normaloff>rsc/icon.svg</iconset>
+  </property>
+  <property name="modal">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <property name="leftMargin">
+      <number>2</number>
+     </property>
+     <property name="topMargin">
+      <number>2</number>
+     </property>
+     <property name="rightMargin">
+      <number>2</number>
+     </property>
+     <property name="bottomMargin">
+      <number>2</number>
+     </property>
+     <item>
+      <widget class="QLabel" name="picSearch">
+       <property name="minimumSize">
+        <size>
+         <width>16</width>
+         <height>16</height>
+        </size>
+       </property>
+       <property name="text">
+        <string/>
+       </property>
+       <property name="pixmap">
+        <pixmap>rsc/search.png</pixmap>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLineEdit" name="searchBox">
+       <property name="minimumSize">
+        <size>
+         <width>50</width>
+         <height>20</height>
+        </size>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QListWidget" name="listWidget"/>
+   </item>
+   <item>
+    <widget class="QPushButton" name="btn_ok">
+     <property name="enabled">
+      <bool>false</bool>
+     </property>
+     <property name="text">
+      <string>Sélectionner</string>
+     </property>
+     <property name="default">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

BIN=BIN
rsc/search.png


BIN=BIN
rsc/warning_16.png


+ 74 - 0
test/source/forms/Chevaliers.bas

@@ -0,0 +1,74 @@
+Version =20
+VersionRequired =20
+Begin Form
+    DividingLines = NotDefault
+    AllowDesignChanges = NotDefault
+    DefaultView =0
+    PictureAlignment =2
+    DatasheetGridlinesBehavior =3
+    GridY =10
+    Width =6994
+    DatasheetFontHeight =11
+    ItemSuffix =1
+    Right =14175
+    Bottom =12135
+    DatasheetGridlinesColor =14806254
+    RecSrcDt = Begin
+        0x32ec7f1a8f14e540
+    End
+    DatasheetFontName ="Calibri"
+    FilterOnLoad =0
+    ShowPageMargins =0
+    DisplayOnSharePointSite =1
+    DatasheetAlternateBackColor =15921906
+    DatasheetGridlinesColor12 =0
+    FitToScreen =1
+    DatasheetBackThemeColorIndex =1
+    BorderThemeColorIndex =3
+    ThemeFontIndex =1
+    ForeThemeColorIndex =0
+    AlternateBackThemeColorIndex =1
+    AlternateBackShade =95.0
+    Begin
+        Begin Label
+            BackStyle =0
+            FontSize =11
+            FontName ="Calibri"
+            ThemeFontIndex =1
+            BackThemeColorIndex =1
+            BorderThemeColorIndex =0
+            BorderTint =50.0
+            ForeThemeColorIndex =0
+            ForeTint =50.0
+            GridlineThemeColorIndex =1
+            GridlineShade =65.0
+        End
+        Begin Section
+            Height =5952
+            Name ="Détail"
+            AutoHeight =1
+            AlternateBackColor =15921906
+            AlternateBackThemeColorIndex =1
+            AlternateBackShade =95.0
+            BackThemeColorIndex =1
+            Begin
+                Begin Label
+                    OverlapFlags =85
+                    Left =1360
+                    Top =566
+                    Width =3799
+                    Height =567
+                    BorderColor =8355711
+                    ForeColor =8355711
+                    Name ="Étiquette0"
+                    Caption ="Test de doublon dans les noms"
+                    GridlineColor =10921638
+                    LayoutCachedLeft =1360
+                    LayoutCachedTop =566
+                    LayoutCachedWidth =5159
+                    LayoutCachedHeight =1133
+                End
+            End
+        End
+    End
+End

+ 2 - 2
test/source/tables/Chevaliers.xml

@@ -17,7 +17,7 @@
 "/>
 <od:tableProperty name="Orientation" type="2" value="0"/>
 <od:tableProperty name="OrderByOn" type="1" value="0"/>
-<od:tableProperty name="NameMap" type="11" value="CswOVQAAAACH3XtV+nXLS4096Mv1L9rbAAAAAHucBrPTEuVAAAAAAAAAAABDAGgA
+<od:tableProperty name="NameMap" type="11" value="CswOVQAAAACH3XtV+nXLS4096Mv1L9rbAAAAAMv2XEgWE+VAAAAAAAAAAABDAGgA
 ZQB2AGEAbABpAGUAcgBzAAAAAAAAAMjnyDy/e5JLjAarR06iDUwHAAAAh917Vfp1
 y0uNPejL9S/a22kAZAAAAAAAAACKJMh2B8/HTYmbnQO9cmpHBwAAAIfde1X6dctL
 jT3oy/Uv2ttuAG8AbQAAAAAAAADLxf3XXVY0SIVuj0wdT8ZUBwAAAIfde1X6dctL
@@ -137,5 +137,5 @@ AAAAAAAAAAAAAAAAAAAAAAAADAAAAAUAAAAAAAAAAAAAAAAAAAAAAA==
 </xsd:complexType>
 </xsd:element>
 </xsd:schema>
-<dataroot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" generated="2018-02-27T14:52:41"/>
+<dataroot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" generated="2018-03-13T11:19:48"/>
 </root>

+ 1 - 1
test/source/tables/tblChateaux.xml

@@ -161,5 +161,5 @@ AAAAAAAA
 </xsd:complexType>
 </xsd:element>
 </xsd:schema>
-<dataroot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" generated="2018-02-27T14:52:41"/>
+<dataroot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" generated="2018-03-13T11:19:48"/>
 </root>

BIN=BIN
test/test.zip