Lines 94-100
let icon =
Link Here
|
94 |
let icon = |
94 |
let icon = |
95 |
let p = GdkPixbuf.create ~width:48 ~height:48 ~has_alpha:true () in |
95 |
let p = GdkPixbuf.create ~width:48 ~height:48 ~has_alpha:true () in |
96 |
Gpointer.blit |
96 |
Gpointer.blit |
97 |
(Gpointer.region_of_bytes (Bytes.of_string Pixmaps.icon_data)) (GdkPixbuf.get_pixels p); |
97 |
~src:(Gpointer.region_of_bytes (Bytes.of_string Pixmaps.icon_data)) |
|
|
98 |
~dst:(GdkPixbuf.get_pixels p); |
98 |
p |
99 |
p |
99 |
|
100 |
|
100 |
let leftPtrWatch = |
101 |
let leftPtrWatch = |
Lines 119-131
type stateItem = { mutable ri : reconIte
Link Here
|
119 |
let theState = ref [||] |
120 |
let theState = ref [||] |
120 |
let unsynchronizedPaths = ref None |
121 |
let unsynchronizedPaths = ref None |
121 |
|
122 |
|
122 |
module IntSet = Set.Make (struct type t = int let compare = compare end) |
|
|
123 |
|
124 |
let current = ref IntSet.empty |
125 |
|
126 |
let currentRow () = |
127 |
if IntSet.cardinal !current = 1 then Some (IntSet.choose !current) else None |
128 |
|
129 |
(* ---- *) |
123 |
(* ---- *) |
130 |
|
124 |
|
131 |
let theToplevelWindow = ref None |
125 |
let theToplevelWindow = ref None |
Lines 591-601
let statistics () =
Link Here
|
591 |
let data_row = lst#append () in |
585 |
let data_row = lst#append () in |
592 |
ignore (lst#set data_row c_1 "File data written"); |
586 |
ignore (lst#set data_row c_1 "File data written"); |
593 |
(* |
587 |
(* |
594 |
ignore (t#event#connect#map (fun _ -> |
588 |
ignore (t#event#connect#map ~callback:(fun _ -> |
595 |
emission#activate true; |
589 |
emission#activate true; |
596 |
reception#activate true; |
590 |
reception#activate true; |
597 |
false)); |
591 |
false)); |
598 |
ignore (t#event#connect#unmap (fun _ -> |
592 |
ignore (t#event#connect#unmap ~callback:(fun _ -> |
599 |
emission#activate false; |
593 |
emission#activate false; |
600 |
reception#activate false; |
594 |
reception#activate false; |
601 |
false));*) |
595 |
false));*) |
Lines 1488-1494
let createProfile parent =
Link Here
|
1488 |
options#as_widget |
1482 |
options#as_widget |
1489 |
in |
1483 |
in |
1490 |
ignore |
1484 |
ignore |
1491 |
(assistant#connect#prepare (fun () -> |
1485 |
(assistant#connect#prepare ~callback:(fun () -> |
1492 |
if assistant#current_page = p && |
1486 |
if assistant#current_page = p && |
1493 |
not (Util.osType <> `Win32 || React.state askUnicode) |
1487 |
not (Util.osType <> `Win32 || React.state askUnicode) |
1494 |
then |
1488 |
then |
Lines 2697-2762
let createToplevelWindow () =
Link Here
|
2697 |
let ctx = mainWindowSW#misc#pango_context in |
2691 |
let ctx = mainWindowSW#misc#pango_context in |
2698 |
let metrics = ctx#get_metrics () in |
2692 |
let metrics = ctx#get_metrics () in |
2699 |
let h = GPango.to_pixels (metrics#ascent+metrics#descent) in |
2693 |
let h = GPango.to_pixels (metrics#ascent+metrics#descent) in |
2700 |
mainWindowSW#misc#set_size_request |
2694 |
toplevelWindow#set_default_height |
2701 |
~height:((h + 1) * (Prefs.read Uicommon.mainWindowHeight + 1) + 10) () |
2695 |
((h + 3) * (Prefs.read Uicommon.mainWindowHeight + 1) + 200) |
2702 |
in |
2696 |
in |
2703 |
let mainWindow = |
|
|
2704 |
GList.clist ~columns:5 ~titles_show:true |
2705 |
~selection_mode:`MULTIPLE ~packing:mainWindowSW#add () |
2706 |
in |
2707 |
(* |
2708 |
let cols = new GTree.column_list in |
2697 |
let cols = new GTree.column_list in |
2709 |
let c_replica1 = cols#add Gobject.Data.string in |
2698 |
let c_replica1 = cols#add Gobject.Data.string in |
2710 |
let c_action = cols#add Gobject.Data.gobject in |
2699 |
let c_action = cols#add Gobject.Data.gobject in |
2711 |
let c_replica2 = cols#add Gobject.Data.string in |
2700 |
let c_replica2 = cols#add Gobject.Data.string in |
2712 |
let c_status = cols#add Gobject.Data.string in |
2701 |
let c_status = cols#add Gobject.Data.gobject_option in |
|
|
2702 |
let c_statust = cols#add Gobject.Data.string in |
2713 |
let c_path = cols#add Gobject.Data.string in |
2703 |
let c_path = cols#add Gobject.Data.string in |
2714 |
let lst_store = GTree.list_store cols in |
2704 |
(*let c_rowid = cols#add Gobject.Data.uint in*) |
2715 |
let lst = |
2705 |
(* With current implementation the [list_store] view model and [theState] |
2716 |
GTree.view ~model:lst_store ~packing:(toplevelVBox#add) |
2706 |
array have one-to-one correspondence, so that list_store's tree path index |
2717 |
~headers_clickable:false () in |
2707 |
is the same as theState array index. |
2718 |
let s = Uicommon.roots2string () in |
2708 |
This changes when, for example, [tree_store] would be used instead of |
2719 |
ignore (lst#append_column |
2709 |
list_store, or a separate view-only sorting is implemented without sorting |
|
|
2710 |
the backing theState array. In that case, the column [c_rowid] must be |
2711 |
used to store the index of [theState] array in the view model. Tree path |
2712 |
index must not be used directly as [theState] array index and vice versa. *) |
2713 |
let mainWindowModel = GTree.list_store cols in |
2714 |
let mainWindow = |
2715 |
GTree.view ~model:mainWindowModel ~packing:(mainWindowSW#add) |
2716 |
~headers_clickable:false ~enable_search:false () in |
2717 |
mainWindow#selection#set_mode `MULTIPLE; |
2718 |
ignore (mainWindow#append_column |
2720 |
(GTree.view_column |
2719 |
(GTree.view_column |
2721 |
~title:(" " ^ Unicode.protect (String.sub s 0 12) ^ " ") |
2720 |
~title:(" ") |
2722 |
~renderer:(GTree.cell_renderer_text [], ["text", c_replica1]) ())); |
2721 |
~renderer:(GTree.cell_renderer_text [], ["text", c_replica1]) ())); |
2723 |
ignore (lst#append_column |
2722 |
ignore (mainWindow#append_column |
2724 |
(GTree.view_column ~title:" Action " |
2723 |
(GTree.view_column ~title:" Action " |
2725 |
~renderer:(GTree.cell_renderer_pixbuf [], ["pixbuf", c_action]) ())); |
2724 |
~renderer:(GTree.cell_renderer_pixbuf [], ["pixbuf", c_action]) ())); |
2726 |
ignore (lst#append_column |
2725 |
ignore (mainWindow#append_column |
2727 |
(GTree.view_column |
2726 |
(GTree.view_column |
2728 |
~title:(" " ^ Unicode.protect (String.sub s 15 12) ^ " ") |
2727 |
~title:(" ") |
2729 |
~renderer:(GTree.cell_renderer_text [], ["text", c_replica2]) ())); |
2728 |
~renderer:(GTree.cell_renderer_text [], ["text", c_replica2]) ())); |
2730 |
ignore (lst#append_column |
2729 |
let status_view_col = GTree.view_column ~title:" Status " |
2731 |
(GTree.view_column ~title:" Status " ())); |
2730 |
~renderer:(GTree.cell_renderer_pixbuf [], ["pixbuf", c_status]) () in |
2732 |
ignore (lst#append_column |
2731 |
let status_t_rend = GTree.cell_renderer_text [] in |
|
|
2732 |
status_view_col#pack ~expand:false ~from:`END status_t_rend; |
2733 |
status_view_col#add_attribute status_t_rend "text" c_statust; |
2734 |
ignore (mainWindow#append_column status_view_col); |
2735 |
ignore (mainWindow#append_column |
2733 |
(GTree.view_column ~title:" Path " |
2736 |
(GTree.view_column ~title:" Path " |
2734 |
~renderer:(GTree.cell_renderer_text [], ["text", c_path]) ())); |
2737 |
~renderer:(GTree.cell_renderer_text [], ["text", c_path]) ())); |
2735 |
*) |
|
|
2736 |
|
2737 |
(* |
2738 |
let status_width = |
2739 |
let font = mainWindow#misc#style#font in |
2740 |
4 + max (max (Gdk.Font.string_width font "working") |
2741 |
(Gdk.Font.string_width font "skipped")) |
2742 |
(Gdk.Font.string_width font " Action ") |
2743 |
in |
2744 |
*) |
2745 |
mainWindow#set_column ~justification:`CENTER 1; |
2746 |
mainWindow#set_column |
2747 |
~justification:`CENTER (*~auto_resize:false ~width:status_width*) 3; |
2748 |
|
2738 |
|
2749 |
let setMainWindowColumnHeaders s = |
2739 |
let setMainWindowColumnHeaders s = |
2750 |
Array.iteri |
2740 |
Array.iteri |
2751 |
(fun i data -> |
2741 |
(fun i data -> |
2752 |
mainWindow#set_column |
2742 |
(mainWindow#get_column i)#set_title data) |
2753 |
~title_active:false ~auto_resize:true ~title:data i) |
|
|
2754 |
[| " " ^ Unicode.protect (String.sub s 0 12) ^ " "; " Action "; |
2743 |
[| " " ^ Unicode.protect (String.sub s 0 12) ^ " "; " Action "; |
2755 |
" " ^ Unicode.protect (String.sub s 15 12) ^ " "; " Status "; |
2744 |
" " ^ Unicode.protect (String.sub s 15 12) ^ " "; " Status "; |
2756 |
" Path" |]; |
2745 |
" Path" |]; |
2757 |
sizeMainWindow () |
|
|
2758 |
in |
2746 |
in |
2759 |
setMainWindowColumnHeaders " "; |
2747 |
sizeMainWindow (); |
|
|
2748 |
|
2749 |
(* See above for comment about tree path index and [theState] array index |
2750 |
equivalence. *) |
2751 |
let siOfRow f path = |
2752 |
let row = mainWindowModel#get_iter path in |
2753 |
let i = (GTree.Path.get_indices path).(0) in |
2754 |
(*let i = mainWindowModel#get ~row ~column:c_rowid in*) |
2755 |
f i !theState.(i) row |
2756 |
in |
2757 |
let rowOfSi i = GTree.Path.create [i] in |
2758 |
let currentNumberRows () = mainWindow#selection#count_selected_rows in |
2759 |
let currentRow () = |
2760 |
match currentNumberRows () with |
2761 |
| 1 -> siOfRow (fun i si row -> Some (i, !theState.(i), row)) |
2762 |
(List.hd mainWindow#selection#get_selected_rows) |
2763 |
| _ -> None |
2764 |
in |
2765 |
let currentSelectedIter f = |
2766 |
Safelist.iter (fun r -> siOfRow f r) |
2767 |
mainWindow#selection#get_selected_rows |
2768 |
in |
2769 |
let currentSelectedFold f a = |
2770 |
Safelist.fold_left (fun a r -> siOfRow (fun _ si _ -> f a si) r) |
2771 |
a mainWindow#selection#get_selected_rows |
2772 |
in |
2773 |
let currentSelectedExists pred = |
2774 |
Safelist.exists (fun r -> siOfRow (fun _ si _ -> pred si) r) |
2775 |
mainWindow#selection#get_selected_rows |
2776 |
in |
2760 |
|
2777 |
|
2761 |
(********************************************************************* |
2778 |
(********************************************************************* |
2762 |
Create the details window |
2779 |
Create the details window |
Lines 2767-2781
let createToplevelWindow () =
Link Here
|
2767 |
match currentRow () with |
2784 |
match currentRow () with |
2768 |
None -> |
2785 |
None -> |
2769 |
None |
2786 |
None |
2770 |
| Some row -> |
2787 |
| Some (_, si, _) -> |
2771 |
let path = Path.toString !theState.(row).ri.path1 in |
2788 |
let path = Path.toString si.ri.path1 in |
2772 |
match !theState.(row).whatHappened with |
2789 |
match si.whatHappened with |
2773 |
Some (Util.Failed _, Some det) -> |
2790 |
Some (Util.Failed _, Some det) -> |
2774 |
Some ("Merge execution details for file" ^ |
2791 |
Some ("Merge execution details for file" ^ |
2775 |
transcodeFilename path, |
2792 |
transcodeFilename path, |
2776 |
det) |
2793 |
det) |
2777 |
| _ -> |
2794 |
| _ -> |
2778 |
match !theState.(row).ri.replicas with |
2795 |
match si.ri.replicas with |
2779 |
Problem err -> |
2796 |
Problem err -> |
2780 |
Some ("Errors for file " ^ transcodeFilename path, err) |
2797 |
Some ("Errors for file " ^ transcodeFilename path, err) |
2781 |
| Different diff -> |
2798 |
| Different diff -> |
Lines 2788-2794
let createToplevelWindow () =
Link Here
|
2788 |
(prefix "[root 2]: " diff.errors2) |
2805 |
(prefix "[root 2]: " diff.errors2) |
2789 |
in |
2806 |
in |
2790 |
let errors = |
2807 |
let errors = |
2791 |
match !theState.(row).whatHappened with |
2808 |
match si.whatHappened with |
2792 |
Some (Util.Failed err, _) -> err :: errors |
2809 |
Some (Util.Failed err, _) -> err :: errors |
2793 |
| _ -> errors |
2810 |
| _ -> errors |
2794 |
in |
2811 |
in |
Lines 2817-2850
let createToplevelWindow () =
Link Here
|
2817 |
|
2834 |
|
2818 |
let updateButtons () = |
2835 |
let updateButtons () = |
2819 |
if not !busy then |
2836 |
if not !busy then |
2820 |
let actionPossible row = |
2837 |
let actionPossible si = |
2821 |
let si = !theState.(row) in |
|
|
2822 |
match si.whatHappened, si.ri.replicas with |
2838 |
match si.whatHappened, si.ri.replicas with |
2823 |
None, Different _ -> true |
2839 |
None, Different _ -> true |
2824 |
| _ -> false |
2840 |
| _ -> false |
2825 |
in |
2841 |
in |
2826 |
match currentRow () with |
2842 |
match currentRow () with |
2827 |
None -> |
2843 |
None -> |
2828 |
grSet grAction (IntSet.exists actionPossible !current); |
2844 |
grSet grAction (currentSelectedExists actionPossible); |
2829 |
grSet grDiff false; |
2845 |
grSet grDiff false; |
2830 |
grSet grDetail false |
2846 |
grSet grDetail false |
2831 |
| Some row -> |
2847 |
| Some (_, si, _) -> |
2832 |
let details = |
2848 |
let details = |
2833 |
begin match !theState.(row).ri.replicas with |
2849 |
begin match si.ri.replicas with |
2834 |
Different diff -> diff.errors1 <> [] || diff.errors2 <> [] |
2850 |
Different diff -> diff.errors1 <> [] || diff.errors2 <> [] |
2835 |
| Problem _ -> true |
2851 |
| Problem _ -> true |
2836 |
end |
2852 |
end |
2837 |
|| |
2853 |
|| |
2838 |
begin match !theState.(row).whatHappened with |
2854 |
begin match si.whatHappened with |
2839 |
Some (Util.Failed _, _) -> true |
2855 |
Some (Util.Failed _, _) -> true |
2840 |
| _ -> false |
2856 |
| _ -> false |
2841 |
end |
2857 |
end |
2842 |
in |
2858 |
in |
2843 |
grSet grDetail details; |
2859 |
grSet grDetail details; |
2844 |
let activateAction = actionPossible row in |
2860 |
let activateAction = actionPossible si in |
2845 |
let activateDiff = |
2861 |
let activateDiff = |
2846 |
activateAction && |
2862 |
activateAction && |
2847 |
match !theState.(row).ri.replicas with |
2863 |
match si.ri.replicas with |
2848 |
Different {rc1 = {typ = `FILE}; rc2 = {typ = `FILE}} -> |
2864 |
Different {rc1 = {typ = `FILE}; rc2 = {typ = `FILE}} -> |
2849 |
true |
2865 |
true |
2850 |
| _ -> |
2866 |
| _ -> |
Lines 2855-2868
let createToplevelWindow () =
Link Here
|
2855 |
in |
2871 |
in |
2856 |
|
2872 |
|
2857 |
let makeRowVisible row = |
2873 |
let makeRowVisible row = |
2858 |
if mainWindow#row_is_visible row <> `FULL then begin |
2874 |
mainWindow#scroll_to_cell row status_view_col (* just a dummy column *) |
2859 |
let adj = mainWindow#vadjustment in |
2875 |
in |
2860 |
let upper = adj#upper and lower = adj#lower in |
|
|
2861 |
let v = |
2862 |
float row /. float (mainWindow#rows + 1) *. (upper-.lower) +. lower |
2863 |
in |
2864 |
adj#set_value (min v (upper -. adj#page_size)); |
2865 |
end in |
2866 |
|
2876 |
|
2867 |
(* |
2877 |
(* |
2868 |
let makeFirstUnfinishedVisible pRiInFocus = |
2878 |
let makeFirstUnfinishedVisible pRiInFocus = |
Lines 2880-2899
let createToplevelWindow () =
Link Here
|
2880 |
begin match currentRow () with |
2890 |
begin match currentRow () with |
2881 |
None -> |
2891 |
None -> |
2882 |
detailsWindow#buffer#set_text "" |
2892 |
detailsWindow#buffer#set_text "" |
2883 |
| Some row -> |
2893 |
| Some (_, si, _) -> |
2884 |
(* makeRowVisible row;*) |
|
|
2885 |
let (formated, details) = |
2894 |
let (formated, details) = |
2886 |
match !theState.(row).whatHappened with |
2895 |
match si.whatHappened with |
2887 |
| Some(Util.Failed(s), _) -> |
2896 |
| Some(Util.Failed(s), _) -> |
2888 |
(false, s) |
2897 |
(false, s) |
2889 |
| None | Some(Util.Succeeded, _) -> |
2898 |
| None | Some(Util.Succeeded, _) -> |
2890 |
match !theState.(row).ri.replicas with |
2899 |
match si.ri.replicas with |
2891 |
Problem _ -> |
2900 |
Problem _ -> |
2892 |
(false, Uicommon.details2string !theState.(row).ri " ") |
2901 |
(false, Uicommon.details2string si.ri " ") |
2893 |
| Different _ -> |
2902 |
| Different _ -> |
2894 |
(true, Uicommon.details2string !theState.(row).ri " ") |
2903 |
(true, Uicommon.details2string si.ri " ") |
2895 |
in |
2904 |
in |
2896 |
let path = Path.toString !theState.(row).ri.path1 in |
2905 |
let path = Path.toString si.ri.path1 in |
2897 |
detailsWindow#buffer#set_text ""; |
2906 |
detailsWindow#buffer#set_text ""; |
2898 |
detailsWindow#buffer#insert ~tags:[detailsWindowPath] |
2907 |
detailsWindow#buffer#insert ~tags:[detailsWindowPath] |
2899 |
(transcodeFilename path); |
2908 |
(transcodeFilename path); |
Lines 2948-3030
let createToplevelWindow () =
Link Here
|
2948 |
Functions used to print in the main window |
2957 |
Functions used to print in the main window |
2949 |
*********************************************************************) |
2958 |
*********************************************************************) |
2950 |
let delayUpdates = ref false in |
2959 |
let delayUpdates = ref false in |
2951 |
let hasFocus = ref false in |
|
|
2952 |
|
2960 |
|
2953 |
let select i scroll = |
2961 |
let select row scroll = |
2954 |
if !hasFocus then begin |
2962 |
delayUpdates := true; |
2955 |
(* If we have the focus, we move the focus row directely *) |
2963 |
mainWindow#selection#unselect_all (); |
2956 |
if scroll then begin |
2964 |
mainWindow#selection#select_path row; |
2957 |
let r = mainWindow#rows in |
2965 |
mainWindow#set_cursor row status_view_col (* just a dummy column *); |
2958 |
let p = if r < 2 then 0. else (float i +. 0.5) /. float (r - 1) in |
2966 |
delayUpdates := false; |
2959 |
mainWindow#scroll_vertical `JUMP (min p 1.) |
2967 |
if scroll then makeRowVisible row; |
2960 |
end; |
2968 |
updateDetails () |
2961 |
if IntSet.is_empty !current then mainWindow#select i 0 |
|
|
2962 |
end else begin |
2963 |
(* If we don't have the focus, we just move the selection. |
2964 |
We delay updates to make sure not to change the button |
2965 |
states unnecessarily (which could result in a button |
2966 |
losing the focus). *) |
2967 |
delayUpdates := true; |
2968 |
mainWindow#unselect_all (); |
2969 |
mainWindow#select i 0; |
2970 |
delayUpdates := false; |
2971 |
if scroll then makeRowVisible i; |
2972 |
updateDetails () |
2973 |
end |
2974 |
in |
2969 |
in |
2975 |
ignore (mainWindow#event#connect#focus_in ~callback: |
2970 |
let selectI i scroll = select (rowOfSi i) scroll in |
2976 |
(fun _ -> |
2971 |
|
2977 |
hasFocus := true; |
2972 |
ignore (mainWindow#selection#connect#changed ~callback: |
2978 |
(* Adjust the focus row. We cannot do it immediately, |
2973 |
(fun () -> if not !delayUpdates then updateDetails ())); |
2979 |
otherwise the focus row is not drawn correctly. *) |
|
|
2980 |
ignore (GMain.Idle.add (fun () -> |
2981 |
begin match currentRow () with |
2982 |
Some i -> select i false |
2983 |
| None -> () |
2984 |
end; |
2985 |
false)); |
2986 |
false)); |
2987 |
ignore (mainWindow#event#connect#focus_out ~callback: |
2988 |
(fun _ -> hasFocus := false; false)); |
2989 |
|
2990 |
ignore (mainWindow#connect#select_row ~callback: |
2991 |
(fun ~row ~column ~event -> |
2992 |
current := IntSet.add row !current; |
2993 |
if not !delayUpdates then updateDetails ())); |
2994 |
ignore (mainWindow#connect#unselect_row ~callback: |
2995 |
(fun ~row ~column ~event -> |
2996 |
current := IntSet.remove row !current; |
2997 |
if not !delayUpdates then updateDetails ())); |
2998 |
|
2974 |
|
2999 |
let nextInteresting () = |
2975 |
let nextInteresting () = |
3000 |
let l = Array.length !theState in |
2976 |
let l = Array.length !theState in |
3001 |
let start = match currentRow () with Some i -> i + 1 | None -> 0 in |
2977 |
let start = match currentRow () with Some (i, _, _) -> i + 1 | None -> 0 in |
3002 |
let rec loop i = |
2978 |
let rec loop i = |
3003 |
if i < l then |
2979 |
if i < l then |
3004 |
match !theState.(i).ri.replicas with |
2980 |
match !theState.(i).ri.replicas with |
3005 |
Different {direction = dir} |
2981 |
Different {direction = dir} |
3006 |
when not (Prefs.read Uicommon.auto) || isConflict dir -> |
2982 |
when not (Prefs.read Uicommon.auto) || isConflict dir -> |
3007 |
select i true |
2983 |
selectI i true |
3008 |
| _ -> |
2984 |
| _ -> |
3009 |
loop (i + 1) in |
2985 |
loop (i + 1) in |
3010 |
loop start in |
2986 |
loop start in |
3011 |
let selectSomethingIfPossible () = |
2987 |
let selectSomethingIfPossible () = |
3012 |
if IntSet.is_empty !current then nextInteresting () in |
2988 |
if currentNumberRows () = 0 then nextInteresting () in |
3013 |
|
2989 |
|
3014 |
let columnsOf i = |
2990 |
let columnsOf si = |
3015 |
let oldPath = if i = 0 then Path.empty else !theState.(i-1).ri.path1 in |
2991 |
let oldPath = Path.empty in |
3016 |
let status = |
2992 |
let status = |
3017 |
match !theState.(i).ri.replicas with |
2993 |
match si.ri.replicas with |
3018 |
Different {direction = Conflict _} | Problem _ -> |
2994 |
Different {direction = Conflict _} | Problem _ -> |
3019 |
NoStatus |
2995 |
NoStatus |
3020 |
| _ -> |
2996 |
| _ -> |
3021 |
match !theState.(i).whatHappened with |
2997 |
match si.whatHappened with |
3022 |
None -> NoStatus |
2998 |
None -> NoStatus |
3023 |
| Some (Util.Succeeded, _) -> Done |
2999 |
| Some (Util.Succeeded, _) -> Done |
3024 |
| Some (Util.Failed _, _) -> Failed |
3000 |
| Some (Util.Failed _, _) -> Failed |
3025 |
in |
3001 |
in |
3026 |
let (r1, action, r2, path) = |
3002 |
let (r1, action, r2, path) = |
3027 |
Uicommon.reconItem2stringList oldPath !theState.(i).ri in |
3003 |
Uicommon.reconItem2stringList oldPath si.ri in |
3028 |
(r1, action, r2, status, path) |
3004 |
(r1, action, r2, status, path) |
3029 |
in |
3005 |
in |
3030 |
|
3006 |
|
Lines 3037-3043
let createToplevelWindow () =
Link Here
|
3037 |
let blackPixel = "000000" in |
3013 |
let blackPixel = "000000" in |
3038 |
*) |
3014 |
*) |
3039 |
let buildPixmap p = |
3015 |
let buildPixmap p = |
3040 |
GDraw.pixmap_from_xpm_d ~window:toplevelWindow ~data:p () in |
3016 |
GdkPixbuf.from_xpm_data p in |
3041 |
let buildPixmaps f c1 = |
3017 |
let buildPixmaps f c1 = |
3042 |
(buildPixmap (f c1), buildPixmap (f lightbluePixel)) in |
3018 |
(buildPixmap (f c1), buildPixmap (f lightbluePixel)) in |
3043 |
|
3019 |
|
Lines 3056-3062
let createToplevelWindow () =
Link Here
|
3056 |
let mergeLogoBlack = buildPixmap (Pixmaps.mergeLogo blackPixel) in |
3032 |
let mergeLogoBlack = buildPixmap (Pixmaps.mergeLogo blackPixel) in |
3057 |
*) |
3033 |
*) |
3058 |
|
3034 |
|
3059 |
let displayArrow i j action = |
3035 |
let getArrow j action = |
3060 |
let changedFromDefault = match !theState.(j).ri.replicas with |
3036 |
let changedFromDefault = match !theState.(j).ri.replicas with |
3061 |
Different diff -> diff.direction <> diff.default_direction |
3037 |
Different diff -> diff.direction <> diff.default_direction |
3062 |
| _ -> false in |
3038 |
| _ -> false in |
Lines 3072-3144
let createToplevelWindow () =
Link Here
|
3072 |
| Uicommon.ARtoL true -> orangeLeftArrow |
3048 |
| Uicommon.ARtoL true -> orangeLeftArrow |
3073 |
| Uicommon.AMerge -> mergeLogo |
3049 |
| Uicommon.AMerge -> mergeLogo |
3074 |
in |
3050 |
in |
3075 |
mainWindow#set_cell ~pixmap:(sel pixmaps) i 1 |
3051 |
sel pixmaps |
3076 |
in |
3052 |
in |
3077 |
|
3053 |
|
3078 |
|
3054 |
|
3079 |
let displayStatusIcon i status = |
3055 |
let getStatusIcon = function |
3080 |
match status with |
3056 |
| Failed -> Some failedIcon |
3081 |
| Failed -> mainWindow#set_cell ~pixmap:failedIcon i 3 |
3057 |
| Done -> Some doneIcon |
3082 |
| Done -> mainWindow#set_cell ~pixmap:doneIcon i 3 |
3058 |
| NoStatus -> None in |
3083 |
| NoStatus -> mainWindow#set_cell ~text:" " i 3 in |
3059 |
|
|
|
3060 |
let displayRowAction row i action = |
3061 |
mainWindowModel#set ~row ~column:c_action (getArrow i action) in |
3062 |
let displayRowStatus row status = |
3063 |
mainWindowModel#set ~row ~column:c_status (getStatusIcon status); |
3064 |
if status <> NoStatus then |
3065 |
mainWindowModel#set ~row ~column:c_statust "" in |
3066 |
let displayRowPath row path = |
3067 |
mainWindowModel#set ~row ~column:c_path (transcodeFilename path) in |
3068 |
let displayRow row i r1 r2 action status path = |
3069 |
mainWindowModel#set ~row ~column:c_replica1 r1; |
3070 |
mainWindowModel#set ~row ~column:c_replica2 r2; |
3071 |
displayRowAction row i action; |
3072 |
displayRowStatus row status; |
3073 |
displayRowPath row path; |
3074 |
(*mainWindowModel#set ~row ~column:c_rowid i;*) |
3075 |
in |
3084 |
|
3076 |
|
3085 |
let displayMain() = |
3077 |
let displayMain() = |
3086 |
(* The call to mainWindow#clear below side-effect current, |
3078 |
(* The call to mainWindow#clear below side-effect current, |
3087 |
so we save the current value before we clear out the main window and |
3079 |
so we save the current value before we clear out the main window and |
3088 |
rebuild it. *) |
3080 |
rebuild it. *) |
3089 |
let savedCurrent = currentRow () in |
3081 |
let savedCurrent = mainWindow#selection#get_selected_rows in |
3090 |
mainWindow#freeze (); |
3082 |
mainWindow#set_model None; |
3091 |
mainWindow#clear (); |
3083 |
mainWindowModel#clear (); |
3092 |
for i = Array.length !theState - 1 downto 0 do |
3084 |
let tot = Array.length !theState - 1 in |
3093 |
let (r1, action, r2, status, path) = columnsOf i in |
3085 |
let totf = float_of_int (tot + 1) in |
3094 |
(* |
3086 |
progressBar#set_text (Printf.sprintf "Displaying %i items..." (tot + 1)); |
3095 |
let row = lst_store#prepend () in |
3087 |
for i = 0 to tot do |
3096 |
lst_store#set ~row ~column:c_replica1 r1; |
3088 |
if i mod 1024 = 0 then begin |
3097 |
lst_store#set ~row ~column:c_replica2 r2; |
3089 |
progressBar#set_fraction (max 0. (min 1. ((float_of_int i) /. totf))); |
3098 |
lst_store#set ~row ~column:c_status status; |
3090 |
gtk_sync false |
3099 |
lst_store#set ~row ~column:c_path path; |
3091 |
end; |
3100 |
*) |
3092 |
|
3101 |
ignore (mainWindow#prepend |
3093 |
let (r1, action, r2, status, path) = columnsOf !theState.(i) in |
3102 |
[ r1; ""; r2; ""; transcodeFilename path ]); |
3094 |
|
3103 |
displayArrow 0 i action; |
3095 |
let row = mainWindowModel#append () in |
3104 |
displayStatusIcon i status |
3096 |
displayRow row i r1 r2 action status path; |
3105 |
done; |
3097 |
done; |
3106 |
debug (fun()-> Util.msg "reset current to %s\n" |
3098 |
mainWindow#set_model (Some mainWindowModel#coerce); |
3107 |
(match savedCurrent with None->"None" | Some(i) -> string_of_int i)); |
3099 |
match savedCurrent with |
3108 |
begin match savedCurrent with |
3100 |
| [] -> selectSomethingIfPossible () |
3109 |
None -> selectSomethingIfPossible () |
3101 |
| [x] -> select x true |
3110 |
| Some idx -> select idx true |
3102 |
| _ -> Safelist.iter (fun p -> mainWindow#selection#select_path p) savedCurrent; |
3111 |
end; |
3103 |
|
3112 |
mainWindow#thaw (); |
3104 |
progressBar#set_text ""; progressBar#set_fraction 0.; |
3113 |
updateDetails (); (* Do we need this line? *) |
3105 |
updateDetails (); (* Do we need this line? *) |
3114 |
in |
3106 |
in |
3115 |
|
3107 |
|
3116 |
let redisplay i = |
3108 |
let redisplay i si iter = |
3117 |
let (r1, action, r2, status, path) = columnsOf i in |
3109 |
let (_, action, _, status, path) = columnsOf si in |
3118 |
(*mainWindow#freeze ();*) |
3110 |
displayRowAction iter i action; |
3119 |
mainWindow#set_cell ~text:r1 i 0; |
3111 |
displayRowStatus iter status; |
3120 |
displayArrow i i action; |
3112 |
if status = Failed then displayRowPath iter (path ^ |
3121 |
mainWindow#set_cell ~text:r2 i 2; |
3113 |
" [failed: click on this line for details]"); |
3122 |
displayStatusIcon i status; |
|
|
3123 |
mainWindow#set_cell ~text:(transcodeFilename path) i 4; |
3124 |
if status = Failed then |
3125 |
mainWindow#set_cell |
3126 |
~text:(transcodeFilename path ^ |
3127 |
" [failed: click on this line for details]") i 4; |
3128 |
(*mainWindow#thaw ();*) |
3129 |
if currentRow () = Some i then begin |
3130 |
updateDetails (); updateButtons () |
3131 |
end |
3132 |
in |
3114 |
in |
3133 |
|
3115 |
|
3134 |
let fastRedisplay i = |
3116 |
let fastRedisplay i = |
3135 |
let (r1, action, r2, status, path) = columnsOf i in |
3117 |
let si = !theState.(i) in |
3136 |
displayStatusIcon i status; |
3118 |
let iter = mainWindowModel#get_iter (rowOfSi i) in |
3137 |
if status = Failed then |
3119 |
let (_, action, _, status, path) = columnsOf si in |
3138 |
mainWindow#set_cell |
3120 |
displayRowStatus iter status; |
3139 |
~text:(transcodeFilename path ^ |
3121 |
if status = Failed then begin |
3140 |
" [failed: click on this line for details]") i 4; |
3122 |
displayRowPath iter (path ^ |
3141 |
if currentRow () = Some i then updateDetails (); |
3123 |
" [failed: click on this line for details]"); |
|
|
3124 |
match currentRow () with |
3125 |
| Some (_, csi, _) when csi = si -> updateDetails () |
3126 |
| Some _ | None -> () |
3127 |
end |
3128 |
in |
3129 |
|
3130 |
let updateRowStatus i newstatus = |
3131 |
let row = mainWindowModel#get_iter (rowOfSi i) in |
3132 |
let oldstatus = mainWindowModel#get ~row ~column:c_statust in |
3133 |
if oldstatus <> newstatus then mainWindowModel#set ~row ~column:c_statust newstatus |
3142 |
in |
3134 |
in |
3143 |
|
3135 |
|
3144 |
let totalBytesToTransfer = ref Uutil.Filesize.zero in |
3136 |
let totalBytesToTransfer = ref Uutil.Filesize.zero in |
Lines 3221-3228
lst_store#set ~row ~column:c_path path;
Link Here
|
3221 |
else Util.percent2string (Uutil.Filesize.percentageOfTotalSize b len) in |
3213 |
else Util.percent2string (Uutil.Filesize.percentageOfTotalSize b len) in |
3222 |
let dbg = if Trace.enabled "progress" then dbg ^ "/" else "" in |
3214 |
let dbg = if Trace.enabled "progress" then dbg ^ "/" else "" in |
3223 |
let newstatus = dbg ^ newstatus in |
3215 |
let newstatus = dbg ^ newstatus in |
3224 |
let oldstatus = mainWindow#cell_text i 3 in |
3216 |
updateRowStatus i newstatus; |
3225 |
if oldstatus <> newstatus then mainWindow#set_cell ~text:newstatus i 3; |
|
|
3226 |
showGlobalProgress bytes; |
3217 |
showGlobalProgress bytes; |
3227 |
gtk_sync false; |
3218 |
gtk_sync false; |
3228 |
begin match item.ri.replicas with |
3219 |
begin match item.ri.replicas with |
Lines 3259-3284
lst_store#set ~row ~column:c_path path;
Link Here
|
3259 |
let lst = Array.to_list !theState in |
3250 |
let lst = Array.to_list !theState in |
3260 |
(* FIX: we should actually test whether any prefix is now ignored *) |
3251 |
(* FIX: we should actually test whether any prefix is now ignored *) |
3261 |
let keep sI = not (Globals.shouldIgnore sI.ri.path1) in |
3252 |
let keep sI = not (Globals.shouldIgnore sI.ri.path1) in |
3262 |
begin match currentRow () with |
3253 |
theState := Array.of_list (Safelist.filter keep lst); |
3263 |
None -> |
|
|
3264 |
theState := Array.of_list (Safelist.filter keep lst); |
3265 |
current := IntSet.empty |
3266 |
| Some index -> |
3267 |
let i = ref index in |
3268 |
let l = ref [] in |
3269 |
Array.iteri |
3270 |
(fun j sI -> if keep sI then l := sI::!l |
3271 |
else if j < !i then decr i) |
3272 |
!theState; |
3273 |
theState := Array.of_list (Safelist.rev !l); |
3274 |
current := |
3275 |
if !l = [] then IntSet.empty |
3276 |
else IntSet.singleton (min (!i) ((Array.length !theState) - 1)) |
3277 |
end; |
3278 |
displayMain() in |
3254 |
displayMain() in |
3279 |
|
3255 |
|
3280 |
let sortAndRedisplay () = |
3256 |
let sortAndRedisplay () = |
3281 |
current := IntSet.empty; |
|
|
3282 |
let compareRIs = Sortri.compareReconItems() in |
3257 |
let compareRIs = Sortri.compareReconItems() in |
3283 |
Array.stable_sort (fun si1 si2 -> compareRIs si1.ri si2.ri) !theState; |
3258 |
Array.stable_sort (fun si1 si2 -> compareRIs si1.ri si2.ri) !theState; |
3284 |
displayMain() in |
3259 |
displayMain() in |
Lines 3298-3304
lst_store#set ~row ~column:c_path path;
Link Here
|
3298 |
let clearMainWindow () = |
3273 |
let clearMainWindow () = |
3299 |
grDisactivateAll (); |
3274 |
grDisactivateAll (); |
3300 |
make_busy toplevelWindow; |
3275 |
make_busy toplevelWindow; |
3301 |
mainWindow#clear(); |
3276 |
mainWindowModel#clear (); |
3302 |
detailsWindow#buffer#set_text "" |
3277 |
detailsWindow#buffer#set_text "" |
3303 |
in |
3278 |
in |
3304 |
|
3279 |
|
Lines 3340-3346
lst_store#set ~row ~column:c_path path;
Link Here
|
3340 |
reconItemList); |
3315 |
reconItemList); |
3341 |
unsynchronizedPaths := |
3316 |
unsynchronizedPaths := |
3342 |
Some (Safelist.map (fun ri -> ri.path1) reconItemList, []); |
3317 |
Some (Safelist.map (fun ri -> ri.path1) reconItemList, []); |
3343 |
current := IntSet.empty; |
3318 |
progressBarPulse := false; sync_action := None; displayGlobalProgress 0.; |
3344 |
displayMain(); |
3319 |
displayMain(); |
3345 |
progressBarPulse := false; sync_action := None; displayGlobalProgress 0.; |
3320 |
progressBarPulse := false; sync_action := None; displayGlobalProgress 0.; |
3346 |
stopStats (); |
3321 |
stopStats (); |
Lines 3374-3382
lst_store#set ~row ~column:c_path path;
Link Here
|
3374 |
*********************************************************************) |
3349 |
*********************************************************************) |
3375 |
let addRegExpByPath pathfunc = |
3350 |
let addRegExpByPath pathfunc = |
3376 |
Util.StringSet.iter (fun pat -> Uicommon.addIgnorePattern pat) |
3351 |
Util.StringSet.iter (fun pat -> Uicommon.addIgnorePattern pat) |
3377 |
(IntSet.fold |
3352 |
(currentSelectedFold |
3378 |
(fun i s -> Util.StringSet.add (pathfunc !theState.(i).ri.path1) s) |
3353 |
(fun s si -> Util.StringSet.add (pathfunc si.ri.path1) s) |
3379 |
!current Util.StringSet.empty); |
3354 |
Util.StringSet.empty); |
3380 |
ignoreAndRedisplay () |
3355 |
ignoreAndRedisplay () |
3381 |
in |
3356 |
in |
3382 |
grAdd grAction |
3357 |
grAdd grAction |
Lines 3671-3719
lst_store#set ~row ~column:c_path path;
Link Here
|
3671 |
(********************************************************************* |
3646 |
(********************************************************************* |
3672 |
Buttons for -->, M, <--, Skip |
3647 |
Buttons for -->, M, <--, Skip |
3673 |
*********************************************************************) |
3648 |
*********************************************************************) |
3674 |
let doActionOnRow f i = |
3649 |
let doActionOnRow f i theSI iter = |
3675 |
let theSI = !theState.(i) in |
|
|
3676 |
begin match theSI.whatHappened, theSI.ri.replicas with |
3650 |
begin match theSI.whatHappened, theSI.ri.replicas with |
3677 |
None, Different diff -> |
3651 |
None, Different diff -> |
3678 |
f theSI.ri diff; |
3652 |
f theSI.ri diff; |
3679 |
redisplay i |
3653 |
redisplay i theSI iter |
3680 |
| _ -> |
3654 |
| _ -> |
3681 |
() |
3655 |
() |
3682 |
end |
3656 |
end |
3683 |
in |
3657 |
in |
3684 |
let updateCurrent () = |
|
|
3685 |
let n = mainWindow#rows in |
3686 |
(* This has quadratic complexity, thus we only do it when |
3687 |
the list is not too long... *) |
3688 |
if n < 300 then begin |
3689 |
current := IntSet.empty; |
3690 |
for i = 0 to n -1 do |
3691 |
if mainWindow#get_row_state i = `SELECTED then |
3692 |
current := IntSet.add i !current |
3693 |
done |
3694 |
end |
3695 |
in |
3696 |
let doAction f = |
3658 |
let doAction f = |
3697 |
(* FIX: when the window does not have the focus, we are not notified |
|
|
3698 |
immediately from changes to the list of selected items. So, we |
3699 |
update our view of the current selection here. *) |
3700 |
updateCurrent (); |
3701 |
match currentRow () with |
3659 |
match currentRow () with |
3702 |
Some i -> |
3660 |
Some (i, si, iter) -> |
3703 |
doActionOnRow f i; |
3661 |
doActionOnRow f i si iter; |
3704 |
nextInteresting () |
3662 |
nextInteresting () |
3705 |
| None -> |
3663 |
| None -> |
3706 |
(* FIX: this is quadratic when all items are selected. |
3664 |
currentSelectedIter (fun i si iter -> doActionOnRow f i si iter); |
3707 |
We could trigger a redisplay instead, but it may be tricky |
3665 |
updateDetails () |
3708 |
to preserve the set of selected rows, the focus row and the |
|
|
3709 |
scrollbar position. |
3710 |
The right fix is probably to move to a GTree.column_list. *) |
3711 |
let n = IntSet.cardinal !current in |
3712 |
if n > 0 then begin |
3713 |
if n > 20 then mainWindow#freeze (); |
3714 |
IntSet.iter (fun i -> doActionOnRow f i) !current; |
3715 |
if n > 20 then mainWindow#thaw () |
3716 |
end |
3717 |
in |
3666 |
in |
3718 |
let leftAction _ = |
3667 |
let leftAction _ = |
3719 |
doAction (fun _ diff -> diff.direction <- Replica2ToReplica1) in |
3668 |
doAction (fun _ diff -> diff.direction <- Replica2ToReplica1) in |
Lines 3764-3772
lst_store#set ~row ~column:c_path path;
Link Here
|
3764 |
*********************************************************************) |
3713 |
*********************************************************************) |
3765 |
let diffCmd () = |
3714 |
let diffCmd () = |
3766 |
match currentRow () with |
3715 |
match currentRow () with |
3767 |
Some i -> |
3716 |
Some (i, item, _) -> |
3768 |
getLock (fun () -> |
3717 |
getLock (fun () -> |
3769 |
let item = !theState.(i) in |
|
|
3770 |
let len = |
3718 |
let len = |
3771 |
match item.ri.replicas with |
3719 |
match item.ri.replicas with |
3772 |
Problem _ -> |
3720 |
Problem _ -> |
Lines 3844-3852
lst_store#set ~row ~column:c_path path;
Link Here
|
3844 |
debug (fun()-> Util.msg "Loading profile %s..." p); |
3792 |
debug (fun()-> Util.msg "Loading profile %s..." p); |
3845 |
Trace.status "Loading profile"; |
3793 |
Trace.status "Loading profile"; |
3846 |
unsynchronizedPaths := None; |
3794 |
unsynchronizedPaths := None; |
3847 |
Uicommon.initPrefs p |
3795 |
Uicommon.initPrefs ~profileName:p |
3848 |
(fun () -> if not reload then displayWaitMessage ()) |
3796 |
~displayWaitMessage:(fun () -> if not reload then displayWaitMessage ()) |
3849 |
getFirstRoot getSecondRoot termInteract; |
3797 |
~getFirstRoot ~getSecondRoot ~termInteract; |
3850 |
!updateFromProfile () |
3798 |
!updateFromProfile () |
3851 |
in |
3799 |
in |
3852 |
|
3800 |
|
Lines 3858-3864
lst_store#set ~row ~column:c_path path;
Link Here
|
3858 |
in |
3806 |
in |
3859 |
clearMainWindow (); |
3807 |
clearMainWindow (); |
3860 |
if not (Prefs.profileUnchanged ()) then loadProfile n true |
3808 |
if not (Prefs.profileUnchanged ()) then loadProfile n true |
3861 |
else Uicommon.refreshConnection displayWaitMessage termInteract |
3809 |
else Uicommon.refreshConnection ~displayWaitMessage ~termInteract |
3862 |
in |
3810 |
in |
3863 |
|
3811 |
|
3864 |
let detectCmd () = |
3812 |
let detectCmd () = |
Lines 3908-3923
lst_store#set ~row ~column:c_path path;
Link Here
|
3908 |
Action menu |
3856 |
Action menu |
3909 |
*********************************************************************) |
3857 |
*********************************************************************) |
3910 |
let buildActionMenu init = |
3858 |
let buildActionMenu init = |
|
|
3859 |
let withDelayedUpdates f x = |
3860 |
delayUpdates := true; |
3861 |
f x; |
3862 |
delayUpdates := false; |
3863 |
updateDetails () in |
3911 |
let actionMenu = replace_submenu "_Actions" actionItem in |
3864 |
let actionMenu = replace_submenu "_Actions" actionItem in |
3912 |
grAdd grRescan |
3865 |
grAdd grRescan |
3913 |
(actionMenu#add_image_item |
3866 |
(actionMenu#add_image_item |
3914 |
~callback:(fun _ -> mainWindow#select_all ()) |
3867 |
~callback:(fun _ -> withDelayedUpdates mainWindow#selection#select_all ()) |
3915 |
~image:((GMisc.image ~stock:`SELECT_ALL ~icon_size:`MENU ())#coerce) |
3868 |
~image:((GMisc.image ~stock:`SELECT_ALL ~icon_size:`MENU ())#coerce) |
3916 |
~modi:[`CONTROL] ~key:GdkKeysyms._A |
3869 |
~modi:[`CONTROL] ~key:GdkKeysyms._A |
3917 |
"Select _All"); |
3870 |
"Select _All"); |
3918 |
grAdd grRescan |
3871 |
grAdd grRescan |
3919 |
(actionMenu#add_item |
3872 |
(actionMenu#add_item |
3920 |
~callback:(fun _ -> mainWindow#unselect_all ()) |
3873 |
~callback:(fun _ -> withDelayedUpdates mainWindow#selection#unselect_all ()) |
3921 |
~modi:[`SHIFT; `CONTROL] ~key:GdkKeysyms._A |
3874 |
~modi:[`SHIFT; `CONTROL] ~key:GdkKeysyms._A |
3922 |
"_Deselect All"); |
3875 |
"_Deselect All"); |
3923 |
|
3876 |
|
Lines 4213-4225
let start _ =
Link Here
|
4213 |
let detectCmd = createToplevelWindow() in |
4166 |
let detectCmd = createToplevelWindow() in |
4214 |
|
4167 |
|
4215 |
Uicommon.uiInit |
4168 |
Uicommon.uiInit |
4216 |
fatalError |
4169 |
~reportError:fatalError |
4217 |
tryAgainOrQuit |
4170 |
~tryAgainOrQuit |
4218 |
displayWaitMessage |
4171 |
~displayWaitMessage |
4219 |
(fun () -> getProfile true) |
4172 |
~getProfile:(fun () -> getProfile true) |
4220 |
getFirstRoot |
4173 |
~getFirstRoot |
4221 |
getSecondRoot |
4174 |
~getSecondRoot |
4222 |
termInteract; |
4175 |
~termInteract; |
4223 |
detectCmd (); |
4176 |
detectCmd (); |
4224 |
|
4177 |
|
4225 |
(* Display the ui *) |
4178 |
(* Display the ui *) |