itkdb-gtk 0.0.3__py3-none-any.whl → 0.20.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- itkdb_gtk/{sendShipments.py → CreateShipments.py} +74 -78
- itkdb_gtk/{getShipments.py → GetShipments.py} +99 -106
- itkdb_gtk/GlueWeight.py +45 -66
- itkdb_gtk/ITkDB.desktop +8 -0
- itkdb_gtk/ITkDB.svg +380 -0
- itkdb_gtk/ITkDBlogin.py +10 -6
- itkdb_gtk/ITkDButils.py +295 -57
- itkdb_gtk/PanelVisualInspection.py +590 -0
- itkdb_gtk/QRScanner.py +120 -0
- itkdb_gtk/SensorUtils.py +492 -0
- itkdb_gtk/ShowAttachments.py +267 -0
- itkdb_gtk/ShowComments.py +94 -0
- itkdb_gtk/ShowDefects.py +103 -0
- itkdb_gtk/UploadModuleIV.py +566 -0
- itkdb_gtk/UploadMultipleTests.py +746 -0
- itkdb_gtk/UploadTest.py +509 -0
- itkdb_gtk/VisualInspection.py +297 -0
- itkdb_gtk/WireBondGui.py +1304 -0
- itkdb_gtk/__init__.py +38 -12
- itkdb_gtk/dashBoard.py +292 -33
- itkdb_gtk/dbGtkUtils.py +356 -75
- itkdb_gtk/findComponent.py +242 -0
- itkdb_gtk/findVTRx.py +36 -0
- itkdb_gtk/readGoogleSheet.py +1 -2
- itkdb_gtk/untrash_component.py +35 -0
- {itkdb_gtk-0.0.3.dist-info → itkdb_gtk-0.20.1.dist-info}/METADATA +21 -12
- itkdb_gtk-0.20.1.dist-info/RECORD +30 -0
- {itkdb_gtk-0.0.3.dist-info → itkdb_gtk-0.20.1.dist-info}/WHEEL +1 -1
- itkdb_gtk-0.20.1.dist-info/entry_points.txt +12 -0
- itkdb_gtk/checkComponent.py +0 -131
- itkdb_gtk/groundingTest.py +0 -225
- itkdb_gtk/readAVSdata.py +0 -565
- itkdb_gtk/uploadPetalInformation.py +0 -604
- itkdb_gtk/uploadTest.py +0 -384
- itkdb_gtk-0.0.3.dist-info/RECORD +0 -19
- itkdb_gtk-0.0.3.dist-info/entry_points.txt +0 -7
- {itkdb_gtk-0.0.3.dist-info → itkdb_gtk-0.20.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""PB/Hybrid panel Visual inspection GUI.."""
|
|
3
|
+
import sys
|
|
4
|
+
import copy
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
import itkdb_gtk
|
|
9
|
+
|
|
10
|
+
except ImportError:
|
|
11
|
+
cwd = Path(__file__).parent.parent
|
|
12
|
+
sys.path.append(cwd.as_posix())
|
|
13
|
+
|
|
14
|
+
from itkdb_gtk import dbGtkUtils, ITkDBlogin, ITkDButils, QRScanner
|
|
15
|
+
from itkdb_gtk.ShowComments import ShowComments
|
|
16
|
+
from itkdb_gtk.ShowDefects import ShowDefects
|
|
17
|
+
from itkdb_gtk.UploadTest import create_json_data_editor
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
import gi
|
|
21
|
+
gi.require_version("Gtk", "3.0")
|
|
22
|
+
from gi.repository import Gtk, Gdk, Gio, GObject
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class TestJson(GObject.Object):
|
|
26
|
+
"""To store test JSOn."""
|
|
27
|
+
__gtype_name__ = "TestJson"
|
|
28
|
+
|
|
29
|
+
def __init__(self, js=None):
|
|
30
|
+
super().__init__()
|
|
31
|
+
self.js = copy.deepcopy(js)
|
|
32
|
+
|
|
33
|
+
def set_js(self, js):
|
|
34
|
+
"""SEts the dictionary"""
|
|
35
|
+
self.js = copy.deepcopy(js)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class PanelVisualInspection(dbGtkUtils.ITkDBWindow):
|
|
39
|
+
"""PB/Hybryd panel visual inspection GUI."""
|
|
40
|
+
SN, ORDER, PASSED, N_FILES, F_LIST, TEST_J, ALL = range(7)
|
|
41
|
+
F_DEFECT, F_NAME, F_PATH = range(3)
|
|
42
|
+
|
|
43
|
+
def __init__(self, session, title="PanelVisualInspection", help_link=None):
|
|
44
|
+
super().__init__(title=title,
|
|
45
|
+
session=session,
|
|
46
|
+
show_search="Find object with given SN.",
|
|
47
|
+
help_link=help_link)
|
|
48
|
+
|
|
49
|
+
self.institute = self.pdb_user["institutions"][0]["code"]
|
|
50
|
+
self.global_image = None
|
|
51
|
+
self.global_link = None
|
|
52
|
+
|
|
53
|
+
# action button in header
|
|
54
|
+
button = Gtk.Button()
|
|
55
|
+
icon = Gio.ThemedIcon(name="document-send-symbolic")
|
|
56
|
+
image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.BUTTON)
|
|
57
|
+
button.add(image)
|
|
58
|
+
button.set_tooltip_text("Click to upload ALL tests.")
|
|
59
|
+
button.connect("clicked", self.upload_tests)
|
|
60
|
+
self.hb.pack_end(button)
|
|
61
|
+
|
|
62
|
+
grid = Gtk.Grid(column_spacing=5, row_spacing=1)
|
|
63
|
+
self.mainBox.pack_start(grid, False, False, 5)
|
|
64
|
+
|
|
65
|
+
irow = 0
|
|
66
|
+
receiver = self.create_institute_combo(only_user=True)
|
|
67
|
+
receiver.connect("changed", self.on_institute)
|
|
68
|
+
receiver.set_tooltip_text("Select the Institute making the test.")
|
|
69
|
+
dbGtkUtils.set_combo_iter(receiver, self.institute)
|
|
70
|
+
|
|
71
|
+
lbl = Gtk.Label(label="Institute")
|
|
72
|
+
lbl.set_xalign(0)
|
|
73
|
+
grid.attach(lbl, 0, irow, 1, 1)
|
|
74
|
+
grid.attach(receiver, 1, irow, 1, 1)
|
|
75
|
+
|
|
76
|
+
irow += 1
|
|
77
|
+
lbl = Gtk.Label(label="Serial Number")
|
|
78
|
+
lbl.set_xalign(0)
|
|
79
|
+
grid.attach(lbl, 0, irow, 1, 1)
|
|
80
|
+
|
|
81
|
+
self.SN = dbGtkUtils.TextEntry(small=True)
|
|
82
|
+
self.SN.connect("text_changed", self.SN_ready)
|
|
83
|
+
self.SN.widget.set_tooltip_text("Enter SN of PWD or Hybrid panel.")
|
|
84
|
+
grid.attach(self.SN.widget, 1, irow, 1, 1)
|
|
85
|
+
|
|
86
|
+
self.panel_type = Gtk.Label(label="")
|
|
87
|
+
grid.attach(self.panel_type, 2, irow, 1, 1)
|
|
88
|
+
|
|
89
|
+
irow += 1
|
|
90
|
+
lbl = Gtk.Label(label="Date")
|
|
91
|
+
lbl.set_xalign(0)
|
|
92
|
+
grid.attach(lbl, 0, irow, 1, 1)
|
|
93
|
+
|
|
94
|
+
self.date = dbGtkUtils.TextEntry(small=True)
|
|
95
|
+
grid.attach(self.date.widget, 1, irow, 1, 1)
|
|
96
|
+
self.date.entry.set_text(ITkDButils.get_db_date())
|
|
97
|
+
self.date.connect("text_changed", self.new_date)
|
|
98
|
+
|
|
99
|
+
irow += 1
|
|
100
|
+
self.fC = Gtk.FileChooserButton()
|
|
101
|
+
self.fC.connect("file-set", self.on_global_image)
|
|
102
|
+
|
|
103
|
+
lbl = Gtk.Label(label="Global Image")
|
|
104
|
+
lbl.set_xalign(0)
|
|
105
|
+
grid.attach(lbl, 0, irow, 1, 1)
|
|
106
|
+
grid.attach(self.fC, 1, irow, 1, 1)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
# Paned object
|
|
110
|
+
paned = Gtk.Paned(orientation=Gtk.Orientation.VERTICAL)
|
|
111
|
+
paned.set_size_request(-1, 200)
|
|
112
|
+
self.mainBox.pack_start(paned, True, True, 5)
|
|
113
|
+
|
|
114
|
+
# the list of attachments
|
|
115
|
+
tree_view = self.create_tree_view()
|
|
116
|
+
paned.add1(tree_view)
|
|
117
|
+
|
|
118
|
+
# The text view
|
|
119
|
+
paned.add2(self.message_panel.frame)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
self.show_all()
|
|
123
|
+
self.scanner = QRScanner.QRScanner(self.get_qrcode)
|
|
124
|
+
|
|
125
|
+
def on_global_image(self, *args):
|
|
126
|
+
"""We choose the global image."""
|
|
127
|
+
fnam = self.fC.get_filename()
|
|
128
|
+
if fnam is None or not Path(fnam).exists():
|
|
129
|
+
dbGtkUtils.complain("Could not find image", fnam, parent=self)
|
|
130
|
+
return
|
|
131
|
+
|
|
132
|
+
self.global_image = Path(fnam).expanduser().resolve()
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def on_institute(self, combo):
|
|
137
|
+
"""A new recipient has been chosen."""
|
|
138
|
+
name = self.get_institute_from_combo(combo)
|
|
139
|
+
if name:
|
|
140
|
+
self.institute = name
|
|
141
|
+
|
|
142
|
+
def new_date(self, entry, value):
|
|
143
|
+
"""new date given at input."""
|
|
144
|
+
d = dbGtkUtils.parse_date_as_string(value)
|
|
145
|
+
if d is not None:
|
|
146
|
+
self.date.set_text(d)
|
|
147
|
+
|
|
148
|
+
def create_model(self):
|
|
149
|
+
"""Create tree view model."""
|
|
150
|
+
return Gtk.ListStore(str, int, bool, int, Gtk.ListStore, TestJson)
|
|
151
|
+
|
|
152
|
+
def create_file_model(self):
|
|
153
|
+
"""Create model for file list"""
|
|
154
|
+
return Gtk.ListStore(str, str, str)
|
|
155
|
+
|
|
156
|
+
def create_tree_view(self, size=150):
|
|
157
|
+
"""Create the TreeView with the children."""
|
|
158
|
+
model = self.create_model()
|
|
159
|
+
self.tree = Gtk.TreeView(model=model)
|
|
160
|
+
self.tree.connect("button-press-event", self.button_pressed)
|
|
161
|
+
|
|
162
|
+
scrolled = Gtk.ScrolledWindow()
|
|
163
|
+
scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
|
|
164
|
+
scrolled.add(self.tree)
|
|
165
|
+
scrolled.set_size_request(-1, size)
|
|
166
|
+
|
|
167
|
+
renderer = Gtk.CellRendererText()
|
|
168
|
+
column = Gtk.TreeViewColumn("SN", renderer, text=PanelVisualInspection.SN)
|
|
169
|
+
self.tree.append_column(column)
|
|
170
|
+
|
|
171
|
+
renderer = Gtk.CellRendererText()
|
|
172
|
+
column = Gtk.TreeViewColumn("position", renderer, text=PanelVisualInspection.ORDER)
|
|
173
|
+
self.tree.append_column(column)
|
|
174
|
+
|
|
175
|
+
renderer = Gtk.CellRendererToggle()
|
|
176
|
+
renderer.set_property("activatable", True)
|
|
177
|
+
renderer.set_property("radio", True)
|
|
178
|
+
renderer.set_padding(5, 0)
|
|
179
|
+
|
|
180
|
+
_, y = renderer.get_alignment()
|
|
181
|
+
renderer.set_alignment(0, y)
|
|
182
|
+
# renderer.set_property("inconsistent", True)
|
|
183
|
+
renderer.connect("toggled", self.btn_toggled)
|
|
184
|
+
|
|
185
|
+
column = Gtk.TreeViewColumn("Passed", renderer, active=PanelVisualInspection.PASSED)
|
|
186
|
+
self.tree.append_column(column)
|
|
187
|
+
|
|
188
|
+
renderer = Gtk.CellRendererText()
|
|
189
|
+
column = Gtk.TreeViewColumn("N. Images", renderer, text=PanelVisualInspection.N_FILES)
|
|
190
|
+
self.tree.append_column(column)
|
|
191
|
+
|
|
192
|
+
return scrolled
|
|
193
|
+
|
|
194
|
+
def btn_toggled(self, renderer, path, *args):
|
|
195
|
+
"""Toggled."""
|
|
196
|
+
model = self.tree.get_model()
|
|
197
|
+
val = not model[path][PanelVisualInspection.PASSED]
|
|
198
|
+
model[path][PanelVisualInspection.PASSED] = val
|
|
199
|
+
model[path][PanelVisualInspection.TEST_J].js["passed"] = val
|
|
200
|
+
|
|
201
|
+
def get_iter_at_position(self, tree, event):
|
|
202
|
+
"""Get the model and iterator at position."""
|
|
203
|
+
# Create popup menu
|
|
204
|
+
select = tree.get_selection()
|
|
205
|
+
model, lv_iter = select.get_selected()
|
|
206
|
+
values = None
|
|
207
|
+
if lv_iter:
|
|
208
|
+
values = model[lv_iter]
|
|
209
|
+
|
|
210
|
+
else:
|
|
211
|
+
P = tree.get_path_at_pos(event.x, event.y)
|
|
212
|
+
if P:
|
|
213
|
+
lv_iter = model.get_iter(P[0])
|
|
214
|
+
values = model[lv_iter]
|
|
215
|
+
|
|
216
|
+
return model, lv_iter, values
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def button_pressed(self, tree, event):
|
|
220
|
+
"""Button pressed on tree view."""
|
|
221
|
+
# Create popup menu
|
|
222
|
+
model, lv_iter, values = self.get_iter_at_position(tree, event)
|
|
223
|
+
if not values:
|
|
224
|
+
return
|
|
225
|
+
|
|
226
|
+
# double click shows attachments
|
|
227
|
+
if event.button == 1 and event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
|
|
228
|
+
#self.write_message("This is a double click.\n")
|
|
229
|
+
self.on_upload_image(None, (model, lv_iter, values))
|
|
230
|
+
return
|
|
231
|
+
|
|
232
|
+
if event.button != 3:
|
|
233
|
+
return
|
|
234
|
+
|
|
235
|
+
menu = Gtk.Menu()
|
|
236
|
+
|
|
237
|
+
item_show = Gtk.MenuItem(label="Upload Image")
|
|
238
|
+
item_show.connect("activate", self.on_upload_image, (model, lv_iter, values))
|
|
239
|
+
menu.append(item_show)
|
|
240
|
+
|
|
241
|
+
item_show_json = Gtk.MenuItem(label="Show JSOn")
|
|
242
|
+
item_show_json.connect("activate", self.on_show_json, (model, lv_iter, values))
|
|
243
|
+
menu.append(item_show_json)
|
|
244
|
+
|
|
245
|
+
item_show_com = Gtk.MenuItem(label="Edit Comments")
|
|
246
|
+
item_show_com.connect("activate", self.on_show_comments, (model, lv_iter, values))
|
|
247
|
+
menu.append(item_show_com)
|
|
248
|
+
|
|
249
|
+
item_show_def = Gtk.MenuItem(label="Edit Defects")
|
|
250
|
+
item_show_def.connect("activate", self.on_show_defects, (model, lv_iter, values))
|
|
251
|
+
menu.append(item_show_def)
|
|
252
|
+
|
|
253
|
+
menu.show_all()
|
|
254
|
+
menu.popup_at_pointer(event)
|
|
255
|
+
|
|
256
|
+
def on_upload_image(self, item, data):
|
|
257
|
+
"""Add defects with images.."""
|
|
258
|
+
|
|
259
|
+
model, lv_iter, val = data
|
|
260
|
+
|
|
261
|
+
irow = 0
|
|
262
|
+
tree = Gtk.TreeView(model=val[self.F_LIST])
|
|
263
|
+
tree.connect("button-press-event", self.on_file_pressed)
|
|
264
|
+
|
|
265
|
+
btn = Gtk.Button(label="Add image")
|
|
266
|
+
btn.set_tooltip_text("Click to add a new image.")
|
|
267
|
+
btn.connect("clicked", self.on_add_image, val[PanelVisualInspection.F_LIST])
|
|
268
|
+
|
|
269
|
+
scrolled = Gtk.ScrolledWindow()
|
|
270
|
+
scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
|
|
271
|
+
scrolled.add(tree)
|
|
272
|
+
scrolled.set_size_request(-1, 150)
|
|
273
|
+
|
|
274
|
+
renderer = Gtk.CellRendererText()
|
|
275
|
+
column = Gtk.TreeViewColumn("Description", renderer, text=PanelVisualInspection.F_DEFECT)
|
|
276
|
+
tree.append_column(column)
|
|
277
|
+
|
|
278
|
+
renderer = Gtk.CellRendererText()
|
|
279
|
+
column = Gtk.TreeViewColumn("File", renderer, text=PanelVisualInspection.F_NAME)
|
|
280
|
+
tree.append_column(column)
|
|
281
|
+
|
|
282
|
+
dlg = Gtk.Dialog(title="Add Image")
|
|
283
|
+
dlg.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
|
|
284
|
+
Gtk.STOCK_OK, Gtk.ResponseType.OK)
|
|
285
|
+
box = dlg.get_content_area()
|
|
286
|
+
box.add(btn)
|
|
287
|
+
box.add(scrolled)
|
|
288
|
+
dlg.show_all()
|
|
289
|
+
rc = dlg.run()
|
|
290
|
+
if rc == Gtk.ResponseType.OK:
|
|
291
|
+
f_model = tree.get_model()
|
|
292
|
+
n_files = f_model.iter_n_children()
|
|
293
|
+
model.set_value(lv_iter, PanelVisualInspection.F_LIST, f_model)
|
|
294
|
+
model.set_value(lv_iter, PanelVisualInspection.N_FILES, n_files)
|
|
295
|
+
|
|
296
|
+
dlg.hide()
|
|
297
|
+
dlg.destroy()
|
|
298
|
+
|
|
299
|
+
self.write_message("Defects added\n")
|
|
300
|
+
|
|
301
|
+
def on_file_pressed(self, tree, event):
|
|
302
|
+
"""Called when right button clicked in add image dialog.
|
|
303
|
+
|
|
304
|
+
Opens a pop-up menu to delete the selected entry."""
|
|
305
|
+
# double click shows attachments
|
|
306
|
+
if event.button == 1 and event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
|
|
307
|
+
self.write_message("This is a double click.\n")
|
|
308
|
+
return
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
if event.button != 3:
|
|
312
|
+
return
|
|
313
|
+
|
|
314
|
+
model, lv_iter, values = self.get_iter_at_position(tree, event)
|
|
315
|
+
if not values:
|
|
316
|
+
return
|
|
317
|
+
menu = Gtk.Menu()
|
|
318
|
+
|
|
319
|
+
item_show = Gtk.MenuItem(label="Delete")
|
|
320
|
+
item_show.connect("activate", self.on_delete_image, (model, lv_iter, values))
|
|
321
|
+
menu.append(item_show)
|
|
322
|
+
|
|
323
|
+
menu.show_all()
|
|
324
|
+
menu.popup_at_pointer(event)
|
|
325
|
+
|
|
326
|
+
def on_delete_image(self, item, data):
|
|
327
|
+
"""Delete a defect and image"""
|
|
328
|
+
model, lv_iter, _ = data
|
|
329
|
+
model.remove(lv_iter)
|
|
330
|
+
|
|
331
|
+
def on_add_image(self, btn, model):
|
|
332
|
+
"""Adds a new image."""
|
|
333
|
+
dlg = Gtk.Dialog(title="Add Image")
|
|
334
|
+
|
|
335
|
+
dlg.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
|
|
336
|
+
Gtk.STOCK_OK, Gtk.ResponseType.OK)
|
|
337
|
+
box = dlg.get_content_area()
|
|
338
|
+
grid = Gtk.Grid(column_spacing=5, row_spacing=1)
|
|
339
|
+
box.add(grid)
|
|
340
|
+
|
|
341
|
+
irow = 0
|
|
342
|
+
lbl = Gtk.Label(label="Description")
|
|
343
|
+
lbl.set_xalign(0)
|
|
344
|
+
grid.attach(lbl, 0, irow, 1, 1)
|
|
345
|
+
|
|
346
|
+
desc = Gtk.Entry()
|
|
347
|
+
grid.attach(desc, 1, irow, 1, 1)
|
|
348
|
+
|
|
349
|
+
irow += 1
|
|
350
|
+
lbl = Gtk.Label(label="Image")
|
|
351
|
+
lbl.set_xalign(0)
|
|
352
|
+
grid.attach(lbl, 0, irow, 1, 1)
|
|
353
|
+
|
|
354
|
+
fC = Gtk.FileChooserButton()
|
|
355
|
+
grid.attach(fC, 1, irow, 1, 1)
|
|
356
|
+
|
|
357
|
+
dlg.show_all()
|
|
358
|
+
|
|
359
|
+
rc = dlg.run()
|
|
360
|
+
if rc == Gtk.ResponseType.OK:
|
|
361
|
+
D = desc.get_text()
|
|
362
|
+
P = Path(fC.get_filename()).expanduser().resolve()
|
|
363
|
+
model.append([D, P.name, P.as_posix()])
|
|
364
|
+
|
|
365
|
+
dlg.hide()
|
|
366
|
+
dlg.destroy()
|
|
367
|
+
|
|
368
|
+
def on_show_json(self, item, data):
|
|
369
|
+
"""Test JSon."""
|
|
370
|
+
model, lv_iter, val = data
|
|
371
|
+
payload = val[PanelVisualInspection.TEST_J].js
|
|
372
|
+
value, dlg = create_json_data_editor(payload)
|
|
373
|
+
rc = dlg.run()
|
|
374
|
+
if rc == Gtk.ResponseType.OK:
|
|
375
|
+
payload = value.values
|
|
376
|
+
model.set_value(lv_iter, PanelVisualInspection.TEST_J, TestJson(payload))
|
|
377
|
+
|
|
378
|
+
dlg.hide()
|
|
379
|
+
dlg.destroy()
|
|
380
|
+
|
|
381
|
+
def on_show_comments(self, item, data):
|
|
382
|
+
"""Show comments"""
|
|
383
|
+
model, lv_iter, val = data
|
|
384
|
+
js = val[PanelVisualInspection.TEST_J].js
|
|
385
|
+
SC = ShowComments("Test Comments", js["comments"], self)
|
|
386
|
+
rc = SC.run()
|
|
387
|
+
if rc == Gtk.ResponseType.OK:
|
|
388
|
+
js["comments"] = SC.comments
|
|
389
|
+
model.set_value(lv_iter, PanelVisualInspection.TEST_J, TestJson(js))
|
|
390
|
+
|
|
391
|
+
SC.hide()
|
|
392
|
+
SC.destroy()
|
|
393
|
+
|
|
394
|
+
def on_show_defects(self, item, data):
|
|
395
|
+
"""Show comments"""
|
|
396
|
+
model, lv_iter, val = data
|
|
397
|
+
js = val[PanelVisualInspection.TEST_J].js
|
|
398
|
+
SD = ShowDefects("Test Defects", js["defects"], self)
|
|
399
|
+
rc = SD.run()
|
|
400
|
+
if rc == Gtk.ResponseType.OK:
|
|
401
|
+
js["defects"] = SD.defects
|
|
402
|
+
model.set_value(lv_iter, PanelVisualInspection.TEST_J, TestJson(js))
|
|
403
|
+
|
|
404
|
+
SD.hide()
|
|
405
|
+
SD.destroy()
|
|
406
|
+
|
|
407
|
+
def SN_ready(self, *args):
|
|
408
|
+
"""SN is ready in the TextEnttry."""
|
|
409
|
+
SN = self.SN.get_text()
|
|
410
|
+
# GEt children.
|
|
411
|
+
panel = ITkDButils.get_DB_component(self.session, SN)
|
|
412
|
+
if panel is None:
|
|
413
|
+
self.write_message(ITkDButils.get_db_response())
|
|
414
|
+
return
|
|
415
|
+
|
|
416
|
+
SN = panel["serialNumber"]
|
|
417
|
+
args[0].set_text(SN)
|
|
418
|
+
is_PWB = False
|
|
419
|
+
defaults = {
|
|
420
|
+
"institution": self.institute,
|
|
421
|
+
"runNumber": "1",
|
|
422
|
+
"date": self.date.get_text()
|
|
423
|
+
}
|
|
424
|
+
component_type = None
|
|
425
|
+
test_code = None
|
|
426
|
+
if "USED" in SN:
|
|
427
|
+
# Powerboard Carrier
|
|
428
|
+
if not SN[6].isdigit():
|
|
429
|
+
dbGtkUtils.complain("Not a Powerboard Carrier",
|
|
430
|
+
"{}: wrong SN for a powerboard carrier".format(SN))
|
|
431
|
+
self.SN.widget.set_text("")
|
|
432
|
+
return
|
|
433
|
+
|
|
434
|
+
self.panel_type.set_text("PWB carrier")
|
|
435
|
+
is_PWB = True
|
|
436
|
+
component_type = "PWB"
|
|
437
|
+
test_code = "PICTURE"
|
|
438
|
+
|
|
439
|
+
elif "USET" in SN:
|
|
440
|
+
# Hybrid test panel
|
|
441
|
+
component_type = "HYBRID_TEST_PANEL"
|
|
442
|
+
test_code = "VISUAL_INSPECTION"
|
|
443
|
+
|
|
444
|
+
if not SN[6].isdigit or int(SN[6])>5:
|
|
445
|
+
dbGtkUtils.complain("Not a Hybrid Test Panel",
|
|
446
|
+
"{}: wrong SN for a hybrid test panel".format(SN))
|
|
447
|
+
self.SN.widget.set_text("")
|
|
448
|
+
return
|
|
449
|
+
|
|
450
|
+
self.panel_type.set_text("HYB test panel")
|
|
451
|
+
|
|
452
|
+
else:
|
|
453
|
+
dbGtkUtils.complain("Invalid SN.",
|
|
454
|
+
"{}\nNot a PWB carrier not HYB test panel.".format(SN))
|
|
455
|
+
self.SN.widget.set_text("")
|
|
456
|
+
return
|
|
457
|
+
|
|
458
|
+
# GEt children.
|
|
459
|
+
skltn = ITkDButils.get_test_skeleton(self.session, component_type, test_code, defaults)
|
|
460
|
+
model = self.create_model()
|
|
461
|
+
for child in panel["children"]:
|
|
462
|
+
if child["component"] is not None:
|
|
463
|
+
child_SN = child["component"]["serialNumber"]
|
|
464
|
+
skltn["component"] = child_SN
|
|
465
|
+
if is_PWB:
|
|
466
|
+
position = child["order"]
|
|
467
|
+
else:
|
|
468
|
+
position = -1
|
|
469
|
+
for P in child["properties"]:
|
|
470
|
+
if P["code"] == "HYBRID_POSITION":
|
|
471
|
+
if P["value"] is not None:
|
|
472
|
+
position = int(P["value"])
|
|
473
|
+
break
|
|
474
|
+
|
|
475
|
+
model.append([child_SN, position, True, 0, self.create_file_model(), TestJson(skltn)])
|
|
476
|
+
|
|
477
|
+
self.tree.set_model(model)
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
def upload_tests(self, *args):
|
|
481
|
+
"""Upload the current test."""
|
|
482
|
+
SN = self.SN.get_text()
|
|
483
|
+
|
|
484
|
+
model = self.tree.get_model()
|
|
485
|
+
lv_iter = model.get_iter_first()
|
|
486
|
+
n_items = 0
|
|
487
|
+
global_link = None
|
|
488
|
+
while lv_iter:
|
|
489
|
+
values = model[lv_iter]
|
|
490
|
+
payload = values[PanelVisualInspection.TEST_J].js
|
|
491
|
+
|
|
492
|
+
attachments = []
|
|
493
|
+
if global_link is None:
|
|
494
|
+
if self.global_image is not None:
|
|
495
|
+
A = ITkDButils.Attachment(path=self.global_image, title="Global Image", desc="Image of whole panel")
|
|
496
|
+
attachments.append(A)
|
|
497
|
+
|
|
498
|
+
im_model = values[PanelVisualInspection.F_LIST]
|
|
499
|
+
im_iter = im_model.get_iter_first()
|
|
500
|
+
idef = 1
|
|
501
|
+
while im_iter:
|
|
502
|
+
defect, name, path = im_model[im_iter]
|
|
503
|
+
A = ITkDButils.Attachment(path=path, title="Defect {}".format(idef), desc=defect)
|
|
504
|
+
attachments.append(A)
|
|
505
|
+
idef += 1
|
|
506
|
+
im_iter = im_model.iter_next(im_iter)
|
|
507
|
+
|
|
508
|
+
rc = ITkDButils.upload_test(self.session, payload, attachments, check_runNumber=True)
|
|
509
|
+
if rc:
|
|
510
|
+
ipos = rc.find("The following details may help:")
|
|
511
|
+
msg = rc[ipos:]
|
|
512
|
+
dbGtkUtils.complain("Failed uploading test {}-{}".format(payload["component"], payload["testType"]), msg)
|
|
513
|
+
self.write_message(msg+"\n")
|
|
514
|
+
|
|
515
|
+
else:
|
|
516
|
+
self.write_message("Upload {}-{} successfull\n".format(payload["component"], payload["testType"]))
|
|
517
|
+
if global_link is None:
|
|
518
|
+
try:
|
|
519
|
+
if self.global_image is not None:
|
|
520
|
+
global_link = ITkDButils.attachment_urls[self.global_image.name]
|
|
521
|
+
except KeyError:
|
|
522
|
+
pass
|
|
523
|
+
|
|
524
|
+
if payload["testType"] == "PICTURE":
|
|
525
|
+
rc = ITkDButils.set_test_run_parameter(self.session,
|
|
526
|
+
ITkDButils.uploaded_test_runs[0],
|
|
527
|
+
"COMMENT", "Picture of PW carrier")
|
|
528
|
+
|
|
529
|
+
rc = ITkDButils.set_test_run_parameter(self.session,
|
|
530
|
+
ITkDButils.uploaded_test_runs[0],
|
|
531
|
+
"LINK_TO_PICTURE", global_link)
|
|
532
|
+
if rc:
|
|
533
|
+
ipos = rc.find("The following details may help:")
|
|
534
|
+
msg = rc[ipos:]
|
|
535
|
+
dbGtkUtils.complain("Failed updating LINK_TO_PICTURE {}-{}".format(payload["component"],
|
|
536
|
+
payload["testType"]), msg)
|
|
537
|
+
self.write_message(msg+'\n')
|
|
538
|
+
|
|
539
|
+
elif payload["testType"] == "VISUAL_INSPECTION":
|
|
540
|
+
rc = ITkDButils.create_test_run_comment(self.session,
|
|
541
|
+
ITkDButils.uploaded_test_runs[0],
|
|
542
|
+
["Link to global image:\n {}".format(global_link)])
|
|
543
|
+
if rc:
|
|
544
|
+
ipos = rc.find("The following details may help:")
|
|
545
|
+
msg = rc[ipos:]
|
|
546
|
+
dbGtkUtils.complain("Failed adding global link as comment: {}-{}".format(payload["component"],
|
|
547
|
+
payload["testType"]), msg)
|
|
548
|
+
self.write_message(msg+"\n")
|
|
549
|
+
else:
|
|
550
|
+
self.write_message("Image: {}\n".format(global_link))
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
n_items += 1
|
|
554
|
+
lv_iter = model.iter_next(lv_iter)
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
def get_qrcode(self,txt):
|
|
558
|
+
"""Read SN from scanner."""
|
|
559
|
+
self.write_message("SN: {}\n".format(txt))
|
|
560
|
+
self.SN_ready(txt, self.SN.widget)
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
def main():
|
|
564
|
+
"""Main entry."""
|
|
565
|
+
# DB login
|
|
566
|
+
HELP_LINK="https://itkdb-gtk.docs.cern.ch/panelVisualInspection.html"
|
|
567
|
+
|
|
568
|
+
dlg = ITkDBlogin.ITkDBlogin()
|
|
569
|
+
client = dlg.get_client()
|
|
570
|
+
if client is None:
|
|
571
|
+
print("Could not connect to DB with provided credentials.")
|
|
572
|
+
dlg.die()
|
|
573
|
+
sys.exit()
|
|
574
|
+
|
|
575
|
+
client.user_gui = dlg
|
|
576
|
+
|
|
577
|
+
gTest = PanelVisualInspection(client, help_link=HELP_LINK)
|
|
578
|
+
|
|
579
|
+
gTest.present()
|
|
580
|
+
gTest.connect("destroy", Gtk.main_quit)
|
|
581
|
+
try:
|
|
582
|
+
Gtk.main()
|
|
583
|
+
|
|
584
|
+
except KeyboardInterrupt:
|
|
585
|
+
print("Arrrgggg!!!")
|
|
586
|
+
|
|
587
|
+
dlg.die()
|
|
588
|
+
|
|
589
|
+
if __name__ == "__main__":
|
|
590
|
+
main()
|
itkdb_gtk/QRScanner.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""A set of utilities for teh warp scanner."""
|
|
3
|
+
import pathlib
|
|
4
|
+
import serial
|
|
5
|
+
import serial.tools.list_ports as list_ports
|
|
6
|
+
|
|
7
|
+
import gi
|
|
8
|
+
gi.require_version("Gtk", "3.0")
|
|
9
|
+
from gi.repository import GLib
|
|
10
|
+
|
|
11
|
+
class QRScanner:
|
|
12
|
+
"""Contains information to detect the scanner."""
|
|
13
|
+
def __init__(self, callback):
|
|
14
|
+
self.reader = None
|
|
15
|
+
self.callback = callback
|
|
16
|
+
self.timer_id = None
|
|
17
|
+
self.source_id = None
|
|
18
|
+
self.init_scanner()
|
|
19
|
+
|
|
20
|
+
def init_scanner(self):
|
|
21
|
+
"""Sets the scanner."""
|
|
22
|
+
self.setup_scanner()
|
|
23
|
+
if self.reader is None:
|
|
24
|
+
self.timer_id = GLib.timeout_add(500, self.find_scanner)
|
|
25
|
+
else:
|
|
26
|
+
print("Found scanner in {}".format(self.reader.name))
|
|
27
|
+
|
|
28
|
+
def find_scanner(self, *args):
|
|
29
|
+
"""Check if the scanner is there."""
|
|
30
|
+
# if the reader is there, stop the timeput
|
|
31
|
+
if self.reader is not None:
|
|
32
|
+
return False
|
|
33
|
+
|
|
34
|
+
# Try to setup the scanner
|
|
35
|
+
self.setup_scanner()
|
|
36
|
+
if self.reader is not None:
|
|
37
|
+
self.timer_id = None
|
|
38
|
+
print("Found scanner in {}".format(self.reader.name))
|
|
39
|
+
return False
|
|
40
|
+
else:
|
|
41
|
+
return True
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def setup_scanner(self):
|
|
45
|
+
"""Setup scanner and callback function."""
|
|
46
|
+
if self.reader is not None:
|
|
47
|
+
return
|
|
48
|
+
|
|
49
|
+
self.reader = None
|
|
50
|
+
device_signature = '05f9:4204|1a86:7523'
|
|
51
|
+
candidates = list(list_ports.grep(device_signature))
|
|
52
|
+
if not candidates:
|
|
53
|
+
return
|
|
54
|
+
|
|
55
|
+
self.reader = serial.Serial(candidates[0].device, 9600)
|
|
56
|
+
self.source_id = GLib.unix_fd_add_full(
|
|
57
|
+
GLib.PRIORITY_DEFAULT,
|
|
58
|
+
self.reader.fileno(),
|
|
59
|
+
GLib.IOCondition.IN | GLib.IOCondition.ERR | GLib.IOCondition.NVAL,
|
|
60
|
+
self.get_line,
|
|
61
|
+
self.callback,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def finish_timeout(self):
|
|
66
|
+
"""Finishes the timeout."""
|
|
67
|
+
GLib.source_remove(self.source_id)
|
|
68
|
+
self.source_id = None
|
|
69
|
+
|
|
70
|
+
self.reader.close()
|
|
71
|
+
self.reader = None
|
|
72
|
+
|
|
73
|
+
# re-start the search of the scanner
|
|
74
|
+
self.timer_id = GLib.timeout_add(500, self.find_scanner)
|
|
75
|
+
|
|
76
|
+
def get_line(self, fd, state, callback):
|
|
77
|
+
"""Has to info to read."""
|
|
78
|
+
if state == GLib.IOCondition.IN:
|
|
79
|
+
try:
|
|
80
|
+
available = self.reader.in_waiting
|
|
81
|
+
while True:
|
|
82
|
+
delta = self.reader.in_waiting - available
|
|
83
|
+
if not delta:
|
|
84
|
+
break
|
|
85
|
+
|
|
86
|
+
# Get data from serial device passed in via
|
|
87
|
+
data = self.reader.read_until(expected='\r', size=self.reader.in_waiting).strip()
|
|
88
|
+
txt = data.decode('utf-8')
|
|
89
|
+
if callback:
|
|
90
|
+
callback(txt)
|
|
91
|
+
|
|
92
|
+
except OSError:
|
|
93
|
+
if not pathlib.Path(self.reader.name).exists():
|
|
94
|
+
print("Device unplugged.")
|
|
95
|
+
self.finish_timeout()
|
|
96
|
+
return False
|
|
97
|
+
|
|
98
|
+
return True
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
else:
|
|
102
|
+
self.finish_timeout()
|
|
103
|
+
return False
|
|
104
|
+
|
|
105
|
+
def get_text_from_scanner(txt):
|
|
106
|
+
"""Callback where the scanners sends the text."""
|
|
107
|
+
print("### {}".format(txt))
|
|
108
|
+
|
|
109
|
+
def test_scanner():
|
|
110
|
+
"""Test the thing."""
|
|
111
|
+
scanner = QRScanner(get_text_from_scanner)
|
|
112
|
+
|
|
113
|
+
loop = GLib.MainLoop()
|
|
114
|
+
try:
|
|
115
|
+
loop.run()
|
|
116
|
+
except KeyboardInterrupt:
|
|
117
|
+
loop.quit()
|
|
118
|
+
|
|
119
|
+
if __name__ == "__main__":
|
|
120
|
+
test_scanner()
|