?? browser.c
字號:
#include "navigation.h"
void on_delete_clicked (GtkToolButton*);
static void setup_tree_view (GtkWidget*);
static void setup_tree_model (GtkWidget*);
int main (int argc,
char *argv[])
{
GtkWidget *window, *treeview, *statusbar;
gtk_init (&argc, &argv);
current_path = NULL;
history_pos = 0;
xml = glade_xml_new ("browser.glade", NULL, NULL);
window = glade_xml_get_widget (xml, "window");
treeview = glade_xml_get_widget (xml, "treeview");
statusbar = glade_xml_get_widget (xml, "statusbar");
size_type[0] = "B";
size_type[1] = "KiB";
size_type[2] = "MiB";
size_type[3] = "GiB";
history = g_ptr_array_new ();
g_ptr_array_add (history, (gpointer) g_strdup (G_DIR_SEPARATOR_S));
context_id = gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), "Message");
glade_xml_signal_autoconnect (xml);
setup_tree_view (treeview);
setup_tree_model (treeview);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
/* Display an error message to the user using GtkMessageDialog. */
void
file_manager_error (gchar *message)
{
GtkWidget *dialog, *window;
window = glade_xml_get_widget (xml, "window");
dialog = gtk_message_dialog_new (GTK_WINDOW (window), GTK_DIALOG_MODAL,
GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
"File Manager Error");
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), message);
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
}
/* Setup the columns in the tree view. These include a column for the GdkPixbuf,
* file name, file size, and last modification time/date. */
static void
setup_tree_view (GtkWidget *treeview)
{
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
/* Create a tree view column with an icon and file name. */
column = gtk_tree_view_column_new ();
gtk_tree_view_column_set_title (column, "File Browser");
renderer = gtk_cell_renderer_pixbuf_new ();
gtk_tree_view_column_pack_start (column, renderer, FALSE);
gtk_tree_view_column_set_attributes (column, renderer, "pixbuf", ICON, NULL);
renderer = gtk_cell_renderer_text_new ();
gtk_tree_view_column_pack_start (column, renderer, TRUE);
gtk_tree_view_column_set_attributes (column, renderer, "text", FILENAME, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
/* Insert a second tree view column that displays the file size. */
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes
("Size", renderer, "text", SIZE, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
/* Insert a third tree view column that displays the last modified time/date. */
renderer = gtk_cell_renderer_text_new ();
column = gtk_tree_view_column_new_with_attributes
("Last Modified", renderer, "text", MODIFIED, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
}
/* Convert the GList path into a character string. */
gchar*
path_to_string ()
{
gchar *location;
GList *temp;
/* If there is no content, use the root directory. */
if (g_list_length (current_path) == 0)
location = G_DIR_SEPARATOR_S;
/* Otherwise, build the path out of the GList content. */
else
{
temp = current_path;
location = g_strconcat (G_DIR_SEPARATOR_S, (gchar*) temp->data, NULL);
temp = temp->next;
while (temp != NULL)
{
location = g_strconcat (location, G_DIR_SEPARATOR_S, (gchar*) temp->data, NULL);
temp = temp->next;
}
}
return location;
}
/* Setup the content of the tree model. */
void
populate_tree_model (GtkWidget *treeview)
{
GtkWidget *entry, *statusbar; GdkPixbuf *pixbuf_file, *pixbuf_dir;
GtkListStore *store;
GtkTreeIter iter;
GdkPixbuf *directory;
struct stat st;
gchar *location, *file, *message;
gfloat size, total_size = 0;
gint i, items = 0;;
GDir *dir;
store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)));
gtk_list_store_clear (store);
location = path_to_string ();
/* If the current location is not the root directory, add the '..' entry. */
if (g_list_length (current_path) > 0)
{
directory = gdk_pixbuf_new_from_file ("directory.png", NULL);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, ICON, directory, FILENAME, "..", -1);
}
/* Return if the path does not exist. */
if (!g_file_test (location, G_FILE_TEST_IS_DIR))
{
file_manager_error ("The path %s does not exist!"); g_free (location);
return;
}
/* Display the new location in the address bar. */
entry = glade_xml_get_widget (xml, "location");
gtk_entry_set_text (GTK_ENTRY (entry), location);
/* Add each file to the list along with the file size and modified date. */
pixbuf_dir = gdk_pixbuf_new_from_file ("directory.png", NULL);
pixbuf_file = gdk_pixbuf_new_from_file ("file.png", NULL);
dir = g_dir_open (location, 0, NULL);
while ((file = (gchar*) g_dir_read_name (dir)))
{
gchar *fn, *filesize, *modified;
fn = g_strconcat (location, "/", file, NULL);
if (g_stat (fn, &st) == 0)
{
/* Calculate the file size and order of magnitude. */
i = 0;
size = (gfloat) st.st_size;
total_size += size;
while (size >= 1024.0)
{
size = size / 1024.0;
i++;
}
/* Create strings for the file size and last modified date. */
filesize = g_strdup_printf ("%.1f %s", size, size_type[i]);
modified = g_strdup (ctime (&st.st_mtime));
modified[strlen(modified)-1] = '\0';
}
/* Add the file and its properties as a new tree view row. */
gtk_list_store_append (store, &iter); if (g_file_test (fn, G_FILE_TEST_IS_DIR))
gtk_list_store_set (store, &iter, ICON, pixbuf_dir, FILENAME, file,
SIZE, filesize, MODIFIED, modified, -1); else gtk_list_store_set (store, &iter, ICON, pixbuf_file, FILENAME, file,
SIZE, filesize, MODIFIED, modified, -1);
items++;
g_free (fn);
}
/* Calculate the total size of the directory content. */
i = 0;
while (total_size >= 1024.0)
{
total_size = total_size / 1024.0;
i++;
}
/* Add the number of items and the total size of the directory content
* to the status bar. */
statusbar = glade_xml_get_widget (xml, "statusbar");
message = g_strdup_printf ("%d items, Total Size: %.1f %s", items,
total_size, size_type[i]);
gtk_statusbar_pop (GTK_STATUSBAR (statusbar), context_id);
gtk_statusbar_push (GTK_STATUSBAR (statusbar), context_id, message); g_object_unref (pixbuf_dir); g_object_unref (pixbuf_file);
g_free (message);
}
/* Add the tree store, but the actual content is setup in populate_tree_model(). */
static void
setup_tree_model (GtkWidget *treeview)
{
GtkListStore *store;
store = gtk_list_store_new (COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING,
G_TYPE_STRING, G_TYPE_STRING);
gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store));
g_object_unref (store);
populate_tree_model (treeview);
}
/* Store the current location as the history stack. */
void
store_history ()
{
gchar *previous, *current;
GList *temp; gint i;
/* Build a string that contains the current path. */
previous = G_DIR_SEPARATOR_S;
temp = current_path;
while (temp != NULL)
{
previous = g_strconcat (previous, (gchar*) temp->data, "/", NULL);
temp = temp->next;
}
/* Remove all strings that occur after history_pos and append the new path. */
if (strlen (previous) > 1)
previous[strlen(previous)-1] = '\0';
current = (gchar*) g_ptr_array_index (history, history_pos);
if (g_ascii_strcasecmp (previous, current) != 0)
{
if (history_pos + 1 != history->len) { for (i = history_pos + 1; i <= (history->len - history_pos - 1); i++) g_free (g_ptr_array_index (history, i)); g_ptr_array_remove_range (history, history_pos + 1, history->len - history_pos - 1); }
g_ptr_array_add (history, (gpointer) g_strdup (previous));
history_pos++;
}
}
/* Convert the GString into a list of path elements stored in current_path. */
void
parse_location (GString *location)
{
gchar *find;
gsize len;
/* Free the current content stored in current_path. */
g_list_foreach (current_path, (GFunc) g_free, NULL);
g_list_free (current_path);
current_path = NULL;
/* Erase all forward slashes from the end of the string. */
while (location->str[location->len - 1] == '/')
g_string_erase (location, location->len - 1, 1);
/* Parse through the string, splitting it into a GList at the '/' character. */
while (location->str[0] == '/')
{
while (location->str[0] == '/')
g_string_erase (location, 0, 1);
find = g_strstr_len (location->str, location->len, "/");
if (find == NULL)
current_path = g_list_append (current_path, g_strdup (location->str));
else
{
len = (gsize) (strlen (location->str) - strlen (find));
current_path = g_list_append (current_path, g_strndup (location->str, len));
g_string_erase (location, 0, len);
}
}
}
/* Delete the currently selected file or folder. Folders will only be removed if
* it does not include any content. */
void
on_delete_clicked (GtkToolButton *item)
{
GtkWidget *entry, *treeview, *dialog, *window;
GtkTreeSelection *selection;
GtkTreeModel *model;
GtkTreeIter iter;
GString *location;
GList *temp;
gchar *file;
entry = glade_xml_get_widget (xml, "location");
treeview = glade_xml_get_widget (xml, "treeview");
window = glade_xml_get_widget (xml, "window");
location = g_string_new ("/");
temp = current_path;
/* Create the current path out of the content of current_path. */
while (temp != NULL)
{
g_string_append_printf (location, "%s/", (gchar*) temp->data);
temp = temp->next;
}
/* If there is a selected file, delete it if the user approves. */
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
if (gtk_tree_selection_get_selected (selection, &model, &iter))
{
gtk_tree_model_get (model, &iter, FILENAME, &file, -1);
if (g_ascii_strcasecmp (file, "..") == 0)
{
file_manager_error ("You cannot remove the '..' directory!");
return;
}
gtk_entry_set_text (GTK_ENTRY (entry), location->str);
g_string_append (location, file);
/* Ask the user if it is okay to remove the file or folder. */
dialog = gtk_message_dialog_new (GTK_WINDOW (window), GTK_DIALOG_MODAL,
GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
"Do you really want to delete %s?", file);
/* If the user approves, remove the file or report if it can't be done. */
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES)
if (g_remove (location->str) != 0)
file_manager_error ("The file or folder could not be removed!");
gtk_widget_destroy (dialog);
populate_tree_model (NULL);
}
g_string_free (location, TRUE);
}
/* Display information about the currently selected file or folder. */
void
on_info_clicked (GtkToolButton *item)
{
GtkWidget *dialog, *name, *loc, *type, *size, *mod, *access, *treeview;
gchar *file, *location, *modified, *accessed;
GtkTreeSelection *selection;
GtkTreeModel *model;
GtkTreeIter iter;
struct stat st;
gfloat file_size;
gint i;
treeview = glade_xml_get_widget (xml, "treeview");
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
if (gtk_tree_selection_get_selected (selection, &model, &iter))
{
dialog = glade_xml_get_widget (xml, "dialog");
name = glade_xml_get_widget (xml, "name");
loc = glade_xml_get_widget (xml, "filelocation");
type = glade_xml_get_widget (xml, "type");
size = glade_xml_get_widget (xml, "size");
mod = glade_xml_get_widget (xml, "modified");
access = glade_xml_get_widget (xml, "accessed");
gtk_tree_model_get (model, &iter, FILENAME, &file, -1);
/* Set the file name, location and whether it is a file or directory. */
location = path_to_string ();
gtk_label_set_text (GTK_LABEL (name), file);
gtk_label_set_text (GTK_LABEL (loc), location);
file = g_strconcat (location, "/", file, NULL);
if (g_file_test (file, G_FILE_TEST_IS_DIR))
gtk_label_set_text (GTK_LABEL (type), "Directory");
else
gtk_label_set_text (GTK_LABEL (type), "File");
/* Set the file size, last modified date and last accessed date. */
if (g_stat (file, &st) == 0)
{
i = 0;
file_size = (gfloat) st.st_size;
while (file_size >= 1024.0)
{
file_size = file_size / 1024.0;
i++;
}
modified = g_strndup (ctime (&st.st_mtime), strlen (ctime (&st.st_mtime))-1);
accessed = g_strndup (ctime (&st.st_atime), strlen (ctime (&st.st_atime))-1);
gtk_label_set_text (GTK_LABEL (mod), modified);
gtk_label_set_text (GTK_LABEL (access), accessed);
gtk_label_set_text (GTK_LABEL (size),
g_strdup_printf ("%.1f %s", file_size, size_type[i]));
}
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_hide (dialog);
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -