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