00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
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
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
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
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
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
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
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