Main Page | Class List | Directories | File List | Class Members | File Members

baobab-tree-map.c

Go to the documentation of this file.
00001 /*
00002  * baobab-tree-map.c
00003  * This file is part of baobab
00004  *
00005  * Copyright (C) 2005-2006 Fabio Marzocca  <thesaltydog@gmail.com>
00006  *
00007  * This program is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, 
00020  * Boston, MA  02110-1301  USA
00021  */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026 
00027 #include <glib.h>
00028 #include <gtk/gtk.h>
00029 #include <glib/gi18n.h>
00030 
00031 #include "baobab-tree-map.h"
00032 
00033 struct _rect_coords {
00034         gdouble x1;
00035         gdouble y1;
00036         gdouble x2;
00037         gdouble y2;
00038 };
00039 
00040 typedef struct _rect_coords rect_coords;
00041 
00042 #define BAOBAB_TREE_MAP_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), \
00043                                            BAOBAB_TYPE_TREE_MAP, BaobabTreeMapPrivate))
00044 
00045 
00046 struct _BaobabTreeMapPrivate
00047 {
00048         GtkTooltips                     *tooltips;
00049         GnomeCanvasGroup                *group;
00050         GtkTreeModel                    *model;
00051         gint                            COL_FOLDERNAME;
00052         gint                            COL_SIZE;
00053         gint                            req_depth;
00054         gint                            total_elements;
00055         GtkTreePath                     *first_path;
00056         gchar                           *item_name;
00057 };
00058 
00059 G_DEFINE_TYPE(BaobabTreeMap, baobab_tree_map, GNOME_TYPE_CANVAS)
00060 
00061 static void
00062 baobab_tree_map_finalize (GObject *object)
00063 {
00064         BaobabTreeMap *treemap = BAOBAB_TREE_MAP(object);
00065 
00066         g_object_unref (treemap->priv->tooltips);
00067 
00068         G_OBJECT_CLASS (baobab_tree_map_parent_class)->finalize (object);
00069 }
00070 
00071 static void 
00072 baobab_tree_map_class_init (BaobabTreeMapClass *klass)
00073 {
00074         GObjectClass *object_class = G_OBJECT_CLASS (klass);
00075 
00076         object_class->finalize = baobab_tree_map_finalize;
00077 
00078         g_type_class_add_private (object_class, sizeof (BaobabTreeMapPrivate));
00079 }
00080 
00081 static gint
00082 item_event (GtkWidget           *item,
00083             GdkEventButton      *event,
00084             BaobabTreeMap *tm)
00085 {
00086         switch (event->button) {
00087         case 1:
00088         case 3:
00089                 {
00090                         /* get item name */
00091                         GtkTooltipsData * t_data = gtk_tooltips_data_get(item);
00092                         if (t_data) tm->priv->item_name = t_data->tip_text;
00093                 }
00094                 break;
00095         default:
00096                 break;
00097         }
00098 
00099         return FALSE;
00100 }
00101 
00102 static void
00103 setup_widget_item (BaobabTreeMap *tm,
00104                    GnomeCanvasItem     *item)
00105 {
00106         GtkWidget *widget = ((GnomeCanvasWidget *)item)->widget; 
00107 
00108         g_signal_connect (widget,
00109                           "button-press-event",
00110                           G_CALLBACK (item_event),
00111                           tm);
00112 }
00113 
00114 static void 
00115 draw_rect (BaobabTreeMap *tm,
00116            const rect_coords   *R,
00117            guint                color,
00118            gchar               *tip)
00119 {
00120         GtkWidget *widget;
00121 
00122         gnome_canvas_item_new (tm->priv->group,
00123                                gnome_canvas_rect_get_type(),
00124                                "x1", R->x1,
00125                                "y1", R->y1,
00126                                "x2", R->x2,
00127                                "y2", R->y2,
00128                                "fill_color_rgba", color,
00129                                "outline_color_rgba", 200,
00130                                "width_pixels", 0, 
00131                                NULL);
00132 
00133         tm->priv->total_elements++;
00134 
00135         /* setup the event box for tooltips */
00136         if ((R->x2 - R->x1) < 1.5 || (R->y2 - R->y1) < 1.5)
00137                 return;
00138 
00139         widget = gtk_event_box_new ();
00140         gtk_event_box_set_visible_window (GTK_EVENT_BOX (widget), FALSE);
00141         gtk_tooltips_set_tip (tm->priv->tooltips, widget, tip, NULL);
00142 
00143         setup_widget_item(tm,gnome_canvas_item_new (tm->priv->group,
00144                            gnome_canvas_widget_get_type(),
00145                            "x", R->x1,
00146                            "y", R->y1,
00147                            "width", R->x2-R->x1,
00148                            "height", R->y2-R->y1,
00149                            "widget", widget,                                             
00150                            NULL));
00151 
00152         gtk_widget_show(widget);
00153 }
00154 
00155 static void
00156 loop_treemap (BaobabTreeMap *tm, 
00157               GtkTreeIter          anc_iter, 
00158               guint64              anc_size,
00159               rect_coords         *R, 
00160               gboolean             b_horiz, 
00161               gint                 cur_depth)
00162 {
00163         gchar *name;
00164         gdouble ratio;
00165         guint64 cur_size;
00166         GtkTreeIter cur_iter;
00167         rect_coords cur_R;
00168 
00169         if (tm->priv->req_depth > -1)
00170                 if (cur_depth > tm->priv->req_depth)
00171                         return;
00172 
00173         cur_R.x1 = R->x1;
00174         cur_R.y1 = R->y1;
00175         cur_R.x2 = R->x2;
00176         cur_R.y2 = R->y2;
00177 
00178         gtk_tree_model_iter_children(tm->priv->model,&cur_iter,&anc_iter);
00179         do {    
00180                 gtk_tree_model_get(tm->priv->model,&cur_iter,tm->priv->COL_FOLDERNAME,&name,-1);
00181                 gtk_tree_model_get(tm->priv->model,&cur_iter,tm->priv->COL_SIZE,&cur_size,-1);
00182                 if (cur_size == 0 || anc_size ==0) {
00183                         g_free(name);
00184                         continue;
00185                 }
00186                 ratio = (gdouble)cur_size/(gdouble)anc_size;
00187 
00188                 /* check if rect is horiz or vert */
00189                 if (!b_horiz) {
00190                         cur_R.x2 = (R->x2-R->x1)*ratio+cur_R.x1;
00191                 }
00192                 else  {
00193                         cur_R.y2 = (R->y2-R->y1)*ratio+cur_R.y1;
00194                 }
00195                         
00196                 draw_rect(tm,(const rect_coords *)&cur_R,g_random_int(),name);
00197                 
00198                 /* recurse if iter has child */         
00199                 if (gtk_tree_model_iter_has_child(tm->priv->model,&cur_iter)) {
00200                         gtk_tree_model_get(tm->priv->model,
00201                                                 &cur_iter,
00202                                                 tm->priv->COL_SIZE,
00203                                                 &cur_size,
00204                                                 -1);
00205                         loop_treemap(tm, cur_iter,cur_size,&cur_R,!b_horiz, cur_depth+1);
00206                 }
00207                 
00208                 /* set up new rect for next child (sibling)*/
00209                 if (!b_horiz) {
00210                         cur_R.x1 = cur_R.x2;
00211                         cur_R.x2 = R->x2;
00212                 }
00213                 else {
00214                         cur_R.y1 = cur_R.y2;
00215                         cur_R.y2 = R->y2;
00216                 }
00217                 g_free(name);
00218         } while (gtk_tree_model_iter_next(tm->priv->model,&cur_iter));          
00219 }
00220 
00221 static void
00222 baobab_tree_map_init (BaobabTreeMap *treemap)
00223 {
00224         treemap->priv = BAOBAB_TREE_MAP_GET_PRIVATE (treemap);
00225 
00226         treemap->priv->tooltips = gtk_tooltips_new ();
00227         g_object_ref (treemap->priv->tooltips);
00228         gtk_object_sink (GTK_OBJECT(treemap->priv->tooltips));
00229 }
00230 
00231 /**************  Start of public functions *****************************/
00232 void
00233 baobab_tree_map_draw (BaobabTreeMap *tm,
00234                      GtkTreeModel *model,
00235                      GtkTreePath *path,
00236                      gint nNameCol,
00237                      gint nSizeCol,
00238                      gint required_depth)
00239 {
00240         GtkTreeIter iter;
00241         gchar *name;
00242         gboolean b_horiz;
00243         guint64 size;
00244         rect_coords R;
00245 
00246         tm->priv->model = model;
00247         tm->priv->first_path = path;
00248         tm->priv->COL_FOLDERNAME = nNameCol;
00249         tm->priv->COL_SIZE = nSizeCol;
00250         tm->priv->req_depth = required_depth;
00251         tm->priv->item_name = NULL;
00252 
00253         gnome_canvas_get_scroll_region (GNOME_CANVAS (tm), &R.x1, &R.y1, &R.x2, &R.y2);
00254         baobab_tree_map_clear (tm);
00255 
00256         gtk_tree_model_get_iter (tm->priv->model, &iter,tm->priv->first_path);  
00257         gtk_tree_model_get(tm->priv->model,&iter,tm->priv->COL_FOLDERNAME,&name,-1);
00258 
00259         /* how to draw the rectangle */
00260         b_horiz = ((R.y2-R.y1) >= (R.x2-R.x1));
00261 
00262         draw_rect (tm, (const rect_coords *)&R, g_random_int(), name);
00263         
00264         if (gtk_tree_model_iter_has_child(tm->priv->model,&iter)) {
00265                 gtk_tree_model_get(tm->priv->model,&iter,tm->priv->COL_SIZE,&size,-1);
00266                 loop_treemap(tm,iter,size,&R,b_horiz,1);
00267         }
00268 
00269         g_free(name);
00270 }
00271 
00272 void
00273 baobab_tree_map_refresh(BaobabTreeMap *tm, gint new_depth)
00274 {
00275         baobab_tree_map_draw (tm, tm->priv->model,
00276                                 tm->priv->first_path,
00277                                 tm->priv->COL_FOLDERNAME,
00278                                 tm->priv->COL_SIZE,
00279                                 new_depth);
00280 }
00281 
00282 gint
00283 baobab_tree_map_get_total_elements (BaobabTreeMap *tm)
00284 {
00285         return tm->priv->total_elements;
00286 }
00287 
00288 void
00289 baobab_tree_map_clear (BaobabTreeMap *tm)
00290 {
00291         GList *a, *b;
00292 
00293         a = tm->priv->group->item_list;
00294         while (a)
00295         {
00296                 b = a->next;
00297                 gtk_object_destroy (GTK_OBJECT (a->data));
00298                 a = b;
00299         }
00300 
00301         tm->priv->total_elements = 0;
00302 }
00303 
00304 GdkPixbuf *
00305 baobab_tree_map_get_pixbuf (BaobabTreeMap *tm)
00306 {
00307         gint w,h;
00308         GdkPixbuf *map_pixbuf;
00309         
00310         gdk_drawable_get_size ((GTK_WIDGET(tm))->window, &w, &h);
00311         map_pixbuf = gdk_pixbuf_get_from_drawable(NULL,
00312                                             GTK_WIDGET (tm)->window,
00313                                             gdk_colormap_get_system(),
00314                                             0, 0,
00315                                             0, 0,
00316                                             w, h);
00317 
00318         return map_pixbuf;
00319 }
00320 
00321 gdouble
00322 baobab_tree_map_get_zoom (BaobabTreeMap *tm)
00323 {
00324         return GNOME_CANVAS (tm)->pixels_per_unit;
00325 }
00326 
00327 void
00328 baobab_tree_map_set_zoom (BaobabTreeMap *tm,
00329                          gdouble        new_zoom)
00330 {
00331         gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (tm), new_zoom);
00332 }
00333 
00334 const gchar *
00335 baobab_tree_map_get_selected_item_name(BaobabTreeMap *tm)
00336 {
00337         return (const gchar *)tm->priv->item_name;
00338 }
00339 
00340 BaobabTreeMap *
00341 baobab_tree_map_new (void)
00342 {
00343         BaobabTreeMap * tm;
00344         gint screen_w, screen_h;
00345 
00346         tm = g_object_new (BAOBAB_TYPE_TREE_MAP, "aa", TRUE, NULL); 
00347 
00348         screen_w = gdk_screen_get_width (gdk_screen_get_default());
00349         screen_h = gdk_screen_get_height (gdk_screen_get_default()) * 0.83;
00350         gnome_canvas_set_scroll_region (GNOME_CANVAS (tm), 0.0, 0.0, screen_w, screen_h);
00351         gnome_canvas_set_center_scroll_region (GNOME_CANVAS (tm), TRUE);
00352         tm->priv->group = gnome_canvas_root (GNOME_CANVAS (tm));
00353 
00354         return tm;
00355 }
00356 

© sourcejam.com 2005-2008