Imported Upstream version 0.3~20101209
[debian/pino.git] / src / accounts.vala
1 using Gee;
2 using Xml;
3 using PinoEnums;
4
5 public class Accounts : ArrayList<AAccount> {
6         
7         public signal void insert_new_account(AAccount account);
8         public signal void insert_new_stream_after(string after_path, AStream stream);
9         public signal void element_was_removed(string path, AAccount account, AStream? stream = null);
10         public signal void fresh_items_changed(int items, string path);
11         public signal void account_was_changed(string path, AAccount account);
12         public signal void stream_was_changed(string path, AStream stream);
13         public signal void stream_was_updated(string hash, AStream stream);
14         public signal void status_sent(AAccount account, bool ok, string error_msg = "");
15         public signal void message_indicate(string msg);
16         public signal void stop_indicate();
17         public signal void do_reply(AAccount account, Status status);
18         public signal void insert_reply(string stream_hash, string status_id, Status result);
19         
20         private string accounts_path;
21         
22         public Accounts() {
23                 base();
24                 
25                 init();
26         }
27         
28         private void init() {
29                 string app_dir = Environment.get_user_config_dir() + "/%s".printf(Config.APPNAME);
30                 
31                 var dir = File.new_for_path(app_dir);
32                 
33                 if(!dir.query_exists(null)) {
34                         try {
35                                 dir.make_directory(null);
36                         } catch(GLib.Error e) {
37                                 debug(e.message); //TODO
38                         }
39                 }
40                 
41                 dir = null;
42                 
43                 accounts_path = app_dir + "/accounts.xml";
44                 File acc_file = File.new_for_path(accounts_path);
45                 
46                 if(acc_file.query_exists(null)) {
47                         FileInputStream fstream;
48                         try {
49                                 fstream = acc_file.read(null);
50                         } catch(GLib.Error e) {
51                                 debug(e.message); //TODO
52                                 return;
53                         }
54                         DataInputStream stream = new DataInputStream(fstream);
55                         
56                         string data;
57                         try {
58                                 data = stream.read_until("", null, null);
59                         } catch(GLib.Error e) {
60                                 debug(e.message); //TODO
61                                 return;
62                         }
63                         from_xml(data);
64                 }
65         }
66         
67         public void sync() {
68                 File file = File.new_for_path(accounts_path);
69                 
70                 FileOutputStream stream;
71                 try {
72                         stream = file.replace(null, false, FileCreateFlags.NONE, null);
73                 } catch(GLib.Error e) {
74                         debug(e.message); //TODO
75                         return;
76                 }
77                 
78                 DataOutputStream data_stream = new DataOutputStream(stream);
79                 
80                 try {
81                         data_stream.put_string(to_xml(), null);
82                 } catch(GLib.Error e) {
83                         debug(e.message); //TODO
84                 }
85         }
86         
87         /** Converting values to string */
88         public static string value_to_string(Value v, Type t) {
89                 switch(t.name()) {
90                 case "gint":
91                         return v.get_int().to_string();
92                 
93                 case "gdouble":
94                         return v.get_double().to_string();
95                 
96                 case "gboolean":
97                         return v.get_boolean().to_string();
98                 
99                 case "gchararray":
100                         return v.get_string();
101                 
102                 case "PinoEnumsStreamEnum":
103                         return v.get_enum().to_string();
104                 
105                 default:
106                         return "";
107                 }
108         }
109         
110         /** Restoring values from string */
111         public static Value? value_from_string(string data, Type t) {
112                 Value? v = Value(t);
113                 
114                 switch(t.name()) {
115                 case "gint":
116                         v.set_int(data.to_int());
117                         break;
118                 
119                 case "gdouble":
120                         v.set_double(data.to_double());
121                         break;
122                 
123                 case "gboolean":
124                         v.set_boolean(data.to_bool());
125                         break;
126                 
127                 case "gchararray":
128                         v.set_string(data);
129                         break;
130                 
131                 case "PinoEnumsStreamEnum":
132                         v.set_enum(data.to_int());
133                         break;
134                 
135                 default:
136                         v = null;
137                         break;
138                 }
139                 
140                 return v;
141         }
142         
143         /** Save all accounts and it's streams properties to xml */
144         public string to_xml() {
145                 string result = "\n<accounts>\n%s</accounts>";
146                 string istr = "";
147                 
148                 foreach(AAccount account in this) {
149                         var obj = (ObjectClass) account.get_type().class_ref();
150                         
151                         string account_str = "\t<account type=\"%s\">\n%s\t</account>\n";
152                         string account_props = "";
153                         
154                         foreach(var p in obj.list_properties()) {
155                                 //debug("%s, %s", p.value_type.name(), p.get_name());
156                                 
157                                 if(p.get_name().substring(0, 2) != "s-") //we need only s-* properties
158                                         continue;
159                                 
160                                 Value v = Value(p.value_type);
161                                 account.get_property(p.get_name(), ref v);
162                         
163                                 string s_val = value_to_string(v, p.value_type);
164                         
165                                 if(s_val != "")
166                                         account_props += "\t\t<%s>%s</%s>\n".printf(p.get_name(), s_val, p.get_name());
167                         }
168                         
169                         string streams_result = "\t\t<streams>\n%s\t\t</streams>\n";
170                         string streams_str = "";
171                         
172                         foreach(AStream stream in account.streams) { //saving streams
173                                 var obj_stream = (ObjectClass) stream.get_type().class_ref();
174                                 string stream_str = "\t\t\t<stream type=\"%d\">\n%s\t\t\t</stream>\n";
175                                 string stream_props = "";
176                                 
177                                 foreach(var p in obj_stream.list_properties()) {
178                                         if(p.get_name().substring(0, 2) != "s-") //we need only s-* properties
179                                                 continue;
180                                         
181                                         Value v = Value(p.value_type);
182                                         stream.get_property(p.get_name(), ref v);
183                                         
184                                         string s_val = value_to_string(v, p.value_type);
185                                         
186                                         if(s_val != "")
187                                                 stream_props += "\t\t\t\t<%s>%s</%s>\n".printf(p.get_name(), s_val, p.get_name());
188                                 }
189                                 
190                                 streams_str += stream_str.printf(stream.stream_type, stream_props);
191                         }
192                         
193                         account_props += streams_result.printf(streams_str);
194                         
195                         //debug(streams_str);
196                         istr += account_str.printf(account.get_type().name(), account_props);
197                 }
198                 
199                 return result.printf(istr);
200         }
201         
202         /** Restore accounts and streams from xml */
203         public void from_xml(string data) {
204                 Doc* xml_doc = Parser.parse_memory(data, (int) data.size());
205                 Xml.Node* root_node = xml_doc->get_root_element();
206                 
207                 if(root_node == null)
208                         return;
209                 
210                 for(Xml.Node* iter = root_node->children; iter != null; iter = iter->next) {
211                         if(iter->type != ElementType.ELEMENT_NODE || iter->name != "account")
212                                 continue;
213                         
214                         string? account_type = iter->get_prop("type");
215                         if(account_type == null)
216                                 continue;
217                         
218                         AAccount account = (AAccount) Object.new(Type.from_name(account_type));
219                         prepare_account(account);
220                         
221                         HashMap<string, string> account_map = new HashMap<string, string>();
222                         
223                         /** Getting properties into hashmap and adding streams to account */
224                         for(Xml.Node* iter_acc = iter->children; iter_acc != null; iter_acc = iter_acc->next) {
225                                 if(iter_acc->type != ElementType.ELEMENT_NODE)
226                                         continue;
227                                 
228                                 switch(iter_acc->name) {
229                                 case "streams": //streams list
230                                         for(Xml.Node* iter_streams = iter_acc->children; iter_streams != null; iter_streams = iter_streams->next) {
231                                                 if(iter_streams->type != ElementType.ELEMENT_NODE || iter_streams->name != "stream")
232                                                         continue;
233                                                 debug("ok");
234                                                 string? stream_type = iter_streams->get_prop("type");
235                                                 if(stream_type == null)
236                                                         continue;
237                                                 
238                                                 HashMap<string, string> stream_map = new HashMap<string, string>();
239                                                 
240                                                 for(Xml.Node* iter_stream = iter_streams->children; iter_stream != null; iter_stream = iter_stream->next) {
241                                                         if(iter_stream->type != ElementType.ELEMENT_NODE)
242                                                                 continue;
243                                                         
244                                                         stream_map.set(iter_stream->name, iter_stream->get_content());
245                                                 }
246                                                 
247                                                 account.add_stream((StreamEnum) stream_type.to_int(),
248                                                         false, stream_map);
249                                         }
250                                         break;
251                                 
252                                 default: //all other properties
253                                         account_map.set(iter_acc->name, iter_acc->get_content());
254                                         break;
255                                 }
256                         }
257                         
258                         /** Setting properties to account */
259                         var obj = (ObjectClass) Type.from_name(account_type).class_ref();
260                         foreach(var p in obj.list_properties()) {
261                                 string? pval = account_map.get(p.get_name());
262                                 
263                                 if(pval == null)
264                                         continue;
265                                 
266                                 Value? val = value_from_string(pval, p.value_type);
267                                 
268                                 if(val == null) {
269                                         debug("this value type is not supported");
270                                         continue;
271                                 }
272                                 
273                                 account.set_property(p.get_name(), val);
274                         }
275                         
276                         account.post_install();
277                         add(account);
278                 }
279         }
280         
281         /** Add new account */
282         public void add_account(Type t, Gtk.Window w) {
283                 AAccount account = (AAccount) GLib.Object.new(t);
284                 
285                 if(!account.create(w))
286                         return;
287                 
288                 prepare_account(account);
289                 account.post_install();
290                 insert_new_account(account); //signal for tree and others
291                 
292                 add(account);
293         }
294         
295         private void prepare_account(AAccount account) {
296                 account.stream_was_added.connect(new_stream);
297                 account.stream_was_removed.connect(remove_stream);
298                 account.account_was_changed.connect(account_update);
299                 account.stream_was_changed.connect(stream_change);
300                 account.stream_was_updated.connect(stream_update);
301                 account.status_sent.connect((ac, ok, msg) => {
302                         status_sent(ac, ok, msg);
303                 });
304                 account.message_indicate.connect((msg) => {
305                         message_indicate(msg);
306                 });
307                 account.stop_indicate.connect(() => {
308                         stop_indicate();
309                 });
310                 
311                 account.do_reply.connect((acc, status) => {
312                         do_reply(acc, status);
313                 });
314                 
315                 account.insert_reply.connect((stream_hash, status_id, result) => {
316                         insert_reply(stream_hash, status_id, result);
317                 });
318         }
319
320         /** New stream was added, we need to report about this to the tree widget */
321         private void new_stream(AAccount account, AStream stream) {
322                 int account_index = index_of(account);
323                 insert_new_stream_after(account_index.to_string(), stream);
324         }
325         
326         /** Stream was removed from some account */
327         private void remove_stream(AAccount account, int stream_index) {
328                 int account_index = index_of(account);
329                 AStream stream = account.streams.get(stream_index);
330                 element_was_removed("%d:%d".printf(account_index, stream_index), account, stream);
331         }
332         
333         /** New data in account */
334         private void account_update(AAccount account) {
335                 int account_index = index_of(account);
336                 account_was_changed(account_index.to_string(), account);
337         }
338         
339         /** New data in stream */
340         private void stream_change(AAccount account, AStream stream, int stream_index) {
341                 int account_index = index_of(account);
342                 stream_was_changed("%d:%d".printf(account_index, stream_index), stream);
343         }
344         
345         /** Generate list from stream */
346         private void stream_update(string hash, AStream stream) {
347                 stream_was_updated(hash, stream);
348         }
349         
350         /** Send 'updated' signal from all streams */
351         public void update_all_streams() {
352                 foreach(AAccount account in this) {
353                         foreach(AStream stream in account.streams) {
354                                 stream.updated();
355                         }
356                 }
357         }
358         
359         /** Somesing pressed in content view */
360         public void new_content_action(string action_type, string path) {
361                 string[] params = path.split("##");
362                 
363                 if(params.length < 3)
364                         return;
365                 
366                 string account_hash = params[0];
367                 string stream_hash = params[1];
368                 string val = params[2];
369                 
370                 
371                 AAccount? account = null;
372                 foreach(AAccount acc in this) {
373                         if(acc.get_hash() == account_hash) {
374                                 account = acc;
375                                 break;
376                         }
377                 }
378                 
379                 if(account == null) {
380                         debug("can't find this account");
381                         return;
382                 }
383                 
384                 account.new_content_action(action_type, stream_hash, val);
385         }
386         
387         /** Return stream from hash */
388         public AStream? stream_from_hash(string hash) {
389                 foreach(AAccount account in this) {
390                         foreach(AStream fstream in account.streams) {
391                                 if(account.get_stream_hash(fstream) == hash)
392                                         return fstream;
393                         }
394                 }
395                 
396                 return null;
397         }
398         
399         /** Action for accounts */
400         public virtual void actions_tracker(AAccount account, MenuItems item,
401                 Gtk.Window parent) {
402                 
403                 switch(item) {
404                 case MenuItems.REMOVE:
405                         Gtk.MessageDialog dlg = new Gtk.MessageDialog(parent, Gtk.DialogFlags.MODAL,
406                                 Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO,
407                                 _("Do you realy want to remove this account?"));
408                         
409                         int result = dlg.run();
410                         dlg.close();
411                         
412                         if(result == Gtk.ResponseType.YES) {
413                                 debug("remove");
414                                 int account_index = index_of(account);
415                                 element_was_removed(account_index.to_string(), account);
416                                 this.remove(account);
417                         }
418                         break;
419                 }
420         }
421         
422         public AAccount? get_by_hash(string hash) {
423                 foreach(AAccount account in this) {
424                         if(account.get_hash() == hash)
425                                 return account;
426                 }
427                 
428                 return null;
429         }
430 }