~jon-hill/supertree-toolkit/sub_in_subfile

« back to all changes in this revision

Viewing changes to gui/diamond/attributewidget.py

  • Committer: Jon Hill
  • Date: 2011-11-01 13:43:31 UTC
  • Revision ID: jon.hill@imperial.ac.uk-20111101134331-f5zwsc3p3guht6pj
sync from laptop

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
 
 
3
#    This file is part of Diamond.
 
4
#
 
5
#    Diamond is free software: you can redistribute it and/or modify
 
6
#    it under the terms of the GNU General Public License as published by
 
7
#    the Free Software Foundation, either version 3 of the License, or
 
8
#    (at your option) any later version.
 
9
#
 
10
#    Diamond is distributed in the hope that it will be useful,
 
11
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
#    GNU General Public License for more details.
 
14
#
 
15
#    You should have received a copy of the GNU General Public License
 
16
#    along with Diamond.  If not, see <http://www.gnu.org/licenses/>.
 
17
 
 
18
import gobject
 
19
import gtk
 
20
 
 
21
import datatype
 
22
import dialogs
 
23
 
 
24
class AttributeWidget(gtk.Frame):
 
25
 
 
26
  __gsignals__ = { "on-store" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
 
27
                   "update-name"  : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ())}
 
28
 
 
29
  def __init__(self):
 
30
    gtk.Frame.__init__(self)
 
31
 
 
32
    scrolledWindow = gtk.ScrolledWindow()
 
33
    scrolledWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
 
34
 
 
35
    treeview = self.treeview = gtk.TreeView()
 
36
 
 
37
    model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_PYOBJECT)
 
38
    treeview.set_model(model)
 
39
    treeview.connect("motion-notify-event", self.treeview_mouse_over)
 
40
 
 
41
    key_renderer = gtk.CellRendererText()
 
42
    key_renderer.set_property("editable", False)
 
43
 
 
44
    column1 = gtk.TreeViewColumn("Name", key_renderer, text = 0)
 
45
    column1.set_cell_data_func(key_renderer, self.key_data_func)
 
46
    column1.set_property("min-width", 75)
 
47
 
 
48
    entry_renderer = gtk.CellRendererText()
 
49
    entry_renderer.connect("edited", self.entry_edited)
 
50
    entry_renderer.connect("editing-started", self.entry_edit_start)
 
51
 
 
52
    combo_renderer = gtk.CellRendererCombo()
 
53
    combo_renderer.set_property("text-column", 0)
 
54
    combo_renderer.connect("edited", self.combo_selected)
 
55
    combo_renderer.connect("editing-started", self.combo_edit_start)
 
56
 
 
57
    column2 = gtk.TreeViewColumn("Value", entry_renderer, text = 1)
 
58
    column2.pack_start(combo_renderer)
 
59
    column2.set_attributes(combo_renderer, text = 1)
 
60
    column2.set_cell_data_func(entry_renderer, self.entry_data_func)
 
61
    column2.set_cell_data_func(combo_renderer, self.combo_data_func)
 
62
    column2.set_property("expand", True)
 
63
    column2.set_property("min-width", 75)
 
64
 
 
65
    icon_renderer = gtk.CellRendererPixbuf()
 
66
 
 
67
    column3 = gtk.TreeViewColumn("", icon_renderer)
 
68
    column3.set_cell_data_func(icon_renderer, self.icon_data_func)
 
69
 
 
70
    treeview.append_column(column1)
 
71
    treeview.append_column(column2)
 
72
    treeview.append_column(column3)
 
73
 
 
74
    scrolledWindow.add(treeview)
 
75
 
 
76
    label = gtk.Label()
 
77
    label.set_markup("<b>Attributes</b>")
 
78
 
 
79
    self.set_label_widget(label)
 
80
    self.set_shadow_type(gtk.SHADOW_NONE)
 
81
    self.add(scrolledWindow)
 
82
 
 
83
  def update(self, node):
 
84
 
 
85
    self.treeview.get_model().clear()
 
86
 
 
87
    self.node = node
 
88
 
 
89
    if node is None or not node.attrs.keys():
 
90
      self.set_property("visible", False)
 
91
    else:
 
92
      self.set_property("visible", True)
 
93
 
 
94
      for key in node.attrs.keys():
 
95
        model = self.treeview.get_model()
 
96
        cell_model = gtk.ListStore(gobject.TYPE_STRING)
 
97
 
 
98
        iter = model.append()
 
99
        model.set_value(iter, 0, key)
 
100
        model.set_value(iter, 2, cell_model)
 
101
 
 
102
        if isinstance(node.attrs[key][0], tuple):
 
103
          if node.attrs[key][1] is None:
 
104
            if isinstance(node.attrs[key][0][0], tuple):
 
105
              model.set_value(iter, 1, "Select " + datatype.print_type(node.attrs[key][0][1]) + "...")
 
106
            else:
 
107
              model.set_value(iter, 1, "Select...")
 
108
          else:
 
