iconview.c 8.5 KB
Newer Older
Matthias Clasen's avatar
Matthias Clasen committed
1
/* Icon View/Icon View Basics
2
 *
3 4
 * The GtkIconView widget is used to display and manipulate icons.
 * It uses a GtkTreeModel for data storage, so the list store
Matthias Clasen's avatar
Matthias Clasen committed
5
 * example might be helpful.
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
 */

#include <gtk/gtk.h>
#include <string.h>
#include "demo-common.h"

static GtkWidget *window = NULL;

#define FOLDER_NAME "gnome-fs-directory.png"
#define FILE_NAME "gnome-fs-regular.png"

enum
{
  COL_PATH,
  COL_DISPLAY_NAME,
  COL_PIXBUF,
  COL_IS_DIRECTORY,
  NUM_COLS
};


static GdkPixbuf *file_pixbuf, *folder_pixbuf;
gchar *parent;
GtkToolItem *up_button;

/* Loads the images for the demo and returns whether the operation succeeded */
static gboolean
load_pixbufs (GError **error)
{
  char *filename;

  if (file_pixbuf)
    return TRUE; /* already loaded earlier */

Matthias Clasen's avatar
Matthias Clasen committed
40
  /* demo_find_file() looks in the current directory first,
41 42 43 44 45 46 47 48 49
   * so you can run gtk-demo without installing GTK, then looks
   * in the location where the file is installed.
   */
  filename = demo_find_file (FILE_NAME, error);
  if (!filename)
    return FALSE; /* note that "error" was filled in and returned */

  file_pixbuf = gdk_pixbuf_new_from_file (filename, error);
  g_free (filename);
50

51 52
  if (!file_pixbuf)
    return FALSE; /* Note that "error" was filled with a GError */
53

54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
  filename = demo_find_file (FOLDER_NAME, error);
  if (!filename)
    return FALSE; /* note that "error" was filled in and returned */

  folder_pixbuf = gdk_pixbuf_new_from_file (filename, error);
  g_free (filename);

  return TRUE;
}

static void
fill_store (GtkListStore *store)
{
  GDir *dir;
  const gchar *name;
  GtkTreeIter iter;
70

71 72 73 74 75 76 77 78 79 80 81 82 83 84
  /* First clear the store */
  gtk_list_store_clear (store);

  /* Now go through the directory and extract all the file
   * information */
  dir = g_dir_open (parent, 0, NULL);
  if (!dir)
    return;

  name = g_dir_read_name (dir);
  while (name != NULL)
    {
      gchar *path, *display_name;
      gboolean is_dir;
85

86 87 88 89 90 91
      /* We ignore hidden files that start with a '.' */
      if (name[0] != '.')
	{
	  path = g_build_filename (parent, name, NULL);

	  is_dir = g_file_test (path, G_FILE_TEST_IS_DIR);
92

93 94 95 96 97 98 99 100 101 102 103 104 105
	  display_name = g_filename_to_utf8 (name, -1, NULL, NULL, NULL);

	  gtk_list_store_append (store, &iter);
	  gtk_list_store_set (store, &iter,
			      COL_PATH, path,
			      COL_DISPLAY_NAME, display_name,
			      COL_IS_DIRECTORY, is_dir,
			      COL_PIXBUF, is_dir ? folder_pixbuf : file_pixbuf,
			      -1);
	  g_free (path);
	  g_free (display_name);
	}

106
      name = g_dir_read_name (dir);
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
    }
}

