/*
    本程式由 洪任諭 (PCMan) 撰寫於 2006.02.16,以 GNU GPL 授權釋出
    本程式並無超級牛力,僅為了供 TnLug 示範 gtk+ 入門的教學用途撰寫
    關於檔案路徑的處理,實際仍需考慮 UTF-8 和 on-disk encoding 不同的編碼轉換
    為簡化程式,在此全部忽略。
    許多細節礙於對初學者過度複雜,為避免妨礙學習徒增挫折,在此暫且略過 :-)
*/

#ifdef HAVE_CONFIG_H
#  include <config.h> /* 由 configure 生成的編譯設定值檔案 */
#endif

#include <gtk/gtk.h>
#include <glade/glade-xml.h>

/* 關於這個程式 */
void on_about_activate( GtkWidget* menu_item, gpointer user_data )
{
  const char* authors[]={"PCMan", NULL}; /* 定義一個儲存各位作者名稱的字串陣列 */
  GladeXML* xml = glade_get_widget_tree(menu_item); /* 取得建立 menu_item 的 GladeXML 物件 */
  GtkWidget* main_window = glade_xml_get_widget( xml, "main_window" ); /* 透過GladeXML物件取得主視窗 main_window */
  GtkWidget* dlg = gtk_about_dialog_new(); /* 建立「關於」對話框 */
  gtk_about_dialog_set_name (GTK_ABOUT_DIALOG(dlg), "TnLug GTK+ demo"); /* 設定軟體名稱 */
  gtk_about_dialog_set_version (GTK_ABOUT_DIALOG(dlg), VERSION); /* 設定軟體版本,VERSION 為 configure 時產生的 #define */
  gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG(dlg), authors); /* 設定作者 */
  gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG(dlg), "Copyright (C) 2006" ); /* 設定版權資訊 */
  gtk_window_set_transient_for( GTK_WINDOW(dlg), GTK_WINDOW(main_window) );  /* 將 main_window 設定為對話框的父視窗 */
  gtk_dialog_run( GTK_DIALOG(dlg) ); /* 執行對話框 */
}

/* 在 icon view 內顯示目錄內容 */
static void show_directory( GladeXML* xml, const char* dir_path )
{
  GtkIconView* icon_view;
  GtkEntry* path_entry;
  GDir* dir;
  const char* file_name;
  char* file_path;
  GtkListStore* list;
  GtkTreeIter it;
  int pos = 0;
  GdkPixbuf* folder_icon;
  GdkPixbuf* file_icon;
  GdkPixbuf* icon;

  dir = g_dir_open( dir_path, NULL, NULL ); /* 開啟目錄,用來讀取裡面有那些檔案 */
  if( !dir ) /* 開啟失敗,直接退出 */
    return;
  icon_view = GTK_ICON_VIEW(glade_xml_get_widget( xml, "icon_view" )); /* 透過GladeXML物件取得 icon view */
  folder_icon = gtk_widget_render_icon( GTK_WIDGET(icon_view),
                        GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_DIALOG, NULL ); /* 載入 gtk+ 內建的目錄圖示 */
  file_icon = gtk_widget_render_icon( GTK_WIDGET(icon_view),
                        GTK_STOCK_FILE, GTK_ICON_SIZE_DIALOG, NULL ); /* 載入gtk+ 內建的檔案圖示 */
  list = gtk_list_store_new( 2, GDK_TYPE_PIXBUF, G_TYPE_STRING );  /* 建立清單,來儲存目錄中的檔案列表 */
  while( file_name = g_dir_read_name( dir ) ) /* 依序列出目錄下的每個檔案,直到沒有下個檔案 */
  {
    file_path = g_build_filename( dir_path, file_name, NULL );  /* 將目錄下的檔案名稱前面加上目錄路徑,生成檔案的完整路徑 */
    if( g_file_test( file_path, G_FILE_TEST_IS_DIR ) )  /* 測試此檔案是否為目錄 */
      icon = folder_icon;  /* 是目錄則使用資料夾圖示 */
    else
      icon = file_icon;  /* 否則使用一般檔案圖示 */
    g_free( file_path );  /* 使用完畢,釋放剛剛生成的檔案路徑 */
    gtk_list_store_insert_with_values( list, &it, pos,  /* 將這個檔案的名稱和圖示,插入到清單中 pos 這個位置 */
                                       0, icon,
                                       1, file_name, -1 );
    ++pos; /* 移到下一個位置 */
  }
  g_dir_close(dir);  /* 完成列出所有檔案,關閉目錄 */

  /* 圖示使用完畢,釋放 */
  gdk_pixbuf_unref( folder_icon );
  gdk_pixbuf_unref( file_icon );

  g_object_set_data_full( G_OBJECT(list), "cwd",   /* 將目前目錄路徑複製起來,並存在清單物件 list 裡面,並以 "cwd" 作為存取這筆資料的索引 */
                          g_strdup(dir_path), g_free );  /* 同時將 g_free 傳入 destroy notify,使得複製起來的路徑能在 list 物件被釋放時,一起釋放 */
  gtk_icon_view_set_model( icon_view, GTK_TREE_MODEL(list) );  /* 將此清單設定給 icon view,要 icon view 顯示清單內容 */
  gtk_icon_view_set_pixbuf_column( icon_view, 0 );  /* 圖示 (檔案圖示) 位於清單第 0 個欄位 */
  gtk_icon_view_set_text_column( icon_view, 1 );  /* 文字 (檔案名稱) 位於清單第 1 個欄位 */
  gtk_icon_view_set_item_width ( icon_view, 80 );  /* 設定每個項目的寬度為 80,避免太擁擠 */

  path_entry = GTK_ENTRY(glade_xml_get_widget( xml, "path_entry" ));  /* 透過 GladeXML 物件取得 path_entry (位址列) */
  gtk_entry_set_text( path_entry, dir_path );  /* 將目前目錄的網址設定給 path_entry (位址列),讓他顯示 */
}

