// FIXME_pcm: maybe we can support different encoding for different mount points? char *fm_path_display_basename (FmPath *path) { if (G_UNLIKELY (!path->parent)) // root_path element { if (!fm_path_is_native (path) && fm_path_is_virtual (path)) { if (fm_path_is_root (path) && fm_path_is_trash (path)) return g_strdup (_("Trash Can")); //~ if (g_str_has_prefix (path->name, "computer:/")) //~ return g_strdup (_("My Computer")); if (fm_path_is_computer (path)) return g_strdup (_("My Computer")); if (g_str_has_prefix (path->name, "menu:/")) { // FIXME_pcm: this should be more flexible const char *p = path->name + 5; while (p[0] == '/') ++p; if (g_str_has_prefix (p, "applications.menu")) return g_strdup (_("Applications")); } if (g_str_has_prefix (path->name, "network:/")) return g_strdup (_("Network")); } } return g_filename_display_name (path->name); }
static void fm_dir_tree_model_add_place_holder_child_item (FmDirTreeModel *dir_tree_model, GList *parent_node, GtkTreePath *tree_path, gboolean emit_signal) { FmDirTreeItem *parent_item = (FmDirTreeItem*) parent_node->data; // Check if the parent node can expand... FmFileInfo *file_info = parent_item->file_info; FmPath *path = fm_file_info_get_path (file_info); TREEVIEW_DEBUG ("TREEVIEW_DEBUG: fm_dir_tree_model_add_place_holder_child_item: file = %s\t emit_signal = %d\n", fm_file_info_get_name (file_info), emit_signal); // don't expand the trash can... // TODO_axl: add a can_expand flag into the file_info if (fm_path_is_trash (path) && fm_path_is_root (path)) return; TREEVIEW_DEBUG ("TREEVIEW_DEBUG: fm_dir_tree_model_add_place_holder_child_item: create place holder\n\n"); FmDirTreeItem *dir_tree_item = fm_dir_tree_item_new (dir_tree_model, parent_node, NULL); parent_item->children = g_list_prepend (parent_item->children, dir_tree_item); if (!emit_signal) return; GtkTreeIter it; fm_dir_tree_model_item_to_tree_iter (dir_tree_model, parent_item->children, &it); gtk_tree_path_append_index (tree_path, 0); gtk_tree_model_row_inserted (GTK_TREE_MODEL (dir_tree_model), tree_path, &it); gtk_tree_path_up (tree_path); }
/** * fm_trash_or_delete_files * @parent: a window to place progress dialog over it * @files: list of files to delete * * Removes files into trash can if that operation is supported. * Otherwise erases them. If that operation takes some time then progress * dialog will be opened. * * Before 0.1.15 this call had different arguments. * * Since: 0.1.0 */ void fm_trash_or_delete_files(GtkWindow* parent, FmPathList* files) { if( !fm_path_list_is_empty(files) ) { gboolean all_in_trash = TRUE; if(fm_config->use_trash) { GList* l = fm_path_list_peek_head_link(files); for(;l;l=l->next) { FmPath* path = FM_PATH(l->data); if(!fm_path_is_trash(path)) all_in_trash = FALSE; } } /* files already in trash:/// should only be deleted and cannot be trashed again. */ if(fm_config->use_trash && !all_in_trash) fm_trash_files(parent, files); else fm_delete_files(parent, files); } }
/* translate gvfs trash:///path to real path of the trashed file on disk. * this only works when path is a trashed file and gvfs is active. */ char* fm_path_get_trash_real_path(FmPath* path) { char* path_str, *p; GString* result; /* The filenames listed in trash:/// by gvfs are carefully encoded * to carry important information. * Handling of trashed file name can be found in gvfs source code: * gvfs/daemon/trashlib/trashitem.c: trash_item_escape_name(). * The filename listed under trash:/// are encoded according to the * real path on disk. */ if(!fm_path_is_trash(path)) /* this only works for files in trash:/// */ return NULL; /* converting it to string first for ease of handling */ path_str = fm_path_to_str(path); p = path_str + 9; /* skip "trash:///" */ result = g_string_sized_new(1024); if(*p == '\\') /* files not in home trash */ { /* the basename is an encoded full path */ for(; *p; ++p) { if(*p == '\\') /* translate all \ to / */ g_string_append_c(result, '/'); else if(*p == '`') /* special handling for ` */ { ++p; if(*p == '\\') /* translate `\ to \ */ g_string_append_c(result, '\\'); else if(*p == '`') /* translate `` to ` */ g_string_append_c(result, '`'); else { g_string_append_c(result, '`'); g_string_append_c(result, *p); } } else g_string_append_c(result, *p); } } else /* files in home trash */ { g_string_append(result, g_get_user_data_dir()); g_string_append_c(result, '/'); g_string_append(result, "Trash/files/"); if(*p == '`') /* special handling of the first character */ { ++p; if(*p == '`') /* translate `` to ` */ { g_string_append_c(result, '`'); ++p; } else if(*p == '\\') /* translate `\ to \ */ { g_string_append_c(result, '\\'); ++p; } else g_string_append_c(result, '`'); /* don't translate anything */ } g_string_append(result, p); /* append the remaining part */ } return g_string_free(result, FALSE); }
/** * fm_dnd_dest_get_default_action * @dd FmDndDest object * @target GdkTarget of the target data type * @dest FmFileInfo of the destination file at drop site. * * Returns the default action to take for the dragged files. */ GdkDragAction fm_dnd_dest_get_default_action(FmDndDest* dd, GdkDragContext* drag_context, GdkTarget target) { GdkDragAction action; FmFileInfo* dest = dd->dest_file; if(!dest || !dest->path) return FALSE; /* this is XDirectSave */ if(target == xds_target_atom) return GDK_ACTION_COPY; if(dd->src_files) /* we have got drag source files */ { FmPath* dest_path = dest->path; if(fm_path_is_trash(dest_path)) { if(fm_path_is_trash_root(dest_path)) /* we can only move files to trash can */ action = GDK_ACTION_MOVE; else /* files inside trash are read only */ action = 0; } else if(fm_path_is_virtual(dest_path)) { /* computer:/// and network:/// shouldn't received dropped files. */ /* FIXME: some special handling can be done with menu:// */ action = 0; } else if(list_contains_path(dd->src_files, dest_path)) { /* don't allow dropping files into themselves */ action = 0; } else /* dest is a ordinary path */ { /* determine if the dragged files are on the same device as destination file */ /* Here we only check the first dragged file since checking all of them can * make the operation very slow. */ gboolean same_fs; if(dd->src_dev || dd->src_fs_id) /* we know the device of dragged source files */ { /* compare the device/filesystem id against that of destination file */ if(fm_path_is_native(dest_path)) same_fs = dd->src_dev && (dd->src_dev == dest->dev); else /* FIXME: can we use direct comparison here? */ same_fs = dd->src_fs_id && (0 == g_strcmp0(dd->src_fs_id, dest->fs_id)); action = same_fs ? GDK_ACTION_MOVE : GDK_ACTION_COPY; } else /* we don't know on which device the dragged source files are. */ action = 0; } } else /* we didn't have any data */ { action = 0; if(!dd->waiting_data) /* we're still waiting for "drag-data-received" signal */ { /* retrieve the source files */ gtk_drag_get_data(dd->widget, drag_context, target, time); dd->waiting_data = TRUE; } } if( action && 0 == (drag_context->actions & action) ) action = drag_context->suggested_action; return action; }
static gboolean deep_count_gio(FmDeepCountJob* job, GFileInfo* inf, GFile* gf) { FmJob* fmjob = FM_JOB(job); GError* err = NULL; GFileType type; const char* fs_id; gboolean descend; if(inf) g_object_ref(inf); else { _retry_query_info: inf = g_file_query_info(gf, query_str, (job->flags & FM_DC_JOB_FOLLOW_LINKS) ? 0 : G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, fm_job_get_cancellable(fmjob), &err); if(!inf) { FmJobErrorAction act = fm_job_emit_error(fmjob, err, FM_JOB_ERROR_MILD); g_error_free(err); err = NULL; if(act == FM_JOB_RETRY) goto _retry_query_info; return FALSE; } } if(fm_job_is_cancelled(fmjob)) { g_object_unref(inf); return FALSE; } type = g_file_info_get_file_type(inf); descend = TRUE; ++job->count; job->total_size += g_file_info_get_size(inf); job->total_ondisk_size += g_file_info_get_attribute_uint64(inf, G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE); /* prepare for moving across different devices */ if( job->flags & FM_DC_JOB_PREPARE_MOVE ) { fs_id = g_file_info_get_attribute_string(inf, G_FILE_ATTRIBUTE_ID_FILESYSTEM); if( g_strcmp0(fs_id, job->dest_fs_id) != 0 ) { /* files on different device requires an additional 'delete' for the source file. */ ++job->total_size; /* this is for the additional delete */ ++job->total_ondisk_size; ++job->count; } else descend = FALSE; } if( type == G_FILE_TYPE_DIRECTORY ) { FmPath* fm_path = fm_path_new_for_gfile(gf); /* check if we need to decends into the dir. */ /* trash:/// doesn't support deleting files recursively */ if(job->flags & FM_DC_JOB_PREPARE_DELETE && fm_path_is_trash(fm_path) && ! fm_path_is_trash_root(fm_path)) descend = FALSE; else { /* only descends into files on the same filesystem */ if( job->flags & FM_DC_JOB_SAME_FS ) { fs_id = g_file_info_get_attribute_string(inf, G_FILE_ATTRIBUTE_ID_FILESYSTEM); descend = (g_strcmp0(fs_id, job->dest_fs_id) == 0); } } fm_path_unref(fm_path); g_object_unref(inf); inf = NULL; if(descend) { GFileEnumerator* enu; _retry_enum_children: enu = g_file_enumerate_children(gf, query_str, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, fm_job_get_cancellable(fmjob), &err); if(enu) { while( !fm_job_is_cancelled(fmjob) ) { inf = g_file_enumerator_next_file(enu, fm_job_get_cancellable(fmjob), &err); if(inf) { GFile* child = g_file_get_child(gf, g_file_info_get_name(inf)); deep_count_gio(job, inf, child); g_object_unref(child); g_object_unref(inf); inf = NULL; } else { if(err) /* error! */ { /* FM_JOB_RETRY is not supported */ /*FmJobErrorAction act = */ fm_job_emit_error(fmjob, err, FM_JOB_ERROR_MILD); g_error_free(err); err = NULL; } else { /* EOF is reached, do nothing. */ break; } } } g_file_enumerator_close(enu, NULL, NULL); g_object_unref(enu); } else { FmJobErrorAction act = fm_job_emit_error(fmjob, err, FM_JOB_ERROR_MILD); g_error_free(err); err = NULL; if(act == FM_JOB_RETRY) goto _retry_enum_children; } } } else g_object_unref(inf); return TRUE; }