Imported Upstream version 0.2.1
[debian/pino.git] / src / main_window.vala
1 /* main_window.vala
2  *
3  * Copyright (C) 2009-2010  troorl
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser 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  * This program 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 Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  * Author:
19  *      troorl <troorl@gmail.com>
20  */
21
22 using Gtk;
23 using WebKit;
24 using RestAPI;
25 using Auth;
26
27 public class MainWindow : Window {
28         
29         unowned SList<RadioAction> list_group;
30         
31         private Action updateAct;
32         private ToggleAction menuAct;
33         private ToggleAction toolbarAct;
34         private AccountAction accountAct;
35         
36         private TrayIcon tray;
37         
38         private Gdk.Pixbuf logo;
39         private Gdk.Pixbuf logo_fresh;
40         
41         private Widget menubar;
42         private Widget toolbar;
43         private Menu popup;
44         //private IconEntry searchEntry;
45         private HBox sbox;
46         
47         private SystemStyle gtk_style;
48         
49         public TimelineList home;
50         public TimelineList mentions;
51         public TimelineDirectList direct;
52         public UserInfoList user_info;
53         
54         public ReTweet re_tweet;
55         public StatusbarSmart statusbar;
56         
57         //private TwitterInterface twee;
58         private Cache cache;
59         private Template template;
60         
61         private Prefs prefs;
62         private Accounts accounts;
63         private SmartTimer timer;
64         
65         private AuthData auth_data;
66         
67         private Popups notify;
68         
69         public bool first_show = true;
70         
71         public MainWindow() {
72                 logo = new Gdk.Pixbuf.from_file(Config.LOGO_PATH);
73                 logo_fresh = new Gdk.Pixbuf.from_file(Config.LOGO_FRESH_PATH);
74                 
75                 //getting settings
76                 prefs = new Prefs();
77                 
78                 accounts = new Accounts();
79                 accounts.active_changed.connect(() => {
80                         refresh_auth();
81                 });
82                 
83                 accounts.changed.connect((hash) => {
84                         var acc = accounts.get_current_account();
85                         string cur_hash = acc.login + acc.password + acc.proxy;
86                         
87                         if(cur_hash == hash)
88                                 refresh_auth();
89                 });
90                 
91                 set_default_size (prefs.width, prefs.height);
92                 set_size_request(350, 300);
93                 
94                 //set window position
95                 if(prefs.left >= 0 && prefs.top >= 0)
96                         move(prefs.left, prefs.top);
97                 
98                 configure_event.connect((widget, event) => {
99                         //saving window size and position
100                         prefs.width = event.width;
101                         prefs.height = event.height;
102                         prefs.left = event.x;
103                         prefs.top = event.y;
104                         
105                         return false;
106                 });
107                 
108                 set_icon(logo);
109                 set_title(Config.APPNAME);
110                 
111                 destroy.connect(() => before_close());
112                 
113                 gtk_style = new SystemStyle(rc_get_style(this));
114                 this.map_event.connect((event) => {
115                         gtk_style = new SystemStyle(rc_get_style(this));
116                         return true;
117                 });
118                 
119                 cache = new Cache();
120                 //template setup
121                 template = new Template(prefs, accounts, gtk_style, cache);
122                 
123                 //home timeline
124                 home = new TimelineList(this, accounts, TimelineType.HOME,
125                         template, prefs.numberStatuses,
126                         Icon.new_for_string(Config.TIMELINE_PATH),
127                         Icon.new_for_string(Config.TIMELINE_FRESH_PATH), "HomeAct", _("Home timeline"),
128                         _("Show your home timeline"), true);
129                 
130                 //mentions
131                 mentions = new TimelineList(this, accounts, TimelineType.MENTIONS,
132                         template, prefs.numberStatuses,
133                         Icon.new_for_string(Config.MENTIONS_PATH),
134                         Icon.new_for_string(Config.MENTIONS_FRESH_PATH), "MentionsAct", _("Mentions"),
135                         _("Show mentions"));
136                 
137                 //direct messages
138                 direct = new TimelineDirectList(this, accounts,
139                         template, prefs.numberStatuses,
140                         Icon.new_for_string(Config.DIRECT_PATH),
141                         Icon.new_for_string(Config.DIRECT_FRESH_PATH), "DirectAct", _("Direct messages"),
142                         _("Show direct messages"));
143                 
144                 //user info
145                 user_info = new UserInfoList(this, accounts, template, prefs.numberStatuses,
146                         Icon.new_for_string(Config.USERPIC_PATH), "UserInfoAct",
147                         _("User info"), _("Show information about user"));
148                 
149                 home.fresh.connect(() => tray.new_tweets(true));
150                 mentions.fresh.connect(() => tray.new_tweets(true));
151                 direct.fresh.connect(() => tray.new_tweets(true));
152                 home.no_fresh.connect(() => check_fresh());
153                 mentions.no_fresh.connect(() => check_fresh());
154                 direct.no_fresh.connect(() => check_fresh());
155                 
156                 //group for lists
157                 list_group = home.act.get_group();
158                 mentions.act.set_group(home.act.get_group());
159                 direct.act.set_group(home.act.get_group());
160                 user_info.act.set_group(home.act.get_group());
161                 
162                 //retweet widget
163                 re_tweet = new ReTweet(this, prefs, accounts, cache, gtk_style);
164                 re_tweet.status_updated.connect((status) => {
165                         home.insert_status(status);
166                 });
167                 
168                 menu_init();
169                 
170                 //set popup menu to the views
171                 home.popup = popup;
172                 mentions.popup = popup;
173                 direct.popup = popup;
174                 user_info.popup = popup;
175                 
176                 //tray setup
177                 tray = new TrayIcon(this, logo, logo_fresh);
178                 tray.set_visible(prefs.showTray);
179                 
180                 tray.popup = popup;
181                 prefs.showTrayChanged.connect(() => {
182                         tray.set_visible(prefs.showTray);
183                 });
184                 
185                 //hiding on closing main window
186                 delete_event.connect((event) => {
187                         if(!tray.visible) { //close pino, if tray is hided
188                                 before_close();
189                                 return true;
190                         }
191                         
192                         this.hide_on_delete();
193                         visible = false;
194                         return true;
195                 });
196                 
197                 re_tweet.sending_data.connect((msg) => {
198                         statusbar.set_status(StatusbarSmart.StatusType.SENDING_DATA, msg);
199                 });
200                 
201                 re_tweet.data_sent.connect((msg) => {
202                         statusbar.set_status(StatusbarSmart.StatusType.DATA_SENT, msg);
203                 });
204                 
205                 re_tweet.data_error_sent.connect((msg) => {
206                         statusbar.set_status(StatusbarSmart.StatusType.FINISH_ERROR, msg);
207                 });
208                 
209                 home.nickto.connect((screen_name) => {
210                         re_tweet.set_nickto(screen_name);
211                 });
212                 mentions.nickto.connect((screen_name) => {
213                         re_tweet.set_nickto(screen_name);
214                 });
215                 direct.nickto.connect((screen_name) => {
216                         re_tweet.set_nickto(screen_name);
217                 });
218                 home.user_info.connect((screen_name) => {
219                         user_info.show_user(screen_name);
220                 });
221                 mentions.user_info.connect((screen_name) => {
222                         user_info.show_user(screen_name);
223                 });
224                 direct.user_info.connect((screen_name) => {
225                         user_info.show_user(screen_name);
226                 });
227                 user_info.user_info.connect((screen_name) => {
228                         user_info.show_user(screen_name);
229                 });
230                 home.retweet.connect((status) => {
231                         re_tweet.set_state_retweet(status);
232                 });
233                 mentions.retweet.connect((status) => {
234                         re_tweet.set_state_retweet(status);
235                 });
236                 home.directreply.connect((screen_name) => {
237                         re_tweet.set_state_directreply(screen_name);
238                 });
239                 mentions.directreply.connect((screen_name) => {
240                         re_tweet.set_state_directreply(screen_name);
241                 });
242                 direct.directreply.connect((screen_name) => {
243                         re_tweet.set_state_directreply(screen_name);
244                 });
245                 home.replyto.connect((status) => {
246                         re_tweet.set_state_reply(status);
247                 });
248                 mentions.replyto.connect((status) => {
249                         re_tweet.set_state_reply(status);
250                 });
251                 home.deleted.connect((msg) => {
252                         statusbar.set_status(StatusbarSmart.StatusType.DATA_SENT, msg);
253                 });
254                 direct.deleted.connect((msg) => {
255                         statusbar.set_status(StatusbarSmart.StatusType.DATA_SENT, msg);
256                 });
257                 user_info.start_fetch.connect(() => {
258                         statusbar.set_status(StatusbarSmart.StatusType.UPDATING);
259                 });
260                 user_info.end_fetch.connect(() => {
261                         statusbar.set_status(StatusbarSmart.StatusType.FINISH_OK);
262                 });
263                 user_info.follow_event.connect((msg) => {
264                         statusbar.set_status(StatusbarSmart.StatusType.DATA_SENT, msg);
265                 });
266                 
267                 //setup logging
268                 statusbar = new StatusbarSmart();
269                 home.start_update.connect((req) => statusbar.logging(req));
270                 mentions.start_update.connect((req) => statusbar.logging(req));
271                 direct.start_update.connect((req) => statusbar.logging(req));
272                 re_tweet.start_update.connect((req) => statusbar.logging(req));
273                 
274                 home.finish_update.connect(() => statusbar.logging(_("updated ")));
275                 mentions.finish_update.connect(() => statusbar.logging(_("updated ")));
276                 direct.finish_update.connect(() => statusbar.logging(_("updated ")));
277                 home.updating_error.connect((msg) => {
278                         statusbar.set_status(StatusbarSmart.StatusType.FINISH_ERROR, msg);
279                 });
280                 mentions.updating_error.connect((msg) => {
281                         statusbar.set_status(StatusbarSmart.StatusType.FINISH_ERROR, msg);
282                 });
283                 direct.updating_error.connect((msg) => {
284                         statusbar.set_status(StatusbarSmart.StatusType.FINISH_ERROR, msg);
285                 });
286                 user_info.updating_error.connect((msg) => {
287                         statusbar.set_status(StatusbarSmart.StatusType.FINISH_ERROR, msg);
288                 });
289                 
290                 VBox vbox = new VBox(false, 0);
291                 vbox.pack_start(menubar, false, false, 0);
292                 vbox.pack_start(toolbar, false, false, 0);
293                 //vbox.pack_start(sbox, false, false, 0);
294                 vbox.pack_start(home, true, true, 0);
295                 vbox.pack_start(mentions, true, true, 0);
296                 vbox.pack_start(direct, true, true, 0);
297                 vbox.pack_start(user_info, true, true, 0);
298                 vbox.pack_end(statusbar, false, false, 0);
299                 vbox.pack_end(re_tweet, false, false, 0);
300                 
301                 this.add(vbox);
302                 
303                 //show window
304                 if(!prefs.startMin || !prefs.showTray) {
305                         first_show = false;
306                         show_all();
307                         first_hide();
308                 }
309                 
310                 //hide menubar and toolbar if needed
311                 if(!prefs.menuShow)
312                         menuAct.set_active(false);
313                 if(!prefs.toolbarShow)
314                         toolbarAct.set_active(false);
315                 
316                 if(accounts.is_new)
317                         run_prefs();
318                 
319                 //notification popups
320                 notify = new Popups(prefs, accounts, cache, logo);
321                 
322                 //first_hide();
323                 
324                 //getting updates
325                 if(accounts.accounts.size > 0) {
326                         refresh_action();
327                 }
328                 
329                 style_set.connect((prev_style) => { //when gtk style is changing
330                         gtk_style.updateStyle(rc_get_style(this));
331                         template.refresh_gtk_style(gtk_style);
332                 });
333                 
334                 //start timer
335                 timer = new SmartTimer(prefs.updateInterval * 60);
336                 timer.timeout.connect(refresh_action);
337         }
338         
339         public void first_hide() { //when starts minimized
340                 re_tweet.hide();
341                 mentions.hide();
342                 direct.hide();
343                 user_info.hide();
344                 user_info.set_empty();
345                 
346                 if(!prefs.menuShow)
347                         menubar.hide();
348                 if(!prefs.toolbarShow)
349                         toolbar.hide();
350         }
351         
352         private void refresh_auth() {
353                 updateAct.set_sensitive(false);
354                 statusbar.set_status(StatusbarSmart.StatusType.UPDATING);
355                 
356                 re_tweet.update_auth();
357                 home.update_auth();
358                 mentions.update_auth();
359                 direct.update_auth();
360                 user_info.update_auth();
361                 
362                 statusbar.set_status(StatusbarSmart.StatusType.FINISH_OK);
363                 updateAct.set_sensitive(true);
364         }
365         
366         private void menu_init() {      
367                 var actGroup = new ActionGroup("main");
368                 
369                 //file menu
370                 var fileMenu = new Action("FileMenu", "Pino", null, null);
371                 
372                 var createAct = new Action("FileCreate", _("New status"),
373                         _("Create new status"), STOCK_EDIT);
374                 createAct.activate.connect(() => { re_tweet.set_state_new(); });
375                 
376                 var createDirectAct = new Action("FileCreateDirect", _("New direct message"),
377                         _("Create new direct message"), null);
378                 createDirectAct.set_gicon(Icon.new_for_string(Config.DIRECT_REPLY_PATH));
379                 createDirectAct.activate.connect(() => {
380                         re_tweet.set_state_directreply("");
381                 });
382                 
383                 var showUserAct = new Action("ShowUser", _("Show user"),
384                         _("Show information about specified user"), null);
385                 showUserAct.activate.connect(() => {
386                         user_info.set_empty();
387                         user_info.act.activate();
388                 });
389                 
390                 updateAct = new Action("FileUpdate", _("Update timeline"),
391                         null, STOCK_REFRESH);
392                 updateAct.activate.connect(refresh_action);
393                 var quitAct = new Action("FileQuit", _("Quit"),
394                         null, STOCK_QUIT);
395                 quitAct.activate.connect(before_close);
396                 
397                 //edit menu
398                 var editMenu = new Action("EditMenu", _("Edit"), null, null);
399                 accountAct = new AccountAction();
400                 accountAct.set_accounts(accounts);
401                 var prefAct = new Action("EditPref", _("Preferences"),
402                         null, STOCK_PREFERENCES);
403                 prefAct.activate.connect(run_prefs);
404                 
405                 //view menu
406                 var viewMenu = new Action("ViewMenu", _("View"), null, null);
407                 
408                 menuAct = new ToggleAction("ViewMenuAct", _("Show menu"), null, null);
409                 menuAct.set_active(true);
410                 
411                 menuAct.toggled.connect(() => {
412                         if(menuAct.active)
413                                 menubar.show();
414                         else
415                                 menubar.hide();
416                 });
417                 
418                 toolbarAct = new ToggleAction("ViewToolbar", _("Show toolbar"),
419                         null, null);
420                 toolbarAct.set_active(true);
421                 
422                 toolbarAct.toggled.connect(() => {
423                         if(toolbarAct.active)
424                                 toolbar.show();
425                         else
426                                 toolbar.hide();
427                 });
428                 
429                 //help menu
430                 var helpMenu = new Action("HelpMenu", _("Help"), null, null);
431                 var aboutAct = new Action("HelpAbout", _("About %s").printf(Config.APPNAME),
432                         null, STOCK_ABOUT);
433                 
434                 aboutAct.activate.connect(() => {
435                         var about_dlg = new AboutDialog();
436                         about_dlg.set_logo(logo);
437                         about_dlg.set_program_name(Config.APPNAME);
438                         about_dlg.set_version(Config.APP_VERSION);
439                         about_dlg.set_website("http://pino-app.appspot.com/");
440                         about_dlg.set_authors({Config.AUTHORS});
441                         about_dlg.set_copyright("© 2009 troorl");
442                         
443                         about_dlg.set_transient_for(this);
444                         about_dlg.run();
445                         about_dlg.hide();
446                 });
447                 
448                 actGroup.add_action(fileMenu);
449                 actGroup.add_action_with_accel(createAct, "<Ctrl>N");
450                 actGroup.add_action_with_accel(createDirectAct, "<Ctrl>D");
451                 actGroup.add_action(showUserAct);
452                 actGroup.add_action_with_accel(updateAct, "<Ctrl>R");
453                 actGroup.add_action_with_accel(quitAct, "<Ctrl>Q");
454                 actGroup.add_action(editMenu);
455                 actGroup.add_action_with_accel(re_tweet.shortAct, "<Ctrl>U");
456                 actGroup.add_action(accountAct);
457                 actGroup.add_action_with_accel(prefAct, "<Ctrl>P");
458                 actGroup.add_action(viewMenu);
459                 actGroup.add_action_with_accel(home.act, "<Ctrl>1");
460                 actGroup.add_action_with_accel(mentions.act, "<Ctrl>2");
461                 actGroup.add_action_with_accel(direct.act, "<Ctrl>3");
462                 actGroup.add_action_with_accel(user_info.act, "<Ctrl>4");
463                 actGroup.add_action_with_accel(menuAct, "<Ctrl>M");
464                 actGroup.add_action(toolbarAct);
465                 actGroup.add_action(helpMenu);
466                 actGroup.add_action(aboutAct);
467                 
468                 var ui = new UIManager();
469                 ui.insert_action_group(actGroup, 0);
470                 this.add_accel_group(ui.get_accel_group());
471                 
472                 var uiString = """
473                 <ui>
474                         <menubar name="MenuBar">
475                                 <menu action="FileMenu">
476                                         <menuitem action="FileCreate" />
477                                         <menuitem action="FileCreateDirect" />
478                                         <separator />
479                                         <menuitem action="ShowUser" />
480                                         <separator />
481                                         <menuitem action="FileUpdate" />
482                                         <separator />
483                                         <menuitem action="FileQuit" />
484                                 </menu>
485                                 <menu action="EditMenu">
486                                         <menuitem action="UrlShort" />
487                                         <menu action="AccountAct">
488                                         </menu>
489                                         <separator />
490                                         <menuitem action="EditPref" />
491                                 </menu>
492                                 <menu action="ViewMenu">
493                                         <menuitem action="HomeAct" />
494                                         <menuitem action="MentionsAct" />
495                                         <menuitem action="DirectAct" />
496                                         <separator />
497                                         <menuitem action="UserInfoAct" />
498                                         <separator />
499                                         <menuitem action="ViewMenuAct" />
500                                         <menuitem action="ViewToolbar" />
501                                 </menu>
502                                 <menu action="HelpMenu">
503                                         <menuitem action="HelpAbout" />
504                                 </menu>
505                         </menubar>
506                         <popup name="MenuPopup">
507                                 <menuitem action="FileCreate" />
508                                 <menuitem action="FileCreateDirect" />
509                                 <menuitem action="FileUpdate" />
510                                 <separator />
511                                 <menuitem action="EditPref" />
512                                 <separator />
513                                 <menuitem action="ViewMenuAct" />
514                                 <menuitem action="ViewToolbar" />
515                                 <separator />
516                                 <menuitem action="HelpAbout" />
517                                 <menuitem action="FileQuit" />
518                         </popup>
519                         <toolbar name="ToolBar">
520                                 <toolitem action="FileCreate" />
521                                 <toolitem action="FileUpdate" />
522                                 <separator />
523                                 <toolitem action="HomeAct" />
524                                 <toolitem action="MentionsAct" />
525                                 <toolitem action="DirectAct" />
526                                 <separator />
527                                 <toolitem action="UserInfoAct" />
528                                 <separator expand="true" draw="false" />
529                                 <toolitem action="AccountAct" />
530                         </toolbar>
531                 </ui>
532                 """;
533                 
534                 ui.add_ui_from_string(uiString, uiString.length);
535                 
536                 menubar = ui.get_widget("/MenuBar");
537                 popup = (Menu)ui.get_widget("/MenuPopup");
538                 toolbar = ui.get_widget("/ToolBar");
539                 
540                 accountAct.set_ui(ui, cache);
541                 //var toolitem = new AccountAction(accounts);
542                 //((Toolbar)toolbar).insert(toolitem, 9);
543         }
544         
545         public void refresh_action() {
546                 updateAct.set_sensitive(false);
547                 
548                 statusbar.set_status(StatusbarSmart.StatusType.UPDATING);
549                 
550                 var home_list = home.update();
551                 var mentions_list = mentions.update();
552                 var direct_list = direct.update();
553                 
554                 statusbar.set_status(StatusbarSmart.StatusType.FINISH_OK);
555                 
556                 notify.start(home_list, mentions_list, direct_list);
557                 
558                 updateAct.set_sensitive(true);
559         }
560         
561         private void run_prefs() {
562                 var pref_dialog = new PrefDialog(prefs, this, accounts);
563                 
564                 pref_dialog.delete_cache.connect(() => {
565                         cache.delete_cache();
566                 });
567                 
568                 pref_dialog.destroy.connect(() => {
569                         //timer interval update
570                         timer.set_interval(prefs.updateInterval * 60);
571                         prefs.write();
572                 });
573                 
574                 //pref_dialog.set_transient_for(this);
575                 //pref_dialog.show();
576         }
577         
578         /* saving settings */
579         private void before_close() {
580                 prefs.menuShow = menubar.visible;
581                 prefs.toolbarShow = toolbar.visible;
582                 
583                 prefs.write();
584                 main_quit();
585         }
586         
587         private void check_fresh() {
588                 if(!(home.have_fresh || mentions.have_fresh || direct.have_fresh))
589                         tray.new_tweets(false);
590         }       
591 }