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
itkdb_gtk/dbGtkUtils.py
CHANGED
|
@@ -1,39 +1,107 @@
|
|
|
1
1
|
"""A set of GTK utilities for DB scripts."""
|
|
2
|
+
import sys
|
|
2
3
|
import json
|
|
3
4
|
import time
|
|
5
|
+
import pathlib
|
|
6
|
+
|
|
4
7
|
from collections.abc import Iterable
|
|
5
8
|
from copy import deepcopy
|
|
6
9
|
from datetime import datetime
|
|
10
|
+
import webbrowser
|
|
7
11
|
|
|
8
12
|
import dateutil.parser
|
|
9
|
-
import
|
|
13
|
+
import numpy as np
|
|
14
|
+
|
|
10
15
|
|
|
16
|
+
import gi
|
|
11
17
|
gi.require_version("Gtk", "3.0")
|
|
12
|
-
from gi.repository import Gtk, Gio, GLib
|
|
18
|
+
from gi.repository import Gtk, GObject, Gio, GLib
|
|
13
19
|
|
|
14
20
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if val == txt:
|
|
22
|
-
combo.set_active_iter(iter)
|
|
23
|
-
break
|
|
21
|
+
try:
|
|
22
|
+
import itkdb_gtk
|
|
23
|
+
|
|
24
|
+
except ImportError:
|
|
25
|
+
cwd = pathlib.Path(__file__).parent.parent
|
|
26
|
+
sys.path.append(cwd.as_posix())
|
|
24
27
|
|
|
25
|
-
|
|
28
|
+
from itkdb_gtk import ITkDButils
|
|
26
29
|
|
|
27
30
|
|
|
31
|
+
def parse_date(txt):
|
|
32
|
+
"""Parse a date."""
|
|
33
|
+
try:
|
|
34
|
+
return dateutil.parser.parse(txt, fuzzy=False)
|
|
35
|
+
|
|
36
|
+
except dateutil.parser.ParserError:
|
|
37
|
+
return None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def parse_date_as_string(txt):
|
|
41
|
+
"""Parse data and return DB compatible string."""
|
|
42
|
+
D = parse_date(txt)
|
|
43
|
+
if D is None:
|
|
44
|
+
return D
|
|
45
|
+
|
|
46
|
+
out = D.isoformat(timespec='milliseconds')
|
|
47
|
+
if out[-1] not in ['zZ']:
|
|
48
|
+
out += 'Z'
|
|
49
|
+
|
|
50
|
+
return out
|
|
51
|
+
|
|
52
|
+
def is_a_date(txt):
|
|
53
|
+
"""check tha the input string is a date."""
|
|
54
|
+
try:
|
|
55
|
+
tl = txt.lower()
|
|
56
|
+
if len(txt)<5 and (tl!="now" and tl!="today"):
|
|
57
|
+
return False
|
|
58
|
+
|
|
59
|
+
dateutil.parser.parse(txt, fuzzy=False)
|
|
60
|
+
return True
|
|
61
|
+
|
|
62
|
+
except (dateutil.parser.ParserError, OverflowError):
|
|
63
|
+
return False
|
|
64
|
+
|
|
65
|
+
def new_small_text_entry():
|
|
66
|
+
"""Returs a new, smaller Gtk.Entry."""
|
|
67
|
+
entry = Gtk.Entry()
|
|
68
|
+
provider = Gtk.CssProvider()
|
|
69
|
+
style_context = entry.get_style_context()
|
|
70
|
+
font_size = 2.25*style_context.get_property("font-size", 0)
|
|
71
|
+
css = "entry {{ min-height: {}px; }}".format(font_size)
|
|
72
|
+
provider.load_from_data(css.encode())
|
|
73
|
+
style_context.add_provider(provider, Gtk.STYLE_PROVIDER_PRIORITY_SETTINGS)
|
|
74
|
+
return entry
|
|
75
|
+
|
|
28
76
|
def set_entry_style(container):
|
|
29
77
|
"""Set max entry."""
|
|
30
78
|
provider = Gtk.CssProvider()
|
|
31
|
-
print(container.get_name())
|
|
32
79
|
style_context = container.get_style_context()
|
|
33
80
|
font_size = 2.25*style_context.get_property("font-size", 0)
|
|
34
81
|
css = "{} {{ min-height: {}px; }}".format(container.get_name(), font_size)
|
|
35
82
|
provider.load_from_data(css.encode())
|
|
36
83
|
style_context.add_provider(provider, Gtk.STYLE_PROVIDER_PRIORITY_SETTINGS)
|
|
84
|
+
return container
|
|
85
|
+
|
|
86
|
+
def set_button_color(btn, bg_color, fg_color="white"):
|
|
87
|
+
"""Set button color"""
|
|
88
|
+
css = "#{} {{background-image: none; background-color: {}; color: {}}}".format(btn.get_name(), bg_color, fg_color)
|
|
89
|
+
provider = Gtk.CssProvider()
|
|
90
|
+
provider.load_from_data(css.encode())
|
|
91
|
+
style_context = btn.get_style_context()
|
|
92
|
+
style_context.add_provider(provider, Gtk.STYLE_PROVIDER_PRIORITY_USER)
|
|
93
|
+
|
|
94
|
+
def set_combo_iter(combo, txt, col=0):
|
|
95
|
+
"""Set scombo active iter to that containing txt in column col."""
|
|
96
|
+
model = combo.get_model()
|
|
97
|
+
lv_iter = model.get_iter_first()
|
|
98
|
+
while lv_iter:
|
|
99
|
+
val = model.get_value(lv_iter, col)
|
|
100
|
+
if val == txt:
|
|
101
|
+
combo.set_active_iter(lv_iter)
|
|
102
|
+
break
|
|
103
|
+
|
|
104
|
+
lv_iter = model.iter_next(lv_iter)
|
|
37
105
|
|
|
38
106
|
|
|
39
107
|
def is_iterable(obj):
|
|
@@ -55,6 +123,12 @@ class MyEncoder(json.JSONEncoder):
|
|
|
55
123
|
if isinstance(o, datetime):
|
|
56
124
|
text = o.astimezone().isoformat()
|
|
57
125
|
return text
|
|
126
|
+
elif isinstance(o, np.integer):
|
|
127
|
+
return int(o)
|
|
128
|
+
elif isinstance(o, np.floating):
|
|
129
|
+
return float(o)
|
|
130
|
+
elif isinstance(o, np.ndarray):
|
|
131
|
+
return o.tolist()
|
|
58
132
|
else:
|
|
59
133
|
return super().default(o)
|
|
60
134
|
|
|
@@ -63,7 +137,6 @@ def empty_container(container):
|
|
|
63
137
|
"""Remove all children from a container.
|
|
64
138
|
|
|
65
139
|
Args:
|
|
66
|
-
----
|
|
67
140
|
container: The container.
|
|
68
141
|
|
|
69
142
|
"""
|
|
@@ -76,7 +149,6 @@ def replace_in_container(container, child):
|
|
|
76
149
|
"""Replace a child from a single-child container.
|
|
77
150
|
|
|
78
151
|
Args:
|
|
79
|
-
----
|
|
80
152
|
container: the container
|
|
81
153
|
child: the new child to be added
|
|
82
154
|
|
|
@@ -93,7 +165,6 @@ def complain(main_title, second_text="", parent=None):
|
|
|
93
165
|
"""Open an error dialog.
|
|
94
166
|
|
|
95
167
|
Args:
|
|
96
|
-
----
|
|
97
168
|
main_title: Main text in window
|
|
98
169
|
second_text: Second text
|
|
99
170
|
parent: dialog parent
|
|
@@ -115,13 +186,11 @@ def ask_for_confirmation(main_title, second_text, parent=None):
|
|
|
115
186
|
"""Ask for action cofirmation.
|
|
116
187
|
|
|
117
188
|
Args:
|
|
118
|
-
----
|
|
119
189
|
main_title: Main title in the message window
|
|
120
190
|
second_text: Secondary text in the message widow
|
|
121
191
|
parent (optional): The parent window. Defaults to None.
|
|
122
192
|
|
|
123
193
|
Return:
|
|
124
|
-
------
|
|
125
194
|
OK: True if OK button clicked.
|
|
126
195
|
|
|
127
196
|
"""
|
|
@@ -137,13 +206,18 @@ def ask_for_confirmation(main_title, second_text, parent=None):
|
|
|
137
206
|
dialog.destroy()
|
|
138
207
|
return (out == Gtk.ResponseType.OK)
|
|
139
208
|
|
|
140
|
-
|
|
141
|
-
class TextEntry(object):
|
|
209
|
+
class TextEntry(GObject.GObject):
|
|
142
210
|
"""Create a Gtk text entry/view object."""
|
|
211
|
+
__gsignals__ = {
|
|
212
|
+
"text_changed": (GObject.SIGNAL_RUN_FIRST, None, (str,))
|
|
213
|
+
}
|
|
143
214
|
|
|
144
|
-
def __init__(self, n_lines=1):
|
|
215
|
+
def __init__(self, n_lines=1, small=False):
|
|
145
216
|
"""Init."""
|
|
217
|
+
GObject.GObject.__init__(self)
|
|
218
|
+
self.tmp_txt = ""
|
|
146
219
|
self.nlines = n_lines
|
|
220
|
+
self.do_emit = True
|
|
147
221
|
if self.nlines > 1:
|
|
148
222
|
self.widget = Gtk.Frame()
|
|
149
223
|
scrolled = Gtk.ScrolledWindow()
|
|
@@ -156,9 +230,32 @@ class TextEntry(object):
|
|
|
156
230
|
scrolled.add(self.entry)
|
|
157
231
|
|
|
158
232
|
else:
|
|
159
|
-
|
|
233
|
+
if small:
|
|
234
|
+
self.widget = new_small_text_entry()
|
|
235
|
+
else:
|
|
236
|
+
self.widget = Gtk.Entry()
|
|
237
|
+
|
|
238
|
+
self.widget.connect("focus-in-event", self.on_enter)
|
|
239
|
+
self.widget.connect("focus-out-event", self.on_leave)
|
|
160
240
|
self.entry = self.widget
|
|
161
241
|
|
|
242
|
+
def do_my_signal(self, *args):
|
|
243
|
+
"""Signal handler."""
|
|
244
|
+
return
|
|
245
|
+
|
|
246
|
+
def on_enter(self, *args):
|
|
247
|
+
"""On enter."""
|
|
248
|
+
self.tmp_txt = self.widget.get_text().strip()
|
|
249
|
+
return False
|
|
250
|
+
|
|
251
|
+
def on_leave(self, *args):
|
|
252
|
+
"""On leave."""
|
|
253
|
+
val = self.widget.get_text().strip()
|
|
254
|
+
if val != self.tmp_txt:
|
|
255
|
+
self.do_emit = False
|
|
256
|
+
self.emit("text_changed", val)
|
|
257
|
+
self.do_emit = True
|
|
258
|
+
|
|
162
259
|
def get_text(self):
|
|
163
260
|
"""Return the text."""
|
|
164
261
|
if self.nlines > 1:
|
|
@@ -170,23 +267,34 @@ class TextEntry(object):
|
|
|
170
267
|
else:
|
|
171
268
|
return self.entry.get_text()
|
|
172
269
|
|
|
270
|
+
def set_text(self, text):
|
|
271
|
+
"""Sets text."""
|
|
272
|
+
if text is None:
|
|
273
|
+
return
|
|
274
|
+
|
|
275
|
+
if self.nlines > 1:
|
|
276
|
+
self.entry.get_buffer().set_text(text)
|
|
277
|
+
else:
|
|
278
|
+
self.entry.set_text(text)
|
|
279
|
+
if self.do_emit:
|
|
280
|
+
self.do_emit = False
|
|
281
|
+
self.emit("text_changed", text)
|
|
282
|
+
self.do_emit = True
|
|
173
283
|
|
|
174
284
|
def get_a_value(main_title, second_text=None, is_tv=False, parent=None):
|
|
175
285
|
"""Open a dialog to get a value.
|
|
176
286
|
|
|
177
287
|
Args:
|
|
178
|
-
----
|
|
179
288
|
main_title: Main title in the message window
|
|
180
289
|
is_tv: If true show a text view rathar than an entry.
|
|
181
290
|
second_text: Secondary text in the message widow
|
|
182
291
|
parent (optional): The parent window. Defaults to None.
|
|
183
292
|
|
|
184
293
|
Return:
|
|
185
|
-
------
|
|
186
294
|
value: The value in the entry
|
|
187
295
|
|
|
188
296
|
"""
|
|
189
|
-
dlg = Gtk.Dialog(title="
|
|
297
|
+
dlg = Gtk.Dialog(title="Get a Value",
|
|
190
298
|
transient_for=parent,
|
|
191
299
|
flags=0)
|
|
192
300
|
dlg.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
|
|
@@ -195,9 +303,9 @@ def get_a_value(main_title, second_text=None, is_tv=False, parent=None):
|
|
|
195
303
|
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
|
196
304
|
area.add(box)
|
|
197
305
|
|
|
198
|
-
box.pack_start(Gtk.Label(main_title), False, True, 0)
|
|
306
|
+
box.pack_start(Gtk.Label(label=main_title), False, True, 0)
|
|
199
307
|
if second_text and len(second_text):
|
|
200
|
-
box.pack_start(Gtk.Label(second_text), False, True, 0)
|
|
308
|
+
box.pack_start(Gtk.Label(label=second_text), False, True, 0)
|
|
201
309
|
|
|
202
310
|
entry = TextEntry(3 if is_tv else -1)
|
|
203
311
|
|
|
@@ -216,18 +324,17 @@ def get_a_value(main_title, second_text=None, is_tv=False, parent=None):
|
|
|
216
324
|
return out
|
|
217
325
|
|
|
218
326
|
|
|
219
|
-
def get_a_list_of_values(main_title, labels, second_text=None, parent=None):
|
|
327
|
+
def get_a_list_of_values(main_title, labels, defaults=None, second_text=None, parent=None):
|
|
220
328
|
"""Get a list of values.
|
|
221
329
|
|
|
222
330
|
Args:
|
|
223
|
-
----
|
|
224
331
|
main_title: Main title for window
|
|
225
332
|
labels: List of labes to get the values. If the label ends with /v
|
|
226
333
|
then a TextView will be shown instead of a TextEntry.
|
|
334
|
+
defaults (optional): default values-
|
|
227
335
|
second_text (optional): Second title for window-. Defaults to None.
|
|
228
336
|
|
|
229
|
-
Returns
|
|
230
|
-
-------
|
|
337
|
+
Returns:
|
|
231
338
|
list with values
|
|
232
339
|
|
|
233
340
|
"""
|
|
@@ -245,14 +352,14 @@ def get_a_list_of_values(main_title, labels, second_text=None, parent=None):
|
|
|
245
352
|
lbl.set_markup("<b>{}</b>".format(main_title))
|
|
246
353
|
box.pack_start(lbl, False, True, 5)
|
|
247
354
|
if second_text and len(second_text):
|
|
248
|
-
box.pack_start(Gtk.Label(second_text), False, True, 0)
|
|
355
|
+
box.pack_start(Gtk.Label(label=second_text), False, True, 0)
|
|
249
356
|
|
|
250
357
|
entries = []
|
|
251
358
|
values = []
|
|
252
359
|
is_text_view = []
|
|
253
360
|
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
|
254
361
|
area.pack_start(vbox, False, True, 0)
|
|
255
|
-
for txt in labels:
|
|
362
|
+
for i, txt in enumerate(labels):
|
|
256
363
|
use_tv = False
|
|
257
364
|
if txt.endswith("/v"):
|
|
258
365
|
is_text_view.append(True)
|
|
@@ -261,11 +368,17 @@ def get_a_list_of_values(main_title, labels, second_text=None, parent=None):
|
|
|
261
368
|
else:
|
|
262
369
|
is_text_view.append(False)
|
|
263
370
|
|
|
264
|
-
lbl = Gtk.Label(txt)
|
|
371
|
+
lbl = Gtk.Label(label=txt)
|
|
265
372
|
lbl.set_justify(Gtk.Justification.LEFT)
|
|
266
373
|
vbox.pack_start(lbl, False, False, 0)
|
|
267
374
|
|
|
268
375
|
entry = TextEntry(3 if use_tv else -1)
|
|
376
|
+
try:
|
|
377
|
+
entry.set_text(defaults[i])
|
|
378
|
+
|
|
379
|
+
except (TypeError, IndexError):
|
|
380
|
+
pass
|
|
381
|
+
|
|
269
382
|
vbox.pack_start(entry.widget, False, False, 0)
|
|
270
383
|
entries.append(entry)
|
|
271
384
|
|
|
@@ -284,7 +397,6 @@ def add_button_to_container(box, label, tooltip=None, callback=None):
|
|
|
284
397
|
"""Creates a buttons and adds to container.
|
|
285
398
|
|
|
286
399
|
Args:
|
|
287
|
-
----
|
|
288
400
|
box: The container.
|
|
289
401
|
label: The button label
|
|
290
402
|
tooltip (optional): Tooltip message. Defaults to None.
|
|
@@ -301,15 +413,81 @@ def add_button_to_container(box, label, tooltip=None, callback=None):
|
|
|
301
413
|
|
|
302
414
|
box.pack_start(btn, True, False, 0)
|
|
303
415
|
|
|
416
|
+
return btn
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
class MessagePanel(object):
|
|
420
|
+
"""Encapsulates a TExtView object to show messages."""
|
|
421
|
+
|
|
422
|
+
def __init__(self, size=100):
|
|
423
|
+
"""Initializarion."""
|
|
424
|
+
self.frame = None
|
|
425
|
+
self.text_view = Gtk.TextView()
|
|
426
|
+
self.textbuffer = self.text_view.get_buffer()
|
|
427
|
+
|
|
428
|
+
self.__create_message_panel(size)
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
def __create_message_panel(self, size):
|
|
432
|
+
"""Creates a message panel within a frame.
|
|
433
|
+
|
|
434
|
+
Args:
|
|
435
|
+
size: size of the panel
|
|
436
|
+
|
|
437
|
+
Returns:
|
|
438
|
+
Gtk.TextBuffer, Gtk.Frame
|
|
439
|
+
"""
|
|
440
|
+
frame = Gtk.Frame()
|
|
441
|
+
frame.set_shadow_type(Gtk.ShadowType.IN)
|
|
442
|
+
|
|
443
|
+
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
|
444
|
+
box.set_size_request(-1, size)
|
|
445
|
+
frame.add(box)
|
|
446
|
+
|
|
447
|
+
# The title for the tet view
|
|
448
|
+
box.pack_start(Gtk.Label(label="Messages"), False, True, 0)
|
|
449
|
+
|
|
450
|
+
# A scroll window with the text view
|
|
451
|
+
scrolled = Gtk.ScrolledWindow()
|
|
452
|
+
scrolled.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
|
|
453
|
+
scrolled.add(self.text_view)
|
|
454
|
+
box.pack_start(scrolled, True, True, 0)
|
|
455
|
+
self.frame = frame
|
|
456
|
+
|
|
457
|
+
def scroll_to_end(self):
|
|
458
|
+
"""Scrolls text view to end."""
|
|
459
|
+
end = self.textbuffer.get_end_iter()
|
|
460
|
+
self.text_view.scroll_to_iter(end, 0, False, 0, 0)
|
|
461
|
+
|
|
462
|
+
def write_message(self, text, write_date=True):
|
|
463
|
+
"""Writes text to Text Viewer."""
|
|
464
|
+
nlines = self.textbuffer.get_line_count()
|
|
465
|
+
if nlines > 100:
|
|
466
|
+
start = self.textbuffer.get_iter_at_line(0)
|
|
467
|
+
end = self.textbuffer.get_iter_at_line(75)
|
|
468
|
+
self.textbuffer.delete(start, end)
|
|
469
|
+
|
|
470
|
+
end = self.textbuffer.get_end_iter()
|
|
471
|
+
if write_date:
|
|
472
|
+
msg = "[{}] {}".format(time.strftime("%d/%m/%y %T"), text)
|
|
473
|
+
else:
|
|
474
|
+
msg = text
|
|
475
|
+
|
|
476
|
+
self.textbuffer.insert(end, msg)
|
|
477
|
+
GLib.idle_add(self.scroll_to_end)
|
|
478
|
+
|
|
479
|
+
def write(self, txt):
|
|
480
|
+
"""A write method."""
|
|
481
|
+
self.write_message(txt, write_date=False)
|
|
482
|
+
|
|
304
483
|
|
|
305
484
|
class ITkDBWindow(Gtk.Window):
|
|
306
485
|
"""Base class for GUI main windows."""
|
|
307
486
|
|
|
308
|
-
def __init__(self, title="", session=None, show_search=None, gtk_runs=True):
|
|
487
|
+
def __init__(self, title="", session=None, show_search=None, help_link=None, gtk_runs=True, panel_size=100):
|
|
309
488
|
"""Initialization.
|
|
310
489
|
|
|
311
490
|
Args:
|
|
312
|
-
----
|
|
313
491
|
title: The title of the window.
|
|
314
492
|
session: ITkDB session.
|
|
315
493
|
show_search: tooltip for search button in header (calls to query_db).
|
|
@@ -321,12 +499,15 @@ class ITkDBWindow(Gtk.Window):
|
|
|
321
499
|
self.session = session
|
|
322
500
|
self.inst2code = {}
|
|
323
501
|
self.code2inst = {}
|
|
502
|
+
self.message_panel = None
|
|
503
|
+
self.help = help_link
|
|
504
|
+
self.pdb_user = ITkDButils.get_db_user(self.session)
|
|
324
505
|
|
|
325
506
|
if gtk_runs:
|
|
326
507
|
super().__init__(title=title)
|
|
327
|
-
self.prepare_window(show_search)
|
|
508
|
+
self.prepare_window(title, show_search, panel_size)
|
|
328
509
|
|
|
329
|
-
def prepare_window(self, show_search):
|
|
510
|
+
def prepare_window(self, title, show_search, panel_size):
|
|
330
511
|
"""Inititalizes GUI."""
|
|
331
512
|
# Prepare HeaderBar
|
|
332
513
|
self.hb = Gtk.HeaderBar()
|
|
@@ -349,13 +530,32 @@ class ITkDBWindow(Gtk.Window):
|
|
|
349
530
|
button.connect("clicked", self.query_db)
|
|
350
531
|
self.hb.pack_end(button)
|
|
351
532
|
|
|
533
|
+
if self.help:
|
|
534
|
+
button = Gtk.Button()
|
|
535
|
+
icon = Gio.ThemedIcon(name="help-browser-symbolic")
|
|
536
|
+
image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.BUTTON)
|
|
537
|
+
button.add(image)
|
|
538
|
+
button.connect("clicked", self.show_help)
|
|
539
|
+
self.hb.pack_end(button)
|
|
540
|
+
|
|
541
|
+
|
|
352
542
|
# Create main content box
|
|
353
543
|
self.mainBox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
|
544
|
+
self.mainBox.set_property("margin-left", 6)
|
|
545
|
+
self.mainBox.set_property("margin-right", 6)
|
|
546
|
+
|
|
547
|
+
self.title_label = None
|
|
548
|
+
if len(title)>0:
|
|
549
|
+
lbl = Gtk.Label()
|
|
550
|
+
lbl.set_markup("<big><b>{}\n</b></big>".format(title))
|
|
551
|
+
lbl.set_xalign(0.5)
|
|
552
|
+
self.mainBox.pack_start(lbl, False, False, 2)
|
|
553
|
+
self.title_label = lbl
|
|
554
|
+
|
|
354
555
|
self.add(self.mainBox)
|
|
355
556
|
|
|
356
557
|
# The text view and buffer
|
|
357
|
-
self.
|
|
358
|
-
self.textbuffer = self.text_view.get_buffer()
|
|
558
|
+
self.message_panel = MessagePanel(size=panel_size)
|
|
359
559
|
|
|
360
560
|
# The button box
|
|
361
561
|
btnBox = Gtk.ButtonBox(orientation=Gtk.Orientation.HORIZONTAL)
|
|
@@ -366,20 +566,34 @@ class ITkDBWindow(Gtk.Window):
|
|
|
366
566
|
|
|
367
567
|
self.mainBox.pack_end(btnBox, False, True, 0)
|
|
368
568
|
|
|
569
|
+
def set_window_title(self, title):
|
|
570
|
+
"""Set window title."""
|
|
571
|
+
hb = self.get_titlebar()
|
|
572
|
+
hb.props.title = title
|
|
573
|
+
if self.title_label:
|
|
574
|
+
self.title_label.set_markup("<big><b>{}\n</b></big>".format(title))
|
|
575
|
+
|
|
369
576
|
def quit(self, *args):
|
|
370
577
|
"""Quits the application."""
|
|
371
578
|
self.hide()
|
|
372
579
|
self.destroy()
|
|
373
580
|
|
|
581
|
+
def show_help(self, *args):
|
|
582
|
+
"""Show help"""
|
|
583
|
+
webbrowser.open(self.help)
|
|
584
|
+
|
|
374
585
|
def query_db(self, *args):
|
|
375
586
|
"""Search button clicked."""
|
|
376
|
-
|
|
587
|
+
return
|
|
377
588
|
|
|
378
|
-
def new_login(self, msg):
|
|
589
|
+
def new_login(self, obj, msg):
|
|
379
590
|
"""A new user logged in."""
|
|
380
591
|
if msg == "<OK>":
|
|
381
|
-
self.session
|
|
382
|
-
|
|
592
|
+
if hasattr(self.session, "user_gui"):
|
|
593
|
+
self.session = self.session.user_gui.get_client()
|
|
594
|
+
|
|
595
|
+
if self.userLabel.get_child():
|
|
596
|
+
self.userLabel.get_child().set_text(self.session.user.name)
|
|
383
597
|
|
|
384
598
|
else:
|
|
385
599
|
self.write_message("Could not login.\n{}".format(msg))
|
|
@@ -389,18 +603,32 @@ class ITkDBWindow(Gtk.Window):
|
|
|
389
603
|
if hasattr(self.session, "user_gui"):
|
|
390
604
|
self.session.user_gui.reconnect(force=True)
|
|
391
605
|
|
|
392
|
-
def create_institute_combo(self):
|
|
393
|
-
"""Create a combe with all institutes.
|
|
394
|
-
|
|
606
|
+
def create_institute_combo(self, only_user=False):
|
|
607
|
+
"""Create a combe with all institutes.
|
|
608
|
+
|
|
609
|
+
Args:
|
|
610
|
+
only_user: if True, add only institutes the user belongs to.
|
|
611
|
+
|
|
612
|
+
"""
|
|
613
|
+
compltn = self.get_institute_list(only_user)
|
|
395
614
|
combo = Gtk.ComboBox.new_with_model_and_entry(compltn.get_model())
|
|
396
615
|
combo.set_entry_text_column(0)
|
|
397
616
|
combo.get_child().set_completion(compltn)
|
|
398
617
|
|
|
399
618
|
return combo
|
|
400
619
|
|
|
401
|
-
def get_institute_list(self):
|
|
402
|
-
"""Get the institute list.
|
|
403
|
-
|
|
620
|
+
def get_institute_list(self, only_user=False):
|
|
621
|
+
"""Get the institute list.
|
|
622
|
+
|
|
623
|
+
Args:
|
|
624
|
+
only_user: if True, add only institutes the user belongs to.
|
|
625
|
+
|
|
626
|
+
"""
|
|
627
|
+
if only_user and self.pdb_user:
|
|
628
|
+
sites = self.pdb_user["institutions"]
|
|
629
|
+
else:
|
|
630
|
+
sites = self.session.get("listInstitutions", json={})
|
|
631
|
+
|
|
404
632
|
liststore = Gtk.ListStore(str, str)
|
|
405
633
|
for site in sites:
|
|
406
634
|
self.code2inst[site['code']] = site['name']
|
|
@@ -450,33 +678,18 @@ class ITkDBWindow(Gtk.Window):
|
|
|
450
678
|
|
|
451
679
|
return frame
|
|
452
680
|
|
|
453
|
-
def scroll_to_end(self):
|
|
454
|
-
"""Scrolls text view to end."""
|
|
455
|
-
end = self.textbuffer.get_end_iter()
|
|
456
|
-
self.text_view.scroll_to_iter(end, 0, False, 0, 0)
|
|
457
|
-
|
|
458
681
|
def write_message(self, text):
|
|
459
682
|
"""Writes text to Text Viewer."""
|
|
460
|
-
|
|
461
|
-
if nlines > 100:
|
|
462
|
-
start = self.textbuffer.get_iter_at_line(0)
|
|
463
|
-
end = self.textbuffer.get_iter_at_line(75)
|
|
464
|
-
self.textbuffer.delete(start, end)
|
|
465
|
-
|
|
466
|
-
end = self.textbuffer.get_end_iter()
|
|
467
|
-
msg = "[{}] {}".format(time.strftime("%d/%m/%y %T"), text)
|
|
468
|
-
self.textbuffer.insert(end, msg)
|
|
469
|
-
GLib.idle_add(self.scroll_to_end)
|
|
683
|
+
self.message_panel.write_message(text)
|
|
470
684
|
|
|
471
685
|
|
|
472
686
|
class DictDialog(Gtk.Grid):
|
|
473
687
|
"""Creates a dialog to show and edit variables in a JSon dict."""
|
|
474
688
|
|
|
475
|
-
def __init__(self, values, hidden_keys=
|
|
689
|
+
def __init__(self, values, hidden_keys=None):
|
|
476
690
|
"""Create the Gtk.Grid.
|
|
477
691
|
|
|
478
692
|
Args:
|
|
479
|
-
----
|
|
480
693
|
values: A dict (JSon-like)
|
|
481
694
|
hidden_keys: keys tha twill not be shown.
|
|
482
695
|
|
|
@@ -484,12 +697,18 @@ class DictDialog(Gtk.Grid):
|
|
|
484
697
|
super().__init__(column_spacing=5, row_spacing=1)
|
|
485
698
|
|
|
486
699
|
self.set_border_width(10)
|
|
700
|
+
self.factory = deepcopy(values)
|
|
487
701
|
self.values = deepcopy(values)
|
|
488
702
|
self.keys = {}
|
|
489
703
|
self.containers = {}
|
|
490
|
-
self.hidden_keys = hidden_keys
|
|
704
|
+
self.hidden_keys = hidden_keys if hidden_keys else {}
|
|
491
705
|
self.show_values()
|
|
492
706
|
|
|
707
|
+
def factory_reset(self):
|
|
708
|
+
"""Set values to original values."""
|
|
709
|
+
self.values = deepcopy(self.factory)
|
|
710
|
+
self.refresh()
|
|
711
|
+
|
|
493
712
|
def on_enter(self, entry, *args):
|
|
494
713
|
"""Get the value when we first enter into the Entry."""
|
|
495
714
|
self.keys[args[2]] = entry.get_text()
|
|
@@ -519,9 +738,21 @@ class DictDialog(Gtk.Grid):
|
|
|
519
738
|
elif isinstance(itm[last_key], datetime):
|
|
520
739
|
itm[last_key] = dateutil.parser.parse(txt)
|
|
521
740
|
|
|
741
|
+
elif is_a_date(itm[last_key]):
|
|
742
|
+
D = dateutil.parser.parse(txt)
|
|
743
|
+
out = D.isoformat(timespec='milliseconds')
|
|
744
|
+
if out[-1] not in ['zZ']:
|
|
745
|
+
out += 'Z'
|
|
746
|
+
|
|
747
|
+
itm[last_key] = out
|
|
748
|
+
self.containers[name].set_text(out)
|
|
749
|
+
|
|
522
750
|
else:
|
|
523
|
-
|
|
524
|
-
|
|
751
|
+
if itm[last_key] is None:
|
|
752
|
+
itm[last_key] = txt
|
|
753
|
+
else:
|
|
754
|
+
tp = type(itm[last_key])
|
|
755
|
+
itm[last_key] = tp(txt)
|
|
525
756
|
|
|
526
757
|
def show_item(self, value, name=None):
|
|
527
758
|
"""Handle a single item."""
|
|
@@ -559,6 +790,7 @@ class DictDialog(Gtk.Grid):
|
|
|
559
790
|
css = "entry {{ min-height: {}px; }}".format(font_size)
|
|
560
791
|
provider.load_from_data(css.encode())
|
|
561
792
|
style_context.add_provider(provider, Gtk.STYLE_PROVIDER_PRIORITY_SETTINGS)
|
|
793
|
+
container.connect("populate-popup", self.add_insert_path)
|
|
562
794
|
|
|
563
795
|
if name:
|
|
564
796
|
container.set_name(name)
|
|
@@ -569,6 +801,28 @@ class DictDialog(Gtk.Grid):
|
|
|
569
801
|
|
|
570
802
|
return container
|
|
571
803
|
|
|
804
|
+
def add_insert_path(self, entry, menu, *args):
|
|
805
|
+
"""Adds a new item in the pop-up menu."""
|
|
806
|
+
item = Gtk.MenuItem(label="Get file path")
|
|
807
|
+
item.connect("activate", self.on_set_path, entry)
|
|
808
|
+
menu.append(item)
|
|
809
|
+
menu.show_all()
|
|
810
|
+
|
|
811
|
+
def on_set_path(self, menu_item, entry):
|
|
812
|
+
"""Sets the path to the entry."""
|
|
813
|
+
fdlg = Gtk.FileChooserNative(action=Gtk.FileChooserAction.OPEN, accept_label="Select")
|
|
814
|
+
response = fdlg.run()
|
|
815
|
+
if response == Gtk.ResponseType.ACCEPT:
|
|
816
|
+
ifiles = [ipath for ipath in fdlg.get_filenames()]
|
|
817
|
+
if len(ifiles)<1:
|
|
818
|
+
return
|
|
819
|
+
if len(ifiles) > 1:
|
|
820
|
+
complain("More than one file selected","Choosing first.")
|
|
821
|
+
|
|
822
|
+
fnam = ifiles[0]
|
|
823
|
+
entry.set_text(fnam)
|
|
824
|
+
self.on_leave(entry, None, None, entry.get_name())
|
|
825
|
+
|
|
572
826
|
def set_value(self, key, value):
|
|
573
827
|
"""Set value of a container and key."""
|
|
574
828
|
try:
|
|
@@ -581,7 +835,6 @@ class DictDialog(Gtk.Grid):
|
|
|
581
835
|
"""Show the keys and values of a dictionary (JSON).
|
|
582
836
|
|
|
583
837
|
Args:
|
|
584
|
-
----
|
|
585
838
|
values: The dictionary object
|
|
586
839
|
|
|
587
840
|
"""
|
|
@@ -611,12 +864,36 @@ class DictDialog(Gtk.Grid):
|
|
|
611
864
|
self.show_all()
|
|
612
865
|
self.queue_draw()
|
|
613
866
|
|
|
867
|
+
@staticmethod
|
|
868
|
+
def create_json_data_editor(data):
|
|
869
|
+
"""Create a dialog to show the JSon file."""
|
|
870
|
+
dlg = Gtk.Dialog(title="Test Data")
|
|
871
|
+
dlg.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
|
|
872
|
+
Gtk.STOCK_OK, Gtk.ResponseType.OK)
|
|
873
|
+
|
|
874
|
+
dlg.set_property("height-request", 500)
|
|
875
|
+
box = dlg.get_content_area()
|
|
876
|
+
value = DictDialog(data)
|
|
877
|
+
scrolled = Gtk.ScrolledWindow()
|
|
878
|
+
scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
|
|
879
|
+
scrolled.add(value)
|
|
880
|
+
box.pack_start(scrolled, True, True, 10)
|
|
881
|
+
|
|
882
|
+
dlg.show_all()
|
|
883
|
+
rc = dlg.run()
|
|
884
|
+
dlg.hide()
|
|
885
|
+
dlg.destroy()
|
|
886
|
+
|
|
887
|
+
return value.values, rc
|
|
888
|
+
|
|
614
889
|
|
|
615
890
|
def create_scrolled_dictdialog(the_dict, hidden=("component", "testType")):
|
|
616
891
|
"""Create a DictDialog within a scrolled window.
|
|
617
892
|
|
|
618
|
-
|
|
619
|
-
|
|
893
|
+
Args:
|
|
894
|
+
the_dict: the input dictionary with values.
|
|
895
|
+
|
|
896
|
+
Returns:
|
|
620
897
|
scrolled: the scrolled window
|
|
621
898
|
gM: the DictDialog
|
|
622
899
|
|
|
@@ -628,7 +905,8 @@ def create_scrolled_dictdialog(the_dict, hidden=("component", "testType")):
|
|
|
628
905
|
return scrolled, gM
|
|
629
906
|
|
|
630
907
|
|
|
631
|
-
|
|
908
|
+
def main():
|
|
909
|
+
"""Main entry."""
|
|
632
910
|
result = {
|
|
633
911
|
"component": "the_serial_nukber",
|
|
634
912
|
"testType": "METROLOGY_AVS",
|
|
@@ -690,3 +968,6 @@ if __name__ == "__main__":
|
|
|
690
968
|
|
|
691
969
|
win.show_all()
|
|
692
970
|
Gtk.main()
|
|
971
|
+
|
|
972
|
+
if __name__ == "__main__":
|
|
973
|
+
main()
|