[easytag/wip/musicbrainz-support-merge: 3/75] Implemented Asynchronous Manual Search



commit d1252e798b77f0ccd492c69202e0fc6f0c8a77c2
Author: Abhinav <abhijangda hotmail com>
Date:   Fri May 16 20:07:30 2014 +0530

    Implemented Asynchronous Manual Search
    
    Created a base library for MusicBrainz search in mb_search.c & mb_search.h
    Implemented manual search functions in musicbrainz_dialog.c
    Added support for displaying information about Mb5Entity in mbentityview.c

 Makefile.am                |    3 +
 data/musicbrainz_dialog.ui |   17 ++-
 src/mb_search.c            |  472 ++++++++++++++++++++++++++++++++++++++++++++
 src/mb_search.h            |   92 +++++++++
 src/mbentityview.c         |  427 ++++++++++++++++++++++++++++++----------
 src/mbentityview.h         |   24 +--
 src/musicbrainz_dialog.c   |  200 +++++++++++++++++--
 src/musicbrainz_dialog.h   |   16 ++-
 8 files changed, 1098 insertions(+), 153 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index bed227d..cf2c36a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -67,6 +67,7 @@ easytag_SOURCES = \
        src/musepack_header.c \
        src/musicbrainz_dialog.c \
        src/mbentityview.c \
+       src/mb_search.c \
        src/ogg_header.c \
        src/ogg_tag.c \
        src/opus_header.c \
@@ -115,6 +116,8 @@ easytag_headers = \
        src/mp4_tag.h \
        src/musepack_header.h \
        src/musicbrainz_dialog.h \
+       src/mb_search.h \
+       src/mbentityview.h \
        src/ogg_header.h \
        src/ogg_tag.h \
        src/opus_header.h \
diff --git a/data/musicbrainz_dialog.ui b/data/musicbrainz_dialog.ui
index 92126dd..ade53f4 100755
--- a/data/musicbrainz_dialog.ui
+++ b/data/musicbrainz_dialog.ui
@@ -66,11 +66,13 @@
       <object class="GtkBox" id="dialog-vbox1">
         <property name="can_focus">False</property>
         <property name="orientation">vertical</property>
-        <property name="spacing">2</property>
         <child internal-child="action_area">
           <object class="GtkButtonBox" id="dialog-action_area1">
             <property name="can_focus">False</property>
             <property name="layout_style">end</property>
+            <child>
+              <placeholder/>
+            </child>
           </object>
           <packing>
             <property name="expand">False</property>
@@ -239,9 +241,15 @@
                               <object class="GtkComboBoxText" id="cbManualSearch">
                                 <property name="width_request">240</property>
                                 <property name="visible">True</property>
-                                <property name="can_focus">False</property>
+                                <property name="can_focus">True</property>
+                                <property name="has_entry">True</property>
                                 <property name="entry_text_column">0</property>
                                 <property name="id_column">1</property>
+                                <child internal-child="entry">
+                                  <object class="GtkEntry" id="combobox-entry">
+                                    <property name="can_focus">True</property>
+                                  </object>
+                                </child>
                               </object>
                               <packing>
                                 <property name="expand">False</property>
@@ -263,7 +271,7 @@
                               </packing>
                             </child>
                             <child>
-                              <object class="GtkComboBox" id="cbManualSearchIn">
+                              <object class="GtkComboBoxText" id="cbManualSearchIn">
                                 <property name="width_request">120</property>
                                 <property name="height_request">26</property>
                                 <property name="visible">True</property>
@@ -319,6 +327,7 @@
                   <object class="GtkLabel" id="label13">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
+                    <property name="margin_right">1</property>
                     <property name="label" translatable="yes">Manual Search</property>
                   </object>
                   <packing>
@@ -730,7 +739,7 @@
               </packing>
             </child>
             <child>
-              <object class="GtkStatusbar" id="statusbar1">
+              <object class="GtkStatusbar" id="statusbar">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
                 <property name="spacing">2</property>
diff --git a/src/mb_search.c b/src/mb_search.c
new file mode 100644
index 0000000..1994cb4
--- /dev/null
+++ b/src/mb_search.c
@@ -0,0 +1,472 @@
+/* mb_search.c - 2014/05/05 */
+/*
+ *  EasyTAG - Tag editor for MP3 and Ogg Vorbis files
+ *  Copyright (C) 2000-2014  Abhinav Jangda <abhijangda hotmail com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "mb_search.h"
+
+/*
+ * et_mb5_search_error_quark:
+ *
+ * To get EtMB5SearchError domain.
+ *
+ * Returns: GQuark for EtMB5SearchError domain
+ */
+GQuark
+et_mb5_search_error_quark (void)
+{
+    return g_quark_from_static_string ("et-mb5-search-error-quark");
+}
+
+/*
+ * et_musicbrainz_search_in_entity:
+ * @string:
+ * @child_type:
+ * @parent_type:
+ * @parent_mbid:
+ * @root:
+ *
+ *
+ */
+gboolean
+et_musicbrainz_search_in_entity (enum MB_ENTITY_TYPE child_type,
+                                 enum MB_ENTITY_TYPE parent_type,
+                                 gchar *parent_mbid, GNode *root,
+                                 GError **error)
+{
+    Mb5Query query;
+    Mb5Metadata metadata;
+    char error_message[256];
+    tQueryResult result;
+    char *param_values[1];
+    char *param_names[1];
+
+    param_names [0] = "inc";
+    query = mb5_query_new ("easytag", NULL, 0);
+
+    if (child_type == MB_ENTITY_TYPE_ALBUM &&
+        parent_type == MB_ENTITY_TYPE_ARTIST)
+    {
+        param_values [0] = "releases";
+        metadata = mb5_query_query (query, "artist", parent_mbid, "", 1,
+                                    param_names, param_values);
+        result = mb5_query_get_lastresult (query);
+
+        if (result == eQuery_Success)
+        {
+            if (metadata)
+            {
+                int i;
+                Mb5ReleaseList list;
+                Mb5Artist artist;
+                artist = mb5_metadata_get_artist (metadata);
+                list = mb5_artist_get_releaselist (artist);
+
+                for (i = 0; i < mb5_release_list_size (list); i++)
+                {
+                    Mb5Release release;
+                    release = mb5_release_list_item (list, i);
+                    if (release)
+                    {
+                        GNode *node;
+                        EtMbEntity *entity;
+                        entity = g_malloc (sizeof (EtMbEntity));
+                        entity->entity = release;
+                        entity->type = MB_ENTITY_TYPE_ALBUM;
+                        node = g_node_new (entity);
+                        g_node_append (root, node);
+                    }
+                }
+            }
+        }
+        else
+        {
+            goto err;
+        }
+    }
+    else if (child_type == MB_ENTITY_TYPE_TRACK &&
+             parent_type == MB_ENTITY_TYPE_ALBUM)
+    {
+        param_values [0] = "recordings";
+        metadata = mb5_query_query (query, "release", parent_mbid, "", 1,
+                                    param_names, param_values);
+        result = mb5_query_get_lastresult (query);
+
+        if (result == eQuery_Success)
+        {
+            if (metadata)
+            {
+                int i;
+                Mb5MediumList list;
+                Mb5Release release;
+                release = mb5_metadata_get_release (metadata);
+                list = mb5_release_get_mediumlist (release);
+                param_values[0] = "releases artists";
+
+                for (i = 0; i < mb5_medium_list_size (list); i++)
+                {
+                    Mb5Medium medium;
+                    medium = mb5_medium_list_item (list, i);
+
+                    if (medium)
+                    {
+                        Mb5Metadata metadata_recording;
+                        gchar recording_mbid [NAME_MAX_SIZE];
+                        GNode *node;
+                        EtMbEntity *entity;
+                        Mb5TrackList track_list;
+                        int j;
+
+                        track_list = mb5_medium_get_tracklist (medium);
+
+                        for (j = 0; j < mb5_track_list_size (track_list); j++)
+                        {
+                            Mb5Recording recording;
+
+                            recording = mb5_track_get_recording (mb5_track_list_item (track_list, j));
+                            mb5_recording_get_id (recording,
+                                                  recording_mbid,
+                                                  sizeof (recording_mbid));
+                            metadata_recording = mb5_query_query (query, "recording",
+                                                                  recording_mbid, "",
+                                                                  1, param_names,
+                                                                  param_values);
+                            entity = g_malloc (sizeof (EtMbEntity));
+                            entity->entity = mb5_recording_clone (mb5_metadata_get_recording 
(metadata_recording));
+                            entity->type = MB_ENTITY_TYPE_TRACK;
+                            entity->is_red_line = FALSE;
+                            node = g_node_new (entity);
+                            g_node_append (root, node);
+                            mb5_metadata_delete (metadata_recording);
+                        }
+                    }
+                }
+            }
+
+            mb5_metadata_delete (metadata);
+        }
+        else
+        {
+            goto err;
+        }
+    }
+
+    mb5_query_delete (query);
+
+    return TRUE;
+
+    err:
+    mb5_query_get_lasterrormessage (query, error_message,
+                                    sizeof(error_message));
+
+    switch (result)
+    {
+        case eQuery_ConnectionError:
+            g_set_error (error, ET_MB5_SEARCH_ERROR,
+                         ET_MB5_SEARCH_ERROR_CONNECTION, error_message);
+            break;
+
+        case eQuery_Timeout:
+            g_set_error (error, ET_MB5_SEARCH_ERROR,
+                         ET_MB5_SEARCH_ERROR_TIMEOUT, error_message);
+            break;
+
+        case eQuery_AuthenticationError:
+            g_set_error (error, ET_MB5_SEARCH_ERROR,
+                         ET_MB5_SEARCH_ERROR_AUTHENTICATION, error_message);
+            break;
+
+        case eQuery_FetchError:
+            g_set_error (error, ET_MB5_SEARCH_ERROR,
+                         ET_MB5_SEARCH_ERROR_FETCH, error_message);
+            break;
+ 
+        case eQuery_RequestError:
+            g_set_error (error, ET_MB5_SEARCH_ERROR,
+                         ET_MB5_SEARCH_ERROR_REQUEST, error_message);
+            break;
+ 
+        case eQuery_ResourceNotFound:
+            g_set_error (error, ET_MB5_SEARCH_ERROR, 
+                         ET_MB5_SEARCH_ERROR_RESOURCE_NOT_FOUND,
+                         error_message);
+            break;
+
+        default:
+            break;
+    }
+
+    g_assert (error == NULL || *error != NULL);
+    return FALSE;
+}
+
+/*
+ * et_musicbrainz_search:
+ * @string:
+ * @type:
+ * @root:
+ *
+ *
+ */
+gboolean
+et_musicbrainz_search (gchar *string, enum MB_ENTITY_TYPE type, GNode *root,
+                       GError **error)
+{
+    Mb5Query query;
+    Mb5Metadata metadata;
+    char error_message[256];
+    tQueryResult result;
+    char *param_values[2];
+    char *param_names[2];
+
+    g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+    param_names [0] = "query";
+    param_names [1] = "limit";
+    param_values [1] = SEARCH_LIMIT_STR;
+    query = mb5_query_new ("easytag", NULL, 0);
+
+    if (type == MB_ENTITY_TYPE_ARTIST)
+    {
+        param_values [0] = g_strconcat ("artist:", string, NULL);
+        metadata = mb5_query_query (query, "artist", "", "", 2, param_names,
+                                    param_values);
+        result = mb5_query_get_lastresult (query);
+        if (result == eQuery_Success)
+        {
+            if (metadata)
+            {
+                int i;
+                Mb5ArtistList list;
+                list = mb5_metadata_get_artistlist (metadata);
+
+                for (i = 0; i < mb5_artist_list_size (list); i++)
+                {
+                    Mb5Artist artist;
+                    artist = mb5_artist_list_item (list, i);
+                    if (artist)
+                    {
+                        GNode *node;
+                        EtMbEntity *entity;
+                        entity = g_malloc (sizeof (EtMbEntity));
+                        entity->entity = mb5_artist_clone (artist);
+                        entity->type = MB_ENTITY_TYPE_ARTIST;
+                        node = g_node_new (entity);
+                        g_node_append (root, node);
+                    }
+                }
+            }
+
+            g_free (param_values [0]);
+            mb5_metadata_delete (metadata);
+        }
+        else
+        {
+            goto err;
+        }
+    }
+
+    else if (type == MB_ENTITY_TYPE_ALBUM)
+    {
+        param_values [0] = g_strconcat ("release:", string, NULL);
+        metadata = mb5_query_query (query, "release", "", "", 2, param_names,
+                                    param_values);
+        result = mb5_query_get_lastresult (query);
+
+        if (result == eQuery_Success)
+        {
+            if (metadata)
+            {
+                int i;
+                Mb5ReleaseList list;
+                list = mb5_metadata_get_releaselist (metadata);
+                param_names [0] = "inc";
+                param_values [0] = "artists release-groups";
+
+                for (i = 0; i < mb5_release_list_size (list); i++)
+                {
+                    Mb5Release release;
+                    release = mb5_release_list_item (list, i);
+                    if (release)
+                    {
+                        GNode *node;
+                        EtMbEntity *entity;
+                        entity = g_malloc (sizeof (EtMbEntity));
+                        entity->entity = mb5_release_clone (release);
+                        entity->type = MB_ENTITY_TYPE_ALBUM;
+                        node = g_node_new (entity);
+                        g_node_append (root, node);
+                    }
+                }
+            }
+
+            g_free (param_values [0]);
+            mb5_metadata_delete (metadata);
+        }
+        else
+        {
+            goto err;
+        }
+    }
+
+    else if (type == MB_ENTITY_TYPE_TRACK)
+    {
+        param_values [0] = g_strconcat ("recordings:", string, NULL);
+        metadata = mb5_query_query (query, "recording", "", "", 2,
+                                    param_names, param_values);
+        result = mb5_query_get_lastresult (query);
+        g_free (param_values [0]);
+
+        if (result == eQuery_Success)
+        {
+            if (metadata)
+            {
+                int i;
+                Mb5RecordingList list;
+
+                list = mb5_metadata_get_recordinglist (metadata);
+                param_names [0] = "inc";
+                param_values[0] = "releases artists";
+
+                for (i = 0; i < mb5_recording_list_size (list); i++)
+                {
+                    Mb5Recording recording;
+                    Mb5Metadata metadata_recording;
+                    gchar recording_mbid [NAME_MAX_SIZE];
+                    GNode *node;
+                    EtMbEntity *entity;
+
+                    recording = mb5_recording_list_item (list, i);
+                    mb5_recording_get_id (recording,
+                                          recording_mbid,
+                                          sizeof (recording_mbid));
+                    metadata_recording = mb5_query_query (query, "recording",
+                                                          recording_mbid, "",
+                                                          1, param_names,
+                                                          param_values);
+                    entity = g_malloc (sizeof (EtMbEntity));
+                    entity->entity = mb5_recording_clone (mb5_metadata_get_recording (metadata_recording));
+                    entity->type = MB_ENTITY_TYPE_TRACK;
+                    entity->is_red_line = FALSE;
+                    node = g_node_new (entity);
+                    g_node_append (root, node);
+                    mb5_metadata_delete (metadata_recording);
+                }
+            }
+
+            mb5_metadata_delete (metadata);
+        }
+        else
+        {
+            goto err;
+        }
+    }
+
+    mb5_query_delete (query);
+
+    return TRUE;
+
+    err:
+    mb5_query_get_lasterrormessage (query, error_message,
+                                    sizeof(error_message));
+
+    switch (result)
+    {
+        case eQuery_ConnectionError:
+            g_set_error (error, ET_MB5_SEARCH_ERROR,
+                         ET_MB5_SEARCH_ERROR_CONNECTION, error_message);
+            break;
+
+        case eQuery_Timeout:
+            g_set_error (error, ET_MB5_SEARCH_ERROR,
+                         ET_MB5_SEARCH_ERROR_TIMEOUT, error_message);
+            break;
+
+        case eQuery_AuthenticationError:
+            g_set_error (error, ET_MB5_SEARCH_ERROR,
+                         ET_MB5_SEARCH_ERROR_AUTHENTICATION, error_message);
+            break;
+
+        case eQuery_FetchError:
+            g_set_error (error, ET_MB5_SEARCH_ERROR,
+                         ET_MB5_SEARCH_ERROR_FETCH, error_message);
+            break;
+ 
+        case eQuery_RequestError:
+            g_set_error (error, ET_MB5_SEARCH_ERROR,
+                         ET_MB5_SEARCH_ERROR_REQUEST, error_message);
+            break;
+ 
+        case eQuery_ResourceNotFound:
+            g_set_error (error, ET_MB5_SEARCH_ERROR, 
+                         ET_MB5_SEARCH_ERROR_RESOURCE_NOT_FOUND,
+                         error_message);
+            break;
+
+        default:
+            break;
+    }
+
+    g_assert (error == NULL || *error != NULL);
+    return FALSE;
+}
+
+/*
+ * free_mb_tree:
+ * @node:
+ *
+ *
+ */
+void
+free_mb_tree (GNode *node)
+{
+    EtMbEntity *et_entity;
+    GNode *child;
+
+    et_entity = (EtMbEntity *)node->data;
+
+    if (et_entity)
+    {
+        if (et_entity->type == MB_ENTITY_TYPE_ARTIST)
+        {
+            mb5_artist_delete ((Mb5Artist)et_entity->entity);
+        }
+
+        else if (et_entity->type == MB_ENTITY_TYPE_ALBUM)
+        {
+            mb5_release_delete ((Mb5Release)et_entity->entity);
+        }
+
+        else if (et_entity->type == MB_ENTITY_TYPE_TRACK)
+        {
+            mb5_recording_delete ((Mb5Recording)et_entity->entity);
+        }
+    }
+
+    g_free (et_entity);
+    g_node_unlink (node);
+    child = g_node_first_child (node);
+
+    while (child)
+    {
+        free_mb_tree (child);
+        child = g_node_next_sibling (child);
+    }
+
+    g_node_destroy (node);
+}
diff --git a/src/mb_search.h b/src/mb_search.h
new file mode 100644
index 0000000..f91d920
--- /dev/null
+++ b/src/mb_search.h
@@ -0,0 +1,92 @@
+/* mb_search.h - 2014/05/05 */
+/*
+ *  EasyTAG - Tag editor for MP3 and Ogg Vorbis files
+ *  Copyright (C) 2000-2014  Abhinav Jangda <abhijangda hotmail com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __MB_SEARCH_H__
+#define __MB_SEARCH_H__
+
+#include <gtk/gtk.h>
+#include <musicbrainz5/mb5_c.h>
+
+#define SEARCH_LIMIT_STR "5"
+#define SEARCH_LIMIT_INT 5
+
+/****************
+ * Declarations *
+ ****************/
+
+GCancellable *mb5_search_cancellable;
+
+/*
+ * Error domain and codes for errors while reading/writing Opus files
+ */
+GQuark et_mb5_search_error_quark (void);
+
+#define ET_MB5_SEARCH_ERROR et_mb5_search_error_quark ()
+
+/*
+ * EtMB5SearchError:
+ * @ET_MB5_SEARCH_ERROR_CONNECTION: Connection Error
+ * @ET_MB5_SEARCH_ERROR_TIMEOUT: Timeout reached while communicating
+ * @ET_MB5_SEARCH_ERROR_AUTHENTICATION: Server Authentication not matched
+ * @ET_MB5_SEARCH_ERROR_FETCH: Cannot Fetch Data
+ * @ET_MB5_SEARCH_ERROR_REQUEST: Request to MusicBrainz Server cannot be made
+ * @ET_MB5_SEARCH_ERROR_RESOURCE_NOT_FOUND: Resource user is trying to search is not found
+ *
+ * Errors while searching MusicBrainz Server.
+ */
+typedef enum
+{
+    ET_MB5_SEARCH_ERROR_CONNECTION,
+    ET_MB5_SEARCH_ERROR_TIMEOUT,
+    ET_MB5_SEARCH_ERROR_AUTHENTICATION,
+    ET_MB5_SEARCH_ERROR_FETCH,
+    ET_MB5_SEARCH_ERROR_REQUEST,
+    ET_MB5_SEARCH_ERROR_RESOURCE_NOT_FOUND,
+} EtMB5SearchError;
+
+enum MB_ENTITY_TYPE
+{
+    MB_ENTITY_TYPE_ARTIST = 0,
+    MB_ENTITY_TYPE_ALBUM,
+    MB_ENTITY_TYPE_TRACK,
+    MB_ENTITY_TYPE_COUNT,
+};
+
+typedef struct
+{
+    Mb5Entity entity;
+    enum MB_ENTITY_TYPE type;    
+} EtMbEntity;
+
+/**************
+ * Prototypes *
+ **************/
+
+gboolean
+et_musicbrainz_search_in_entity (enum MB_ENTITY_TYPE child_type,
+                                 enum MB_ENTITY_TYPE parent_type,
+                                 gchar *parent_mbid, GNode *root,
+                                 GError **error);
+gboolean
+et_musicbrainz_search (gchar *string, enum MB_ENTITY_TYPE type, GNode *root,
+                       GError **error);
+void
+free_mb_tree (GNode *node);
+#endif /* __MB_SEARCH_H__ */
\ No newline at end of file
diff --git a/src/mbentityview.c b/src/mbentityview.c
index 22b9dd2..9d4ccb9 100644
--- a/src/mbentityview.c
+++ b/src/mbentityview.c
@@ -18,7 +18,14 @@
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
+#include <gdk/gdkkeysyms.h>
+#include <glib/gi18n.h>
+
+#include "gtk2_compat.h"
+#include "easytag.h"
 #include "mbentityview.h"
