This source file includes following definitions.
- mcview_remove_ext_script
- mcview_continue_search_cmd
- mcview_hook
- mcview_handle_editkey
- mcview_load_next_prev_init
- mcview_scan_for_file
- mcview_load_next_prev
- mcview_load_file_from_history
- mcview_execute_cmd
- mcview_lookup_key
- mcview_handle_key
- mcview_resize
- mcview_ok_to_quit
- mcview_callback
- mcview_dialog_callback
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 #include <config.h>
46
47 #include <stdlib.h>
48
49 #include "lib/global.h"
50
51 #include "lib/tty/tty.h"
52 #include "lib/tty/key.h"
53 #include "lib/lock.h"
54 #include "lib/file-entry.h"
55 #include "lib/widget.h"
56 #include "lib/charsets.h"
57 #include "lib/event.h"
58 #include "lib/mcconfig.h"
59
60 #include "src/filemanager/layout.h"
61 #include "src/filemanager/filemanager.h"
62 #include "src/filemanager/ext.h"
63
64 #include "src/history.h"
65 #include "src/file_history.h"
66 #include "src/execute.h"
67 #include "src/keymap.h"
68
69 #include "internal.h"
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85 static void
86 mcview_remove_ext_script (WView *view)
87 {
88 if (view->ext_script != NULL)
89 {
90 mc_unlink (view->ext_script);
91 vfs_path_free (view->ext_script, TRUE);
92 view->ext_script = NULL;
93 }
94 }
95
96
97
98 static void
99 mcview_continue_search_cmd (WView *view)
100 {
101 if (view->last_search_string != NULL)
102 mcview_search (view, FALSE);
103 else
104 {
105
106 char *s;
107
108 s = mc_config_history_get_recent_item (MC_HISTORY_SHARED_SEARCH);
109 if (s != NULL)
110 {
111 view->last_search_string = s;
112
113 if (mcview_search_init (view))
114 {
115 mcview_search (view, FALSE);
116 return;
117 }
118
119
120 MC_PTR_FREE (view->last_search_string);
121 }
122
123
124 mcview_search (view, TRUE);
125 }
126 }
127
128
129
130 static void
131 mcview_hook (void *v)
132 {
133 WView *view = (WView *) v;
134 WPanel *panel;
135 const file_entry_t *fe;
136
137
138
139 if (!is_idle ())
140 {
141 if (!hook_present (idle_hook, mcview_hook))
142 add_hook (&idle_hook, mcview_hook, v);
143 return;
144 }
145
146 delete_hook (&idle_hook, mcview_hook);
147
148 if (get_current_type () == view_listing)
149 panel = current_panel;
150 else if (get_other_type () == view_listing)
151 panel = other_panel;
152 else
153 return;
154
155 fe = panel_current_entry (panel);
156 if (fe == NULL)
157 return;
158
159 mcview_done (view);
160 mcview_init (view);
161 mcview_load (view, 0, fe->fname->str, 0, 0, 0);
162 mcview_display (view);
163 }
164
165
166
167 static cb_ret_t
168 mcview_handle_editkey (WView *view, int key)
169 {
170 struct hexedit_change_node *node;
171 int byte_val = -1;
172
173
174 node = view->change_list;
175 while ((node != NULL) && (node->offset != view->hex_cursor))
176 node = node->next;
177
178 if (!view->hexview_in_text)
179 {
180
181 unsigned int hexvalue = 0;
182
183 if (key >= '0' && key <= '9')
184 hexvalue = 0 + (key - '0');
185 else if (key >= 'A' && key <= 'F')
186 hexvalue = 10 + (key - 'A');
187 else if (key >= 'a' && key <= 'f')
188 hexvalue = 10 + (key - 'a');
189 else
190 return MSG_NOT_HANDLED;
191
192 if (node != NULL)
193 byte_val = node->value;
194 else
195 mcview_get_byte (view, view->hex_cursor, &byte_val);
196
197 if (view->hexedit_lownibble)
198 byte_val = (byte_val & 0xf0) | (hexvalue);
199 else
200 byte_val = (byte_val & 0x0f) | (hexvalue << 4);
201 }
202 else
203 {
204
205 if (key < 256 && key != '\t')
206 byte_val = key;
207 else
208 return MSG_NOT_HANDLED;
209 }
210
211 if ((view->filename_vpath != NULL)
212 && (*(vfs_path_get_last_path_str (view->filename_vpath)) != '\0')
213 && (view->change_list == NULL))
214 view->locked = lock_file (view->filename_vpath) != 0;
215
216 if (node == NULL)
217 {
218 node = g_new (struct hexedit_change_node, 1);
219 node->offset = view->hex_cursor;
220 node->value = byte_val;
221 mcview_enqueue_change (&view->change_list, node);
222 }
223 else
224 node->value = byte_val;
225
226 view->dirty++;
227 mcview_move_right (view, 1);
228
229 return MSG_HANDLED;
230 }
231
232
233
234 static void
235 mcview_load_next_prev_init (WView *view)
236 {
237 if (mc_global.mc_run_mode != MC_RUN_VIEWER)
238 {
239
240 view->dir = ¤t_panel->dir;
241 view->dir_idx = ¤t_panel->current;
242 }
243 else if (view->dir == NULL)
244 {
245
246
247
248
249
250 dir_sort_options_t sort_op = { FALSE, TRUE, FALSE };
251
252
253 view->dir = g_new0 (dir_list, 1);
254 view->dir_idx = g_new (int, 1);
255
256 if (dir_list_load (view->dir, view->workdir_vpath, (GCompareFunc) sort_name, &sort_op,
257 NULL))
258 {
259 const char *fname;
260 size_t fname_len;
261 int i;
262
263 fname = x_basename (vfs_path_as_str (view->filename_vpath));
264 fname_len = strlen (fname);
265
266
267 for (i = 0; i != view->dir->len; i++)
268 {
269 const file_entry_t *fe = &view->dir->list[i];
270
271 if (fname_len == fe->fname->len && strncmp (fname, fe->fname->str, fname_len) == 0)
272 break;
273 }
274
275 *view->dir_idx = i;
276 }
277 else
278 {
279 message (D_ERROR, MSG_ERROR, _ ("Cannot read directory contents"));
280 MC_PTR_FREE (view->dir);
281 MC_PTR_FREE (view->dir_idx);
282 }
283 }
284 }
285
286
287
288 static void
289 mcview_scan_for_file (WView *view, int direction)
290 {
291 int i;
292
293 for (i = *view->dir_idx + direction; i != *view->dir_idx; i += direction)
294 {
295 if (i < 0)
296 i = view->dir->len - 1;
297 if (i == view->dir->len)
298 i = 0;
299 if (!S_ISDIR (view->dir->list[i].st.st_mode))
300 break;
301 }
302
303 *view->dir_idx = i;
304 }
305
306
307
308 static void
309 mcview_load_next_prev (WView *view, int direction)
310 {
311 dir_list *dir;
312 int *dir_idx;
313 vfs_path_t *vfile;
314 vfs_path_t *ext_script = NULL;
315
316 mcview_load_next_prev_init (view);
317 mcview_scan_for_file (view, direction);
318
319
320 dir = view->dir;
321 dir_idx = view->dir_idx;
322 view->dir = NULL;
323 view->dir_idx = NULL;
324 vfile =
325 vfs_path_append_new (view->workdir_vpath, dir->list[*dir_idx].fname->str, (char *) NULL);
326 mcview_done (view);
327 mcview_remove_ext_script (view);
328 mcview_init (view);
329 if (regex_command_for (view, vfile, "View", &ext_script) == 0)
330 mcview_load (view, NULL, vfs_path_as_str (vfile), 0, 0, 0);
331 vfs_path_free (vfile, TRUE);
332 view->dir = dir;
333 view->dir_idx = dir_idx;
334 view->ext_script = ext_script;
335
336 view->dpy_bbar_dirty = FALSE;
337 view->dirty++;
338 }
339
340
341
342 static void
343 mcview_load_file_from_history (WView *view)
344 {
345 char *filename;
346 int action;
347
348 filename = show_file_history (CONST_WIDGET (view), &action);
349
350 if (filename != NULL && (action == CK_View || action == CK_Enter))
351 {
352 mcview_done (view);
353 mcview_init (view);
354
355 mcview_load (view, NULL, filename, 0, 0, 0);
356
357 view->dpy_bbar_dirty = FALSE;
358 view->dirty++;
359 }
360
361 g_free (filename);
362 }
363
364
365
366 static cb_ret_t
367 mcview_execute_cmd (WView *view, long command)
368 {
369 int res = MSG_HANDLED;
370
371 switch (command)
372 {
373 case CK_HexMode:
374
375 mcview_toggle_hex_mode (view);
376 break;
377 case CK_HexEditMode:
378
379 mcview_toggle_hexedit_mode (view);
380 break;
381 case CK_ToggleNavigation:
382 view->hexview_in_text = !view->hexview_in_text;
383 view->dirty++;
384 break;
385 case CK_LeftQuick:
386 if (!view->mode_flags.hex)
387 mcview_move_left (view, 10);
388 break;
389 case CK_RightQuick:
390 if (!view->mode_flags.hex)
391 mcview_move_right (view, 10);
392 break;
393 case CK_Goto:
394 {
395 off_t addr;
396
397 if (mcview_dialog_goto (view, &addr))
398 {
399 if (addr >= 0)
400 mcview_moveto_offset (view, addr);
401 else
402 {
403 message (D_ERROR, _ ("Warning"), "%s", _ ("Invalid value"));
404 view->dirty++;
405 }
406 }
407 break;
408 }
409 case CK_Save:
410 mcview_hexedit_save_changes (view);
411 break;
412 case CK_Search:
413 mcview_search (view, TRUE);
414 break;
415 case CK_SearchContinue:
416 mcview_continue_search_cmd (view);
417 break;
418 case CK_SearchForward:
419 mcview_search_options.backwards = FALSE;
420 mcview_search (view, TRUE);
421 break;
422 case CK_SearchForwardContinue:
423 mcview_search_options.backwards = FALSE;
424 mcview_continue_search_cmd (view);
425 break;
426 case CK_SearchBackward:
427 mcview_search_options.backwards = TRUE;
428 mcview_search (view, TRUE);
429 break;
430 case CK_SearchBackwardContinue:
431 mcview_search_options.backwards = TRUE;
432 mcview_continue_search_cmd (view);
433 break;
434 case CK_SearchOppositeContinue:
435 {
436 gboolean direction;
437
438 direction = mcview_search_options.backwards;
439 mcview_search_options.backwards = !direction;
440 mcview_continue_search_cmd (view);
441 mcview_search_options.backwards = direction;
442 }
443 break;
444 case CK_WrapMode:
445
446 mcview_toggle_wrap_mode (view);
447 break;
448 case CK_MagicMode:
449 mcview_toggle_magic_mode (view);
450 break;
451 case CK_NroffMode:
452 mcview_toggle_nroff_mode (view);
453 break;
454 case CK_Home:
455 mcview_moveto_bol (view);
456 break;
457 case CK_End:
458 mcview_moveto_eol (view);
459 break;
460 case CK_Left:
461 mcview_move_left (view, 1);
462 break;
463 case CK_Right:
464 mcview_move_right (view, 1);
465 break;
466 case CK_Up:
467 mcview_move_up (view, 1);
468 break;
469 case CK_Down:
470 mcview_move_down (view, 1);
471 break;
472 case CK_HalfPageUp:
473 mcview_move_up (view, (view->data_area.lines + 1) / 2);
474 break;
475 case CK_HalfPageDown:
476 mcview_move_down (view, (view->data_area.lines + 1) / 2);
477 break;
478 case CK_PageUp:
479 mcview_move_up (view, view->data_area.lines);
480 break;
481 case CK_PageDown:
482 mcview_move_down (view, view->data_area.lines);
483 break;
484 case CK_Top:
485 mcview_moveto_top (view);
486 break;
487 case CK_Bottom:
488 mcview_moveto_bottom (view);
489 break;
490 case CK_Shell:
491 toggle_subshell ();
492 break;
493 case CK_Ruler:
494 mcview_display_toggle_ruler (view);
495 break;
496 case CK_Bookmark:
497 view->dpy_start = view->marks[view->marker];
498 view->dpy_paragraph_skip_lines = 0;
499 view->dpy_wrap_dirty = TRUE;
500 view->dirty++;
501 break;
502 case CK_BookmarkGoto:
503 view->marks[view->marker] = view->dpy_start;
504 break;
505 case CK_SelectCodepage:
506 mcview_select_encoding (view);
507 view->dirty++;
508 break;
509 case CK_FileNext:
510 case CK_FilePrev:
511
512 if (!mcview_is_in_panel (view))
513 mcview_load_next_prev (view, command == CK_FileNext ? 1 : -1);
514 break;
515 case CK_History:
516 mcview_load_file_from_history (view);
517 break;
518 case CK_Quit:
519 if (!mcview_is_in_panel (view))
520 dlg_close (DIALOG (WIDGET (view)->owner));
521 break;
522 case CK_Cancel:
523
524 break;
525 default:
526 res = MSG_NOT_HANDLED;
527 }
528 return res;
529 }
530
531
532
533 static long
534 mcview_lookup_key (WView *view, int key)
535 {
536 if (view->mode_flags.hex)
537 return keybind_lookup_keymap_command (view->hex_keymap, key);
538
539 return widget_lookup_key (WIDGET (view), key);
540 }
541
542
543
544 static cb_ret_t
545 mcview_handle_key (WView *view, int key)
546 {
547 long command;
548
549 key = convert_from_input_c (key);
550
551 if (view->hexedit_mode && view->mode_flags.hex
552 && mcview_handle_editkey (view, key) == MSG_HANDLED)
553 return MSG_HANDLED;
554
555 command = mcview_lookup_key (view, key);
556 if (command != CK_IgnoreKey && mcview_execute_cmd (view, command) == MSG_HANDLED)
557 return MSG_HANDLED;
558
559 #ifdef MC_ENABLE_DEBUGGING_CODE
560 if (key == 't')
561 {
562 mcview_ccache_dump (view);
563 return MSG_HANDLED;
564 }
565 #endif
566 if (key >= '0' && key <= '9')
567 view->marker = key - '0';
568
569
570 return MSG_NOT_HANDLED;
571 }
572
573
574
575 static inline void
576 mcview_resize (WView *view)
577 {
578 view->dpy_wrap_dirty = TRUE;
579 mcview_compute_areas (view);
580 mcview_update_bytes_per_line (view);
581 }
582
583
584
585 static gboolean
586 mcview_ok_to_quit (WView *view)
587 {
588 int r;
589
590 if (view->change_list == NULL)
591 return TRUE;
592
593 if (!mc_global.midnight_shutdown)
594 {
595 query_set_sel (2);
596 r = query_dialog (_ ("Quit"), _ ("File was modified. Save with exit?"), D_NORMAL, 3,
597 _ ("&Yes"), _ ("&No"), _ ("&Cancel quit"));
598 }
599 else
600 {
601 r = query_dialog (_ ("Quit"),
602 _ ("Midnight Commander is being shut down.\nSave modified file?"),
603 D_NORMAL, 2, _ ("&Yes"), _ ("&No"));
604
605 if (r == -1)
606 r = 1;
607 }
608
609 switch (r)
610 {
611 case 0:
612 return mcview_hexedit_save_changes (view) || mc_global.midnight_shutdown;
613 case 1:
614 mcview_hexedit_free_change_list (view);
615 return TRUE;
616 default:
617 return FALSE;
618 }
619 }
620
621
622
623
624
625 cb_ret_t
626 mcview_callback (Widget *w, Widget *sender, widget_msg_t msg, int parm, void *data)
627 {
628 WView *view = (WView *) w;
629 cb_ret_t i;
630
631 mcview_compute_areas (view);
632 mcview_update_bytes_per_line (view);
633
634 switch (msg)
635 {
636 case MSG_INIT:
637 if (mcview_is_in_panel (view))
638 add_hook (&select_file_hook, mcview_hook, view);
639 else
640 view->dpy_bbar_dirty = TRUE;
641 return MSG_HANDLED;
642
643 case MSG_DRAW:
644 mcview_display (view);
645 return MSG_HANDLED;
646
647 case MSG_CURSOR:
648 if (view->mode_flags.hex)
649 mcview_place_cursor (view);
650 return MSG_HANDLED;
651
652 case MSG_KEY:
653 i = mcview_handle_key (view, parm);
654 mcview_update (view);
655 return i;
656
657 case MSG_ACTION:
658 i = mcview_execute_cmd (view, parm);
659 mcview_update (view);
660 return i;
661
662 case MSG_FOCUS:
663 view->dpy_bbar_dirty = TRUE;
664
665 mcview_update (view);
666 return MSG_HANDLED;
667
668 case MSG_RESIZE:
669 widget_default_callback (w, NULL, MSG_RESIZE, 0, data);
670 mcview_resize (view);
671 return MSG_HANDLED;
672
673 case MSG_DESTROY:
674 if (mcview_is_in_panel (view))
675 {
676 delete_hook (&select_file_hook, mcview_hook);
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697 delete_hook (&idle_hook, mcview_hook);
698
699 if (mc_global.midnight_shutdown)
700 mcview_ok_to_quit (view);
701 }
702 mcview_done (view);
703 mcview_remove_ext_script (view);
704 return MSG_HANDLED;
705
706 default:
707 return widget_default_callback (w, sender, msg, parm, data);
708 }
709 }
710
711
712
713 cb_ret_t
714 mcview_dialog_callback (Widget *w, Widget *sender, widget_msg_t msg, int parm, void *data)
715 {
716 WDialog *h = DIALOG (w);
717 WView *view;
718
719 switch (msg)
720 {
721 case MSG_ACTION:
722
723
724
725
726 return mcview_execute_cmd (NULL, parm);
727
728 case MSG_VALIDATE:
729 view = (WView *) widget_find_by_type (w, mcview_callback);
730
731 widget_set_state (w, WST_ACTIVE, TRUE);
732 if (mcview_ok_to_quit (view))
733 dlg_close (h);
734 else
735 mcview_update (view);
736 return MSG_HANDLED;
737
738 default:
739 return dlg_default_callback (w, sender, msg, parm, data);
740 }
741 }
742
743