Baby Language Lab Scripts
A collection of data processing tools.
 All Classes Namespaces Files Functions Variables Pages
config_window.py
Go to the documentation of this file.
1 from gi.repository import Gtk as gtk
2 from gi.repository import GObject as gobject
3 
4 from utils.ui_utils import UIUtils
5 from data_structs.output_config import OutputConfig
6 from ui.stats_app.output_window import OutputWindow
7 from db.bll_database import BLLDatabase
8 
9 class ConfigWindow():
10  def __init__(self, action_callback, edit_config=None):
11  self.edit_config = edit_config
12  self.action_callback = action_callback
13 
14  self.window = gtk.Window(gtk.WindowType.TOPLEVEL)
15  self.window.set_title('%s Configuration' % ('Edit' if self.edit_config else 'Create'))
16  self.window.set_border_width(10)
17  self.window.set_default_size(500, 350)
18 
19  vbox = gtk.VBox()
20 
21  #properties frame
22  props_frame = gtk.Frame(label='Properties')
23  grid = gtk.Grid() #gtk.Table(3, 2)
24  grid.set_column_spacing(3)
25  name_label = gtk.Label('Name:')
26  self.name_entry = gtk.Entry()
27  self.name_entry.set_width_chars(50)
28  if self.edit_config:
29  self.name_entry.set_text(self.edit_config.name)
30 
31  #It appears that proper alignment can only be acheived with HBoxes here...
32  name_label_hbox = gtk.HBox()
33  align = gtk.Alignment()
34  align.set(1, 0, 0, 0)
35  name_label_hbox.pack_start(align, True, True, 0)
36  name_label_hbox.pack_start(name_label, False, False, 0)
37  #table.attach(name_label_hbox, 0, 1, 0, 1)
38  grid.attach(name_label_hbox, 0, 0, 1, 1)
39 
40  name_entry_hbox = gtk.HBox()
41  name_entry_hbox.pack_start(self.name_entry, False, False, 0)
42  #table.attach(name_entry_hbox, 1, 2, 0, 1)
43  grid.attach(name_entry_hbox, 1, 0, 1, 1)
44 
45  desc_label = gtk.Label('Description:')
46  self.desc_entry = gtk.Entry()
47  self.desc_entry.set_width_chars(50)
48  if self.edit_config:
49  self.desc_entry.set_text(self.edit_config.desc)
50 
51  desc_label_hbox = gtk.HBox()
52  align = gtk.Alignment()
53  align.set(1, 0, 0, 0)
54  desc_label_hbox.pack_start(align, True, True, 0)
55  desc_label_hbox.pack_start(desc_label, False, False, 0)
56  #table.attach(desc_label_hbox, 0, 1, 1, 2)
57  grid.attach(desc_label_hbox, 0, 1, 1, 1)
58 
59  desc_entry_hbox = gtk.HBox()
60  desc_entry_hbox.pack_start(self.desc_entry, False, False, 0)
61  #table.attach(desc_entry_hbox, 1, 2, 1, 2)#, ypadding=3) #ypadding adds some space between bottom of entry and bottom of frame border
62  grid.attach(desc_entry_hbox, 1, 1, 1, 1)
63 
64  props_frame.add(grid)
65 
66  vbox.pack_start(props_frame, False, False, 0)
67 
68  #outputs frame
69  outputs_frame = gtk.Frame(label='Outputs')
70  outputs_vbox = gtk.VBox()
71  existing_outputs = self.edit_config.outputs if self.edit_config else []
72  self.outputs_treeview = self._build_outputs_treeview(existing_outputs)
73  scrolled_win = gtk.ScrolledWindow()
74  scrolled_win.set_policy(gtk.PolicyType.AUTOMATIC, gtk.PolicyType.AUTOMATIC)
75  scrolled_win.add(self.outputs_treeview)
76  outputs_vbox.pack_start(scrolled_win, True, True, 0)
77 
78  outputs_button_box = gtk.HButtonBox()
79  outputs_button_box.set_layout(gtk.ButtonBoxStyle.EDGE)
80 
81  add_button = UIUtils.create_button('Add Output', UIUtils.BUTTON_ICONS.ADD, UIUtils.BUTTON_ICON_SIZES.PX22)
82  add_button.connect('clicked', lambda w: OutputWindow(self._add_output_callback))
83  outputs_button_box.pack_start(add_button, True, True, 0)
84 
85  edit_button = UIUtils.create_button('Edit Output', UIUtils.BUTTON_ICONS.EDIT, UIUtils.BUTTON_ICON_SIZES.PX22)
86  edit_button.connect('clicked', lambda w: self._edit_output())
87  outputs_button_box.pack_start(edit_button, True, True, 0)
88 
89  remove_button = UIUtils.create_button('Remove Output', UIUtils.BUTTON_ICONS.REMOVE, UIUtils.BUTTON_ICON_SIZES.PX22)
90  remove_button.connect('clicked', lambda w: self._remove_output())
91  outputs_button_box.pack_start(remove_button, True, True, 0)
92 
93  outputs_vbox.pack_start(outputs_button_box, False, False, 0)
94  outputs_frame.add(outputs_vbox)
95 
96  vbox.pack_start(outputs_frame, True, True, 0)
97 
98  #buttons box
99  button_box = gtk.HButtonBox()
100  button_box.set_layout(gtk.ButtonBoxStyle.EDGE)
101  cancel_button = gtk.Button(stock=gtk.STOCK_CANCEL)
102  cancel_button.connect('clicked', lambda w: self.window.destroy())
103  button_box.pack_start(cancel_button, False, False, 0)
104 
105  ok_button = gtk.Button(stock=gtk.STOCK_OK)
106  ok_button.connect('clicked', lambda w: self._create_config())
107  button_box.pack_start(ok_button, False, False, 0)
108 
109  vbox.pack_end(button_box, False, False, 0)
110 
111  self.window.add(vbox)
112  self.window.show_all()
113 
114  def _validate(self):
115  return self.name_entry.get_text() != '' # desc can be left blank
116 
117  def _create_config(self):
118  if self._validate():
119  #extract the output objects from the treeview model
120  outputs = []
121  model = self.outputs_treeview.get_model()
122  row = 0
123  while row < len(model):
124  outputs.append(model[row][4])
125  row += 1
126 
127  name = self.name_entry.get_text()
128  desc = self.desc_entry.get_text()
129 
130  db = BLLDatabase()
131  created = None
132  #if editing, delete previous config from DB
133  if self.edit_config:
134  created = self.edit_config.created
135  self.edit_config.db_delete(db) #this will also delete any associated outputs and entries in output_configs_to_outputs
136  self.edit_config = None
137 
138  config = OutputConfig(name, desc, outputs, created)
139  config.db_insert(db)
140  db.close()
141 
142  self.window.destroy()
143  self.action_callback(config)
144 
145  else:
146  UIUtils.show_message_dialog('Please make sure that all of the fields have been filled out.', gtk.MessageType.WARNING)
147 
148  def _get_output_filters_str(self, output):
149  filters_str = ''
150  i = 0
151  while i < len(output.filters):
152  filters_str += output.filters[i].get_filter_desc_str()
153  if i < len(output.filters) - 1:
154  filters_str += ' and\n'
155  i += 1
156 
157  if not filters_str:
158  filters_str = '-'
159 
160  return filters_str
161 
162  def _add_output_callback(self, new_output):
163  self.outputs_treeview.get_model().append([new_output.name,
164  new_output.desc,
165  'Linked' if new_output.chained else 'Unlinked',
166  self._get_output_filters_str(new_output),
167  new_output,
168  ])
169 
170  def _edit_output(self):
171  model, it = self.outputs_treeview.get_selection().get_selected()
172  if it:
173  OutputWindow(lambda edited_output: self._edit_output_callback(edited_output, it), model.get(it, 4)[0])
174 
175  else:
176  UIUtils.show_message_dialog('Please select a row.', gtk.MessageType.WARNING)
177 
178  def _edit_output_callback(self, edited_output, row_it):
179  model = self.outputs_treeview.get_model()
180 
181  #update the treeview model with the edited properties
182  model.set_value(row_it, 0, edited_output.name)
183  model.set_value(row_it, 1, edited_output.desc)
184  model.set_value(row_it, 2, 'Linked' if edited_output.chained else 'Unlinked')
185  model.set_value(row_it, 3, self._get_output_filters_str(edited_output))
186  model.set_value(row_it, 4, edited_output)
187 
188  def _remove_output(self):
189  model, it = self.outputs_treeview.get_selection().get_selected()
190  if it:
191  if UIUtils.show_confirm_dialog('Are you sure you want to delete this output?'):
192  model.remove(it)
193  else:
194  UIUtils.show_message_dialog('Please select a row.', gtk.MessageType.WARNING)
195 
196  #note: the actual delete from the DB is deferred until the user clicks ok
197 
198  def _build_list_store(self, existing_outputs=[]):
199  list_store = gtk.ListStore(gobject.TYPE_STRING, #name
200  gobject.TYPE_STRING, #desc
201  gobject.TYPE_STRING, #linked
202  gobject.TYPE_STRING, #filters
203  gobject.TYPE_PYOBJECT, #output object
204  )
205 
206  #for edit functionality
207  for cur_output in existing_outputs:
208  list_store.append([cur_output.name,
209  cur_output.desc,
210  'Linked' if cur_output.chained else 'Unlinked',
211  self._get_output_filters_str(cur_output),
212  cur_output,
213  ])
214 
215  return list_store
216 
217  def _build_outputs_treeview(self, existing_outputs=[]):
218  list_store = self._build_list_store(existing_outputs)
219  treeview = gtk.TreeView(list_store)
220 
221  #don't create any column for the PYOBJECT, which is the first element of the list_store rows
222  col_names = ['Name', 'Description', 'Link Segs', 'Filters']
223  for i in range(len(col_names)):
224  col = gtk.TreeViewColumn(col_names[i], gtk.CellRendererText(), text=i)
225  col.set_resizable(True)
226  col.set_min_width( UIUtils.calc_treeview_col_min_width(col_names[i]) )
227  treeview.append_column(col)
228 
229  return treeview