diff options
author | Harley Acheson <harley.acheson@gmail.com> | 2020-02-21 19:18:29 +0300 |
---|---|---|
committer | Harley Acheson <harley.acheson@gmail.com> | 2020-02-21 19:20:58 +0300 |
commit | 1fb62d1272db477277534c5d31ce220afd100637 (patch) | |
tree | 152044d21435b9f3d347b132b8b860d0d706b1f4 /source | |
parent | b1b020806e2d5ca403de62dc956c4a27f36bc377 (diff) |
UI: Windows File Attributes and Hidden Items
File Browser using Windows file attributes for decorating and hiding items.
Differential Revision: https://developer.blender.org/D6816
Reviewed by Campbell Barton
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenlib/BLI_fileops.h | 24 | ||||
-rw-r--r-- | source/blender/blenlib/intern/storage.c | 63 | ||||
-rw-r--r-- | source/blender/editors/include/UI_icons.h | 2 | ||||
-rw-r--r-- | source/blender/editors/space_file/file_draw.c | 30 | ||||
-rw-r--r-- | source/blender/editors/space_file/filelist.c | 116 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_space_types.h | 2 |
6 files changed, 195 insertions, 42 deletions
diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h index 5c20e57181e..3ee22e4ad0a 100644 --- a/source/blender/blenlib/BLI_fileops.h +++ b/source/blender/blenlib/BLI_fileops.h @@ -73,6 +73,29 @@ int BLI_stat(const char *path, BLI_stat_t *buffer) ATTR_WARN_UNUSED_RESULT ATTR_ int BLI_wstat(const wchar_t *path, BLI_stat_t *buffer); #endif +typedef enum eFileAttributes { + FILE_ATTR_READONLY = 1 << 0, /* Read-only or Immutable. */ + FILE_ATTR_HIDDEN = 1 << 1, /* Hidden or invisible. */ + FILE_ATTR_SYSTEM = 1 << 2, /* Used by the Operating System. */ + FILE_ATTR_ARCHIVE = 1 << 3, /* Marked as archived. */ + FILE_ATTR_COMPRESSED = 1 << 4, /* Compressed. */ + FILE_ATTR_ENCRYPTED = 1 << 5, /* Encrypted. */ + FILE_ATTR_RESTRICTED = 1 << 6, /* Protected by OS. */ + FILE_ATTR_TEMPORARY = 1 << 7, /* Used for temporary storage. */ + FILE_ATTR_SPARSE_FILE = 1 << 8, /* Sparse File. */ + FILE_ATTR_OFFLINE = 1 << 9, /* Data is not immediately available. */ + FILE_ATTR_ALIAS = 1 << 10, /* Mac Alias or Windows Lnk. File-based redirection. */ + FILE_ATTR_REPARSE_POINT = 1 << 11, /* File has associated reparse point. */ + FILE_ATTR_SYMLINK = 1 << 12, /* Reference to another file. */ + FILE_ATTR_JUNCTION_POINT = 1 << 13, /* Folder Symlink. */ + FILE_ATTR_MOUNT_POINT = 1 << 14, /* Volume mounted as a folder. */ + FILE_ATTR_HARDLINK = 1 << 15, /* Duplicated directory entry. */ +} eFileAttributes; + +#define FILE_ATTR_ANY_LINK \ + (FILE_ATTR_ALIAS | FILE_ATTR_REPARSE_POINT | FILE_ATTR_SYMLINK | FILE_ATTR_JUNCTION_POINT | \ + FILE_ATTR_MOUNT_POINT | FILE_ATTR_HARDLINK) + /* Directories */ struct direntry; @@ -83,6 +106,7 @@ bool BLI_dir_create_recursive(const char *dir) ATTR_NONNULL(); double BLI_dir_free_space(const char *dir) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); char *BLI_current_working_dir(char *dir, const size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +eFileAttributes BLI_file_attributes(const char *path); /* Filelist */ diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c index 7c481868d64..04b3e8abca2 100644 --- a/source/blender/blenlib/intern/storage.c +++ b/source/blender/blenlib/intern/storage.c @@ -199,6 +199,69 @@ size_t BLI_file_size(const char *path) return stats.st_size; } +eFileAttributes BLI_file_attributes(const char *path) +{ + int ret = 0; + +#ifdef WIN32 + wchar_t wline[FILE_MAXDIR]; + BLI_strncpy_wchar_from_utf8(wline, path, ARRAY_SIZE(wline)); + DWORD attr = GetFileAttributesW(wline); + if (attr & FILE_ATTRIBUTE_READONLY) { + ret |= FILE_ATTR_READONLY; + } + if (attr & FILE_ATTRIBUTE_HIDDEN) { + ret |= FILE_ATTR_HIDDEN; + } + if (attr & FILE_ATTRIBUTE_SYSTEM) { + ret |= FILE_ATTR_SYSTEM; + } + if (attr & FILE_ATTRIBUTE_ARCHIVE) { + ret |= FILE_ATTR_ARCHIVE; + } + if (attr & FILE_ATTRIBUTE_COMPRESSED) { + ret |= FILE_ATTR_COMPRESSED; + } + if (attr & FILE_ATTRIBUTE_ENCRYPTED) { + ret |= FILE_ATTR_ENCRYPTED; + } + if (attr & FILE_ATTRIBUTE_TEMPORARY) { + ret |= FILE_ATTR_TEMPORARY; + } + if (attr & FILE_ATTRIBUTE_SPARSE_FILE) { + ret |= FILE_ATTR_SPARSE_FILE; + } + if (attr & FILE_ATTRIBUTE_OFFLINE) { + ret |= FILE_ATTR_OFFLINE; + } + if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { + ret |= FILE_ATTR_REPARSE_POINT; + } + +#endif + +#ifdef __APPLE__ + + /* TODO: + * If Hidden (Invisible) set FILE_ATTR_HIDDEN + * If Locked set FILE_ATTR_READONLY + * If Restricted set FILE_ATTR_RESTRICTED + */ + +#endif + +#ifdef __linux__ + + /* TODO: + * If Immutable set FILE_ATTR_READONLY + * If Archived set FILE_ATTR_ARCHIVE + */ + +#endif + + return ret; +} + /** * Returns the st_mode from stat-ing the specified path name, or 0 if stat fails * (most likely doesn't exist or no access). diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index fabf6baed23..6739f7cb12c 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -793,7 +793,7 @@ DEF_ICON(BOOKMARKS) DEF_ICON(FONTPREVIEW) DEF_ICON(FILTER) DEF_ICON(NEWFOLDER) -DEF_ICON(FOLDER_REDIRECT) +DEF_ICON_FOLDER(FOLDER_REDIRECT) DEF_ICON(FILE_PARENT) DEF_ICON(FILE_REFRESH) DEF_ICON_FOLDER(FILE_FOLDER) diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 0aec6d5e6a0..1739c15cbc6 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -133,8 +133,15 @@ static void draw_tile(int sx, int sy, int width, int height, int colorid, int sh true, (float)sx, (float)(sy - height), (float)(sx + width), (float)sy, 5.0f, color); } -static void file_draw_icon( - uiBlock *block, const char *path, int sx, int sy, int icon, int width, int height, bool drag) +static void file_draw_icon(uiBlock *block, + const char *path, + int sx, + int sy, + int icon, + int width, + int height, + bool drag, + bool dimmed) { uiBut *but; int x, y; @@ -142,8 +149,11 @@ static void file_draw_icon( x = sx; y = sy - height; + /* For uiDefIconBut(), if a1==1.0 then a2 is alpha 0.0 - 1.0 */ + const float a1 = dimmed ? 1.0f : 0.0f; + const float a2 = dimmed ? 0.3f : 0.0f; but = uiDefIconBut( - block, UI_BTYPE_LABEL, 0, icon, x, y, width, height, NULL, 0.0f, 0.0f, 0.0f, 0.0f, NULL); + block, UI_BTYPE_LABEL, 0, icon, x, y, width, height, NULL, 0.0f, 0.0f, a1, a2, NULL); UI_but_func_tooltip_set(but, file_draw_tooltip_func, BLI_strdup(path)); if (drag) { @@ -210,7 +220,8 @@ static void file_draw_preview(uiBlock *block, FileLayout *layout, const bool is_icon, const int typeflags, - const bool drag) + const bool drag, + const bool dimmed) { uiBut *but; float fx, fy; @@ -273,6 +284,10 @@ static void file_draw_preview(uiBlock *block, UI_GetThemeColor4fv(TH_TEXT, col); } + if (dimmed) { + col[3] *= 0.3f; + } + if (!is_icon && typeflags & FILE_TYPE_BLENDERLIB) { /* Datablock preview images use premultiplied alpha. */ GPU_blend_set_func_separate( @@ -775,6 +790,7 @@ void file_draw_list(const bContext *C, ARegion *ar) /* don't drag parent or refresh items */ do_drag = !(FILENAME_IS_CURRPAR(file->relpath)); + const bool is_hidden = (file->attributes & FILE_ATTR_HIDDEN); if (FILE_IMGDISPLAY == params->display) { const int icon = filelist_geticon(files, i, false); @@ -795,7 +811,8 @@ void file_draw_list(const bContext *C, ARegion *ar) layout, is_icon, file->typeflag, - do_drag); + do_drag, + is_hidden); } else { file_draw_icon(block, @@ -805,7 +822,8 @@ void file_draw_list(const bContext *C, ARegion *ar) filelist_geticon(files, i, true), ICON_DEFAULT_WIDTH_SCALE, ICON_DEFAULT_HEIGHT_SCALE, - do_drag); + do_drag, + is_hidden); icon_ofs += ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X; } diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index b328b32263c..28e6d95beb3 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -213,6 +213,9 @@ typedef struct FileListInternEntry { /** not strictly needed, but used during sorting, avoids to have to recompute it there... */ char *name; + /** Defined in BLI_fileops.h */ + eFileAttributes attributes; + BLI_stat_t st; } FileListInternEntry; @@ -609,54 +612,76 @@ void filelist_setsorting(struct FileList *filelist, const short sort, bool inver /* ********** Filter helpers ********** */ -static bool is_hidden_file(const char *filename, FileListFilter *filter) +/* True if filename is meant to be hidden, eg. starting with period. */ +static bool is_hidden_dot_filename(const char *filename, FileListInternEntry *file) { - char *sep = (char *)BLI_last_slash(filename); - bool is_hidden = false; - - if (filter->flags & FLF_HIDE_DOT) { - if (filename[0] == '.' && filename[1] != '.' && filename[1] != '\0') { - is_hidden = true; /* ignore .file */ - } - else { - int len = strlen(filename); - if ((len > 0) && (filename[len - 1] == '~')) { - is_hidden = true; /* ignore file~ */ - } - } + if (filename[0] == '.' && !ELEM(filename[1], '.', '\0')) { + return true; /* ignore .file */ } - if (!is_hidden && (filter->flags & FLF_HIDE_PARENT)) { - if (filename[0] == '.' && filename[1] == '.' && filename[2] == '\0') { - is_hidden = true; /* ignore .. */ + else { + int len = strlen(filename); + if ((len > 0) && (filename[len - 1] == '~')) { + return true; /* ignore file~ */ } } - if (!is_hidden && ((filename[0] == '.') && (filename[1] == '\0'))) { - is_hidden = true; /* ignore . */ - } + /* filename might actually be a piece of path, in which case we have to check all its parts. */ - if (!is_hidden && sep) { + + bool hidden = false; + char *sep = (char *)BLI_last_slash(filename); + + if (!hidden && sep) { char tmp_filename[FILE_MAX_LIBEXTRA]; BLI_strncpy(tmp_filename, filename, sizeof(tmp_filename)); sep = tmp_filename + (sep - filename); while (sep) { BLI_assert(sep[1] != '\0'); - if (is_hidden_file(sep + 1, filter)) { - is_hidden = true; + if (is_hidden_dot_filename(sep + 1, file)) { + hidden = true; break; } *sep = '\0'; sep = (char *)BLI_last_slash(tmp_filename); } } - return is_hidden; + return hidden; +} + +/* True if should be hidden, based on current filtering. */ +static bool is_filtered_hidden(const char *filename, + FileListFilter *filter, + FileListInternEntry *file) +{ + if ((filename[0] == '.') && (filename[1] == '\0')) { + return true; /* Ignore . */ + } + + if (filter->flags & FLF_HIDE_PARENT) { + if (filename[0] == '.' && filename[1] == '.' && filename[2] == '\0') { + return true; /* Ignore .. */ + } + } + + if ((filter->flags & FLF_HIDE_DOT) && (file->attributes & FILE_ATTR_HIDDEN)) { + return true; /* Ignore files with Hidden attribute. */ + } + +#ifndef WIN32 + /* Check for unix-style names starting with period. */ + if ((filter->flags & FLF_HIDE_DOT) && is_hidden_dot_filename(filename, file)) { + return true; + } +#endif + + return false; } static bool is_filtered_file(FileListInternEntry *file, const char *UNUSED(root), FileListFilter *filter) { - bool is_filtered = !is_hidden_file(file->relpath, filter); + bool is_filtered = !is_filtered_hidden(file->relpath, filter, file); if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) { /* We only check for types if some type are enabled in filtering. */ @@ -699,7 +724,7 @@ static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileLis BLI_join_dirfile(path, sizeof(path), root, file->relpath); if (BLO_library_path_explode(path, dir, &group, &name)) { - is_filtered = !is_hidden_file(file->relpath, filter); + is_filtered = !is_filtered_hidden(file->relpath, filter, file); if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) { /* We only check for types if some type are enabled in filtering. */ if ((filter->filter || filter->filter_id) && (filter->flags & FLF_DO_FILTER)) { @@ -747,7 +772,7 @@ static bool is_filtered_main(FileListInternEntry *file, const char *UNUSED(dir), FileListFilter *filter) { - return !is_hidden_file(file->relpath, filter); + return !is_filtered_hidden(file->relpath, filter, file); } static void filelist_filter_clear(FileList *filelist) @@ -968,7 +993,7 @@ static int filelist_geticon_ex(FileDirEntry *file, else if (is_main) { /* Do not return icon for folders if icons are not 'main' draw type * (e.g. when used over previews). */ - return ICON_FILE_FOLDER; + return (file->attributes & FILE_ATTR_ANY_LINK) ? ICON_FOLDER_REDIRECT : ICON_FILE_FOLDER; } else { /* If this path is in System list then use that icon. */ @@ -984,6 +1009,19 @@ static int filelist_geticon_ex(FileDirEntry *file, } } } + + if (file->attributes & FILE_ATTR_ANY_LINK) { + return ICON_LOOP_FORWARDS; + } + else if (file->attributes & FILE_ATTR_OFFLINE) { + return ICON_ERROR; + } + else if (file->attributes & FILE_ATTR_TEMPORARY) { + return ICON_FILE_CACHE; + } + else if (file->attributes & FILE_ATTR_SYSTEM) { + return ICON_SYSTEM; + } } if (typeflag & FILE_TYPE_BLENDER) { @@ -1621,7 +1659,7 @@ static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int in memcpy(ret->uuid, entry->uuid, sizeof(ret->uuid)); ret->blentype = entry->blentype; ret->typeflag = entry->typeflag; - + ret->attributes = entry->attributes; BLI_addtail(&cache->cached_entries, ret); return ret; } @@ -2401,6 +2439,7 @@ static int filelist_readjob_list_dir(const char *root, { struct direntry *files; int nbr_files, nbr_entries = 0; + char path[FILE_MAX]; nbr_files = BLI_filelist_dir_contents(root, &files); if (files) { @@ -2416,20 +2455,17 @@ static int filelist_readjob_list_dir(const char *root, entry->relpath = MEM_dupallocN(files[i].relname); entry->st = files[i].s; + BLI_join_dirfile(path, sizeof(path), root, entry->relpath); + /* Set file type. */ if (S_ISDIR(files[i].s.st_mode)) { entry->typeflag = FILE_TYPE_DIR; } else if (do_lib && BLO_has_bfile_extension(entry->relpath)) { /* If we are considering .blend files as libs, promote them to directory status. */ - char name[FILE_MAX]; - entry->typeflag = FILE_TYPE_BLENDER; - - BLI_join_dirfile(name, sizeof(name), root, entry->relpath); - /* prevent current file being used as acceptable dir */ - if (BLI_path_cmp(main_name, name) != 0) { + if (BLI_path_cmp(main_name, path) != 0) { entry->typeflag |= FILE_TYPE_DIR; } } @@ -2441,6 +2477,16 @@ static int filelist_readjob_list_dir(const char *root, } } + /* Set file attributes. */ + entry->attributes = BLI_file_attributes(path); + +#ifndef WIN32 + /* Set linux-style dot files hidden too. */ + if (is_hidden_dot_filename(entry->relpath, entry)) { + entry->attributes |= FILE_ATTR_HIDDEN; + } +#endif + BLI_addtail(entries, entry); nbr_entries++; } diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 159c0424ee8..bdfe5040794 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -965,6 +965,8 @@ typedef struct FileDirEntry { short status; short flags; + /* eFileAttributes defined in BLI_fileops.h */ + int attributes; ListBase variants; int nbr_variants; |