+#include "log.h"
+#include "musicbrainz_dialog.h"
 
 #define NAME_MAX_SIZE 256
 #define ET_MB_ENTITY_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
@@ -31,36 +38,44 @@
 
 char *columns [MB_ENTITY_TYPE_COUNT][8] = {
     {"Name", "Gender", "Type"},
-    {"Name", "Artist", "Release", "Type"},
-    {"Name", "Country", "Album", "Date", "Time", "Number"},
+    {"Name", "Artist", "Tracks", "Type"},
+    {"Name", "Album", "Artist", "Time", "Number"},
     };
 
+static GSimpleAsyncResult *async_result;
 
 /*
  * EtMbEntityViewPrivate:
- * @breadCrumbBox: GtkBox which represents the BreadCrumbWidget
- * @treeView: GtkTreeView to display the recieved music brainz data
- * @breadCrumbNodes: Array of GNode being displayed by the GtkToggleButton
- * @listStore: GtkTreeStore for treeView
- * @scrolledWindow: GtkScrolledWindow for treeView
- * @mbTreeRoot: Root Node of the Mb5Entity Tree
- * @mbTreeCurrentNode: Current node being displayed by EtMbEntityView
- * @activeToggleButton: Current active GtkToggleToolButton
+ * @bread_crumb_box: GtkBox which represents the BreadCrumbWidget
+ * @tree_view: GtkTreeView to display the recieved music brainz data
+ * @bread_crumb_nodes: Array of GNode being displayed by the GtkToggleButton
+ * @list_store: GtkTreeStore for treeView
+ * @scrolled_window: GtkScrolledWindow for treeView
+ * @mb_tree_root: Root Node of the Mb5Entity Tree
+ * @mb_tree_current_node: Current node being displayed by EtMbEntityView
+ * @active_toggle_button: Current active GtkToggleToolButton
  *
  * Private data for EtMbEntityView.
  */
 typedef struct
 {
-    GtkWidget *breadCrumbBox;
-    GNode *breadCrumbNodes[MB_ENTITY_TYPE_COUNT];
-    GtkWidget *treeView;
-    GtkTreeModel *listStore;
-    GtkWidget *scrolledWindow;
-    GNode *mbTreeRoot;
-    GNode *mbTreeCurrentNode;
-    GtkWidget *activeToggleButton;
+    GtkWidget *bread_crumb_box;
+    GNode *bread_crumb_nodes[MB_ENTITY_TYPE_COUNT];
+    GtkWidget *tree_view;
+    GtkTreeModel *list_store;
+    GtkWidget *scrolled_window;
+    GNode *mb_tree_root;
+    GNode *mb_tree_current_node;
+    GtkWidget *active_toggle_button;
 } EtMbEntityViewPrivate;
 
