[gnome-chess/chess-telepathy-networking-support-664946-rebase: 60/64] glchess-channel-handler: Enhance display, switch lists



commit cc79666a8ece078a0ac61d4971f5390d4d7cd73c
Author: Chandni Verma <chandniverma2112 gmail com>
Date:   Thu Oct 4 22:02:35 2012 +0530

    glchess-channel-handler: Enhance display, switch lists

 data/gnome-chess-network-window.ui   |  279 ++++++++++++-----------
 src/gnome-chess-channel-handler.vala |  429 +++++++++++++++++++++++++---------
 2 files changed, 465 insertions(+), 243 deletions(-)
---
diff --git a/data/gnome-chess-network-window.ui b/data/gnome-chess-network-window.ui
index f8348eb..897bf46 100644
--- a/data/gnome-chess-network-window.ui
+++ b/data/gnome-chess-network-window.ui
@@ -1,6 +1,15 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface>
   <!-- interface-requires gtk+ 3.0 -->
+  <object class="GtkRadioAction" id="radioaction_channel_list">
+    <property name="draw_as_radio">True</property>
+    <signal name="changed" handler="list_changed_cb" swapped="no"/>
+  </object>
+  <object class="GtkRadioAction" id="radioaction_contact_list">
+    <property name="draw_as_radio">True</property>
+    <property name="group">radioaction_channel_list</property>
+    <signal name="changed" handler="list_changed_cb" swapped="no"/>
+  </object>
   <object class="GtkWindow" id="window_networked_chess">
     <property name="can_focus">False</property>
     <property name="title" translatable="yes">Chess</property>
@@ -10,136 +19,198 @@
       <object class="GtkGrid" id="grid_main">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
+        <property name="margin_left">2</property>
         <property name="margin_right">2</property>
         <property name="margin_top">2</property>
         <property name="margin_bottom">2</property>
         <child>
-          <object class="GtkGrid" id="grid_contacts_presence_and_channels">
+          <object class="GtkPaned" id="paned_window">
             <property name="visible">True</property>
-            <property name="can_focus">False</property>
+            <property name="can_focus">True</property>
             <child>
-              <object class="GtkGrid" id="grid_monitor">
+              <object class="GtkGrid" id="grid_contacts_presence_and_channels">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="margin_left">4</property>
-                <property name="margin_right">4</property>
-                <property name="margin_top">4</property>
-                <property name="margin_bottom">4</property>
-                <property name="hexpand">True</property>
-                <property name="row_spacing">4</property>
-                <property name="column_homogeneous">True</property>
                 <child>
-                  <object class="GtkComboBox" id="combobox_presence">
+                  <object class="GtkGrid" id="grid_monitor">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
-                  </object>
-                  <packing>
-                    <property name="left_attach">0</property>
-                    <property name="top_attach">0</property>
-                    <property name="width">3</property>
-                    <property name="height">1</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkButton" id="button_goa">
-                    <property name="use_action_appearance">False</property>
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">True</property>
-                    <property name="use_action_appearance">False</property>
-                    <signal name="clicked" handler="goa_clicked_cb" swapped="no"/>
+                    <property name="margin_right">4</property>
+                    <property name="margin_top">4</property>
+                    <property name="hexpand">True</property>
+                    <property name="row_spacing">4</property>
+                    <property name="column_homogeneous">True</property>
                     <child>
-                      <object class="GtkImage" id="image_goa">
+                      <object class="GtkComboBox" id="combobox_presence">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
-                        <property name="icon_name">goa</property>
                       </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">0</property>
+                        <property name="width">3</property>
+                        <property name="height">1</property>
+                      </packing>
                     </child>
-                  </object>
-                  <packing>
-                    <property name="left_attach">3</property>
-                    <property name="top_attach">0</property>
-                    <property name="width">1</property>
-                    <property name="height">1</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkButton" id="button_channels">
-                    <property name="use_action_appearance">False</property>
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">True</property>
-                    <property name="use_action_appearance">False</property>
-                    <signal name="clicked" handler="channels_clicked_cb" swapped="no"/>
                     <child>
-                      <object class="GtkImage" id="image_glchess">
+                      <object class="GtkButton" id="button_goa">
+                        <property name="use_action_appearance">False</property>
                         <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="icon_name">glchess</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="use_action_appearance">False</property>
+                        <signal name="clicked" handler="goa_clicked_cb" swapped="no"/>
+                        <child>
+                          <object class="GtkImage" id="image_goa">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="icon_name">goa</property>
+                          </object>
+                        </child>
                       </object>
+                      <packing>
+                        <property name="left_attach">3</property>
+                        <property name="top_attach">0</property>
+                        <property name="width">1</property>
+                        <property name="height">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkToggleButton" id="togglebutton_channels">
+                        <property name="use_action_appearance">False</property>
+                        <property name="related_action">radioaction_channel_list</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="related_action">radioaction_channel_list</property>
+                        <property name="use_action_appearance">False</property>
+                        <property name="use_underline">True</property>
+                        <child>
+                          <object class="GtkImage" id="image_glchess">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="icon_name">glchess</property>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">1</property>
+                        <property name="width">2</property>
+                        <property name="height">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkToggleButton" id="togglebutton_contacts">
+                        <property name="use_action_appearance">False</property>
+                        <property name="related_action">radioaction_contact_list</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="related_action">radioaction_contact_list</property>
+                        <property name="use_action_appearance">False</property>
+                        <property name="use_underline">True</property>
+                        <property name="active">True</property>
+                        <child>
+                          <object class="GtkImage" id="image_user">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="icon_name">user</property>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="left_attach">2</property>
+                        <property name="top_attach">1</property>
+                        <property name="width">2</property>
+                        <property name="height">1</property>
+                      </packing>
                     </child>
                   </object>
                   <packing>
                     <property name="left_attach">0</property>
-                    <property name="top_attach">1</property>
-                    <property name="width">2</property>
+                    <property name="top_attach">0</property>
+                    <property name="width">1</property>
                     <property name="height">1</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkButton" id="button_contacts">
-                    <property name="use_action_appearance">False</property>
+                  <object class="GtkBox" id="contacts_box">
                     <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">True</property>
-                    <property name="use_action_appearance">False</property>
-                    <signal name="clicked" handler="contacts_clicked_cb" swapped="no"/>
+                    <property name="can_focus">False</property>
+                    <property name="hexpand">True</property>
+                    <property name="vexpand">True</property>
+                    <property name="orientation">vertical</property>
                     <child>
-                      <object class="GtkImage" id="image_user">
+                      <object class="GtkScrolledWindow" id="scrolledwindow_list">
                         <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="icon_name">user</property>
+                        <property name="can_focus">True</property>
+                        <property name="hexpand">True</property>
+                        <property name="vexpand">True</property>
+                        <property name="shadow_type">in</property>
+                        <child>
+                          <placeholder/>
+                        </child>
                       </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <placeholder/>
                     </child>
                   </object>
                   <packing>
-                    <property name="left_attach">2</property>
+                    <property name="left_attach">0</property>
                     <property name="top_attach">1</property>
-                    <property name="width">2</property>
+                    <property name="width">1</property>
                     <property name="height">1</property>
                   </packing>
                 </child>
               </object>
               <packing>
-                <property name="left_attach">0</property>
-                <property name="top_attach">0</property>
-                <property name="width">1</property>
-                <property name="height">1</property>
+                <property name="resize">False</property>
+                <property name="shrink">True</property>
               </packing>
             </child>
             <child>
-              <object class="GtkBox" id="contacts_box">
+              <object class="GtkPaned" id="paned_game">
                 <property name="visible">True</property>
-                <property name="can_focus">False</property>
+                <property name="can_focus">True</property>
                 <property name="hexpand">True</property>
                 <property name="vexpand">True</property>
-                <property name="orientation">vertical</property>
                 <child>
-                  <object class="GtkScrolledWindow" id="scrolledwindow_list">
+                  <object class="GtkFrame" id="frame_play">
                     <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="margin_left">4</property>
+                    <property name="can_focus">False</property>
                     <property name="hexpand">True</property>
                     <property name="vexpand">True</property>
+                    <property name="label_xalign">0</property>
                     <property name="shadow_type">in</property>
                     <child>
-                      <placeholder/>
+                      <object class="GtkAlignment" id="alignment_play">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="left_padding">6</property>
+                        <property name="right_padding">6</property>
+                        <child>
+                          <placeholder/>
+                        </child>
+                      </object>
+                    </child>
+                    <child type="label">
+                      <object class="GtkLabel" id="label1">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="use_markup">True</property>
+                      </object>
                     </child>
                   </object>
                   <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">0</property>
+                    <property name="resize">False</property>
+                    <property name="shrink">True</property>
                   </packing>
                 </child>
                 <child>
@@ -147,64 +218,13 @@
                 </child>
               </object>
               <packing>
-                <property name="left_attach">0</property>
-                <property name="top_attach">1</property>
-                <property name="width">1</property>
-                <property name="height">1</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="left_attach">0</property>
-            <property name="top_attach">1</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkPaned" id="paned_game">
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="hexpand">True</property>
-            <property name="vexpand">True</property>
-            <child>
-              <object class="GtkFrame" id="frame_play">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="hexpand">True</property>
-                <property name="vexpand">True</property>
-                <property name="label_xalign">0</property>
-                <property name="shadow_type">in</property>
-                <child>
-                  <object class="GtkAlignment" id="alignment_play">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="left_padding">6</property>
-                    <property name="right_padding">6</property>
-                    <child>
-                      <placeholder/>
-                    </child>
-                  </object>
-                </child>
-                <child type="label">
-                  <object class="GtkLabel" id="label1">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="use_markup">True</property>
-                  </object>
-                </child>
-              </object>
-              <packing>
-                <property name="resize">False</property>
+                <property name="resize">True</property>
                 <property name="shrink">True</property>
               </packing>
             </child>
-            <child>
-              <placeholder/>
-            </child>
           </object>
           <packing>
-            <property name="left_attach">1</property>
+            <property name="left_attach">0</property>
             <property name="top_attach">1</property>
             <property name="width">1</property>
             <property name="height">1</property>
@@ -213,9 +233,6 @@
         <child>
           <placeholder/>
         </child>
-        <child>
-          <placeholder/>
-        </child>
       </object>
     </child>
   </object>
diff --git a/src/gnome-chess-channel-handler.vala b/src/gnome-chess-channel-handler.vala
index 3e86d02..7fb863a 100644
--- a/src/gnome-chess-channel-handler.vala
+++ b/src/gnome-chess-channel-handler.vala
@@ -26,11 +26,12 @@ public class HandlerApplication : Application
     /* Objects from gnome-chess-network-window.ui */
     private Gtk.Window? handler_window = null;
     private Gtk.Widget grid_main;
+    private Gtk.Widget grid_contacts_presence_and_channels;
 
     private Gtk.Widget combobox_presence;
     private Gtk.Widget button_goa;
-    private Gtk.Widget button_channels;
-    private Gtk.Widget button_contacts;
+    private Gtk.Action radioaction_channel_list;
+    private Gtk.Action radioaction_contact_list;
     private Gtk.Container scrolledwindow_list;
     private Gtk.Widget alignment_play;
 
@@ -40,9 +41,12 @@ public class HandlerApplication : Application
     private GamesContacts.IndividualView? individual_view = null;
     private GamesContacts.LiveSearch? search_widget;
 
+    private Gtk.Container scrolledwindow_channels;
     private Gtk.TreeView channel_view;
+    private Gtk.TreeSelection channel_view_selection;
 
     /* Objects from gnome-chess-game-window.ui */
+    private Gtk.Widget navigation_box;
     private Gtk.Widget view_box;
     private Gtk.Widget handler_menubar;
 
@@ -61,14 +65,17 @@ public class HandlerApplication : Application
         CHESS_GAME,
         CHESS_SCENE,
         INFO_BAR,
-        INFO_BAR_VISIBILITY,
         GAME_NEEDS_SAVING,
+        CHANNEL_APPROVED,
+        SHOW_STATUS_SCREEN,
+        STATUS_MESSAGE,
         NUM_COLS
     }
 
     /* Channels */
     Gtk.ListStore channels;
     Gtk.TreeIter? selected_channel_iter = null;
+    HashTable <string, int32> channel_count;
 
     public HandlerApplication ()
     {
@@ -88,12 +95,14 @@ public class HandlerApplication : Application
             typeof (ChessGame),              /* CHESS_GAME */
             typeof (ChessScene),             /* CHESS_SCENE */
             typeof (Gtk.InfoBar),            /* INFO_BAR */
-            typeof (bool),                   /* INFO_BAR_VISIBILITY */
-            typeof (bool)                    /* GAME_NEEDS_SAVING */
-           // typeof (), /*  */
+            typeof (bool),                   /* GAME_NEEDS_SAVING */
+            typeof (bool),                   /* CHANNEL_APPROVED */
+            typeof (bool),                   /* SHOW_STATUS_SCREEN */
+            typeof (string)                  /* STATUS_MESSAGE */
             );
 
-        (channel_view).cursor_changed.connect (cursor_changed_cb);
+        assert (channels != null);
+        channel_count = new HashTable <string, int32> (str_hash, str_equal);
 
         settings = new Settings ("org.gnome.gnome-chess");
         settings_common = new Settings ("org.gnome.gnome-chess.games-common");
@@ -130,15 +139,15 @@ public class HandlerApplication : Application
     {
         ChessGame? game = null;
         ChessScene? scene = null;
-        bool view_visible = true;
 
-        channels  get (channel_iter, ChannelsColumn.CHESS_GAME, out game, ChannelsColumn.CHESS_SCENE, out scene);
+        model  get (channel_iter, ChannelsColumn.CHESS_GAME, out game, ChannelsColumn.CHESS_SCENE, out scene);
         assert (game != null && scene != null);
         ChessView chess_view = (game as Object).get_data<ChessView> ("chess-view");
+
         if (chess_view != null)
         {
-            view_visible = chess_view.get_visible ();
-            view_container.remove (chess_view);
+            if ((chess_view as Gtk.Widget).get_parent () == view_container)
+                view_container.remove (chess_view);
             chess_view.destroy ();
         }
         if (settings_common.get_boolean ("show-3d"))
@@ -147,8 +156,9 @@ public class HandlerApplication : Application
             chess_view = new ChessView2D ();
         chess_view.set_size_request (300, 300);
         chess_view.scene = scene;
-        view_container.add (chess_view);
-        chess_view.set_visible (view_visible);
+        if (channel_iter == selected_channel_iter)
+            view_container.add (chess_view);
+        chess_view.set_visible (true);
 
         return false;
     }
@@ -161,42 +171,133 @@ public class HandlerApplication : Application
         }
     }
 
+    private void clear_view_box (Gtk.Widget child)
+    {
+        (view_box as Gtk.Container).remove (child);
+    }
+
+    private void set_game_screen (bool show_status_screen, string message = "")
+    {
+        List view_box_children = (view_box as Gtk.Container).get_children ();
+
+        if (view_box_children.length () > 0)
+            (view_box as Gtk.Container)  foreach (clear_view_box);
+
+        if (show_status_screen)
+        {
+            (view_box as Gtk.Box).pack_start (new Gtk.Label (message));
+
+            /* Update menus' sensitivities */
+            resign_menu.sensitive =
+            save_menu.sensitive =
+            save_as_menu.sensitive = false;
+        }
+        else
+        {
+            ChessGame game;
+            bool game_needs_saving;
+            ChessScene chess_scene;
+            Gtk.InfoBar info_bar;
+            Gtk.TreeModel history_model;
+
+            assert (selected_channel_iter != null);
+            channels  get (selected_channel_iter,
+                ChannelsColumn.CHESS_GAME, out game,
+                ChannelsColumn.GAME_NEEDS_SAVING, out game_needs_saving,
+                ChannelsColumn.CHESS_SCENE, out chess_scene,
+                ChannelsColumn.INFO_BAR, out info_bar,
+                ChannelsColumn.HISTORY_MODEL, out history_model);
+
+            /* Place the selected channel's infobar into view_box */
+            (view_box as Gtk.Box).pack_start (info_bar, false, true, 0);
+
+            (view_box as Gtk.Box).pack_start (view_container, false, true, 0);
+            (view_box as Gtk.Box).pack_start (navigation_box, false, true, 0);
+
+            /* Place the selected channel's view into view_container */
+            Gtk.Widget child = (view_container as Gtk.Bin).get_child ();
+            if (child != null)
+                view_container.remove (child);
+            Gtk.Widget view = (game as Object).get_data<ChessView> ("chess-view");
+            view_container.add (view);
+            view.show ();
+
+            /* Update menus' sensitivities */
+            if (game_needs_saving)
+            {
+                resign_menu.sensitive = game.n_moves > 0;
+                save_menu.sensitive = true;
+                save_as_menu.sensitive = true;
+            }
+
+            /* Update history-combo's model */
+            history_combo.set_model (history_model);
+
+            /* Update history panel */
+            update_history_panel (game, chess_scene, history_combo.model);
+
+            white_time_label.queue_draw ();
+            black_time_label.queue_draw ();
+        }
+    }
+
     private void show_game ()
     {
-        TelepathyGLib.Contact? remote_player = null;
+        TelepathyGLib.Contact remote_player;
         int64 action_time = -1;
+        bool channel_approved;
 
         if (selected_channel_iter == null)
         {
-            debug ("No channel iteration selected");
+            debug ("No channel selected");
             return;
         }
-        channels  get (selected_channel_iter, ChannelsColumn.TARGET_CONTACT, out remote_player, ChannelsColumn.USER_ACTION_TIME, out action_time);
 
-        if (remote_player != null && action_time != -1)
+        channels  get (selected_channel_iter,
+            ChannelsColumn.TARGET_CONTACT, out remote_player,
+            ChannelsColumn.USER_ACTION_TIME, out action_time,
+            ChannelsColumn.CHANNEL_APPROVED, out channel_approved);
+
+        assert (action_time != -1);
+
+        debug ("Showing game with %s. Initiation timeframe: %lld", remote_player.identifier, action_time);
+
+        if (!channel_approved)
         {
-            debug ("Showing game with %s. Initiation timeframe: %llu", remote_player.identifier, action_time);
+            string status_message = "Waiting for game request to be approved by %s".printf (remote_player.get_alias ());
+            set_game_screen (true, status_message);
+        }
+        else
+        {
+            set_game_screen (false);
         }
     }
 
-    private void cursor_changed_cb ()
+    private void channel_selection_changed_cb ()
     {
-        Gtk.TreePath? path;
-        Gtk.TreeIter iter;
+        Gtk.TreeIter? selected_channel_iter = null;
 
-        channel_view.get_cursor (out path, null);
-        if (path == null)
+        if (! channel_view_selection.get_selected (null, out selected_channel_iter))
         {
-            debug ("Couldn't obtain path the cursor is at");
+            debug ("Couldn't obtain selected channel iterator");
             return;
         }
 
-        if (channels.get_iter (out iter, path))
-        {
-            selected_channel_iter = iter;
+        this.selected_channel_iter = selected_channel_iter;
 
-            show_game ();
-        }
+        show_game ();
+    }
+
+    private void channel_name_func (Gtk.TreeViewColumn tree_column, Gtk.CellRenderer cell, Gtk.TreeModel tree_model, Gtk.TreeIter iter)
+    {
+        string player_name;
+        TelepathyGLib.Contact target_contact;
+        int64 initiation_time;
+
+        channels  get (iter, ChannelsColumn.TARGET_CONTACT, out target_contact, ChannelsColumn.USER_ACTION_TIME, out initiation_time);
+
+        player_name = target_contact.alias;
+        (cell as Gtk.CellRendererText).text = "Game %d with %s".printf (channel_count  get (target_contact.identifier), player_name);
     }
 
     private void create_handler_window ()
@@ -213,33 +314,46 @@ public class HandlerApplication : Application
         handler_window.delete_event.connect (handler_window.hide_on_delete);
 
         grid_main = (Gtk.Widget) builder.get_object ("grid_main");
+        grid_contacts_presence_and_channels = (Gtk.Widget) builder.get_object ("grid_contacts_presence_and_channels");
         combobox_presence = (Gtk.Widget) builder.get_object
             ("combobox_presence");
         button_goa = (Gtk.Widget) builder.get_object ("button_goa");
-        button_channels = (Gtk.Widget) builder.get_object ("button_channels");
-        button_contacts = (Gtk.Widget) builder.get_object ("button_contacts");
+        radioaction_channel_list = (Gtk.Action) builder.get_object ("radioaction_channel_list");
+        radioaction_contact_list = (Gtk.Action) builder.get_object ("radioaction_contact_list");
         scrolledwindow_list = (Gtk.Container) builder.get_object ("scrolledwindow_list");
         contacts_box = (Gtk.Widget) builder.get_object ("contacts_box");
         alignment_play = (Gtk.Widget) builder.get_object ("alignment_play");
 
