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