/* 使用者按下網址列旁的 Go 按鈕 */
void on_go_btn_clicked(GtkWidget* button, gpointer user_data)
{
  GladeXML* xml = glade_get_widget_tree(button);
  GtkWidget* path_entry = glade_xml_get_widget( xml, "path_entry" );
  const char* path = gtk_entry_get_text( GTK_ENTRY(path_entry) );  /* 取得位址列中的位址(目錄路徑) */
  show_directory(xml, path);  /* 呼叫自訂函數,顯示目錄內容 */
}

/* 使用者在位址列上按下 Enter 鍵 */
void on_path_entry_activate( GtkEntry* entry, gpointer user_data )
{
  const char* path = gtk_entry_get_text( entry );    /* 取得位址列中的位址(目錄路徑) */
  show_directory( glade_get_widget_tree( GTK_WIDGET(entry) ), path);   /* 呼叫自訂函數,顯示目錄內容 */
}

/* 使用者在 icon view 中的項目上滑鼠點兩下 */
void on_icon_view_item_activated(GtkIconView* icon_view,
                                 GtkTreePath* tree_path, gpointer user_data )
{
  GladeXML* xml;
  GtkTreeModel* list = gtk_icon_view_get_model(icon_view);  /* 取得 icon view 中顯示的檔案列表清單 */
  GtkTreeIter it;
  char* file_name;
  char* file_path;
  const char* dir_path = (char*)g_object_get_data( G_OBJECT(list), "cwd" ); /* 以"cwd"為索引,取回剛剛儲存的目錄路徑 */
  if( gtk_tree_model_get_iter( list, &it, tree_path ) )  /* 取得被點擊的項目的 iterator,用來存取該項目的圖示和文字 */
  {
    gtk_tree_model_get( list, &it, 1, &file_name , -1);  /* 透過 iterator,從清單中取出該項目的顯示文字 (檔案名稱) */
    file_path = g_build_filename( dir_path, file_name, NULL );  /* 目錄路徑 + 檔案名稱產生完整檔案路徑 */
    g_free( file_name );
    if( g_file_test( file_path, G_FILE_TEST_IS_DIR ) ) {  /* 檢查被點擊的檔案是資料夾還是一般檔案 */
      /* 如果被點選的是目錄,就進入該目錄,顯示其內容 */
      xml = glade_get_widget_tree( GTK_WIDGET(icon_view) );  /* 取得建立 icon view 的 GladeXML 物件 */
      show_directory( xml, file_path );  /* 呼叫自訂函數顯示目錄內容 */
    }
    g_free( file_path );  /* 釋放記憶體 */
  }
}

/* 主視窗物件被摧毀 */
void on_main_window_destroy(GtkWidget* widget, gpointer user_data)
{
  /*
    最上層主視窗已經使用完畢,被摧毀了,其他子視窗也被 gtk+ 釋放,
    所有的視窗都被摧毀釋放了,所以 GladeXML 物件也不再需要
  */
  GladeXML* xml = (GladeXML*)user_data;
  g_object_unref( G_OBJECT(xml) );  /* 釋放不再需要的 GladeXML 物件*/
  gtk_main_quit();  /* 結束程式 */
}

/* 程式開始執行的進入點 */
int
main (int argc, char *argv[])
{
  GladeXML* xml;
  GtkWidget *main_window;

#ifdef ENABLE_NLS  /* 如果 configure 時有開啟多國語言支援 */
  bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);  /* 設定翻譯檔所在位置 */
  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");  /* 設定翻譯訊息使用的編碼為 utf-8 */
  textdomain (GETTEXT_PACKAGE);  /* 設定 gettext 都從我們的 GETTEXT_PACKAGE 裡面找翻譯 */
#endif

  gtk_set_locale ();
  gtk_init (&argc, &argv);  /* 使用 gtk+ 前一定要先呼叫 gtk_init,讓它做好一些準備工作 */


  xml = glade_xml_new( "tnlug.glade", NULL, NULL );  /* 建立新的 GladeXML 物件,讓它載入 tnlug.glade 內的圖形介面 */
  glade_xml_signal_autoconnect( xml );  /* 自動連接所有 signal handlers */

  main_window = glade_xml_get_widget( xml, "main_window" );  /* 透過 GladeXML 物件取得主視窗物件 main_window */
  GtkWidget* toolbar = glade_xml_get_widget( xml, "toolbar" );  /* 透過 GladeXML 物件取得工具列物件 toolbar */
  GtkToolItem* item = gtk_toolbar_get_nth_item( GTK_TOOLBAR(toolbar), 1 );  /* 取得第 2 個工具列項目 (位址列) */
  gtk_tool_item_set_expand( item, TRUE );  /* 設定位址列隨視窗大小變化調整,自動擴展寬度 */

  g_signal_connect( main_window, "destroy",  /* 在 main_window 主視窗物件被摧毀時,呼叫我們自訂的 on_main_window_destroy */
                    G_CALLBACK(on_main_window_destroy), xml );  /* 傳入 GladeXML 物件作為參數 */

  show_directory( xml, g_get_home_dir() );  /* 顯示使用者的主目錄 home dir */
  gtk_widget_show (main_window);  /* 顯示主視窗 */

  gtk_main ();  /* 讓 gtk+ 接管,處理訊息發送,程式開始執行... */
  return 0;
}