Imported Upstream version 0.3~20101209
[debian/pino.git] / src / tree_widget.vala
1 using Gtk;
2 using PinoEnums;
3
4 public class TreeWidget : TreeView {
5         
6         public signal void cursor_moved(AStream stream);
7         
8         private Window parent;
9         private Accounts accounts;
10
11         private TreeStore store;
12         public TreePath current_tree_path;
13         
14         private Gdk.Pixbuf pix_account;
15         private Gdk.Pixbuf pix_updating;
16         
17         public Frame frame;
18         
19         public TreeWidget(Window parent, Accounts accounts) {
20                 this.parent = parent;
21                 this.accounts = accounts;
22                 
23                 try {
24                         pix_account = new Gdk.Pixbuf.from_file("/usr/share/icons/Humanity/places/24/folder-videos.svg");
25                         pix_updating = new Gdk.Pixbuf.from_file(Config.UPDATING_PATH);
26                 } catch(GLib.Error e) {
27                         debug(e.message);
28                 }
29                 
30                 accounts.insert_new_account.connect(new_account);
31                 accounts.insert_new_stream_after.connect((after_path, stream) => {
32                         new_stream(after_path, stream, true);
33                 });
34                 accounts.element_was_removed.connect(remove_element);
35                 
36                 set_rules_hint(false);
37                 set_headers_visible(false);
38                 
39                 frame = new Frame(null);
40                 frame.add(this);
41                 
42                 setup();
43                 
44                 accounts.fresh_items_changed.connect((items, path) => {
45                         TreeIter iter;
46                         
47                         store.get_iter_from_string(out iter, path);
48                         store.set(iter, 2, items.to_string(), -1);
49                 });
50                 
51                 accounts.account_was_changed.connect((path, account) => {
52                         TreeIter iter;
53                         store.get_iter_from_string(out iter, path);
54                         new_account_general(iter, account);
55                 });
56                 
57                 accounts.stream_was_changed.connect((path, stream) => {
58                         debug("stream was changed");
59                         debug(path);
60                         TreeIter iter;
61                         store.get_iter_from_string(out iter, path);
62                         
63                         new_stream_general(iter, stream);
64                 });
65                 
66                 button_release_event.connect(context_menu);
67         }
68
69         /** Building tree of accounts */
70         public void setup() {
71                 //var icon_cell = new CellRendererPixbuf();
72                 //icon_cell.stock_size = 24;
73                 
74                 insert_column_with_attributes(-1, "Icon", new IconWithStatusCellRrenderer(), "meta_row", 0, null);
75                 //insert_column_with_attributes(-1, "Name", new CellRendererText(), "text", 1, null);
76                 //insert_column_with_attributes(-1, "New messages", new UpdatesCellRrenderer(), "text", 2, null);
77         
78                 store = new TreeStore(1, typeof(MetaRow));
79                 set_model(store);
80
81                 foreach(AAccount acc in accounts) {
82                         debug(acc.s_name);
83                         TreeIter iter;
84                         store.append(out iter, null);
85                         new_account_general(iter, acc);
86                         new_streams(acc, iter);
87                 }
88
89                 expand_all();
90
91                 cursor_changed.connect(cursor_changed_callback);
92         }
93         
94         /** Set current item */
95         public void set_current(string path) {
96                 if(path == "")
97                         return;
98                 
99                 TreePath tree_path = new TreePath.from_string(path);
100                 set_cursor(tree_path, null, false);
101         }
102         
103         /** When current stream or account is changed */
104         private void cursor_changed_callback() {
105                 debug("cursor was changed");
106                 TreePath? path;
107                 TreeViewColumn column;
108
109                 get_cursor(out path, out column);
110                 
111                 if(path == null || path.to_string() == current_tree_path.to_string())
112                         return;
113                 
114                 current_tree_path = path;
115                 
116                 debug(path.to_string());
117
118                 if(path.get_depth() == 2) { //stream
119                         int account_index = path.to_string().split(":")[0].to_int();
120                         int stream_index = path.to_string().split(":")[1].to_int();
121                         
122                         AAccount active_account = accounts.get(account_index);
123                         AStream active_stream = active_account.streams.get(stream_index);
124                         
125                         string hash = active_account.get_stream_hash(active_stream);
126
127                         cursor_moved(active_stream);
128                 }
129         }
130
131         /** Get current account */
132         private AAccount? get_current_account() {
133                 TreePath path;
134                 TreeViewColumn column;
135
136                 get_cursor(out path, out column);
137                 string spath = path.to_string().split(":")[0];
138                 
139                 return accounts.get(spath.to_int());
140         }
141
142         /** Get current stream index */
143         private int? get_stream_index() {
144                 TreePath path;
145                 TreeViewColumn column;
146
147                 get_cursor(out path, out column);
148                 if(path.get_depth() < 2)
149                         return null;
150                 
151                 string spath = path.to_string().split(":")[1];
152                 
153                 return spath.to_int();
154         }
155         
156         /** Context menu for accounts and streams */
157         private bool context_menu(Gdk.EventButton event) {
158                 if(event.button != 3)
159                         return false;
160                 
161                 debug("popup");
162                 AAccount? account = get_current_account();
163                 if(account == null)
164                         return false;
165                 
166                 int? stream_index = get_stream_index();
167                 
168                 if(stream_index == null) { //display account menu
169                         Menu menu = new Menu(); //main popup
170
171                         Menu streams_menu = new Menu(); //for streams
172                         
173                         foreach(StreamEnum stream in account.avaliable_streams.keys) {
174                                 string label = streams_types.get(stream).name;
175                                 ImageMenuItem menu_item = new ImageMenuItem.with_label(label);
176                                 Image img = streams_types.get(stream).get_menu_image();
177                                 
178                                 if(img != null)
179                                         menu_item.set_image(img);
180                                 
181                                 menu_item.activate.connect(() => { //add new stream to account
182                                         account.add_stream(stream, true);
183                                 });
184                                 streams_menu.append(menu_item);
185                         }
186                         
187                         MenuItem streams_item = new MenuItem.with_label("Add stream");
188                         streams_item.set_submenu(streams_menu);
189                         menu.append(streams_item);
190                         
191                         foreach(MenuItems item in account.popup_items) {
192                                 MenuItems aitem = item;
193                                 MenuItem? menu_item = item2menu(item);
194                                 
195                                 menu_item.activate.connect(() => {
196                                         accounts.actions_tracker(account, aitem, parent);
197                                 });
198                                 
199                                 if(menu_item != null)
200                                         menu.append(menu_item);
201                                 else
202                                         debug("item doesn't supported");
203                         }
204                         
205                         menu.show_all();
206                         menu.popup(null, null, null, 1, event.time);
207                 } else { //display stream menu
208                         Menu menu = new Menu();
209                         
210                         foreach(MenuItems item in account.streams.get(stream_index).popup_items) {
211                                 MenuItems sitem = item;
212                                 debug("action: %d", sitem);
213                                 ImageMenuItem menu_item = item2menu(sitem);
214                                 
215                                 menu_item.activate.connect(() => {
216                                         account.streams_actions_tracker(stream_index, sitem);
217                                 });
218                                 menu.append(menu_item);
219                         }
220                         
221                         menu.show_all();
222                         debug("%d", (int) event.time);
223                         menu.popup(null, null, null, 1, event.time);
224                 }
225                 return true;
226         }
227         
228         private ImageMenuItem item2menu(MenuItems item) {
229                 string label = "";
230                 
231                 switch(item) {
232                 case MenuItems.SETTINGS:
233                         label = _("Settings...");
234                         break;
235                 
236                 case MenuItems.REMOVE:
237                         label = _("Remove");
238                         break;
239                 
240                 case MenuItems.REFRESH:
241                         label = _("Refresh");
242                         break;
243                 
244                 case MenuItems.MORE:
245                         label = _("Get more");
246                         break;
247                 }
248                 
249                 ImageMenuItem menu_item = new ImageMenuItem.with_label(label);
250                 
251                 return menu_item;
252         }
253         
254         /** add new account to the tree */
255         private void new_account(AAccount account) {
256                 TreeIter iter;
257                 store.append(out iter, null);
258                 
259                 new_account_general(iter, account);
260                 new_streams(account, iter);
261         }
262         
263         private void new_account_general(TreeIter iter, AAccount account) {
264                 Gdk.Pixbuf? acc_icon = account.userpic;
265                 if(acc_icon == null)
266                         acc_icon = pix_account;
267                 
268                 MetaRow meta_icon = new MetaRow(acc_icon,
269                         accounts_types.get(account.get_type()).icon,
270                         "%s (%s)".printf(account.s_name, accounts_types.get(account.get_type()).name),
271                         true);
272                 store.set(iter, 0, meta_icon);
273         }
274         
275         private void new_streams(AAccount account, TreeIter iter) {
276                 foreach(AStream stream in account.streams) {
277                         TreeIter iter_in;
278                         store.append(out iter_in, iter);
279                         
280                         new_stream_general(iter_in, stream);
281                 }
282         }
283         
284         /** add new stream to the tree */
285         private void new_stream(string after_path, AStream stream, bool activate = false) {
286                 TreeIter after_iter;
287                 store.get_iter_from_string(out after_iter, after_path);
288
289                 TreeIter iter;
290                 store.append(out iter, after_iter);
291
292                 new_stream_general(iter, stream);
293                 
294                 if(activate) {
295                         TreePath needed_path = store.get_path(iter);
296                         set_cursor(needed_path, null, false);
297                 }
298         }
299         
300         /** Remove stream or account */
301         private void remove_element(string path, AAccount account, AStream? stream = null) {
302                 TreeIter iter;
303                 store.get_iter_from_string(out iter, path);
304                 
305                 if(!store.remove(iter))
306                         debug("element wasn't removed");
307         }
308         
309         private void new_stream_general(TreeIter iter, AStream stream) {
310                 Gdk.Pixbuf stream_icon = streams_types.get(stream.stream_type).get_tree_pixbuf();
311                 Gdk.Pixbuf? status_icon = null;
312                 
313                 switch(stream.status) {
314                 case StreamStatus.UPDATING:
315                         status_icon = pix_updating;
316                         break;
317                 }
318                 
319                 string stream_name;
320                 if(stream.stream_type == StreamEnum.SEARCH)
321                         stream_name = ((ISearch) stream).s_keyword;
322                 else
323                         stream_name = streams_types.get(stream.stream_type).name;
324                 //MetaIcon meta_icon = new MetaIcon(stream_icon);
325                 store.set(iter, 0, new MetaRow(stream_icon, status_icon, stream_name,
326                         false, stream.fresh_items));
327         }
328 }