+typedef struct
+{
+    EtMbEntityView *entity_view;
+    GNode *child;
+    GtkTreeIter iter;
+} SearchInLevelThreadData;
+
 /**************
  * Prototypes *
  **************/
@@ -93,8 +108,9 @@ tree_view_row_activated (GtkTreeView *tree_view, GtkTreePath *path,
 GType
 et_mb_entity_view_get_type (void)
 {
+    /* TODO: Use G_DEFINE_TYPE */
     static GType et_mb_entity_view_type = 0;
-    
+
     if (!et_mb_entity_view_type)
     {
         static const GTypeInfo et_mb_entity_view_type_info = 
@@ -155,12 +171,16 @@ insert_togglebtn_in_breadcrumb (GtkBox *breadCrumb)
 static void
 add_iter_to_list_store (GtkListStore *list_store, GNode *node)
 {
-    /* Traverse node in GNode and add it to listStore */
+    /* Traverse node in GNode and add it to list_store */
     enum MB_ENTITY_TYPE type;
-    Mb5ReleaseList *release_list;
+    //Mb5ReleaseList *release_list;
     Mb5ArtistCredit artist_credit;
     Mb5NameCreditList name_list;
+    Mb5ReleaseGroup release_group;
+    Mb5ReleaseList release_list;
     int i;
+    int minutes;
+    int seconds;
     GString *gstring;
     GtkTreeIter iter;
     gchar name [NAME_MAX_SIZE];
@@ -172,9 +192,9 @@ add_iter_to_list_store (GtkListStore *list_store, GNode *node)
         entity = ((EtMbEntity *)node->data)->entity;
         switch (type)
         {
-            /* Following code may depend on the search code */
             case MB_ENTITY_TYPE_ARTIST:
                 mb5_artist_get_name ((Mb5Artist)entity, name, sizeof (name));
+                printf ("name %s\n", name);
                 gtk_list_store_append (list_store, &iter);
                 gtk_list_store_set (list_store, &iter, 
                                     MB_ARTIST_COLUMNS_NAME, name, -1);
@@ -187,17 +207,53 @@ add_iter_to_list_store (GtkListStore *list_store, GNode *node)
                 gtk_list_store_set (list_store, &iter,
                                     MB_ARTIST_COLUMNS_TYPE,
                                     name, -1);
+
+                if (((EtMbEntity *)node->data)->is_red_line)
+                {
+                    printf ("IS RED\n");
+                    gtk_list_store_set (list_store, &iter,
+                                        MB_ARTIST_COLUMNS_N, "red", -1);
+                }
+                else
+                {
+                    printf ("IS BLACK\n");
+                    gtk_list_store_set (list_store, &iter,
+                                        MB_ARTIST_COLUMNS_N, "black", -1);
+                }
+
                 break;
 
             case MB_ENTITY_TYPE_ALBUM:
-                mb5_releasegroup_get_title ((Mb5ReleaseGroup)entity, name, sizeof (name));
+                mb5_release_get_title ((Mb5Release)entity, name, sizeof (name));
                 gtk_list_store_append (list_store, &iter);
                 gtk_list_store_set (list_store, &iter, 
-                                     MB_ALBUM_COLUMNS_NAME, name, -1);
+                                    MB_ALBUM_COLUMNS_NAME, name, -1);
+
+                artist_credit = mb5_release_get_artistcredit ((Mb5Release)entity);
 
-                artist_credit = mb5_releasegroup_get_artistcredit ((Mb5ReleaseGroup)entity);
-                name_list = mb5_artistcredit_get_namecreditlist (artist_credit);
-                gstring = g_string_new ("");
+                if (artist_credit)
+                {
+                    name_list = mb5_artistcredit_get_namecreditlist (artist_credit);
+                    gstring = g_string_new ("");
+
+                    for (i = 0; i < mb5_namecredit_list_size (name_list); i++)
+                    {
+                        Mb5NameCredit name_credit;
+                        Mb5Artist name_credit_artist;
+                        int size;
+
+                        name_credit = mb5_namecredit_list_item (name_list, i);
+                        name_credit_artist = mb5_namecredit_get_artist (name_credit);
+                        size = mb5_artist_get_name (name_credit_artist, name, sizeof (name));
+                        g_string_append_len (gstring, name, size);
+                        g_string_append_c (gstring, ' ');
+                    }
+
+                    gtk_list_store_set (list_store, &iter,
+                                        MB_ALBUM_COLUMNS_ARTIST,
+                                        gstring->str, -1);
+                    g_string_free (gstring, TRUE);
+                }
 
                 for (i = 0; i < mb5_namecredit_list_get_count (name_list); i++)
                 {
@@ -218,26 +274,77 @@ add_iter_to_list_store (GtkListStore *list_store, GNode *node)
                                     MB_ALBUM_COLUMNS_ARTIST, gstring->str, -1);
                 g_string_free (gstring, TRUE);
 
-                release_list = mb5_releasegroup_get_releaselist ((Mb5ReleaseGroup)entity);
+                //TODO: Correct below code
+                /*release_list = mb5_release_get_releaselist ((Mb5Release)entity);
                 gtk_list_store_set (list_store, &iter,
                                     MB_ALBUM_COLUMNS_RELEASES,
                                     mb5_release_list_get_count (release_list), -1);
-                mb5_release_list_delete (release_list);
+                mb5_release_list_delete (release_list);*/
                 break;
 
             case MB_ENTITY_TYPE_TRACK:
-                mb5_recording_get_id ((Mb5Recording)entity, name, sizeof (name));
+                mb5_recording_get_title ((Mb5Recording)entity, name, sizeof (name));
                 gtk_list_store_append (list_store, &iter);
                 gtk_list_store_set (list_store, &iter, 
                                     MB_TRACK_COLUMNS_NAME, name, -1);
 
                 /* TODO: Get country and number */
-                gtk_list_store_set (list_store, &iter,
-                                    MB_TRACK_COLUMNS_COUNTRY, name, -1);
+                /*gtk_list_store_set (list_store, &iter,
+                                    MB_TRACK_COLUMNS_COUNTRY, name, -1);*/
+                artist_credit = mb5_recording_get_artistcredit ((Mb5Release)entity);
+                if (artist_credit)
+                {
+                    name_list = mb5_artistcredit_get_namecreditlist (artist_credit);
+                    gstring = g_string_new ("");
+
+                    for (i = 0; i < mb5_namecredit_list_size (name_list); i++)
+                    {
+                        Mb5NameCredit name_credit;
+                        Mb5Artist name_credit_artist;
+                        int size;
+
+                        name_credit = mb5_namecredit_list_item (name_list, i);
+                        name_credit_artist = mb5_namecredit_get_artist (name_credit);
+                        size = mb5_artist_get_name (name_credit_artist, name, sizeof (name));
+                        g_string_append_len (gstring, name, size);
+                        g_string_append_c (gstring, ' ');
+                    }
+
+                    gtk_list_store_set (list_store, &iter,
+                                        MB_TRACK_COLUMNS_ARTIST,
+                                        gstring->str, -1);
+                    g_string_free (gstring, TRUE);
+                }
+
+                release_list = mb5_recording_get_releaselist ((Mb5Recording)entity);
+                if (release_list)
+                {
+                    gstring = g_string_new ("");
+                    for (i = 0; i < mb5_release_list_size (release_list); i++)
+                    {
+                        Mb5Release release;
+                        int size;
+
+                        release = mb5_release_list_item (release_list, i);
+                        size = mb5_release_get_title (release, name, sizeof (name));
+                        g_string_append_len (gstring, name, size);
+                        g_string_append_c (gstring, ' ');
+                    }
+
+                    gtk_list_store_set (list_store, &iter,
+                                        MB_TRACK_COLUMNS_ALBUM,
+                                        gstring->str, -1);
+                    g_string_free (gstring, TRUE);
+                }
 
+                minutes = mb5_recording_get_length ((Mb5Recording)entity)/60000;
+                seconds = mb5_recording_get_length ((Mb5Recording)entity)%60000;
+                i = g_snprintf (name, NAME_MAX_SIZE, "%d:%d", minutes,
+                                seconds/1000);
+                name [i] = '\0';
                 gtk_list_store_set (list_store, &iter,
                                     MB_TRACK_COLUMNS_TIME,
-                                    mb5_recording_get_length ((Mb5Recording)entity), -1);
+                                    name, -1);
                 break;
 
             case MB_ENTITY_TYPE_COUNT:
@@ -267,25 +374,25 @@ show_data_in_entity_view (EtMbEntityView *entity_view)
     priv = ET_MB_ENTITY_VIEW_GET_PRIVATE (entity_view);
 
     /* Remove the previous List Store */
-    if (GTK_IS_LIST_STORE (priv->listStore))
+    if (GTK_IS_LIST_STORE (priv->list_store))
     {
-        gtk_list_store_clear (GTK_LIST_STORE (priv->listStore));
+        gtk_list_store_clear (GTK_LIST_STORE (priv->list_store));
     }
 
-    gtk_tree_view_set_model (GTK_TREE_VIEW (priv->treeView), NULL);
+    gtk_tree_view_set_model (GTK_TREE_VIEW (priv->tree_view), NULL);
 
     /* Remove all colums */
-    list_cols = gtk_tree_view_get_columns (GTK_TREE_VIEW (priv->treeView));
+    list_cols = gtk_tree_view_get_columns (GTK_TREE_VIEW (priv->tree_view));
     for (list = g_list_first (list_cols); list != NULL; list = g_list_next (list))
     {
-        gtk_tree_view_remove_column (GTK_TREE_VIEW (priv->treeView),
+        gtk_tree_view_remove_column (GTK_TREE_VIEW (priv->tree_view),
                                      GTK_TREE_VIEW_COLUMN (list->data));
     }
 
     g_list_free (list_cols);
 
     /* Create new List Store and add it */
-    type = ((EtMbEntity *)(g_node_first_child (priv->mbTreeCurrentNode)->data))->type;
+    type = ((EtMbEntity *)(g_node_first_child (priv->mb_tree_current_node)->data))->type;
     switch (type)
     {
         case MB_ENTITY_TYPE_ARTIST:
@@ -312,17 +419,17 @@ show_data_in_entity_view (EtMbEntityView *entity_view)
         renderer = gtk_cell_renderer_text_new ();
         column = gtk_tree_view_column_new_with_attributes (columns[type][i], 
                                                            renderer, "text", i, NULL);
-        gtk_tree_view_append_column (GTK_TREE_VIEW (priv->treeView), column);
+        gtk_tree_view_append_column (GTK_TREE_VIEW (priv->tree_view), column);
     }
 
-    priv->listStore = GTK_TREE_MODEL (gtk_list_store_newv (total_cols, types));
+    priv->list_store = GTK_TREE_MODEL (gtk_list_store_newv (total_cols, types));
     g_free (types);
 
-    gtk_tree_view_set_model (GTK_TREE_VIEW (priv->treeView), priv->listStore);
-    g_object_unref (priv->listStore);
+    gtk_tree_view_set_model (GTK_TREE_VIEW (priv->tree_view), priv->list_store);
+    g_object_unref (priv->list_store);
 
-    add_iter_to_list_store (GTK_LIST_STORE (priv->listStore),
-                            g_node_first_child (priv->mbTreeCurrentNode));
+    add_iter_to_list_store (GTK_LIST_STORE (priv->list_store),
+                            g_node_first_child (priv->mb_tree_current_node));
 }
 
 /*
@@ -342,89 +449,188 @@ toggle_button_clicked (GtkWidget *btn, gpointer user_data)
     entity_view = ET_MB_ENTITY_VIEW (user_data);
     priv = ET_MB_ENTITY_VIEW_GET_PRIVATE (entity_view);
 
-    if (btn == priv->activeToggleButton)
+    if (btn == priv->active_toggle_button)
     {
         return;
     }
 
-    if (!gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (btn)))
+    if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (btn)))
     {
         return;
     }
 
-    if (priv->activeToggleButton)
+    if (priv->active_toggle_button)
     {
-        gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (priv->activeToggleButton),
-                                           FALSE);
+        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->active_toggle_button),
+                                      FALSE);
     }
 
-    children = gtk_container_get_children (GTK_CONTAINER (priv->breadCrumbBox));
-    priv->mbTreeCurrentNode = priv->breadCrumbNodes[g_list_index (children, btn)];
-    priv->activeToggleButton = btn;
+    children = gtk_container_get_children (GTK_CONTAINER (priv->bread_crumb_box));
+    priv->mb_tree_current_node = priv->bread_crumb_nodes[g_list_index (children, btn)];
+    priv->active_toggle_button = btn;
     show_data_in_entity_view (entity_view);
 }
 
-/*
- * tree_view_row_activated:
- * @tree_view: the object on which the signal is emitted
- * @path: the GtkTreePath for the activated row
- * @column: the GtkTreeViewColumn in which the activation occurred
- * @user_data: user data set when the signal handler was connected.
- *
- * Signal Handler for GtkTreeView "row-activated" signal.
- */
 static void
-tree_view_row_activated (GtkTreeView *tree_view, GtkTreePath *path,
-                         GtkTreeViewColumn *column, gpointer user_data)
+search_in_levels_callback (GObject *source, GAsyncResult *res,
+                           gpointer user_data)
 {
     EtMbEntityView *entity_view;
     EtMbEntityViewPrivate *priv;
     GtkWidget *toggle_btn;
-    int depth;
-    GtkTreeIter iter;
     gchar *entity_name;
-    GNode *child;
+    SearchInLevelThreadData *thread_data;
+    GList *children;
+    GList *active_child;
 
-    entity_view = ET_MB_ENTITY_VIEW (user_data);
+    thread_data = user_data;
+    entity_view = thread_data->entity_view;
     priv = ET_MB_ENTITY_VIEW_GET_PRIVATE (entity_view);
 
-    /* Depth is 1-based */
-    depth = gtk_tree_path_get_depth (path);
-    child = g_node_nth_child (priv->mbTreeCurrentNode,
-                              depth - 1);
-
+    gtk_statusbar_push (GTK_STATUSBAR (gtk_builder_get_object (builder, "statusbar")),
+                        0, "Retrieving Completed");
     /* Check if child node has children or not */
-    if (!g_node_first_child (child))
+    if (!g_node_first_child (thread_data->child))
     {
         return;
     }
 
-    priv->mbTreeCurrentNode = child;
-
-    if (((EtMbEntity *)(priv->mbTreeCurrentNode->data))->type ==
-        MB_ENTITY_TYPE_TRACK)
+    priv->mb_tree_current_node = thread_data->child;
+    children = gtk_container_get_children (GTK_CONTAINER (priv->bread_crumb_box));
+    active_child = g_list_find (children, priv->active_toggle_button);
+    while ((active_child = g_list_next (active_child)))
     {
-        return;
+        gtk_container_remove (GTK_CONTAINER (priv->bread_crumb_box),
+                              GTK_WIDGET (active_child->data));
     }
 
-    toggle_btn = insert_togglebtn_in_breadcrumb (GTK_BOX (priv->breadCrumbBox));
-    priv->breadCrumbNodes [g_list_length (gtk_container_get_children (GTK_CONTAINER (priv->breadCrumbBox))) 
- 1] = priv->mbTreeCurrentNode;
+    toggle_btn = insert_togglebtn_in_breadcrumb (GTK_BOX (priv->bread_crumb_box));
+    children = gtk_container_get_children (GTK_CONTAINER (priv->bread_crumb_box));
+    priv->bread_crumb_nodes [g_list_length (children) - 1] = thread_data->child;
 
-    if (priv->activeToggleButton)
+    if (priv->active_toggle_button)
     {
-        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->activeToggleButton),
-                                           FALSE);
+        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->active_toggle_button),
+                                      FALSE);
     }
 
-    gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (toggle_btn), TRUE);
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle_btn), TRUE);
     g_signal_connect (G_OBJECT (toggle_btn), "clicked",
                       G_CALLBACK (toggle_button_clicked), entity_view);
-    priv->activeToggleButton = toggle_btn;
-    gtk_tree_model_get_iter (priv->listStore, &iter, path);
-    gtk_tree_model_get (priv->listStore, &iter, 0, &entity_name, -1);
+    priv->active_toggle_button = toggle_btn;
+    gtk_tree_model_get (priv->list_store, &thread_data->iter, 0, &entity_name,
+                        -1);
     gtk_button_set_label (GTK_BUTTON (toggle_btn), entity_name);
-    gtk_widget_show_all (GTK_WIDGET (priv->breadCrumbBox));
+    gtk_widget_show_all (GTK_WIDGET (priv->bread_crumb_box));
+    ((EtMbEntity *)thread_data->child->data)->is_red_line = TRUE;
     show_data_in_entity_view (entity_view);
+    g_object_unref (res);
+    g_free (thread_data);
+}
+
+static void
+search_in_levels_thread_func (GSimpleAsyncResult *res, GObject *obj,
+                              GCancellable *cancellable)
+{
+    SearchInLevelThreadData *thread_data;
+    gchar mbid [NAME_MAX_SIZE];
+    GError *error;
+    gchar *status_msg;
+    gchar parent_entity_str [NAME_MAX_SIZE];
+    gchar *child_entity_type_str;
+
+    child_entity_type_str = NULL;
+    thread_data = g_async_result_get_user_data (G_ASYNC_RESULT (res));
+
+    if (((EtMbEntity *)thread_data->child->data)->type ==
+        MB_ENTITY_TYPE_TRACK)
+    {
+        return;
+    }
+    else if (((EtMbEntity *)thread_data->child->data)->type ==
+             MB_ENTITY_TYPE_ARTIST)
+    {
+        child_entity_type_str = g_strdup ("Albums ");
+        mb5_artist_get_id (((EtMbEntity *)thread_data->child->data)->entity,
+                           mbid, sizeof (mbid));
+        mb5_artist_get_name (((EtMbEntity *)thread_data->child->data)->entity,
+                             parent_entity_str, sizeof (parent_entity_str));
+    }
+    else if (((EtMbEntity *)thread_data->child->data)->type ==
+             MB_ENTITY_TYPE_ALBUM)
+    {
+        child_entity_type_str = g_strdup ("Tracks ");
+        mb5_release_get_id (((EtMbEntity *)thread_data->child->data)->entity,
+                            mbid, sizeof (mbid));
+        mb5_release_get_title (((EtMbEntity *)thread_data->child->data)->entity,
+                               parent_entity_str, sizeof (parent_entity_str));
+    }
+
+    error = NULL;
+    status_msg = g_strconcat ("Retrieving ", child_entity_type_str, "for ",
+                              parent_entity_str, NULL);
+    et_show_status_msg_in_idle (status_msg);
+    g_free (status_msg);
+    g_free (child_entity_type_str);
+
+    if (!et_musicbrainz_search_in_entity (((EtMbEntity *)thread_data->child->data)->type + 1,
+                                          ((EtMbEntity *)thread_data->child->data)->type,
+                                          mbid, thread_data->child, &error))
+    {
+        g_simple_async_report_gerror_in_idle (NULL,
+                                              mb5_search_error_callback,
+                                              thread_data, error);
+    }
+}
+
+/*
+ * tree_view_row_activated:
+ * @tree_view: the object on which the signal is emitted
+ * @path: the GtkTreePath for the activated row
+ * @column: the GtkTreeViewColumn in which the activation occurred
+ * @user_data: user data set when the signal handler was connected.
+ *
+ * Signal Handler for GtkTreeView "row-activated" signal.
+ */
+static void
+tree_view_row_activated (GtkTreeView *tree_view, GtkTreePath *path,
+                         GtkTreeViewColumn *column, gpointer user_data)
+{
+    /* TODO: Add Cancellable object */
+    SearchInLevelThreadData *thread_data;
+    EtMbEntityView *entity_view;
+    EtMbEntityViewPrivate *priv;
+    GNode *child;
+    int depth;
+    GtkTreeIter iter;
+
+    entity_view = ET_MB_ENTITY_VIEW (user_data);
+    priv = ET_MB_ENTITY_VIEW_GET_PRIVATE (entity_view);
+    gtk_tree_model_get_iter (priv->list_store, &iter, path);
+    depth = 0;
+
+    while (gtk_tree_model_iter_previous (priv->list_store, &iter))
+    {        
+        depth++;
+    }
+
+    printf ("depth %d\n", depth);
+    child = g_node_nth_child (priv->mb_tree_current_node,
+                              depth);
+
+    thread_data = g_malloc (sizeof (SearchInLevelThreadData));
+    thread_data->entity_view = ET_MB_ENTITY_VIEW (user_data);
+    thread_data->child = child;
+    gtk_tree_model_get_iter (priv->list_store, &thread_data->iter, path);
+    gtk_statusbar_push (GTK_STATUSBAR (gtk_builder_get_object (builder, "statusbar")),
+                        0, "Starting MusicBrainz Search");
+    async_result = g_simple_async_result_new (NULL,
+                                              search_in_levels_callback,
+                                              thread_data,
+                                              tree_view_row_activated);
+    g_simple_async_result_run_in_thread (async_result,
+                                         search_in_levels_thread_func,
+                                         0, NULL);
 }
 
 /*
@@ -438,24 +644,26 @@ et_mb_entity_view_init (EtMbEntityView *entity_view)
 {
     EtMbEntityViewPrivate *priv = ET_MB_ENTITY_VIEW_GET_PRIVATE (entity_view);
 
-    gtk_orientable_set_orientation (GTK_ORIENTABLE (entity_view), GTK_ORIENTATION_VERTICAL);
+    gtk_orientable_set_orientation (GTK_ORIENTABLE (entity_view),
+                                    GTK_ORIENTATION_VERTICAL);
 
-    /* Adding child widgets */    
-    priv->breadCrumbBox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
-    priv->treeView = gtk_tree_view_new ();
-    priv->scrolledWindow = gtk_scrolled_window_new (NULL, NULL);
-    gtk_container_add (GTK_CONTAINER (priv->scrolledWindow), priv->treeView);
-    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolledWindow),
+    /* Adding child widgets */
+    priv->bread_crumb_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
+    priv->tree_view = gtk_tree_view_new ();
+    priv->scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+    gtk_container_add (GTK_CONTAINER (priv->scrolled_window),
+                       priv->tree_view);
+    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolled_window),
                                     GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS);