109
            model.set_value(iter, 1, node.attrs[key][1])
 
110
 
 
111
          if isinstance(node.attrs[key][0][0], tuple):
 
112
            opts = node.attrs[key][0][0]
 
113
          else:
 
114
            opts = node.attrs[key][0]
 
115
 
 
116
          for opt in opts:
 
117
            cell_iter = cell_model.append()
 
118
            cell_model.set_value(cell_iter, 0, opt)
 
119
 
 
120
          self.treeview.get_column(2).set_property("visible", True)
 
121
        elif node.attrs[key][0] is None:
 
122
          model.set_value(iter, 1, "No data")
 
123
        elif node.attrs[key][1] is None:
 
124
          model.set_value(iter, 1, datatype.print_type(node.attrs[key][0]))
 
125
        else:
 
126
          model.set_value(iter, 1, node.attrs[key][1])
 
127
 
 
128
      self.treeview.queue_resize()
 
129
 
 
130
    return
 
131
 
 
132
  def treeview_mouse_over(self, widget, event):
 
133
    """
 
134
    Called when the mouse moves over the attributes widget. Sets the
 
135
    appropriate attribute widget tooltip.
 
136
    """
 
137
 
 
138
    path_info = self.treeview.get_path_at_pos(int(event.x), int(event.y))
 
139
    if path_info is None:
 
140
      try:
 
141
        self.treeview.set_tooltip_text("")
 
142
        self.treeview.set_property("has-tooltip", False)
 
143
      except:
 
144
        pass
 
145
      return
 
146
 
 
147
    path = path_info[0]
 
148
    col = path_info[1]
 
149
    if col is not self.treeview.get_column(1):
 
150
      try:
 
151
        self.treeview.set_tooltip_text("")
 
152
        self.treeview.set_property("has-tooltip", False)
 
153
      except:
 
154
        pass
 
155
      return
 
156
 
 
157
    iter = self.treeview.get_model().get_iter(path)
 
158
    iter_key = self.treeview.get_model().get_value(iter, 0)
 
159
 
 
160
    return
 
161
 
 
162
  def key_data_func(self, col, cell_renderer, model, iter):
 
163
    """
 
164
    Attribute name data function. Sets the cell renderer text colours.
 
165
    """
 
166
 
 
167
    iter_key = model.get_value(iter, 0)
 
168
 
 
169
    if not self.node.active or self.node.attrs[iter_key][0] is None or self.node.attrs[iter_key][0] == "fixed":
 
170
      cell_renderer.set_property("foreground", "grey")
 
171
    elif self.node.attrs[iter_key][1] is None:
 
172
      cell_renderer.set_property("foreground", "blue")
 
173
    else:
 
174
      cell_renderer.set_property("foreground", "black")
 
175
 
 
176
    return
 
177
 
 
178
  def entry_data_func(self, col, cell_renderer, model, iter):
 
179
    """
 
180
    Attribute text data function. Hides the renderer if a combo box is required,
 
181
    and sets colours and editability otherwise.
 
182
    """
 
183
 
 
184
    iter_key = model.get_value(iter, 0)
 
185
 
 
186
    if not self.node.active or self.node.attrs[iter_key][0] is None or self.node.attrs[iter_key][0] == "fixed":
 
187
      cell_renderer.set_property("editable", False)
 
188
      cell_renderer.set_property("foreground", "grey")
 
189
      cell_renderer.set_property("visible", True)
 
190
    elif not isinstance(self.node.attrs[iter_key][0], tuple):
 
191
      cell_renderer.set_property("editable", True)
 
192
      cell_renderer.set_property("visible", True)
 
193
      if self.node.attrs[iter_key][1] is None:
 
194
        cell_renderer.set_property("foreground", "blue")
 
195
      else:
 
196
        cell_renderer.set_property("foreground", "black")
 
197
    else:
 
198
      cell_renderer.set_property("editable", False)
 
199
      cell_renderer.set_property("visible", False)
 
200
 
 
201
    return
 
202
 
 
203
  def combo_data_func(self, col, cell_renderer, model, iter):
 
204
    """
 
205
    Attribute combo box data function. Hides the renderer if a combo box is not
 
206
    required, and sets the combo box options otherwise. Adds an entry if required.
 
207
    """
 
208
 
 
209
    iter_key = model.get_value(iter, 0)
 
210
 
 
211
    if self.node.active and isinstance(self.node.attrs[iter_key][0], tuple):
 
212
      cell_renderer.set_property("editable", True)
 
213
      cell_renderer.set_property("visible", True)
 
214
      if isinstance(self.node.attrs[iter_key][0][0], tuple):
 
215
        cell_renderer.set_property("has-entry", True)
 
216
      else:
 
217
        cell_renderer.set_property("has-entry", False)
 
218
      if self.node.attrs[iter_key][1] is None:
 
219
        cell_renderer.set_property("foreground", "blue")
 
220
      else:
 
221
        cell_renderer.set_property("foreground", "black")
 
222
    else:
 