-        channel_view = new Gtk.TreeView ();
-
         /* Add objects from gnome-chess-game-window.ui */
         try {
             builder.add_objects_from_file (Path.build_filename (Config.PKGDATADIR,
               "gnome-chess-game-window.ui", null),
               objects_from_traditional_window);
 
-            view_box = (Gtk.Widget) builder.get_object ("view_box");
-            view_container = (Gtk.Container) builder.get_object ("view_container");
             handler_menubar = (Gtk.Widget) builder.get_object ("menubar");
 
             handler_menubar.unparent ();
-            (grid_main as Gtk.Grid).attach (handler_menubar, 0, 0, 2, 1);
+            (grid_main as Gtk.Grid).attach (handler_menubar, 0, 0, 1, 1);
 
+            save_menu = (Gtk.Widget) builder.get_object ("menu_save_item");
+            save_as_menu = (Gtk.Widget) builder.get_object ("menu_save_as_item");
+            fullscreen_menu = (Gtk.MenuItem) builder.get_object ("fullscreen_item");
+            resign_menu = (Gtk.Widget) builder.get_object ("resign_item");
+
+            view_box = (Gtk.Widget) builder.get_object ("view_box");
             view_box.reparent (alignment_play);
 
-            grid_main.show_all ();
+            view_container = (Gtk.Container) builder.get_object ("view_container");
+
+            first_move_button = (Gtk.Widget) builder.get_object ("first_move_button");
+            prev_move_button = (Gtk.Widget) builder.get_object ("prev_move_button");
+            next_move_button = (Gtk.Widget) builder.get_object ("next_move_button");
+            last_move_button = (Gtk.Widget) builder.get_object ("last_move_button");
+            history_combo = (Gtk.ComboBox) builder.get_object ("history_combo");
+            white_time_label = (Gtk.Widget) builder.get_object ("white_time_label");
+            black_time_label = (Gtk.Widget) builder.get_object ("black_time_label");
+            navigation_box = (Gtk.Widget) builder.get_object ("navigation_box");
+            settings_common.bind ("show-history", navigation_box, "visible", SettingsBindFlags.DEFAULT);
         }
         catch (Error e)
         {
@@ -253,8 +367,25 @@ public class HandlerApplication : Application
 
         prepare_contact_list ();
 
+        scrolledwindow_channels = new Gtk.ScrolledWindow (null, null);
         channel_view = new Gtk.TreeView ();
         channel_view.model = channels;
+        scrolledwindow_channels.add (channel_view);
+
+        Gtk.CellRendererText text_renderer = new Gtk.CellRendererText ();
+        channel_view.insert_column_with_data_func (-1, "", text_renderer, channel_name_func);
+
+        channel_view_selection = channel_view.get_selection ();
+        /* Enforce: user can't deselect a currently selected element except by selecting
+         * another element*/
+        channel_view_selection.set_mode (Gtk.SelectionMode.BROWSE);
+        channel_view_selection.changed.connect (channel_selection_changed_cb);
+        (channel_view as Gtk.Widget).show ();
+
+        (scrolledwindow_channels as Gtk.Widget).expand = true;
+        (scrolledwindow_channels as Gtk.Widget).show ();
+
+        grid_main.show_all ();
     }
 
     private void prepare_contact_list ()
@@ -289,18 +420,30 @@ public class HandlerApplication : Application
         (contacts_box as Gtk.Container).add (search_widget);
     }
 
-    [CCode (cname = "G_MODULE_EXPORT channels_clicked_cb", instance_pos=-1)]
-    public void channels_clicked_cb (Gtk.Button button)
+    [CCode (cname = "G_MODULE_EXPORT list_changed_cb", instance_pos=-1)]
+    public void list_changed_cb (Gtk.RadioAction action, Gtk.RadioAction current_action)
     {
-        scrolledwindow_list.remove (contacts_box);
-        scrolledwindow_list.add (channel_view);
-    }
+        if (action != current_action)
+            return;
 
-    [CCode (cname = "G_MODULE_EXPORT contacts_clicked_cb", instance_pos=-1)]
-    public void contacts_clicked_cb (Gtk.Button button)
-    {
-        scrolledwindow_list.remove (channel_view);
-        scrolledwindow_list.add (contacts_box);
+        if (current_action == radioaction_channel_list &&
+            (grid_contacts_presence_and_channels as Gtk.Grid).get_child_at (0, 1) == contacts_box &&
+            contacts_box.get_parent () == grid_contacts_presence_and_channels)
+        {
+
+            (grid_contacts_presence_and_channels as Gtk.Container).remove (contacts_box);
+            (grid_contacts_presence_and_channels as Gtk.Grid).attach (scrolledwindow_channels, 0, 1, 1, 1);
+        }
+        else
+        {
+            if (current_action == radioaction_contact_list &&
+                (grid_contacts_presence_and_channels as Gtk.Grid).get_child_at (0, 1) == scrolledwindow_channels &&
+                (scrolledwindow_channels as Gtk.Widget).get_parent () == grid_contacts_presence_and_channels);
+            {
+                (grid_contacts_presence_and_channels as Gtk.Container).remove (scrolledwindow_channels);
+                (grid_contacts_presence_and_channels as Gtk.Grid).attach (contacts_box, 0, 1, 1, 1);
+            }
+        }
     }
 
     [CCode (cname = "G_MODULE_EXPORT goa_clicked_cb", instance_pos=-1)]
@@ -324,7 +467,15 @@ public class HandlerApplication : Application
 
         channels  get (channel_iter, ChannelsColumn.USER_ACTION_TIME, out initiation_time, ChannelsColumn.CHANNEL, out channel);
 
-        debug ("Removing chess tube channel with %s initiated at instance: %lld", channel.target_contact.identifier, initiation_time);
+        var target_id = channel.target_contact.identifier;
+        debug ("Removing chess tube channel with %s initiated at instance: %lld", target_id, initiation_time);
+
+        /* Decrease channel count */
+        var count = channel_count  get (target_id);
+        if (count == 1)
+            channel_count.remove (target_id);
+        else
+            channel_count  set (target_id, count-1);
 
         return false;
     }
