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.
Files changed (37) hide show
  1. itkdb_gtk/{sendShipments.py → CreateShipments.py} +74 -78
  2. itkdb_gtk/{getShipments.py → GetShipments.py} +99 -106
  3. itkdb_gtk/GlueWeight.py +45 -66
  4. itkdb_gtk/ITkDB.desktop +8 -0
  5. itkdb_gtk/ITkDB.svg +380 -0
  6. itkdb_gtk/ITkDBlogin.py +10 -6
  7. itkdb_gtk/ITkDButils.py +295 -57
  8. itkdb_gtk/PanelVisualInspection.py +590 -0
  9. itkdb_gtk/QRScanner.py +120 -0
  10. itkdb_gtk/SensorUtils.py +492 -0
  11. itkdb_gtk/ShowAttachments.py +267 -0
  12. itkdb_gtk/ShowComments.py +94 -0
  13. itkdb_gtk/ShowDefects.py +103 -0
  14. itkdb_gtk/UploadModuleIV.py +566 -0
  15. itkdb_gtk/UploadMultipleTests.py +746 -0
  16. itkdb_gtk/UploadTest.py +509 -0
  17. itkdb_gtk/VisualInspection.py +297 -0
  18. itkdb_gtk/WireBondGui.py +1304 -0
  19. itkdb_gtk/__init__.py +38 -12
  20. itkdb_gtk/dashBoard.py +292 -33
  21. itkdb_gtk/dbGtkUtils.py +356 -75
  22. itkdb_gtk/findComponent.py +242 -0
  23. itkdb_gtk/findVTRx.py +36 -0
  24. itkdb_gtk/readGoogleSheet.py +1 -2
  25. itkdb_gtk/untrash_component.py +35 -0
  26. {itkdb_gtk-0.0.3.dist-info → itkdb_gtk-0.20.1.dist-info}/METADATA +21 -12
  27. itkdb_gtk-0.20.1.dist-info/RECORD +30 -0
  28. {itkdb_gtk-0.0.3.dist-info → itkdb_gtk-0.20.1.dist-info}/WHEEL +1 -1
  29. itkdb_gtk-0.20.1.dist-info/entry_points.txt +12 -0
  30. itkdb_gtk/checkComponent.py +0 -131
  31. itkdb_gtk/groundingTest.py +0 -225
  32. itkdb_gtk/readAVSdata.py +0 -565
  33. itkdb_gtk/uploadPetalInformation.py +0 -604
  34. itkdb_gtk/uploadTest.py +0 -384
  35. itkdb_gtk-0.0.3.dist-info/RECORD +0 -19
  36. itkdb_gtk-0.0.3.dist-info/entry_points.txt +0 -7
  37. {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 gi
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
- def set_combo_iter(combo, txt, col=0):
16
- """Set scombo active iter to that containing txt in column col."""
17
- model = combo.get_model()
18
- iter = model.get_iter_first()
19
- while iter:
20
- val = model.get_value(iter, col)
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
- iter = model.iter_next(iter)
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
- self.widget = Gtk.Entry()
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="Add Attachment",
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.text_view = Gtk.TextView()
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
- pass
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 = self.session.user_gui.get_client()
382
- self.userLabel.get_child().set_text(self.session.user.name)
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
- compltn = self.get_institute_list()
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
- sites = self.session.get("listInstitutions", json={})
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
- nlines = self.textbuffer.get_line_count()
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
- tp = type(itm[last_key])
524
- itm[last_key] = tp(txt)
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
- Return:
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
- if __name__ == "__main__":
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()