static gint
sort_func (GtkTreeModel *model,
	   GtkTreeIter  *a,
	   GtkTreeIter  *b,
	   gpointer      user_data)
{
  gboolean is_dir_a, is_dir_b;
  gchar *name_a, *name_b;
  int ret;

  /* We need this function because we want to sort
   * folders before files.
   */

124

125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
  gtk_tree_model_get (model, a,
		      COL_IS_DIRECTORY, &is_dir_a,
		      COL_DISPLAY_NAME, &name_a,
		      -1);

  gtk_tree_model_get (model, b,
		      COL_IS_DIRECTORY, &is_dir_b,
		      COL_DISPLAY_NAME, &name_b,
		      -1);

  if (!is_dir_a && is_dir_b)
    ret = 1;
  else if (is_dir_a && !is_dir_b)
    ret = -1;
  else
    {
      ret = g_utf8_collate (name_a, name_b);
    }

  g_free (name_a);
  g_free (name_b);

  return ret;
}

Matthias Clasen's avatar
Matthias Clasen committed
150
static GtkListStore *
151 152 153 154 155
create_store (void)
{
  GtkListStore *store;

  store = gtk_list_store_new (NUM_COLS,
156 157
			      G_TYPE_STRING,
			      G_TYPE_STRING,
158 159 160
			      GDK_TYPE_PIXBUF,
			      G_TYPE_BOOLEAN);

161
  /* Set sort column and function */
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
  gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (store),
					   sort_func,
					   NULL, NULL);
  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
					GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
					GTK_SORT_ASCENDING);

  return store;
}

static void
item_activated (GtkIconView *icon_view,
		GtkTreePath *tree_path,
		gpointer     user_data)
{
  GtkListStore *store;
  gchar *path;
  GtkTreeIter iter;
  gboolean is_dir;
181

182 183 184 185 186 187 188 189 190 191 192 193 194 195
  store = GTK_LIST_STORE (user_data);

  gtk_tree_model_get_iter (GTK_TREE_MODEL (store),
			   &iter, tree_path);
  gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
		      COL_PATH, &path,
		      COL_IS_DIRECTORY, &is_dir,
		      -1);

  if (!is_dir)
    {
      g_free (path);
      return;
    }
196

197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
  /* Replace parent with path and re-fill the model*/
  g_free (parent);
  parent = path;

  fill_store (store);

  /* Sensitize the up button */
  gtk_widget_set_sensitive (GTK_WIDGET (up_button), TRUE);
}

static void
up_clicked (GtkToolItem *item,
	    gpointer     user_data)
{
  GtkListStore *store;
  gchar *dir_name;

  store = GTK_LIST_STORE (user_data);

  dir_name = g_path_get_dirname (parent);
  g_free (parent);
218

219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
  parent = dir_name;

  fill_store (store);

  /* Maybe de-sensitize the up button */
  gtk_widget_set_sensitive (GTK_WIDGET (up_button),
			    strcmp (parent, "/") != 0);
}

static void
home_clicked (GtkToolItem *item,
	      gpointer     user_data)
{
  GtkListStore *store;

  store = GTK_LIST_STORE (user_data);

  g_free (parent);
  parent = g_strdup (g_get_home_dir ());

  fill_store (store);

  /* Sensitize the up button */
  gtk_widget_set_sensitive (GTK_WIDGET (up_button),
			    TRUE);
}

246 247 248 249 250 251 252 253 254 255 256 257
static void close_window(void)
{
  gtk_widget_destroy (window);
  window = NULL;

  g_object_unref (file_pixbuf);
  file_pixbuf = NULL;

  g_object_unref (folder_pixbuf);
  folder_pixbuf = NULL;
}