@@ -333,43 +484,52 @@ public class HandlerApplication : Application
     private void quit_game ()
     {
         Settings.sync ();
-        channels  foreach (save_game_and_remove_channel);
+
+        if (channels != null)
+            channels  foreach (save_game_and_remove_channel);
+
+        (handler_window as Gtk.Widget).destroy ();
     }
 
     private new void game_move_cb (ChessGame game, ChessMove move)
     {
-        Gtk.TreeIter *channel_iter;
+        Gtk.TreeIter channel_iter;
         ChessView chess_view;
+        PGNGame pgn_game;
 
-        channel_iter = (game as Object).get_data ("channel-iter");
+        string channel_path_string = (game as Object).get_data<string> ("channel-path-string");
+        channels.get_iter_from_string (out channel_iter, channel_path_string);
         chess_view = (game as Object).get_data<ChessView> ("chess-view");
+        pgn_game = (game as Object).get_data<PGNGame> ("pgn-game");
 
         /* Need to save after each move */
-        channels  set (*channel_iter, ChannelsColumn.GAME_NEEDS_SAVING, true);
+        channels  set (channel_iter, ChannelsColumn.GAME_NEEDS_SAVING, true);
 
         if (move.number > pgn_game.moves.length ())
             pgn_game.moves.append (move.get_san ());
 
         Gtk.ListStore model;
         ChessScene scene;
-        channels  get (*channel_iter, ChannelsColumn.HISTORY_MODEL, out model, ChannelsColumn.CHESS_SCENE, out scene);
+        channels  get (channel_iter, ChannelsColumn.HISTORY_MODEL, out model, ChannelsColumn.CHESS_SCENE, out scene);
 
         Gtk.TreeIter iter;
         model.append (out iter);
-        model.set (iter, 1, move.number, -1);
+        model  set (iter, 1, move.number);
         set_move_text (iter, move, scene, model);
 
         /* Follow the latest move */
         if (move.number == game.n_moves && scene.move_number == -1)
-            channels  set (*channel_iter, ChannelsColumn.HISTORY_COMBO_ACTIVE_ITER, iter);
+            channels  set (channel_iter, ChannelsColumn.HISTORY_COMBO_ACTIVE_ITER, iter);
 
         update_history_model (game, scene, model);
 
         /* UI updation */
-        if (selected_channel_iter == *channel_iter)
+        if (selected_channel_iter == channel_iter)
         {
-            update_history_panel (game,scene, model);
-            update_control_buttons ();
+            update_history_panel (game, scene, model);
+            resign_menu.sensitive = game.n_moves > 0;
+            save_menu.sensitive = true;
+            save_as_menu.sensitive = true;
         }
 
         /* TODO: Acknowledge if opponent made this move */
@@ -378,15 +538,20 @@ public class HandlerApplication : Application
     }
 
     private void create_and_add_game (TelepathyGLib.DBusTubeChannel tube,
-        Gtk.TreeIter iter)
+        Gtk.TreeIter channel_iter)
     {
         /* Create a new game with the offered parameters */
         Variant tube_params = tube.dup_parameters_vardict ();
-        bool our_color_white;
-        tube_params.lookup ("offerer-white", "b", out our_color_white);
+        bool offerer_white, our_color_white;
+        tube_params.lookup ("offerer-white", "b", out offerer_white);
+        our_color_white = (tube as TelepathyGLib.Channel).requested ? offerer_white : !offerer_white;
         int32 duration;
         tube_params.lookup ("duration", "i", out duration);
 
+        debug ("Creating a new chess match with our colour:%s and timeout duration:%s",
+            our_color_white ? "white" : "black",
+            duration > 0 ? duration.to_string () + " seconds" : "no limit");
+
         var pgn_game = new PGNGame ();
         var now = new DateTime.now_local ();
         var now_UTC = now.to_utc ();
@@ -397,7 +562,10 @@ public class HandlerApplication : Application
         if (duration > 0)
             pgn_game.time_control = "%d".printf (duration);
 
-        var history_model = new Gtk.ListStore (2, typeof (string), typeof (int));
+        Gtk.ListStore? history_model = null;
+        history_model = new Gtk.ListStore (2, typeof (string), typeof (int));
+        assert (history_model != null);
+        history_model.insert_with_values (null, -1, 0, _("Game Start"), 1, 0);
 
         string fen = ChessGame.STANDARD_SETUP;
         string[] moves = new string[pgn_game.moves.length ()];
@@ -414,7 +582,9 @@ public class HandlerApplication : Application
         }
         var game = new ChessGame (fen, moves);
         (game as Object).set_data<PGNGame> ("pgn-game", pgn_game);