-    gtk_box_pack_start (GTK_BOX (entity_view), priv->breadCrumbBox,
+    gtk_box_pack_start (GTK_BOX (entity_view), priv->bread_crumb_box,
                         FALSE, FALSE, 2);
-    gtk_box_pack_start (GTK_BOX (entity_view), priv->scrolledWindow,
+    gtk_box_pack_start (GTK_BOX (entity_view), priv->scrolled_window,
                         TRUE, TRUE, 2);
-    priv->mbTreeRoot = NULL;
-    priv->mbTreeCurrentNode = NULL;
-    priv->activeToggleButton = NULL;
+    priv->mb_tree_root = NULL;
+    priv->mb_tree_current_node = NULL;
+    priv->active_toggle_button = NULL;
 
-    g_signal_connect (G_OBJECT (priv->treeView), "row-activated",
+    g_signal_connect (G_OBJECT (priv->tree_view), "row-activated",
                       G_CALLBACK (tree_view_row_activated), entity_view);
 }
 
@@ -473,9 +681,9 @@ et_mb_entity_view_set_tree_root (EtMbEntityView *entity_view, GNode *treeRoot)
     GtkWidget *btn;
     GNode *child;
     priv = ET_MB_ENTITY_VIEW_GET_PRIVATE (entity_view);
-    priv->mbTreeRoot = treeRoot;
-    priv->mbTreeCurrentNode = treeRoot;
-    btn = insert_togglebtn_in_breadcrumb (GTK_BOX (priv->breadCrumbBox));
+    priv->mb_tree_root = treeRoot;
+    priv->mb_tree_current_node = treeRoot;
+    btn = insert_togglebtn_in_breadcrumb (GTK_BOX (priv->bread_crumb_box));
     child = g_node_first_child (treeRoot);
     if (child)
     {
@@ -497,10 +705,13 @@ et_mb_entity_view_set_tree_root (EtMbEntityView *entity_view, GNode *treeRoot)
                 break;
         }
 
-        priv->breadCrumbNodes [0] = treeRoot;
-        priv->activeToggleButton = btn;
+        priv->bread_crumb_nodes [0] = treeRoot;
+        priv->active_toggle_button = btn;
         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (btn), TRUE);
+        gtk_widget_show_all (priv->bread_crumb_box);
         show_data_in_entity_view (entity_view);
+        g_signal_connect (G_OBJECT (btn), "clicked",
+                          G_CALLBACK (toggle_button_clicked), entity_view);
     }
 }
 