258 259 260 261 262 263
GtkWidget *
do_iconview (GtkWidget *do_widget)
{
  if (!window)
    {
      GError *error;
264

265 266
      window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
      gtk_window_set_default_size (GTK_WINDOW (window), 650, 400);
267

268 269 270 271 272
      gtk_window_set_screen (GTK_WINDOW (window),
			     gtk_widget_get_screen (do_widget));
      gtk_window_set_title (GTK_WINDOW (window), "GtkIconView demo");

      g_signal_connect (window, "destroy",
273
			G_CALLBACK (close_window), NULL);
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301

      error = NULL;
      if (!load_pixbufs (&error))
	{
	  GtkWidget *dialog;

	  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
					   GTK_DIALOG_DESTROY_WITH_PARENT,
					   GTK_MESSAGE_ERROR,
					   GTK_BUTTONS_CLOSE,
					   "Failed to load an image: %s",
					   error->message);

	  g_error_free (error);

	  g_signal_connect (dialog, "response",
			    G_CALLBACK (gtk_widget_destroy), NULL);

	  gtk_widget_show (dialog);
	}
      else
	{
	  GtkWidget *sw;
	  GtkWidget *icon_view;
	  GtkListStore *store;
	  GtkWidget *vbox;
	  GtkWidget *tool_bar;
	  GtkToolItem *home_button;
302

303 304 305 306 307
	  vbox = gtk_vbox_new (FALSE, 0);
	  gtk_container_add (GTK_CONTAINER (window), vbox);

	  tool_bar = gtk_toolbar_new ();
	  gtk_box_pack_start (GTK_BOX (vbox), tool_bar, FALSE, FALSE, 0);
308

309 310 311 312 313 314 315 316
	  up_button = gtk_tool_button_new_from_stock (GTK_STOCK_GO_UP);
	  gtk_tool_item_set_is_important (up_button, TRUE);
	  gtk_widget_set_sensitive (GTK_WIDGET (up_button), FALSE);
	  gtk_toolbar_insert (GTK_TOOLBAR (tool_bar), up_button, -1);

	  home_button = gtk_tool_button_new_from_stock (GTK_STOCK_HOME);
	  gtk_tool_item_set_is_important (home_button, TRUE);
	  gtk_toolbar_insert (GTK_TOOLBAR (tool_bar), home_button, -1);
317 318


319 320 321 322 323 324
	  sw = gtk_scrolled_window_new (NULL, NULL);
	  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
					       GTK_SHADOW_ETCHED_IN);
	  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
					  GTK_POLICY_AUTOMATIC,
					  GTK_POLICY_AUTOMATIC);
325

326
	  gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
327

328 329 330 331 332 333
	  /* Create the store and fill it with the contents of '/' */
	  parent = g_strdup ("/");
	  store = create_store ();
	  fill_store (store);

	  icon_view = gtk_icon_view_new_with_model (GTK_TREE_MODEL (store));
334 335
	  gtk_icon_view_set_selection_mode (GTK_ICON_VIEW (icon_view),
					    GTK_SELECTION_MULTIPLE);
336
	  g_object_unref (store);
337

338 339 340 341 342 343 344
	  /* Connect to the "clicked" signal of the "Up" tool button */
	  g_signal_connect (up_button, "clicked",
			    G_CALLBACK (up_clicked), store);

	  /* Connect to the "clicked" signal of the "Home" tool button */
	  g_signal_connect (home_button, "clicked",
			    G_CALLBACK (home_clicked), store);
345

Matthias Clasen's avatar
Matthias Clasen committed
346
	  /* We now set which model columns that correspond to the text
347 348 349 350 351
	   * and pixbuf of each item
	   */
	  gtk_icon_view_set_text_column (GTK_ICON_VIEW (icon_view), COL_DISPLAY_NAME);
	  gtk_icon_view_set_pixbuf_column (GTK_ICON_VIEW (icon_view), COL_PIXBUF);

352 353
	  /* Connect to the "item-activated" signal */
	  g_signal_connect (icon_view, "item-activated",
354 355 356 357 358 359
			    G_CALLBACK (item_activated), store);
	  gtk_container_add (GTK_CONTAINER (sw), icon_view);

	  gtk_widget_grab_focus (icon_view);
	}
    }
360

361
  if (!gtk_widget_get_visible (window))
362 363 364 365 366 367 368 369 370 371
    gtk_widget_show_all (window);
  else
    {
      gtk_widget_destroy (window);
      window = NULL;
    }

  return window;
}