1 /* Copyright (C) 2008 Ricardo Catalinas Jiménez <jimenezrick@gmail.com>
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 WINDOW
*tree_window
, *info_window
;
20 GList
*lines
, *selected_line
, *first_line
, *last_line
;
24 lines
= g_list_append(lines
, tree_root
);
25 FILE(tree_root
)->line
= lines
;
26 selected_line
= lines
;
31 void init_curses(void)
37 halfdelay(GETCH_DELAY
);
47 getmaxyx(stdscr
, screen_size
[0], screen_size
[1]);
48 tree_window
= newwin(screen_size
[0] - 1, screen_size
[1], 0, 0);
49 info_window
= newwin(1, screen_size
[1], screen_size
[0] - 1, 0);
50 scrollok(tree_window
, TRUE
);
51 idlok(tree_window
, TRUE
);
54 void init_ui(char *name
)
59 print_line(FILE(tree_root
)->line
);
61 init_inotify(tree_root
);
63 open_directory(tree_root
);
67 void refresh_screen(void)
69 wnoutrefresh(tree_window
);
70 wnoutrefresh(info_window
);
74 void handle_sigwinch(int signal_number
)
79 void print_lines(GList
*start_line
, GList
*end_line
, gboolean clear_bottom_lines
)
86 else if (start_line
!= NULL
) {
87 for (line_ptr
= start_line
;
88 g_list_position(first_line
, line_ptr
) < getmaxy(tree_window
);
89 line_ptr
= g_list_next(line_ptr
)) {
91 if (line_ptr
== end_line
)
95 line_number
= g_list_position(first_line
, last_line
) + 1;
96 if (clear_bottom_lines
&& line_number
< getmaxy(tree_window
)) {
97 wmove(tree_window
, line_number
, 0);
98 wclrtobot(tree_window
);
102 void print_parents_lines(GList
*line
)
107 for (file_ptr
= NODE(line
)->parent
, depth
= g_node_depth(file_ptr
) - 1;
108 !G_NODE_IS_ROOT(file_ptr
); file_ptr
= file_ptr
->parent
, depth
--) {
109 if (file_ptr
!= g_node_last_sibling(file_ptr
))
110 mvwaddch(tree_window
, g_list_position(first_line
, line
),
111 2 * depth
- 2, ACS_VLINE
);
113 mvwaddch(tree_window
, g_list_position(first_line
, line
),
115 mvwaddch(tree_window
, g_list_position(first_line
, line
), 2 * depth
- 1, ' ');
119 void print_line(GList
*line
)
121 int line_number
= g_list_position(first_line
, line
);
122 GNode
*file
= NODE(line
);
123 int depth
= g_node_depth(file
) - 1;
126 wmove(tree_window
, line_number
, 0);
127 wclrtoeol(tree_window
);
129 if (line
== selected_line
)
130 wattron(tree_window
, A_REVERSE
);
132 if (G_NODE_IS_ROOT(file
)) {
133 wattron(tree_window
, A_BOLD
);
134 waddnstr(tree_window
, FILE(file
)->name
, getmaxx(tree_window
) - 1);
135 if (!g_str_has_suffix(FILE(file
)->name
, "/"))
136 waddch(tree_window
, '/');
137 wattroff(tree_window
, A_BOLD
);
139 if (file
!= g_node_last_sibling(file
))
140 mvwaddch(tree_window
, line_number
, 2 * depth
- 2, ACS_LTEE
);
142 mvwaddch(tree_window
, line_number
, 2 * depth
- 2, ACS_LLCORNER
);
144 waddch(tree_window
, ACS_HLINE
);
145 if (FILE(file
)->link
== TRUE
) {
146 link_str
= g_strdup_printf("%s -> %s", FILE(file
)->name
,
147 FILE(file
)->link_path
);
148 waddnstr(tree_window
, link_str
, getmaxx(tree_window
) - 2 * depth
- 1);
151 waddnstr(tree_window
, FILE(file
)->name
,
152 getmaxx(tree_window
) - 2 * depth
- 1);
154 if (FILE(file
)->type
== directory_type
&& ((FILE(file
)->link
== TRUE
&&
155 !g_str_has_suffix(FILE(file
)->link_path
, "/")) ||
156 (FILE(file
)->link
== FALSE
&&
157 !g_str_has_suffix(FILE(file
)->name
, "/"))))
158 waddch(tree_window
, '/');
159 print_parents_lines(line
);
161 wattroff(tree_window
, A_REVERSE
);
164 void clear_info(void)
169 void print_info(char *message
, gboolean bold
)
171 static char *last_message
= NULL
;
172 static gboolean last_bold
= FALSE
;
174 if (message
!= NULL
) {
175 if (last_message
!= NULL
)
177 last_message
= strdup(message
);
179 if (bold
== TRUE
|| bold
== FALSE
)
181 if (last_bold
== TRUE
)
182 wattron(info_window
, A_BOLD
);
184 if (last_message
!= NULL
)
185 waddnstr(info_window
, last_message
, getmaxx(info_window
));
186 wattroff(info_window
, A_BOLD
);
189 void print_error_info(int last_errno
, char *file
, int line
, char *message
)
191 char *message_format
= "Error (%s:%i): %s";
195 message_str
= g_strdup_printf(message_format
, file
, line
, message
);
197 message_str
= g_strdup_printf(message_format
, file
, line
, strerror(last_errno
));
198 print_info(message_str
, TRUE
);
202 void update_last_line(void)
204 if (g_list_length(first_line
) > getmaxy(tree_window
))
205 last_line
= g_list_nth(first_line
, getmaxy(tree_window
) - 1);
207 last_line
= g_list_last(lines
);
210 void add_directory_content(GNode
*directory
)
212 GNode
*file_ptr
, *directory_sibling
;
215 directory_sibling
= get_next_file_not_deepper(directory
);
217 for (position
= g_list_position(lines
, FILE(directory
)->line
) + 1,
218 file_ptr
= g_node_first_child(directory
);
219 file_ptr
!= NULL
&& file_ptr
!= directory_sibling
;
220 position
++, file_ptr
= get_next_file(file_ptr
)) {
221 lines
= g_list_insert(lines
, file_ptr
, position
);
222 FILE(file_ptr
)->line
= g_list_nth(lines
, position
);
226 void open_directory(GNode
*directory
)
228 if (FILE(directory
)->read
== FALSE
&& read_directory(directory
) == FALSE
)
231 FILE(directory
)->open
= TRUE
;
232 add_directory_content(directory
);
234 print_lines(g_list_next(FILE(directory
)->line
), last_line
, TRUE
);
237 void close_directory(GNode
*directory
)
239 GNode
*directory_sibling
;
242 directory_sibling
= get_next_file_not_deepper(directory
);
244 for (line_ptr
= g_list_next(FILE(directory
)->line
); line_ptr
!= NULL
&&
245 NODE(line_ptr
) != directory_sibling
; line_ptr
= g_list_next(FILE(directory
)->line
))
246 lines
= g_list_delete_link(lines
, line_ptr
);
248 FILE(directory
)->open
= FALSE
;
250 print_lines(g_list_next(FILE(directory
)->line
), last_line
, TRUE
);
253 void update_directory(GNode
*directory
)
255 close_directory(directory
);
256 destroy_directory_content(directory
);
257 open_directory(directory
);
259 if (FILE(directory
)->show_dotfiles
== TRUE
)
260 show_dotfiles(directory
);
263 void show_dotfiles(GNode
*directory
)
265 add_dotfiles(directory
);
267 print_lines(g_list_next(FILE(directory
)->line
), last_line
, TRUE
);
270 void hide_dotfiles(GNode
*directory
)
272 remove_dotfiles(directory
);
274 print_lines(g_list_next(FILE(directory
)->line
), last_line
, TRUE
);
277 void select_line(GList
*line
)
279 select_nth_line(g_list_position(lines
, line
) - g_list_position(lines
, selected_line
));
282 void select_file(GNode
*file
)
284 select_line(FILE(file
)->line
);
287 void select_nth_line(int n_lines
)
289 GList
*old_selected_line
;
290 int min_n_lines
, max_n_lines
;
292 if ((max_n_lines
= g_list_length(selected_line
) - 1) < n_lines
)
293 n_lines
= max_n_lines
;
294 else if((min_n_lines
= (int) g_list_length(selected_line
) -
295 (int) g_list_length(lines
)) > n_lines
)
296 n_lines
= min_n_lines
;
298 old_selected_line
= selected_line
;
300 selected_line
= g_list_nth(lines
, g_list_position(lines
, selected_line
) + n_lines
);
301 else if (n_lines
> 0)
302 selected_line
= g_list_nth(selected_line
, n_lines
);
304 if (g_list_position(lines
, selected_line
) < g_list_position(lines
, first_line
))
305 scroll_tree(g_list_position(lines
, selected_line
) -
306 g_list_position(lines
, first_line
));
307 else if (g_list_position(lines
, selected_line
) > g_list_position(lines
, last_line
))
308 scroll_tree(g_list_position(lines
, selected_line
) -
309 g_list_position(lines
, last_line
));
312 print_line(selected_line
);
313 if (g_list_position(lines
, first_line
) <= g_list_position(lines
, old_selected_line
) &&
314 g_list_position(lines
, old_selected_line
) <=
315 g_list_position(lines
, last_line
))
316 print_line(old_selected_line
);
320 void scroll_tree(int n_lines
)
322 int min_n_lines
, max_n_lines
;
324 if ((min_n_lines
= -g_list_position(lines
, first_line
)) > n_lines
)
325 n_lines
= min_n_lines
;
326 else if ((max_n_lines
= g_list_length(last_line
) - 1) < n_lines
)
327 n_lines
= max_n_lines
;
329 wscrl(tree_window
, n_lines
);
331 first_line
= g_list_nth(lines
, g_list_position(lines
, first_line
) + n_lines
);
333 print_lines(first_line
, g_list_nth(first_line
, -n_lines
), FALSE
);
334 } else if (n_lines
> 0) {
335 first_line
= g_list_nth(first_line
, n_lines
);
337 print_lines(g_list_nth(lines
, g_list_position(lines
, last_line
) - n_lines
),
342 void select_line_inside_window(void)
344 if (g_list_position(lines
, selected_line
) < g_list_position(lines
, first_line
))
345 select_line(first_line
);
346 else if (g_list_position(lines
, selected_line
) > g_list_position(lines
, last_line
))
347 select_line(last_line
);
350 void select_next_line_by_first_letter(char letter
)
354 for (line_ptr
= g_list_next(selected_line
); line_ptr
!= NULL
;
355 line_ptr
= g_list_next(line_ptr
)) {
356 if (FILE(NODE(line_ptr
))->name
[0] == letter
) {
357 select_line(line_ptr
);
363 void select_previous_line_by_first_letter(char letter
)
367 for (line_ptr
= g_list_previous(selected_line
); line_ptr
!= NULL
;
368 line_ptr
= g_list_previous(line_ptr
)) {
369 if (FILE(NODE(line_ptr
))->name
[0] == letter
) {
370 select_line(line_ptr
);