223
      cell_renderer.set_property("visible", False)
 
224
      cell_renderer.set_property("editable", False)
 
225
    cell_renderer.set_property("model", model.get_value(iter, 2))
 
226
 
 
227
    return
 
228
 
 
229
  def icon_data_func(self, col, cell_renderer, model, iter):
 
230
    """
 
231
    Attribute icon data function. Used to add downward pointing arrows for combo
 
232
    attributes, for consistency with the LHS.
 
233
    """
 
234
 
 
235
    iter_key = model.get_value(iter, 0)
 
236
 
 
237
    if self.node.active and isinstance(self.node.attrs[iter_key][0], tuple):
 
238
      cell_renderer.set_property("stock-id", gtk.STOCK_GO_DOWN)
 
239
    else:
 
240
      cell_renderer.set_property("stock-id", None)
 
241
 
 
242
    return
 
243
 
 
244
  def entry_edit_start(self, cell_renderer, editable, path):
 
245
    """
 
246
    Called when editing is started on an attribute text cell. Used to delete the
 
247
    printable_type placeholder.
 
248
    """
 
249
 
 
250
    iter = self.treeview.get_model().get_iter(path)
 
251
    iter_key = self.treeview.get_model().get_value(iter, 0)
 
252
 
 
253
    if self.node.attrs[iter_key][1] is None:
 
254
      editable.set_text("")
 
255
 
 
256
    return
 
257
 
 
258
  def combo_edit_start(self, cell_renderer, editable, path):
 
259
    """
 
260
    Called when editing is started on an attribute combo cell. Used to delete the
 
261
    select placeholder for mixed entry / combo attributes.
 
262
    """
 
263
 
 
264
    iter = self.treeview.get_model().get_iter(path)
 
265
    iter_key = self.treeview.get_model().get_value(iter, 0)
 
266
 
 
267
    if isinstance(self.node.attrs[iter_key][0][0], tuple) and self.node.attrs[iter_key][1] is None:
 
268
      editable.child.set_text("")
 
269
 
 
270
    return
 
271
 
 
272
  def entry_edited(self, cell_renderer, path, new_text):
 
273
    """
 
274
    Called when editing is finished on an attribute text cell. Updates data in the
 
275
    treestore.
 
276
    """
 
277
 
 
278
    iter = self.treeview.get_model().get_iter(path)
 
279
    iter_key = self.treeview.get_model().get_value(iter, 0)
 
280
 
 
281
    if self.node.get_attr(iter_key) is None and new_text == "":
 
282
      return
 
283
 
 
284
    value_check = self.node.validity_check(self.node.attrs[iter_key][0], new_text)
 
285
 
 
286
    if value_check is not None and value_check != self.node.attrs[iter_key][1]:
 
287
      if iter_key == "name" and not self._name_check(value_check):
 
288
        return
 
289
 
 
290
      self.treeview.get_model().set_value(iter, 1, value_check)
 
291
      self.node.set_attr(iter_key, value_check)
 
292
      if iter_key == "name":
 
293
        self.emit("update-name")
 
294
 
 
295
      self.emit("on-store")
 
296
 
 
297
    return
 
298
 
 
299
  def combo_selected(self, cell_renderer, path, new_text):
 
300
    """
 
301
    Called when an attribute combo box element is selected, or combo box entry
 
302
    element entry is edited. Updates data in the treestore.
 
303
    """
 
304
 
 
305
    iter = self.treeview.get_model().get_iter(path)
 
306
    iter_key = self.treeview.get_model().get_value(iter, 0)
 
307
 
 
308
    if new_text is None:
 
309
      return
 
310
 
 
311
    if isinstance(self.node.attrs[iter_key][0][0], tuple) and new_text not in self.node.attrs[iter_key][0][0]:
 
312
      if self.node.get_attr(iter_key) is None and new_text == "":
 
313
        return
 
314
 
 
315
      new_text = self.node.validity_check(self.node.attrs[iter_key][0][1], new_text)
 
316
      if iter_key == "name" and not self._name_check(new_text):
 
317
        return False
 
318
    if new_text != self.node.attrs[iter_key][1]:
 
319
      self.treeview.get_model().set_value(iter, 1, new_text)
 
320
      self.node.set_attr(iter_key, new_text)
 
321
      if iter_key == "name":
 
322
        self.emit("update-name")
 
323
 
 
324
      self.emit("on-store")
 
325
 
 
326
    return
 
327
 
 
328
  def _name_check(self, value):
 
329
    """
 
330
    Check to see if the supplied data is a valid tree name.
 
331
    """
 
332
 
 
333
    valid_chars = "_:[]1234567890qwertyuioplkjhgfdsazxcvbnmMNBVCXZASDFGHJKLPOIUYTREWQ"
 
334
    for char in value:
 
335
      if char not in valid_chars:
 
336
        dialogs.error(None, "Invalid value entered")
 
337
        return False
 
338
 
 
339
    return True
 
340
 
 
341
gobject.type_register(AttributeWidget)