Viewer.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. '''
  2. '''
  3. from PyQt5 import uic
  4. from PyQt5.Qt import Qt, QEvent, QGraphicsScene, QPointF, QFileDialog, \
  5. QApplication, QMessageBox, QTreeWidgetItem, \
  6. QGraphicsTextItem, QGraphicsItem, QGraphicsRectItem, \
  7. QBrush, QColor, QGraphicsLineItem, QLineF, \
  8. QPen, QPainter, QSvgGenerator, QSize, QRect, QGraphicsItemGroup, \
  9. QGraphicsColorizeEffect, QFont, QDialog, QTableWidgetItem, QAbstractItemView, \
  10. QListWidgetItem, QFrame, QInputDialog, QIcon, QPixmap
  11. from PyQt5.QtWidgets import QMainWindow, QGraphicsView
  12. from path import Path
  13. from core import Mention
  14. import core
  15. Ui_window, _ = uic.loadUiType(Path(__file__).parent / 'qt_viewer.ui')
  16. Ui_details, _ = uic.loadUiType(Path(__file__).parent / 'qt_details.ui')
  17. Ui_select, _ = uic.loadUiType(Path(__file__).parent / 'qt_select_object.ui')
  18. palette = {
  19. "Table": QColor(240, 240, 20),
  20. "Query": QColor(210, 50, 210),
  21. "Module": QColor(220, 10, 33),
  22. "Relation": QColor(122, 50, 209),
  23. "Report": QColor(25, 10, 220),
  24. "Form": QColor(10, 180, 220),
  25. "Macro": QColor(40, 220, 10),
  26. }
  27. v_spacing = 120
  28. cell_width = 150
  29. cell_spacing = 25
  30. class GraphicsObject(QGraphicsItemGroup):
  31. items = []
  32. def __init__(self, obj, parent=None):
  33. super(GraphicsObject, self).__init__(parent=parent)
  34. self.obj = obj
  35. self.links = []
  36. self._x = 0
  37. self._y = 0
  38. self.setFlag(QGraphicsItem.ItemIsMovable, True)
  39. self.setFlag(QGraphicsItem.ItemIsSelectable, True)
  40. self.setFlag(QGraphicsItem.ItemIsFocusable, True)
  41. self.setAcceptHoverEvents(True)
  42. self.label = QGraphicsTextItem()
  43. self.label.setTextWidth(cell_width)
  44. self.label.setZValue(2)
  45. self.setText()
  46. self.addToGroup(self.label)
  47. pen = QPen(palette[self.obj.type_].darker(150))
  48. pen.setWidth(2)
  49. self.rect = QGraphicsRectItem(self.label.boundingRect())
  50. self.rect.setPen(pen)
  51. self.rect.setBrush(palette[self.obj.type_].lighter(150))
  52. self.rect.setZValue(0)
  53. self.addToGroup(self.rect)
  54. self.topAnchorCoords = ((self.boundingRect().topLeft().x() + self.boundingRect().topRight().x() / 2), self.boundingRect().topLeft().y())
  55. self.bottomAnchorCoords = ((self.boundingRect().topLeft().x() + self.boundingRect().topRight().x() / 2), self.boundingRect().bottomLeft().y())
  56. self.top_anchor = QGraphicsRectItem(self.topAnchorCoords[0] - 3, self.topAnchorCoords[1] - 3, 6, 6)
  57. self.bottom_anchor = QGraphicsRectItem(self.bottomAnchorCoords[0] - 3, self.bottomAnchorCoords[1] - 3, 6, 6)
  58. for anchor in (self.top_anchor, self.bottom_anchor):
  59. anchor.setBrush(QBrush(QColor(255, 153, 51)))
  60. anchor.setZValue(1)
  61. self.addToGroup(anchor)
  62. effect = QGraphicsColorizeEffect()
  63. effect.setColor(QColor(255, 255, 255))
  64. effect.setStrength(0.35)
  65. effect.setEnabled(False)
  66. self.rect.setGraphicsEffect(effect)
  67. self.setToolTip("[{}] '{}'".format(self.obj.type_, self.obj.name_))
  68. GraphicsObject.items.append(self)
  69. def setText(self):
  70. self.label.setHtml(self.html())
  71. def html(self):
  72. return "[{}]<br/><b>{}</b>".format(self.obj.type_,
  73. self.obj.name_)
  74. def topAnchorCenter(self):
  75. return self.mapToScene(QPointF(*self.topAnchorCoords))
  76. def bottomAnchorCenter(self):
  77. return self.mapToScene(QPointF(*self.bottomAnchorCoords))
  78. def update(self):
  79. if self.pos() is not QPointF(self._x, self._y):
  80. self.setPos(QPointF(self._x, self._y))
  81. for l in self.links:
  82. l.update()
  83. def paint(self, *args, **kwargs):
  84. super(GraphicsObject, self).paint(*args, **kwargs)
  85. self._x, self._y = self.pos().x(), self.pos().y()
  86. self.update()
  87. def setShining(self, active):
  88. self.rect.graphicsEffect().setEnabled(active)
  89. def hoverEnterEvent(self, *args, **kwargs):
  90. self.setShining(True)
  91. def hoverLeaveEvent(self, *args, **kwargs):
  92. self.setShining(False)
  93. class GraphicsRootObject(GraphicsObject):
  94. def __init__(self, obj, parent=None):
  95. super(GraphicsRootObject, self).__init__(obj, parent=parent)
  96. self.level = 0
  97. self.deps = []
  98. self.refs = []
  99. self._dep_emprise = 0
  100. self._ref_emprise = 0
  101. pen = QPen(QColor("red"))
  102. pen.setWidth(2)
  103. self.rect.setPen(pen)
  104. def xleft(self):
  105. return 0
  106. def compute_coords(self):
  107. return 0, 0
  108. def dep_emprise(self):
  109. if not self._dep_emprise:
  110. self._dep_emprise = sum([d.dep_emprise() for d in self.deps]) if self.deps else (cell_width + 2 * cell_spacing)
  111. return self._dep_emprise
  112. def ref_emprise(self):
  113. if not self._ref_emprise:
  114. self._ref_emprise = sum([r.ref_emprise() for r in self.refs]) if self.refs else (cell_width + 2 * cell_spacing)
  115. return self._ref_emprise
  116. class GraphicsDepObject(GraphicsObject):
  117. def __init__(self, obj, parentItem, parent=None):
  118. super(GraphicsDepObject, self).__init__(obj, parent=parent)
  119. self.deps = []
  120. self.parentItem = parentItem
  121. if parentItem:
  122. parentItem.deps.append(self)
  123. self.level = parentItem.level + 1
  124. self._dep_emprise = 0
  125. def xleft(self):
  126. x0 = sum([n.dep_emprise() for n in self.parentItem.deps[0:self.parentItem.deps.index(self)]])
  127. return self.parentItem.xleft() + x0
  128. def compute_coords(self):
  129. x0 = sum([n.dep_emprise() for n in self.parentItem.deps[0:self.parentItem.deps.index(self)]])
  130. x = self.parentItem.xleft() + (0.5 * self.dep_emprise() - (cell_width / 2 + cell_spacing)) + x0
  131. y = v_spacing * self.level
  132. return x, y
  133. def dep_emprise(self):
  134. if not self._dep_emprise:
  135. self._dep_emprise = sum([d.dep_emprise() for d in self.deps]) if self.deps else (cell_width + 2 * cell_spacing)
  136. return self._dep_emprise
  137. class GraphicsCloneDepObject(GraphicsDepObject):
  138. def __init__(self, obj, childItem, parent=None):
  139. super(GraphicsCloneDepObject, self).__init__(obj, childItem, parent)
  140. self.bottom_anchor.setBrush(QColor("red"))
  141. self.clone_of = next((item for item in GraphicsObject.items if item.obj is obj
  142. and (type(item) is GraphicsDepObject or type(item) is GraphicsRefObject)))
  143. def html(self):
  144. return "* Clone *<br/>" + super(GraphicsCloneDepObject, self).html()
  145. @property
  146. def deps(self):
  147. return []
  148. @deps.setter
  149. def deps(self, value):
  150. pass
  151. def hoverEnterEvent(self, *args, **kwargs):
  152. self.setShining(True)
  153. self.clone_of.setShining(True)
  154. def hoverLeaveEvent(self, *args, **kwargs):
  155. self.setShining(False)
  156. self.clone_of.setShining(False)
  157. class GraphicsRefObject(GraphicsObject):
  158. def __init__(self, obj, childItem, parent=None):
  159. super(GraphicsRefObject, self).__init__(obj, parent=parent)
  160. self.refs = []
  161. self.childItem = childItem
  162. if childItem:
  163. childItem.refs.append(self)
  164. self.level = childItem.level - 1
  165. self._ref_emprise = 0
  166. def xleft(self):
  167. x0 = sum([n.ref_emprise() for n in self.childItem.refs[0:self.childItem.refs.index(self)]])
  168. return self.childItem.xleft() + x0
  169. def compute_coords(self):
  170. x0 = sum([n.ref_emprise() for n in self.childItem.refs[0:self.childItem.refs.index(self)]])
  171. return self.childItem.xleft() + (0.5 * self.ref_emprise() - (cell_width / 2 + cell_spacing)) + x0, v_spacing * self.level
  172. def ref_emprise(self):
  173. if not self._ref_emprise:
  174. self._ref_emprise = sum([d.ref_emprise() for d in self.refs]) if self.refs else (cell_width + 2 * cell_spacing)
  175. return self._ref_emprise
  176. class GraphicsCloneRefObject(GraphicsRefObject):
  177. def __init__(self, obj, childItem, parent=None):
  178. super(GraphicsCloneRefObject, self).__init__(obj, childItem, parent)
  179. self.top_anchor.setBrush(QColor("red"))
  180. self.clone_of = next((item for item in GraphicsObject.items if item.obj is obj
  181. and (type(item) is GraphicsDepObject or type(item) is GraphicsRefObject)))
  182. def html(self):
  183. return "* Clone *<br/>" + super(GraphicsCloneRefObject, self).html()
  184. @property
  185. def refs(self):
  186. return []
  187. @refs.setter
  188. def refs(self, value):
  189. pass
  190. def hoverEnterEvent(self, *args, **kwargs):
  191. self.setShining(True)
  192. self.clone_of.setShining(True)
  193. def hoverLeaveEvent(self, *args, **kwargs):
  194. self.setShining(False)
  195. self.clone_of.setShining(False)
  196. class GraphicsLink(QGraphicsLineItem):
  197. items = []
  198. def __init__(self, topGraphicsObject, bottomGraphicsObject, parent=None):
  199. self.topGraphicsObject = topGraphicsObject
  200. self.topGraphicsObject.links.append(self)
  201. self.bottomGraphicsObject = bottomGraphicsObject
  202. self.bottomGraphicsObject.links.append(self)
  203. super(QGraphicsLineItem, self).__init__(parent=parent)
  204. self.update()
  205. def update(self):
  206. line = QLineF(self.mapToScene(self.topGraphicsObject.bottomAnchorCenter()), self.mapToScene(self.bottomGraphicsObject.topAnchorCenter()))
  207. self.setLine(line)
  208. class Viewer(QMainWindow):
  209. def __init__(self):
  210. super (Viewer, self).__init__()
  211. self.createWidgets()
  212. def createWidgets(self):
  213. self.ui = Ui_window()
  214. self.ui.setupUi(self)
  215. self.ui.progressBar.setVisible(False)
  216. self.ui.stackedWidget.setCurrentIndex(0)
  217. self.ui.btn_test.clicked.connect(self.test)
  218. self.ui.btn_select.clicked.connect(self.selectSourceDir)
  219. self.ui.btn_zoom_plus.clicked.connect(self.zoom_plus)
  220. self.ui.btn_zoom_minus.clicked.connect(self.zoom_minus)
  221. self.ui.btn_zoom_view.clicked.connect(self.fit_in_view)
  222. self.ui.btn_svg.clicked.connect(self.to_png)
  223. self.ui.treeWidget.itemClicked.connect(self.treeItemSelected)
  224. self.ui.btn_edit_item.clicked.connect(self.edit_selected_item)
  225. self._title = "<unknown>"
  226. core.Analyse.report = self.update_progression
  227. self.ui.view.setViewportUpdateMode(QGraphicsView.BoundingRectViewportUpdate)
  228. self.ui.view.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
  229. self.ui.view.viewport().installEventFilter(self)
  230. self._scene = QGraphicsScene()
  231. self._scene.setItemIndexMethod(QGraphicsScene.BspTreeIndex)
  232. self.ui.view.setScene(self._scene)
  233. helpLabel = QGraphicsTextItem()
  234. helpLabel.setPlainText("Sélectionnez le répertoire contenant les sources de la base à analyser,\npuis sélectionnez dans la liste de droite un objet à partir duquel afficher les dépendances...")
  235. helpLabel.setTextWidth(600)
  236. font = QFont()
  237. font.setItalic(True)
  238. font.setWeight(63)
  239. helpLabel.setFont(font)
  240. self._scene.addItem(helpLabel)
  241. def eventFilter(self, _, event):
  242. if event.type() == QEvent.Wheel:
  243. if event.angleDelta().y() > 0:
  244. self.zoom_plus()
  245. elif event.angleDelta().y() < 0:
  246. self.zoom_minus()
  247. return True
  248. return False
  249. def fit_in_view(self):
  250. rect = self._scene.itemsBoundingRect()
  251. rect.adjust(-50, -50, 50, 50)
  252. self._scene.setSceneRect(rect)
  253. self.ui.view.fitInView(self._scene.sceneRect(), Qt.KeepAspectRatio)
  254. def zoom_plus(self):
  255. self.ui.view.scale(1.2, 1.2)
  256. def zoom_minus(self):
  257. self.ui.view.scale(0.8, 0.8)
  258. def to_png(self):
  259. fileName, _ = QFileDialog.getSaveFileName(self, "Save File", "", "Svg File (*.svg)")
  260. if not fileName:
  261. return
  262. gen = QSvgGenerator()
  263. gen.setFileName(fileName)
  264. gen.setSize(QSize(1000, 1000))
  265. gen.setViewBox(QRect(0, 0, 1000, 1000))
  266. gen.setTitle("Access Analyser")
  267. gen.setDescription("Access Analyser Report for {}".format(self._title))
  268. painter = QPainter(gen)
  269. self._scene.render(painter)
  270. painter.end()
  271. def update_progression(self, i, total, msg=""):
  272. self.ui.progressBar.setMaximum(total)
  273. self.ui.progressBar.setValue(i)
  274. if msg:
  275. self.ui.txtPanel.append(msg)
  276. QApplication.processEvents()
  277. def selectSourceDir(self):
  278. source_dir = QFileDialog.getExistingDirectory(self, "Sélectionner le répertoire des sources", "", QFileDialog.ShowDirsOnly)
  279. if not source_dir:
  280. return
  281. self.run(source_dir)
  282. def run(self, source_dir):
  283. source_dir = Path(source_dir)
  284. self._title = source_dir
  285. self.ui.progressBar.setVisible(True)
  286. self.ui.lbl_repertoire.setText(source_dir)
  287. self.ui.txtPanel.clear()
  288. self.ui.treeWidget.clear()
  289. QApplication.setOverrideCursor(Qt.WaitCursor)
  290. core.Analyse.run(source_dir)
  291. QApplication.restoreOverrideCursor()
  292. QMessageBox.information(self, "Analyse", "Analyse terminée: {} objets chargés en mémoire".format(len(core.Analyse.objects)))
  293. if core.Analyse.duplicates():
  294. QMessageBox.warning(self, "Risque d'instabilités", "Attention! Des doublons ont été trouvés dans les noms des objets")
  295. self.ui.progressBar.setVisible(False)
  296. self.ui.stackedWidget.setCurrentIndex(1)
  297. self.ui.txtPanel.clear()
  298. topitem = QTreeWidgetItem()
  299. topitem.setText(0, "Objets")
  300. self.ui.treeWidget.addTopLevelItem(topitem)
  301. groupes = {}
  302. for index, obj in enumerate(core.Analyse.objects):
  303. if not obj.type_ in groupes:
  304. item = QTreeWidgetItem()
  305. item.setText(0, obj.type_)
  306. groupes[obj.type_] = item
  307. topitem.addChild(item)
  308. item = QTreeWidgetItem()
  309. item.setText(0, obj.name_)
  310. item.setData(1, 0, index)
  311. groupes[obj.type_].addChild(item)
  312. self.ui.treeWidget.setColumnHidden(1, True)
  313. self.ui.treeWidget.expandToDepth(1)
  314. def clear_scene(self):
  315. self._scene.clear()
  316. GraphicsObject.items = []
  317. def maj_scene_with(self, root_object):
  318. self.clear_scene()
  319. root = GraphicsRootObject(root_object)
  320. self._scene.addItem(root)
  321. def _addDeps(go):
  322. for dep in go.obj.deps:
  323. if dep not in [go.obj for go in GraphicsObject.items]:
  324. gdep = GraphicsDepObject(dep, go)
  325. if dep.deps:
  326. _addDeps(gdep)
  327. else:
  328. gdep = GraphicsCloneDepObject(dep, go)
  329. self._scene.addItem(gdep)
  330. link = GraphicsLink(go, gdep)
  331. self._scene.addItem(link)
  332. _addDeps(root)
  333. def _addRefs(go):
  334. for ref in go.obj.refs:
  335. if ref not in [go.obj for go in GraphicsObject.items]:
  336. gref = GraphicsRefObject(ref, go)
  337. if ref.refs:
  338. _addRefs(gref)
  339. else:
  340. gref = GraphicsCloneRefObject(ref, go)
  341. self._scene.addItem(gref)
  342. link = GraphicsLink(gref, go)
  343. self._scene.addItem(link)
  344. _addRefs(root)
  345. for item in GraphicsObject.items:
  346. item._x, item._y = item.compute_coords()
  347. if isinstance(item, GraphicsDepObject):
  348. item._x -= (root.dep_emprise() - (cell_width + 2 * cell_spacing)) / 2
  349. if isinstance(item, GraphicsRefObject):
  350. item._x -= (root.ref_emprise() - (cell_width + 2 * cell_spacing)) / 2
  351. item.update()
  352. self.ui.btn_save.setEnabled(True)
  353. self.fit_in_view()
  354. def treeItemSelected(self, item):
  355. index = item.data(1, 0)
  356. if index is None:
  357. self.ui.btn_edit_item.setEnabled(False)
  358. return
  359. obj = core.Analyse.objects[index]
  360. self.maj_scene_with(obj)
  361. self.ui.btn_edit_item.setEnabled(True)
  362. def edit_selected_item(self):
  363. index = self.ui.treeWidget.currentItem().data(1, 0)
  364. obj = core.Analyse.objects[index]
  365. dlg = DetailsDialog(obj, self)
  366. dlg.show()
  367. r = dlg.exec_()
  368. if r:
  369. core.Analyse.build_trees()
  370. self.maj_scene_with(obj)
  371. def test(self):
  372. self.run(Path(__file__).parent / r"test\source")
  373. def keyPressEvent(self, e):
  374. if e.key() == Qt.Key_Control:
  375. self.ui.view.setDragMode(QGraphicsView.ScrollHandDrag)
  376. e.accept()
  377. def keyReleaseEvent(self, e):
  378. if e.key() == Qt.Key_Control:
  379. self.ui.view.setDragMode(QGraphicsView.RubberBandDrag)
  380. class DetailsDialog(QDialog):
  381. def __init__(self, obj, parent=None):
  382. self.obj = obj
  383. super (DetailsDialog, self).__init__(parent)
  384. self.createWidgets()
  385. def createWidgets(self):
  386. self.ui = Ui_details()
  387. self.ui.setupUi(self)
  388. self.ui.tbl_mentions.itemClicked.connect(self.itemClicked)
  389. self.ui.btn_add.clicked.connect(self.add_mention)
  390. self.ui.btn_edit.clicked.connect(self.edit_mention)
  391. self.ui.btn_del.clicked.connect(self.del_mention)
  392. self.ui.btn_ok.clicked.connect(self.ok)
  393. self.ui.lbl_title.setText("{}: {}".format(self.obj.type_, self.obj.name_))
  394. self.ui.tbl_mentions.hideColumn(0)
  395. self.ui.tbl_mentions.setColumnWidth(1, 50)
  396. self.ui.tbl_mentions.setColumnWidth(2, 70)
  397. self.ui.tbl_mentions.setColumnWidth(3, 150)
  398. self.load_table()
  399. def load_table(self):
  400. self.ui.tbl_mentions.setSortingEnabled(False)
  401. self.ui.tbl_mentions.clearContents()
  402. self.ui.tbl_mentions.setRowCount(len(self.obj.mentions))
  403. for index, mention in enumerate(self.obj.mentions):
  404. item = QTableWidgetItem("")
  405. if mention.warning:
  406. item.setIcon(QIcon(QPixmap(core.here / "rsc\\warning_16.png")))
  407. item.setToolTip(mention.warning)
  408. self.ui.tbl_mentions.setVerticalHeaderItem(index, item)
  409. item = QTableWidgetItem("")
  410. item.setData(0, index)
  411. self.ui.tbl_mentions.setItem(index, 0, item)
  412. item = QTableWidgetItem("{}".format(mention.line))
  413. self.ui.tbl_mentions.setItem(index, 1, item)
  414. item = QTableWidgetItem("{}".format(mention.obj.type_))
  415. self.ui.tbl_mentions.setItem(index, 2, item)
  416. item = QTableWidgetItem("{}".format(mention.objname))
  417. self.ui.tbl_mentions.setItem(index, 3, item)
  418. item = QTableWidgetItem("{}".format(mention.quote))
  419. item.setFont(QFont("Consolas", 8))
  420. self.ui.tbl_mentions.setItem(index, 4, item)
  421. self.ui.tbl_mentions.setSortingEnabled(True)
  422. def itemClicked(self):
  423. self.ui.btn_edit.setEnabled(True)
  424. self.ui.btn_del.setEnabled(True)
  425. def add_mention(self):
  426. dlg = ObjectSelectorDialog(parent=self)
  427. dlg.show()
  428. r = dlg.exec_()
  429. if not r:
  430. return
  431. mention = Mention(0, dlg.obj.name_, "(ajouté manuellement)", dlg.obj)
  432. linenum, _ = QInputDialog.getInt(self, "Ligne", "Numéro de ligne correspondant dans le code-source? (facultatif)", 0)
  433. if linenum > 0:
  434. mention.line = linenum
  435. try:
  436. with open(self.obj.sourcefile, "r", encoding='utf-8') as f:
  437. mention.quote = next((line.strip() for i, line in enumerate(f) if i == linenum - 1)).strip()
  438. except FileNotFoundError:
  439. pass
  440. self.obj.mentions.append(mention)
  441. self.load_table()
  442. def selected_index(self):
  443. row = self.ui.tbl_mentions.currentRow()
  444. if row < 0:
  445. return None
  446. return self.ui.tbl_mentions.item(row, 0).data(0)
  447. def edit_mention(self):
  448. row = self.ui.tbl_mentions.currentRow()
  449. if row < 0:
  450. return
  451. item = QTableWidgetItem("")
  452. item.setIcon(QIcon(QPixmap(core.here / "rsc\\edit_16.png")))
  453. self.ui.tbl_mentions.setVerticalHeaderItem(row, item)
  454. index = self.ui.tbl_mentions.item(row, 0).data(0)
  455. mention = self.obj.mentions[index]
  456. dlg = ObjectSelectorDialog(filterStr=mention.objname, parent=self)
  457. dlg.show()
  458. r = dlg.exec_()
  459. if r:
  460. mention.obj = dlg.obj
  461. mention.warning = ""
  462. self.load_table()
  463. def del_mention(self):
  464. index = self.selected_index()
  465. if not QMessageBox.question(self, "Confirmation", "Etes-vous sûr de vouloir supprimer la référence sélectionnée?") == QMessageBox.Yes:
  466. return
  467. del self.obj.mentions[index]
  468. self.load_table()
  469. def ok(self):
  470. self.done(1)
  471. class ObjectSelectorDialog(QDialog):
  472. def __init__(self, filterStr="", parent=None):
  473. self.obj = None
  474. super (ObjectSelectorDialog, self).__init__(parent)
  475. self.createWidgets()
  476. self.ui.searchBox.setText(filterStr)
  477. def createWidgets(self):
  478. self.ui = Ui_select()
  479. self.ui.setupUi(self)
  480. for obj in core.Analyse.objects:
  481. item = QListWidgetItem("{} - {}".format(obj.type_, obj.name_))
  482. item.obj = obj
  483. self.ui.listWidget.addItem(item)
  484. self.ui.searchBox.textChanged.connect(self.filter)
  485. self.ui.listWidget.itemClicked.connect(self.itemClicked)
  486. self.ui.listWidget.itemDoubleClicked.connect(self.itemDoubleClicked)
  487. self.ui.btn_ok.clicked.connect(self.ok)
  488. def itemClicked(self, item):
  489. self.obj = item.obj
  490. self.ui.btn_ok.setEnabled(True)
  491. def itemDoubleClicked(self, item):
  492. self.itemClicked(item)
  493. self.ok()
  494. def filter(self, filterStr):
  495. for i in range(self.ui.listWidget.count()):
  496. item = self.ui.listWidget.item(i)
  497. item.setHidden(filterStr.lower() not in item.text().lower())
  498. def ok(self):
  499. self.done(1)
  500. def done(self, status):
  501. if not status:
  502. self.obj = None
  503. super(ObjectSelectorDialog, self).done(status)