-        (game as Object).set_data<Gtk.TreeIter*> ("channel-iter", &iter);
+        (game as Object).set_data<string> ("channel-path-string", channels.get_string_from_iter (channel_iter));
+        /* Associate history_model for access in scene_changed_cb */
+        game.set_data<Gtk.TreeModel> ("history-model", history_model);
 
         if (pgn_game.time_control != null)
         {
@@ -437,12 +607,17 @@ public class HandlerApplication : Application
         scene.changed.connect (scene_changed_cb);
         scene.choose_promotion_type.connect (show_promotion_type_selector);
         scene.game = game;
+        settings_common.bind ("show-move-hints", scene, "show-move-hints", SettingsBindFlags.GET);
+        settings_common.bind ("show-numbering", scene, "show-numbering", SettingsBindFlags.GET);
+        settings_common.bind ("piece-theme", scene, "theme-name", SettingsBindFlags.GET);
+        settings_common.bind ("show-3d-smooth", scene, "show-3d-smooth", SettingsBindFlags.GET);
+        settings_common.bind ("move-format", scene, "move-format", SettingsBindFlags.GET);
+        settings_common.bind ("board-side", scene, "board-side", SettingsBindFlags.GET);
 
         Gtk.InfoBar info_bar;
 
         info_bar = new Gtk.InfoBar ();
         var content_area = (Gtk.Container) info_bar.get_content_area ();
-        (view_box as Gtk.Box).pack_start (info_bar, false, true, 0);
         var vbox = new Gtk.Box (Gtk.Orientation.VERTICAL, 6);
         vbox.show ();
         content_area.add (vbox);
@@ -455,6 +630,7 @@ public class HandlerApplication : Application
         info_label.show ();
         vbox.pack_start (info_label, true, true, 0);
 
+        /* All info-bars are hidden when created with visibility updated as and when needed */
         info_bar.hide ();
 
         (game as Object).set_data<Gtk.InfoBar> ("info-bar", info_bar);
@@ -481,14 +657,13 @@ public class HandlerApplication : Application
         white_time_label.queue_draw ();
         black_time_label.queue_draw ();
 
-        channels.insert_with_values (null, -1,
+        channels  set (channel_iter,
             ChannelsColumn.OUR_COLOUR_WHITE, our_color_white,
             ChannelsColumn.PGN_GAME, pgn_game,
             ChannelsColumn.HISTORY_MODEL, history_model,
             ChannelsColumn.CHESS_GAME, game,
             ChannelsColumn.CHESS_SCENE, scene,
             ChannelsColumn.INFO_BAR, info_bar,
-            ChannelsColumn.INFO_BAR_VISIBILITY, info_bar.visible,
             ChannelsColumn.GAME_NEEDS_SAVING, game_needs_saving);
     }
 
@@ -496,7 +671,7 @@ public class HandlerApplication : Application
         TelepathyGLib.DBusTubeChannel tube,
         Gtk.TreeIter channel_iter)
     {
-      //  display_game ();
+        debug ("Registering objects over dbus connection");
     }
 
     private void offer_tube (TelepathyGLib.DBusTubeChannel tube,
@@ -514,7 +689,7 @@ public class HandlerApplication : Application
 
         debug ("Offering tube with offerer-white:%s and duration:%ld",
         colour_val.get_boolean () ? "true" : "false", duration_val.get_int ());
-//        debug ("Parameters passed: %s", );
+        /* This hashtable is purely offerer defined and cast here is the secret gotcha */
         tube.offer_async.begin ((HashTable<void*, void*>?)tube_params,
             (obj, res)=>{
                 try
@@ -526,20 +701,10 @@ public class HandlerApplication : Application
                     debug ("Failed to offer tube to %s: %s",
                         (tube as TelepathyGLib.Channel).target_contact.identifier,
                         e.message);
-                  //  display_channel_error (channel_iter, e, "Failed to offer chess game channel to %s", (tube as TelepathyGLib.Channel).target_contact.identifier);
-                    debug ("Closing channel.");
-                    (tube as TelepathyGLib.Channel).close_async.begin ((obj, res)=>
-                        {
-                            try
-                            {
-                                (tube as TelepathyGLib.Channel).close_async.end (res);
-                            }
-                            catch (Error e)
-                            {
-                                debug ("Couldn't close the channel: %s", e.message);
-                            }
-                        });
 
+                    channels  set (channel_iter,
+                        ChannelsColumn.SHOW_STATUS_SCREEN, true,
+                        ChannelsColumn.STATUS_MESSAGE, "Failed to offer chess game channel to %s\n The error was: %s", (tube as TelepathyGLib.Channel).target_contact.identifier, e.message);
 
                     /* Nothing to do */
                     return;
@@ -547,7 +712,7 @@ public class HandlerApplication : Application
 
                 assert (connection != null);
 
-                debug ("Tube opened.");
+                debug ("Offered tube opened.");
                 connection.notify["closed"].connect (
                     (s, p)=>{
                         debug ("Connection to %s closed unexpectedly",
@@ -557,8 +722,19 @@ public class HandlerApplication : Application
                 );
                 create_and_add_game (tube, channel_iter);
                 register_objects (connection, tube, channel_iter);
+
+                /* Now we can display the game */
+                channels  set (channel_iter, ChannelsColumn.CHANNEL_APPROVED, true);
+
+                /* If this is the selected channel, update it's display since it has been approved */
+                if (channel_iter == selected_channel_iter)
+                    set_game_screen (false);
+
               }
             );
+
+        /* This offered tube has not yet been approved by remote contact */
+        channels  set (channel_iter, ChannelsColumn.CHANNEL_APPROVED, false);
     }
 
     private void accept_tube (TelepathyGLib.DBusTubeChannel tube,
@@ -576,22 +752,11 @@ public class HandlerApplication : Application
                 catch (Error e)
                 {
                     debug ("Failed to accept tube from %s: %s",
-                        (tube as TelepathyGLib.Channel).target_contact.identifier,
-                        e.message);
-//                    display_error (channel_iter, e, "Failed to offer chess game channel to %s", (tube as TelepathyGLib.Channel).target_contact.identifer);
-                    debug ("Closing channel.");
-
-                    (tube as TelepathyGLib.Channel).close_async.begin ((obj, res)=>
-                        {
-                            try
-                            {
-                                (tube as TelepathyGLib.Channel).close_async.end (res);
-                            }
-                            catch (Error e)
-                            {
-                                debug ("Couldn't close the channel: %s", e.message);
-                            }
-                        });
+                        (tube as TelepathyGLib.Channel).target_contact.identifier, e.message);
+
+                    channels  set (channel_iter,
+                        ChannelsColumn.SHOW_STATUS_SCREEN, true,
+                        ChannelsColumn.STATUS_MESSAGE, "Failed to accept chess game channel from %s\n The error was: %s", (tube as TelepathyGLib.Channel).target_contact.identifier, e.message);
 
                     /* Nothing to do */
                     return;
@@ -599,7 +764,7 @@ public class HandlerApplication : Application
 
                 assert (connection != null);
 
-                debug ("Tube opened.");
+                debug ("Accepted tube opened.");
                 connection.notify["closed"].connect (
                     (s, p)=>{
                         debug ("Connection to %s closed unexpectedly",
@@ -608,9 +773,38 @@ public class HandlerApplication : Application
                     }
                 );
                 create_and_add_game (tube, channel_iter);
+
+                /* We can now display the game */
+                channels  set (channel_iter, ChannelsColumn.CHANNEL_APPROVED, true);
+
+                /* If this is the selected channel, update it's display since it has been approved */
+                if (channel_iter == selected_channel_iter)
+                    set_game_screen (false);
+
               }
             );
 
+        /* Channels at accepter end are never waiting for approval from anyone
+         * but just for accept_async() to finish and call the callback */
+        channels  set (channel_iter, ChannelsColumn.CHANNEL_APPROVED, false);
+    }
+
+    private void close_channel (TelepathyGLib.Channel tube)
+    {
+        debug ("Closing channel.");
+
+        (tube).close_async.begin ((obj, res)=>
+            {
+                try
+                {
+                    (tube).close_async.end (res);
+                }
+                catch (Error e)
+                {
+                    debug ("Couldn't close the channel: %s", e.message);
+                }
+            }
+            );
     }
 
     private void tube_invalidated_cb (TelepathyGLib.Proxy tube_channel,
@@ -620,16 +814,16 @@ public class HandlerApplication : Application
     {
         debug ("Tube has been invalidated: %s", message);
 
-        channels  foreach ((model, path, iter)=>
+        (channels as Gtk.TreeModel)  foreach ((model, path, iter)=>
             {
                 TelepathyGLib.Channel stored_tube;
-                uint64 user_action_time;
-                channels  get (iter, ChannelsColumn.CHANNEL, out stored_tube,
+                int64 user_action_time;
+                (channels as Gtk.TreeModel)  get (iter, ChannelsColumn.CHANNEL, out stored_tube,
                     ChannelsColumn.USER_ACTION_TIME, out user_action_time);
 
                 if (stored_tube == tube_channel)
                 {
-                    debug ("Removing chess dbus-tube channel initiated at timeframe %llu with remote player %s",
+                    debug ("Removing chess dbus-tube channel initiated at timeframe %lld with remote player %s",
                         user_action_time, stored_tube.target_contact.identifier);
                     channels.remove (iter);
                     return true;
@@ -648,14 +842,13 @@ public class HandlerApplication : Application
         int64 action_time,
         TelepathyGLib.HandleChannelsContext context)
     {
-        Error error = new TelepathyGLib.Error.NOT_AVAILABLE (
-            "No channel to be handled");
+        Error error = new TelepathyGLib.Error.NOT_AVAILABLE ("No channel to be handled");
 
         debug ("Handling channels");
 
         foreach (TelepathyGLib.Channel tube_channel in channel_bundle)
         {
-          Gtk.TreeIter iter;
+          Gtk.TreeIter channel_iter;
 
           if (! (tube_channel is TelepathyGLib.DBusTubeChannel))
             continue;
@@ -664,22 +857,34 @@ public class HandlerApplication : Application
             continue;
 
           /* Add channel to list of currently handled channels */
-          channels.insert_with_values (out iter, -1,
+          channels.insert_with_values (out channel_iter, -1,
               ChannelsColumn.USER_ACTION_TIME, action_time,
               ChannelsColumn.TARGET_CONTACT, tube_channel.target_contact,
               ChannelsColumn.CHANNEL, tube_channel);
 
+          debug ("Channel inserted into cache. Total channels: %d", channels.iter_n_children (null));
+
+          var target_id = tube_channel.target_contact.identifier;
+          if (channel_count.contains (target_id))
+              channel_count  set (target_id, channel_count  get (target_id) + 1);
+          else
+              channel_count.insert (target_id, 1);
+
+          debug ("We now hold %d channels with %s", channel_count  get (target_id), target_id);
+
+          /* If this is the first insertion, set it as selected */
+          if (channels.iter_n_children (null) == 1)
+              channel_view_selection.select_iter (channel_iter);
+
           if (tube_channel.requested)
           {
-              /* We created this channel. Make a tube offer and wait for
-               * approval */
-              offer_tube (tube_channel as TelepathyGLib.DBusTubeChannel, iter);
-             // display_waiting_for_approval (iter);
+              /* We created this channel. Make a tube offer and wait for approval */
+              offer_tube (tube_channel as TelepathyGLib.DBusTubeChannel, channel_iter);
           }
           else
           {
               /* This is an incoming channel request */
-              accept_tube (tube_channel as TelepathyGLib.DBusTubeChannel, iter);
+              accept_tube (tube_channel as TelepathyGLib.DBusTubeChannel, channel_iter);
           }
 
           (tube_channel as TelepathyGLib.Proxy).invalidated.connect (



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]