/******************************************************************** Copyright (C) 2000 Bassoukos Tassos This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *********************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "connection.h" #include "protocol.h" #include "filelist.h" #include "files.h" #include "guiprefs.h" #include "guiutils.h" #include "pixmap.h" void filelist_viewpush(FileList *fl, short pos) { fl->viewpos[(int)fl->view++] = pos; } static short filelist_viewpop(FileList *fl) { /* We tried to pop too much. This looks like a bug but actually it is possible because we could have started (locally) in a dir without pushing anything. Actually can't happen cause we always check for fl->view >fl->numpaths */ if(!fl->view) printf("Bug in viewpop, please report\n"); return fl->viewpos[(int)--fl->view]; } void filelist_viewpopsel(FileList *fl) { short row = filelist_viewpop(fl); gtk_clist_moveto(GTK_CLIST(fl->list), row, 0, 0.5, 0); gtk_clist_select_row(GTK_CLIST(fl->list), row, 0); filelist_change_selection(fl); } typedef int (*SortFunc)(const void *, const void *); static int sortsize(const FileEntry **a, const FileEntry **b){ if(mix_files_and_folders==FALSE) if((*a)->is_folder!=(*b)->is_folder) return (*b)->is_folder - (*a)->is_folder; return (*a)->size - (*b)->size; } static int sortname(const FileEntry **a, const FileEntry **b){ if(mix_files_and_folders==FALSE) if((*a)->is_folder!=(*b)->is_folder) return (*b)->is_folder - (*a)->is_folder; return strcmp((*a)->name,(*b)->name); } void filelist_set_busy(FileList *fl){ char *ptr[3]; ptr[0]=""; ptr[1]=_("Fetching directory..."); ptr[2]=""; gtk_clist_prepend(GTK_CLIST(fl->list),ptr); } static void filelist_fill_list(FileList *fl){ int i,k; GdkPixmap *pix=NULL; GdkPixmap *mask=NULL; char buf[1024],*ptr[3]; gtk_clist_freeze(GTK_CLIST(fl->list)); gtk_clist_clear(GTK_CLIST(fl->list)); ptr[0]=""; ptr[2]=buf; if(fl->numfiles>0){ FileEntry **fe; fe=malloc(sizeof(FileEntry *)*fl->numfiles); memcpy(fe,fl->files,sizeof(FileEntry *)*fl->numfiles); qsort((void *)fe,fl->numfiles,sizeof(FileEntry *), (SortFunc)(abs(fl->sortby) == 1 ? sortname : sortsize)); for(i=0;inumfiles;i++) { if(fe[i]->is_folder) sprintf(buf,"(%d)",fe[i]->size); else file_format_size(buf,fe[i]->size,FALSE); ptr[1]=fe[i]->name; if(fl->sortby<0) k=gtk_clist_prepend(GTK_CLIST(fl->list),ptr); else k=gtk_clist_append(GTK_CLIST(fl->list),ptr); gtk_clist_set_row_data(GTK_CLIST(fl->list),k,fe[i]); fileentry_get_icon(fe[i],&pix,&mask); gtk_clist_set_pixmap(GTK_CLIST(fl->list),k,0,pix,mask); if(fe[i]->is_selected) gtk_clist_select_row(GTK_CLIST(fl->list),k,-1); } free(fe); } if(fl->numpaths!=0){ static FileEntry fie={ NULL,0,{'f','l','d','r','\0'},{'f','l','d','r','\0'},TRUE,FALSE}; strcpy(buf,"(0)"); ptr[1]=_(".. (Parent folder)"); k=gtk_clist_prepend(GTK_CLIST(fl->list),ptr); gtk_clist_set_row_data(GTK_CLIST(fl->list),k,NULL); fie.name=ptr[1]; fileentry_get_icon(&fie,&pix,&mask); gtk_clist_set_pixmap(GTK_CLIST(fl->list),k,0,pix,mask); } gtk_clist_thaw(GTK_CLIST(fl->list)); } static void filelist_change_sort(GtkCList *clist, gint column, FileList *fl){ if(!column) return; if(column==abs(fl->sortby)) fl->sortby*=-1; else fl->sortby=column; filelist_fill_list(fl); } static void fl_cs_helper(gpointer data, FileList *fl) { FileEntry *fe; if((fe=gtk_clist_get_row_data(GTK_CLIST(fl->list),GPOINTER_TO_INT(data)))) { fe->is_selected=TRUE; fl->count_selected++; } } void filelist_change_selection(FileList *fl){ int k; FL_SETALLFILES(k, fl, is_selected, 0); fl->count_selected=0; /* This depends on the selection being a GList ... */ g_list_foreach(GTK_CLIST(fl->list)->selection, (GFunc) fl_cs_helper, fl); gtk_widget_set_sensitive(fl->toolbar[3],fl->count_selected>0?TRUE:FALSE); gtk_widget_set_sensitive(fl->toolbar[4],fl->count_selected==1?TRUE:FALSE); gtk_widget_set_sensitive(fl->toolbar[5],fl->count_selected>0?TRUE:FALSE); clist_popup_set_sensitive(fl->list,0,fl->count_selected>0?TRUE:FALSE); clist_popup_set_sensitive(fl->list,3,fl->count_selected>0?TRUE:FALSE); clist_popup_set_sensitive(fl->list,1,fl->count_selected==1?TRUE:FALSE); if(fl->flops && fl->flops->change_selection) fl->flops->change_selection(fl,fl->data); } void filelist_clear(FileList *fl){ int i; gtk_clist_clear(GTK_CLIST(fl->list)); if(fl->files){ for(i=0;inumfiles;i++) fileentry_free(fl->files[i]); free(fl->files); } fl->files=NULL; fl->numfiles=0; fl->count_selected=0; fl->last_selected=NULL; filelist_change_selection(fl); } void filelist_deselect_all(gpointer dummy,FileList *fl){ int i; FL_SETALLFILES(i, fl, is_selected, FALSE); gtk_clist_unselect_all(GTK_CLIST(fl->list)); filelist_change_selection(fl); } /* Added by Caspian */ void filelist_select_all(FileList *fl){ int i; FL_SETALLFILES(i, fl, is_selected, TRUE); gtk_clist_select_all(GTK_CLIST(fl->list)); filelist_change_selection(fl); } void filelist_set_contents(FileList *fl,int count, FileEntry **files){ filelist_clear(fl); fl->numfiles=count; fl->files=files; filelist_deselect_all(NULL,fl); filelist_fill_list(fl); } static void filelist_menu_chdir(GtkMenuItem *m,gpointer data){ FileList *fl=gtk_object_get_data(GTK_OBJECT(m),"FileList"); if(fl->flops && fl->flops->chdir_to) fl->flops->chdir_to(fl,GPOINTER_TO_INT(data),fl->data); } static void filelist_chdir_up(GtkButton *b, FileList *fl){ if(fl->numpaths && fl->flops && fl->flops->chdir_to) fl->flops->chdir_to(fl,fl->numpaths-2,fl->data); } static void filelist_clear_path(FileList *fl){ int i; if(fl->path!=NULL) { for(i=0;inumpaths;i++) free(fl->path[i]); free(fl->path); fl->path=NULL; } fl->numpaths=0; } void filelist_set_path(FileList *fl,char **path){ int i = 0; GtkWidget *m,*l; filelist_clear_path(fl); if(path) for(;path[i]!=NULL;i++); fl->numpaths=i; fl->path=path; m=gtk_menu_new(); for(i=-1;inumpaths;i++){ l=gtk_menu_item_new_with_label(i==-1?"/":fl->path[i]); gtk_object_set_data(GTK_OBJECT(l),"FileList",fl); gtk_signal_connect(GTK_OBJECT(l),"activate", GTK_SIGNAL_FUNC(filelist_menu_chdir), GINT_TO_POINTER(i)); gtk_menu_prepend(GTK_MENU(m),l); } if(fl->path_menu!=NULL) gtk_widget_destroy(fl->path_menu); fl->path_menu=m; gtk_widget_show_all(m); gtk_option_menu_set_menu(GTK_OPTION_MENU(fl->path_widget),m); gtk_widget_set_sensitive(fl->toolbar[0],fl->numpaths>0?TRUE:FALSE); } static void filelist_refresh(GtkButton *b,FileList *fl) { if(fl->flops && fl->flops->refresh) fl->flops->refresh(fl,fl->data); } static void filelist_mkdir_dir(char *name,FileList *fl){ if(name) { fl->flops->mkdir(fl,name,fl->data); free(name); if(fl->flops->refresh) fl->flops->refresh(fl,fl->data); } } static void filelist_mkdir(GtkButton *b,FileList *fl){ GtkWindow *w=NULL; if(fl->flops && fl->flops->mkdir) { if(fl->c && fl->c->gui && fl->c->gui->main_window) w=GTK_WINDOW(fl->c->gui->main_window); gnome_request_dialog(FALSE,_("Directory to create:"),"",0, (void(*)(char *, gpointer))filelist_mkdir_dir,fl,w); } } static void filelist_send_delete(GtkButton *b,FileList *fl){ int i; FL_DOALLSELECTED(i, fl, fl->flops->delete(fl,i,fl->data)); if(fl->flops->refresh) fl->flops->refresh(fl,fl->data); } static void filelist_delete(GtkButton *b,FileList *fl){ GtkWidget *d,*l,*s; int i; if(fl->flops==NULL || fl->flops->delete==NULL || fl->count_selected==0) return; d=gnome_dialog_new(_("Delete files?"),GNOME_STOCK_BUTTON_YES, GNOME_STOCK_BUTTON_NO,NULL); if(fl->c!=NULL && fl->c->gui!=NULL && fl->c->gui->main_window!=NULL) gnome_dialog_set_parent(GNOME_DIALOG(d), GTK_WINDOW(fl->c->gui->main_window)); gnome_dialog_button_connect(GNOME_DIALOG(d),0, GTK_SIGNAL_FUNC(filelist_send_delete), (gpointer)fl); gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(d)->vbox), gtk_label_new(_("Delete these files?")), FALSE,FALSE,0); l=gtk_clist_new(1); s=gtk_scrolled_window_new(NULL,NULL); gtk_container_add(GTK_CONTAINER(s),l); gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(d)->vbox),s,TRUE,TRUE,0); gtk_clist_freeze(GTK_CLIST(l)); FL_DOALLSELECTED(i, fl, gtk_clist_append(GTK_CLIST(l),&fl->files[i]->name)); gtk_clist_thaw(GTK_CLIST(l)); gnome_dialog_set_close(GNOME_DIALOG(d),TRUE); gtk_widget_show_all(d); } static void filelist_select_row(GtkWidget *widget, gint row, gint column, GdkEventButton *event, FileList *fl) { if(row != -1 && gtk_clist_get_row_data(GTK_CLIST(widget),row)) filelist_change_selection(fl); } static void filelist_dblclick_row(GtkWidget *w,gint row,FileList *fl){ FileEntry *fe; if(row==-1 || fl->flops==NULL || fl->flops->select_one==NULL) return; if(!(fe=(FileEntry *)gtk_clist_get_row_data(GTK_CLIST(fl->list),row))) filelist_chdir_up(NULL,fl); else { if(fe->is_folder) filelist_viewpush(fl, row); fl->flops->select_one(fl,fe,fl->data); } gtk_clist_unselect_row(GTK_CLIST(fl->list),row,-1); filelist_change_selection(fl); } static void filelist_properties(GtkButton *w,FileList *fl){ int i; if(fl->flops && fl->flops->properties) FL_DOALLSELECTED(i, fl, fl->flops->properties(fl,fl->files[i],fl->data)); } void filelist_start_transfer(FileList *fl){ int i,j; for(i=0;inumfiles;i++) if(fl->files[i]->is_selected==TRUE){ if(fl->flops!=NULL && fl->flops->start_transfer!=NULL) fl->flops->start_transfer(fl,fl->files[i],fl->data); j=gtk_clist_find_row_from_data(GTK_CLIST(fl->list),fl->files[i]); if(j!=-1) gtk_clist_unselect_row(GTK_CLIST(fl->list),j,-1); } filelist_change_selection(fl); } static void filelist_start_transfer_signal(GtkWidget *w,gpointer data){ FileList *fl=(FileList *)data; filelist_start_transfer(fl); } typedef struct { char *tooltips; void (*cb_func)(GtkButton *,gpointer); char *name; } TBInfo; TBInfo tb_info[]={ {N_("Goto parent directory"),(void(*)(GtkButton *, gpointer))filelist_chdir_up,HL_MENU HL_STOCK_PIXMAP_FILES_PARENT}, {N_("Rescan this directory"),(void(*)(GtkButton *, gpointer))filelist_refresh,HL_MENU HL_STOCK_PIXMAP_REFRESH}, {N_("Make a new Directory"),(void(*)(GtkButton *, gpointer))filelist_mkdir,HL_MENU HL_STOCK_PIXMAP_FOLDER_NEW}, {NULL,NULL,"Separator"}, {N_("Clear Selection"),(void (*)(GtkButton *,gpointer))filelist_deselect_all,GNOME_STOCK_PIXMAP_CLEAR}, {N_("Properties of this file"),(void(*)(GtkButton *, gpointer))filelist_properties,HL_MENU HL_STOCK_PIXMAP_FILE_INFO}, {N_("Delete file(s)"),(void(*)(GtkButton *, gpointer))filelist_delete,HL_MENU HL_STOCK_PIXMAP_TRASH}, {NULL,NULL,NULL}, }; static GtkWidget *mkhtoolbar(TBInfo *t,gpointer data, GtkWidget **w){ GtkWidget *tb=gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL,GTK_TOOLBAR_ICONS); GtkWidget *p; int i; for(i=0;t[i].name!=NULL;i++){ if(t[i].cb_func==NULL) gtk_toolbar_append_space(GTK_TOOLBAR(tb)); else { p=gnome_stock_new_with_icon(t[i].name); *(w++)=gtk_toolbar_append_item(GTK_TOOLBAR(tb),NULL,t[i].tooltips,NULL, p,t[i].cb_func,data); } } return tb; } static GnomeUIInfo files_remote_menu[]={ GNOMEUIINFO_ITEM_STOCK("Download",N_("Download file(s)"), filelist_start_transfer_signal, HL_MENU HL_STOCK_PIXMAP_DOWNLOAD), GNOMEUIINFO_ITEM_STOCK("Properties",N_("Properties of this file"), filelist_properties, HL_MENU HL_STOCK_PIXMAP_FILE_INFO), GNOMEUIINFO_SEPARATOR, GNOMEUIINFO_ITEM_STOCK("Delete",N_("Delete file(s)"), filelist_delete, HL_MENU HL_STOCK_PIXMAP_TRASH), GNOMEUIINFO_END }; static GnomeUIInfo files_local_menu[]={ GNOMEUIINFO_ITEM_STOCK("Upload",N_("Upload file(s)"), filelist_start_transfer_signal, HL_MENU HL_STOCK_PIXMAP_UPLOAD), GNOMEUIINFO_ITEM_STOCK("Properties",N_("Properties of this file"), filelist_properties, HL_MENU HL_STOCK_PIXMAP_FILE_INFO), GNOMEUIINFO_SEPARATOR, GNOMEUIINFO_ITEM_STOCK("Delete",N_("Delete file(s)"), filelist_delete, HL_MENU HL_STOCK_PIXMAP_TRASH), GNOMEUIINFO_END }; FileList *filelist_new(Connection *c,FLOps *flops,gpointer data){ FileList *fl=malloc(sizeof(FileList)); GtkWidget *f,*sl; static char *list_names[]={"",N_("Name"),N_("Size")}; GnomeUIInfo *info; fl->c=c; fl->numfiles=0; fl->files=NULL; fl->sortby=1; fl->is_remote=flops->is_remote; fl->data=data; fl->path=NULL; fl->flops=flops; fl->numpaths=0; fl->last_selected=NULL; fl->count_selected=0; fl->view = 0; fl->frame=gtk_vbox_new(FALSE,0); f=gtk_hbox_new(FALSE,0); gtk_box_pack_start(GTK_BOX(fl->frame),f,FALSE,FALSE,0); fl->list=gtk_clist_new_with_titles(3,list_names); gtk_clist_set_selection_mode(GTK_CLIST(fl->list),GTK_SELECTION_EXTENDED); gtk_clist_set_column_justification(GTK_CLIST(fl->list),2, GTK_JUSTIFY_RIGHT); sl=gtk_scrolled_window_new(NULL,NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sl), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_container_add(GTK_CONTAINER(sl),fl->list); gtk_box_pack_start(GTK_BOX(fl->frame),sl,TRUE,TRUE,0); gtk_signal_connect(GTK_OBJECT(fl->list), "click-column", GTK_SIGNAL_FUNC(filelist_change_sort), (gpointer)fl); guiprefs_add_clist(GTK_CLIST(fl->list), fl->is_remote==TRUE?"Main/Files/RemoteList": "Main/Files/LocalList","16,150,0"); gutils_clist_on_dblclick(fl->list,(void (*)(GtkWidget *,gint row,gpointer data))filelist_dblclick_row,(gpointer)fl); gtk_clist_set_row_height(GTK_CLIST(fl->list),18); info=fl->is_remote==TRUE?files_remote_menu:files_local_menu; gutils_clist_add_popup_menu(fl->list,info,(gpointer)fl); sl=mkhtoolbar(tb_info,fl,&fl->toolbar[0]); gtk_box_pack_start(GTK_BOX(f),sl,FALSE,FALSE,0); fl->path_menu=NULL; fl->path_widget=gtk_option_menu_new(); gtk_box_pack_end(GTK_BOX(f),fl->path_widget,TRUE,TRUE,0); filelist_set_path(fl,NULL); gtk_signal_connect(GTK_OBJECT(fl->list), "select_row", GTK_SIGNAL_FUNC(filelist_select_row), (gpointer)fl); gtk_signal_connect(GTK_OBJECT(fl->list), "unselect_row", GTK_SIGNAL_FUNC(filelist_select_row), (gpointer)fl); gtk_signal_connect_object(GTK_OBJECT(fl->list),"start_selection", GTK_SIGNAL_FUNC(filelist_change_selection), (GtkObject *)fl); gtk_signal_connect_object(GTK_OBJECT(fl->list),"end_selection", GTK_SIGNAL_FUNC(filelist_change_selection), (GtkObject *)fl); gtk_signal_connect_object(GTK_OBJECT(fl->list),"extend_selection", GTK_SIGNAL_FUNC(filelist_change_selection), (GtkObject *)fl); gtk_signal_connect_object(GTK_OBJECT(fl->list),"undo_selection", GTK_SIGNAL_FUNC(filelist_change_selection), (GtkObject *)fl); return fl; } void filelist_destroy(FileList *fl){ filelist_clear(fl); filelist_clear_path(fl); free(fl); }