@@ -516,4 +727,4 @@ GtkWidget *
 et_mb_entity_view_new ()
 {
     return GTK_WIDGET (g_object_new (et_mb_entity_view_get_type (), NULL));
-}
\ No newline at end of file
+}
diff --git a/src/mbentityview.h b/src/mbentityview.h
index eeb08d5..d16642d 100644
--- a/src/mbentityview.h
+++ b/src/mbentityview.h
@@ -22,7 +22,7 @@
 #define __MB_ENTITY_VIEW_H__
 
 #include <gtk/gtk.h>
-#include <musicbrainz5/mb5_c.h>
+#include "mb_search.h"
 
 #define ET_MB_ENTITY_VIEW_TYPE (et_mb_entity_view_get_type ())
 #define ET_MB_ENTITY_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
@@ -66,14 +66,6 @@ typedef struct
     GtkBoxClass parent;
 } EtMbEntityViewClass;
 
-enum MB_ENTITY_TYPE
-{
-    MB_ENTITY_TYPE_ARTIST = 0,
-    MB_ENTITY_TYPE_ALBUM,
-    MB_ENTITY_TYPE_TRACK,
-    MB_ENTITY_TYPE_COUNT,
-};
-
 enum MB_ARTIST_COLUMNS
 {
     MB_ARTIST_COLUMNS_NAME,
@@ -86,7 +78,7 @@ enum MB_ALBUM_COLUMNS
 {
     MB_ALBUM_COLUMNS_NAME,
     MB_ALBUM_COLUMNS_ARTIST,
-    MB_ALBUM_COLUMNS_RELEASES,
+    MB_ALBUM_COLUMNS_TRACKS,
     MB_ALBUM_COLUMNS_TYPE,
     MB_ALBUM_COLUMNS_N
 };
@@ -94,24 +86,18 @@ enum MB_ALBUM_COLUMNS
 enum MB_TRACK_COLUMNS
 {
     MB_TRACK_COLUMNS_NAME,
-    MB_TRACK_COLUMNS_COUNTRY,
+    MB_TRACK_COLUMNS_ALBUM,
+    MB_TRACK_COLUMNS_ARTIST,
     MB_TRACK_COLUMNS_TIME,
-    MB_TRACK_COLUMNS_NUMBER,
     MB_TRACK_COLUMNS_N
 };
 
-typedef struct
-{
-    Mb5Entity entity;
-    enum MB_ENTITY_TYPE type;    
-} EtMbEntity;
-
 /**************
  * Prototypes *
  **************/
 
 GType
-et_mb_entity_view_get_type (void) G_GNUC_CONST;
+et_mb_entity_view_get_type (void);
 GtkWidget *
 et_mb_entity_view_new (void);
 void
diff --git a/src/musicbrainz_dialog.c b/src/musicbrainz_dialog.c
index 6548360..8daa722 100644
--- a/src/musicbrainz_dialog.c
+++ b/src/musicbrainz_dialog.c
@@ -25,33 +25,165 @@
 #include <glib/gi18n.h>
 
 #include "gtk2_compat.h"
-#include "cddb.h"
 #include "easytag.h"
-#include "et_core.h"
-#include "browser.h"
-#include "scan_dialog.h"
 #include "log.h"
-#include "misc.h"
-#include "setting.h"
-#include "id3_tag.h"
-#include "setting.h"
-#include "charset.h"
 #include "musicbrainz_dialog.h"
 #include "mbentityview.h"
-
+ 
 /***************
  * Declaration *
  ***************/
 
-static GtkBuilder *builder;
-static GtkWidget *mbDialog;
-static GtkWidget *entityView;
+static GNode *mb_tree_root;
+static GSimpleAsyncResult *async_result;
+
+typedef struct
+{
+    gchar *text_to_search;
+    int type;
+} ManualSearchThreadData;
 
 /*************
  * Functions *
  *************/
 
 /*
+ * manual_search_callback:
+ * @source: Source Object
+ * @res: GAsyncResult
+ * @user_data: User data
+ *
+ * Callback function for GAsyncResult for Manual Search.
+ */
+static void
+manual_search_callback (GObject *source, GAsyncResult *res,
+                        gpointer user_data)
+{
+    et_mb_entity_view_set_tree_root (ET_MB_ENTITY_VIEW (entityView),
+                                     mb_tree_root);
+    gtk_statusbar_push (GTK_STATUSBAR (gtk_builder_get_object (builder, "statusbar")),
+                        0, "Searching Completed");
+    g_object_unref (res);
+    g_free (user_data);
+}
+
+static void
+et_show_status_msg_in_idle_cb (GObject *obj, GAsyncResult *res,
+                               gpointer user_data)
+{
+    gtk_statusbar_push (GTK_STATUSBAR (gtk_builder_get_object (builder, "statusbar")),
+                        0, user_data);
+    g_free (user_data);
+    g_object_unref (res);
+}
+
+void
+et_show_status_msg_in_idle (gchar *message)
+{
+    GSimpleAsyncResult *async_res;
+
+    async_res = g_simple_async_result_new (NULL,
+                                           et_show_status_msg_in_idle_cb,
+                                           g_strdup (message),
+                                           et_show_status_msg_in_idle);
+    g_simple_async_result_complete_in_idle (async_res);
+}
+
+void
+mb5_search_error_callback (GObject *source, GAsyncResult *res,
+                           gpointer user_data)
+{
+    GError *dest;
+    dest = NULL;
+    g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res),
+                                           &dest);
+    Log_Print (LOG_ERROR,
+               _("Error searching MusicBrainz Database '%s'"), dest->message);
+    gtk_statusbar_push (GTK_STATUSBAR (gtk_builder_get_object (builder, "statusbar")),
+                        0, dest->message);
+    g_error_free (dest);
+    g_free (user_data);
+}
+
+/*
+ * manual_search_thread_func:
+ * @res: GSimpleAsyncResult
+ * @obj: Source GObject
+ * @cancellable: GCancellable to cancel the operation
+ *
+ * Thread func of GSimpleAsyncResult to do Manual Search in another thread.
+ */
+static void
+manual_search_thread_func (GSimpleAsyncResult *res, GObject *obj,
+                           GCancellable *cancellable)
+{
+    GError *error;
+    ManualSearchThreadData *thread_data;
+    gchar *status_msg;
+
+    error = NULL;
+    thread_data = (ManualSearchThreadData *)g_async_result_get_user_data (G_ASYNC_RESULT (res));
+    status_msg = g_strconcat ("Searching ", thread_data->text_to_search, NULL);
+    et_show_status_msg_in_idle (status_msg);
+    g_free (status_msg);
+
+    if (!et_musicbrainz_search (thread_data->text_to_search,
+                                thread_data->type, mb_tree_root, &error))
+    {
+        g_simple_async_report_gerror_in_idle (NULL,
+                                              mb5_search_error_callback,
+                                              thread_data, error);
+    }
+}
+
+/*
+ * btn_manual_find_clicked:
+ * @btn: The source GtkButton
+ * @user_data: User data passed
+ *
+ * Signal Handler for "clicked" signal of mbSearchButton.
+ */
+static void
+btn_manual_find_clicked (GtkWidget *btn, gpointer user_data)
+{
+    GtkWidget *cb_manual_search;
+    GtkWidget *cb_manual_search_in;
+    int type;
+    ManualSearchThreadData *thread_data;
+
+    if (g_node_first_child (mb_tree_root))
+    {
+        free_mb_tree (mb_tree_root);
+        mb_tree_root = g_node_new (NULL);
+    }
+  
+    cb_manual_search = GTK_WIDGET (gtk_builder_get_object (builder,
+                                                           "cbManualSearch"));
+    cb_manual_search_in = GTK_WIDGET (gtk_builder_get_object (builder,
+                                                              "cbManualSearchIn"));
+    type = gtk_combo_box_get_active (GTK_COMBO_BOX (cb_manual_search_in));
+    thread_data = g_malloc (sizeof (ManualSearchThreadData));
+    thread_data->type = type;
+    thread_data->text_to_search = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (cb_manual_search));
+    mb5_search_cancellable = g_cancellable_new ();
+    /* TODO: Add Cancellable object */
+    gtk_statusbar_push (GTK_STATUSBAR (gtk_builder_get_object (builder, "statusbar")),
+                        0, "Starting MusicBrainz Search");
+    async_result = g_simple_async_result_new (NULL, manual_search_callback, 
+                                              thread_data,
+                                              btn_manual_find_clicked);
+    g_simple_async_result_run_in_thread (async_result,
+                                         manual_search_thread_func, 0,
+                                         mb5_search_cancellable);
+}
+
+static void
+btn_manual_stop_clicked (GtkWidget *btn, gpointer user_data)
+{
+    g_cancellable_cancel (mb5_search_cancellable);
+}
+
+/*
  * et_open_musicbrainz_dialog:
  *
  * This function will open the musicbrainz dialog.
@@ -59,22 +191,50 @@ static GtkWidget *entityView;
 void
 et_open_musicbrainz_dialog ()
 {
-    entityView = et_mb_entity_view_new ();
+    GtkWidget *cb_manual_search_in;
+    GError *error;
+
     builder = gtk_builder_new ();
-    /* TODO: Check the error. */
-    gtk_builder_add_from_resource (builder,
-                                   "/org/gnome/EasyTAG/musicbrainz_dialog.ui",
-                                   NULL);
+    error = NULL;
 
-    mbDialog = GTK_WIDGET (gtk_builder_get_object (builder, "mbDialog"));
+    if (!gtk_builder_add_from_resource (builder,
+                                        "/org/gnome/EasyTAG/musicbrainz_dialog.ui",
+                                        &error))
+    {
+        Log_Print (LOG_ERROR,
+                   _("Error loading MusicBrainz Search Dialog '%s'"),
+                   error->message);
+        g_error_free (error);
+        g_object_unref (G_OBJECT (builder));
+        return;
+    }
 
+    mb_tree_root = g_node_new (NULL);
+    entityView = et_mb_entity_view_new ();
+    mbDialog = GTK_WIDGET (gtk_builder_get_object (builder, "mbDialog"));
     gtk_box_pack_start (GTK_BOX (gtk_builder_get_object (builder, "centralBox")),
                         entityView, TRUE, TRUE, 2);
     /* FIXME: This should not be needed. */
     gtk_box_reorder_child (GTK_BOX (gtk_builder_get_object (builder, "centralBox")),
                            entityView, 0);
+    g_signal_connect (gtk_builder_get_object (builder, "btnManualFind"),
+                      "clicked", G_CALLBACK (btn_manual_find_clicked),
+                      NULL);
+    g_signal_connect (gtk_builder_get_object (builder, "btnManualStop"),
+                      "clicked", G_CALLBACK (btn_manual_stop_clicked),
+                      NULL);
+
+    /* Fill Values in cb_manual_search_in */
+    cb_manual_search_in = GTK_WIDGET (gtk_builder_get_object (builder,
+                                                              "cbManualSearchIn"));
+
+    gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (cb_manual_search_in), "Artist");
+    gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (cb_manual_search_in), "Album");
+    gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (cb_manual_search_in), "Track");
+
     gtk_widget_show_all (mbDialog);
     gtk_dialog_run (GTK_DIALOG (mbDialog));
     gtk_widget_destroy (mbDialog);
     g_object_unref (G_OBJECT (builder));
-}
+    free_mb_tree (mb_tree_root);
+}
\ No newline at end of file
diff --git a/src/musicbrainz_dialog.h b/src/musicbrainz_dialog.h
index 32e5cad..ed5f02f 100644
--- a/src/musicbrainz_dialog.h
+++ b/src/musicbrainz_dialog.h
@@ -21,11 +21,23 @@
 #ifndef __MUSICBRAINZ_DIALOG_H__
 #define __MUSICBRAINZ_DIALOG_H__
 
+/****************
+ * Declarations *
+ ****************/
+
+GtkBuilder *builder;
+GtkWidget *mbDialog;
+GtkWidget *entityView;
+
 /**************
  * Prototypes *
  **************/
 
 void
 et_open_musicbrainz_dialog (void);
-
-#endif /* __MUSICBRAINZ_DIALOG_H__ */
+void
+mb5_search_error_callback (GObject *source, GAsyncResult *res,
+                           gpointer user_data);
+void
+et_show_status_msg_in_idle (gchar *message);
+#endif /* __MUSICBRAINZ_DIALOG_H__ */
\ No newline at end of file


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