diff options
author | Tudor Florea <tudor.florea@enea.com> | 2014-10-16 03:05:19 +0200 |
---|---|---|
committer | Tudor Florea <tudor.florea@enea.com> | 2014-10-16 03:05:19 +0200 |
commit | c527fd1f14c27855a37f2e8ac5346ce8d940ced2 (patch) | |
tree | bb002c1fdf011c41dbd2f0927bed23ecb5f83c97 /bitbake/lib/bb/ui/crumbs/hig/layerselectiondialog.py | |
download | poky-c527fd1f14c27855a37f2e8ac5346ce8d940ced2.tar.gz |
initial commit for Enea Linux 4.0-140929daisy-140929
Migrated from the internal git server on the daisy-enea-point-release branch
Signed-off-by: Tudor Florea <tudor.florea@enea.com>
Diffstat (limited to 'bitbake/lib/bb/ui/crumbs/hig/layerselectiondialog.py')
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/hig/layerselectiondialog.py | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/bitbake/lib/bb/ui/crumbs/hig/layerselectiondialog.py b/bitbake/lib/bb/ui/crumbs/hig/layerselectiondialog.py new file mode 100644 index 0000000000..52d57b6738 --- /dev/null +++ b/bitbake/lib/bb/ui/crumbs/hig/layerselectiondialog.py | |||
@@ -0,0 +1,298 @@ | |||
1 | # | ||
2 | # BitBake Graphical GTK User Interface | ||
3 | # | ||
4 | # Copyright (C) 2011-2012 Intel Corporation | ||
5 | # | ||
6 | # Authored by Joshua Lock <josh@linux.intel.com> | ||
7 | # Authored by Dongxiao Xu <dongxiao.xu@intel.com> | ||
8 | # Authored by Shane Wang <shane.wang@intel.com> | ||
9 | # | ||
10 | # This program is free software; you can redistribute it and/or modify | ||
11 | # it under the terms of the GNU General Public License version 2 as | ||
12 | # published by the Free Software Foundation. | ||
13 | # | ||
14 | # This program is distributed in the hope that it will be useful, | ||
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | # GNU General Public License for more details. | ||
18 | # | ||
19 | # You should have received a copy of the GNU General Public License along | ||
20 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
22 | |||
23 | import gtk | ||
24 | import gobject | ||
25 | import os | ||
26 | import tempfile | ||
27 | from bb.ui.crumbs.hobwidget import hic, HobButton, HobAltButton | ||
28 | from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog | ||
29 | from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog | ||
30 | |||
31 | """ | ||
32 | The following are convenience classes for implementing GNOME HIG compliant | ||
33 | BitBake GUI's | ||
34 | In summary: spacing = 12px, border-width = 6px | ||
35 | """ | ||
36 | |||
37 | class CellRendererPixbufActivatable(gtk.CellRendererPixbuf): | ||
38 | """ | ||
39 | A custom CellRenderer implementation which is activatable | ||
40 | so that we can handle user clicks | ||
41 | """ | ||
42 | __gsignals__ = { 'clicked' : (gobject.SIGNAL_RUN_LAST, | ||
43 | gobject.TYPE_NONE, | ||
44 | (gobject.TYPE_STRING,)), } | ||
45 | |||
46 | def __init__(self): | ||
47 | gtk.CellRendererPixbuf.__init__(self) | ||
48 | self.set_property('mode', gtk.CELL_RENDERER_MODE_ACTIVATABLE) | ||
49 | self.set_property('follow-state', True) | ||
50 | |||
51 | """ | ||
52 | Respond to a user click on a cell | ||
53 | """ | ||
54 | def do_activate(self, even, widget, path, background_area, cell_area, flags): | ||
55 | self.emit('clicked', path) | ||
56 | |||
57 | # | ||
58 | # LayerSelectionDialog | ||
59 | # | ||
60 | class LayerSelectionDialog (CrumbsDialog): | ||
61 | |||
62 | TARGETS = [ | ||
63 | ("MY_TREE_MODEL_ROW", gtk.TARGET_SAME_WIDGET, 0), | ||
64 | ("text/plain", 0, 1), | ||
65 | ("TEXT", 0, 2), | ||
66 | ("STRING", 0, 3), | ||
67 | ] | ||
68 | |||
69 | def gen_label_widget(self, content): | ||
70 | label = gtk.Label() | ||
71 | label.set_alignment(0, 0) | ||
72 | label.set_markup(content) | ||
73 | label.show() | ||
74 | return label | ||
75 | |||
76 | def layer_widget_toggled_cb(self, cell, path, layer_store): | ||
77 | name = layer_store[path][0] | ||
78 | toggle = not layer_store[path][1] | ||
79 | layer_store[path][1] = toggle | ||
80 | |||
81 | def layer_widget_add_clicked_cb(self, action, layer_store, parent): | ||
82 | dialog = gtk.FileChooserDialog("Add new layer", parent, | ||
83 | gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER) | ||
84 | button = dialog.add_button("Cancel", gtk.RESPONSE_NO) | ||
85 | HobAltButton.style_button(button) | ||
86 | button = dialog.add_button("Open", gtk.RESPONSE_YES) | ||
87 | HobButton.style_button(button) | ||
88 | label = gtk.Label("Select the layer you wish to add") | ||
89 | label.show() | ||
90 | dialog.set_extra_widget(label) | ||
91 | response = dialog.run() | ||
92 | path = dialog.get_filename() | ||
93 | dialog.destroy() | ||
94 | |||
95 | lbl = "<b>Error</b>" | ||
96 | msg = "Unable to load layer <i>%s</i> because " % path | ||
97 | if response == gtk.RESPONSE_YES: | ||
98 | import os | ||
99 | import os.path | ||
100 | layers = [] | ||
101 | it = layer_store.get_iter_first() | ||
102 | while it: | ||
103 | layers.append(layer_store.get_value(it, 0)) | ||
104 | it = layer_store.iter_next(it) | ||
105 | |||
106 | if not path: | ||
107 | msg += "it is an invalid path." | ||
108 | elif not os.path.exists(path+"/conf/layer.conf"): | ||
109 | msg += "there is no layer.conf inside the directory." | ||
110 | elif path in layers: | ||
111 | msg += "it is already in loaded layers." | ||
112 | else: | ||
113 | layer_store.append([path]) | ||
114 | return | ||
115 | dialog = CrumbsMessageDialog(parent, lbl, gtk.MESSAGE_ERROR, msg) | ||
116 | dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_OK) | ||
117 | response = dialog.run() | ||
118 | dialog.destroy() | ||
119 | |||
120 | def layer_widget_del_clicked_cb(self, action, tree_selection, layer_store): | ||
121 | model, iter = tree_selection.get_selected() | ||
122 | if iter: | ||
123 | layer_store.remove(iter) | ||
124 | |||
125 | |||
126 | def gen_layer_widget(self, layers, layers_avail, window, tooltip=""): | ||
127 | hbox = gtk.HBox(False, 6) | ||
128 | |||
129 | layer_tv = gtk.TreeView() | ||
130 | layer_tv.set_rules_hint(True) | ||
131 | layer_tv.set_headers_visible(False) | ||
132 | tree_selection = layer_tv.get_selection() | ||
133 | tree_selection.set_mode(gtk.SELECTION_SINGLE) | ||
134 | |||
135 | # Allow enable drag and drop of rows including row move | ||
136 | dnd_internal_target = '' | ||
137 | dnd_targets = [(dnd_internal_target, gtk.TARGET_SAME_WIDGET, 0)] | ||
138 | layer_tv.enable_model_drag_source( gtk.gdk.BUTTON1_MASK, | ||
139 | dnd_targets, | ||
140 | gtk.gdk.ACTION_MOVE) | ||
141 | layer_tv.enable_model_drag_dest(dnd_targets, | ||
142 | gtk.gdk.ACTION_MOVE) | ||
143 | layer_tv.connect("drag_data_get", self.drag_data_get_cb) | ||
144 | layer_tv.connect("drag_data_received", self.drag_data_received_cb) | ||
145 | |||
146 | col0= gtk.TreeViewColumn('Path') | ||
147 | cell0 = gtk.CellRendererText() | ||
148 | cell0.set_padding(5,2) | ||
149 | col0.pack_start(cell0, True) | ||
150 | col0.set_cell_data_func(cell0, self.draw_layer_path_cb) | ||
151 | layer_tv.append_column(col0) | ||
152 | |||
153 | scroll = gtk.ScrolledWindow() | ||
154 | scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) | ||
155 | scroll.set_shadow_type(gtk.SHADOW_IN) | ||
156 | scroll.add(layer_tv) | ||
157 | |||
158 | table_layer = gtk.Table(2, 10, False) | ||
159 | hbox.pack_start(table_layer, expand=True, fill=True) | ||
160 | |||
161 | table_layer.attach(scroll, 0, 10, 0, 1) | ||
162 | |||
163 | layer_store = gtk.ListStore(gobject.TYPE_STRING) | ||
164 | for layer in layers: | ||
165 | layer_store.append([layer]) | ||
166 | |||
167 | col1 = gtk.TreeViewColumn('Enabled') | ||
168 | layer_tv.append_column(col1) | ||
169 | |||
170 | cell1 = CellRendererPixbufActivatable() | ||
171 | cell1.set_fixed_size(-1,35) | ||
172 | cell1.connect("clicked", self.del_cell_clicked_cb, layer_store) | ||
173 | col1.pack_start(cell1, True) | ||
174 | col1.set_cell_data_func(cell1, self.draw_delete_button_cb, layer_tv) | ||
175 | |||
176 | add_button = gtk.Button() | ||
177 | add_button.set_relief(gtk.RELIEF_NONE) | ||
178 | box = gtk.HBox(False, 6) | ||
179 | box.show() | ||
180 | add_button.add(box) | ||
181 | add_button.connect("enter-notify-event", self.add_hover_cb) | ||
182 | add_button.connect("leave-notify-event", self.add_leave_cb) | ||
183 | self.im = gtk.Image() | ||
184 | self.im.set_from_file(hic.ICON_INDI_ADD_FILE) | ||
185 | self.im.show() | ||
186 | box.pack_start(self.im, expand=False, fill=False, padding=6) | ||
187 | lbl = gtk.Label("Add layer") | ||
188 | lbl.set_alignment(0.0, 0.5) | ||
189 | lbl.show() | ||
190 | box.pack_start(lbl, expand=True, fill=True, padding=6) | ||
191 | add_button.connect("clicked", self.layer_widget_add_clicked_cb, layer_store, window) | ||
192 | table_layer.attach(add_button, 0, 10, 1, 2, gtk.EXPAND | gtk.FILL, 0, 0, 6) | ||
193 | layer_tv.set_model(layer_store) | ||
194 | |||
195 | hbox.show_all() | ||
196 | |||
197 | return hbox, layer_store | ||
198 | |||
199 | def drag_data_get_cb(self, treeview, context, selection, target_id, etime): | ||
200 | treeselection = treeview.get_selection() | ||
201 | model, iter = treeselection.get_selected() | ||
202 | data = model.get_value(iter, 0) | ||
203 | selection.set(selection.target, 8, data) | ||
204 | |||
205 | def drag_data_received_cb(self, treeview, context, x, y, selection, info, etime): | ||
206 | model = treeview.get_model() | ||
207 | data = selection.data | ||
208 | drop_info = treeview.get_dest_row_at_pos(x, y) | ||
209 | if drop_info: | ||
210 | path, position = drop_info | ||
211 | iter = model.get_iter(path) | ||
212 | if (position == gtk.TREE_VIEW_DROP_BEFORE or position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE): | ||
213 | model.insert_before(iter, [data]) | ||
214 | else: | ||
215 | model.insert_after(iter, [data]) | ||
216 | else: | ||
217 | model.append([data]) | ||
218 | if context.action == gtk.gdk.ACTION_MOVE: | ||
219 | context.finish(True, True, etime) | ||
220 | return | ||
221 | |||
222 | def add_hover_cb(self, button, event): | ||
223 | self.im.set_from_file(hic.ICON_INDI_ADD_HOVER_FILE) | ||
224 | |||
225 | def add_leave_cb(self, button, event): | ||
226 | self.im.set_from_file(hic.ICON_INDI_ADD_FILE) | ||
227 | |||
228 | def __init__(self, title, layers, layers_non_removable, all_layers, parent, flags, buttons=None): | ||
229 | super(LayerSelectionDialog, self).__init__(title, parent, flags, buttons) | ||
230 | |||
231 | # class members from other objects | ||
232 | self.layers = layers | ||
233 | self.layers_non_removable = layers_non_removable | ||
234 | self.all_layers = all_layers | ||
235 | self.layers_changed = False | ||
236 | |||
237 | # icon for remove button in TreeView | ||
238 | im = gtk.Image() | ||
239 | im.set_from_file(hic.ICON_INDI_REMOVE_FILE) | ||
240 | self.rem_icon = im.get_pixbuf() | ||
241 | |||
242 | # class members for internal use | ||
243 | self.layer_store = None | ||
244 | |||
245 | # create visual elements on the dialog | ||
246 | self.create_visual_elements() | ||
247 | self.connect("response", self.response_cb) | ||
248 | |||
249 | def create_visual_elements(self): | ||
250 | layer_widget, self.layer_store = self.gen_layer_widget(self.layers, self.all_layers, self, None) | ||
251 | layer_widget.set_size_request(450, 250) | ||
252 | self.vbox.pack_start(layer_widget, expand=True, fill=True) | ||
253 | self.show_all() | ||
254 | |||
255 | def response_cb(self, dialog, response_id): | ||
256 | model = self.layer_store | ||
257 | it = model.get_iter_first() | ||
258 | layers = [] | ||
259 | while it: | ||
260 | layers.append(model.get_value(it, 0)) | ||
261 | it = model.iter_next(it) | ||
262 | |||
263 | self.layers_changed = (self.layers != layers) | ||
264 | self.layers = layers | ||
265 | |||
266 | """ | ||
267 | A custom cell_data_func to draw a delete 'button' in the TreeView for layers | ||
268 | other than the meta layer. The deletion of which is prevented so that the | ||
269 | user can't shoot themselves in the foot too badly. | ||
270 | """ | ||
271 | def draw_delete_button_cb(self, col, cell, model, it, tv): | ||
272 | path = model.get_value(it, 0) | ||
273 | if path in self.layers_non_removable: | ||
274 | cell.set_sensitive(False) | ||
275 | cell.set_property('pixbuf', None) | ||
276 | cell.set_property('mode', gtk.CELL_RENDERER_MODE_INERT) | ||
277 | else: | ||
278 | cell.set_property('pixbuf', self.rem_icon) | ||
279 | cell.set_sensitive(True) | ||
280 | cell.set_property('mode', gtk.CELL_RENDERER_MODE_ACTIVATABLE) | ||
281 | |||
282 | return True | ||
283 | |||
284 | """ | ||
285 | A custom cell_data_func to write an extra message into the layer path cell | ||
286 | for the meta layer. We should inform the user that they can't remove it for | ||
287 | their own safety. | ||
288 | """ | ||
289 | def draw_layer_path_cb(self, col, cell, model, it): | ||
290 | path = model.get_value(it, 0) | ||
291 | if path in self.layers_non_removable: | ||
292 | cell.set_property('markup', "<b>It cannot be removed</b>\n%s" % path) | ||
293 | else: | ||
294 | cell.set_property('text', path) | ||
295 | |||
296 | def del_cell_clicked_cb(self, cell, path, model): | ||
297 | it = model.get_iter_from_string(path) | ||
298 | model.remove(it) | ||