/* * One-pane (file)compare view widget module * * Copyright INOUE Seiichiro , licensed under the GPL. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "diff.h" #include "gui.h" #include "onepaneview.h" #include "onepane-widget.h" #include "dtextmap.h" #include "rmenu.h" /* Constant number */ enum { ARG_0, ARG_BASEPANE }; /* signals */ enum { SCROLLUP, SCROLLDOWN, LAST_SIGNAL }; /* Private function declarations */ static void gdiff_onepview_class_init(GdiffOnepViewClass *klass); static void gdiff_onepview_set_arg(GtkObject *object, GtkArg *arg, guint arg_id); static void gdiff_onepview_get_arg(GtkObject *object, GtkArg *arg, guint arg_id); static void gdiff_onepview_init(GdiffOnepView *onepview); static void gdiff_onepview_scrollup(GdiffOnepView *onepview); static void gdiff_onepview_scrolldown(GdiffOnepView *onepview); static void gdiff_onepview_set_basepane(GdiffOnepView *onepview, GdiffBasePane *basepane); static void create_onepane(GdiffOnepView *onepview, DiffDir *diffdir, DiffFiles *dfiles); static void create_overview(GdiffOnepView *onepview, DiffFiles *dfiles); static void create_rmenu(GdiffOnepView *onepview); static void move_diff_cb(GdiffOnePane *onepane, MoveDiff mv_diff, gpointer data); static void update_statusbar(GdiffOnepView *onepview); static GtkHBoxClass *parent_class = NULL; static guint onepview_signals[LAST_SIGNAL] = { 0 }; GtkType gdiff_onepview_get_type(void) { static GtkType onepview_type = 0; if (!onepview_type) { static const GtkTypeInfo onepview_info = { "GdiffOnepView", sizeof(GdiffOnepView), sizeof(GdiffOnepViewClass), (GtkClassInitFunc)gdiff_onepview_class_init, (GtkObjectInitFunc)gdiff_onepview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc)NULL, }; onepview_type = gtk_type_unique(GTK_TYPE_HBOX, &onepview_info); } return onepview_type; } static void gdiff_onepview_class_init(GdiffOnepViewClass *klass) { GtkObjectClass *object_class; GtkWidgetClass *widget_class; gtk_object_add_arg_type("GdiffOnepView::basepane", GDIFF_TYPE_ONEPANE, GTK_ARG_READWRITE, ARG_BASEPANE); object_class = (GtkObjectClass*)klass; widget_class = (GtkWidgetClass*)klass; parent_class = gtk_type_class(GTK_TYPE_HBOX); onepview_signals[SCROLLUP] = gtk_signal_new("scrollup", GTK_RUN_FIRST, object_class->type, GTK_SIGNAL_OFFSET(GdiffOnepViewClass, scrollup), gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); onepview_signals[SCROLLDOWN] = gtk_signal_new("scrolldown", GTK_RUN_FIRST, object_class->type, GTK_SIGNAL_OFFSET(GdiffOnepViewClass, scrolldown), gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); gtk_object_class_add_signals(object_class, onepview_signals, LAST_SIGNAL); object_class->set_arg = gdiff_onepview_set_arg; object_class->get_arg = gdiff_onepview_get_arg; klass->scrollup = gdiff_onepview_scrollup; klass->scrolldown = gdiff_onepview_scrolldown; } static void gdiff_onepview_set_arg(GtkObject *object, GtkArg *arg, guint arg_id) { GdiffOnepView *onepview; onepview = GDIFF_ONEPVIEW(object); switch (arg_id) { case ARG_BASEPANE: gdiff_onepview_set_basepane(onepview, GTK_VALUE_POINTER(*arg)); break; default: break; } } static void gdiff_onepview_get_arg(GtkObject *object, GtkArg *arg, guint arg_id) { GdiffOnepView *onepview; onepview = GDIFF_ONEPVIEW(object); switch (arg_id) { case ARG_BASEPANE: GTK_VALUE_POINTER(*arg) = onepview->onepane; break; default: arg->type = GTK_TYPE_INVALID; break; } } static void gdiff_onepview_init(GdiffOnepView *onepview) { onepview->onepane = NULL; onepview->overview = NULL; onepview->gdwin = NULL; onepview->is_under_dir = FALSE; } GtkWidget* gdiff_onepview_new(DiffDir *diffdir, DiffFiles *dfiles, gboolean is_under_dir) { GdiffOnepView *onepview; onepview = gtk_type_new(GDIFF_TYPE_ONEPVIEW); create_onepane(onepview, diffdir, dfiles); create_overview(onepview, dfiles); create_rmenu(onepview); onepview->is_under_dir = is_under_dir; return GTK_WIDGET(onepview); } /** Internal functions **/ static void gdiff_onepview_scrollup(GdiffOnepView *onepview) { GtkWidget *scrollwin = GDIFF_ONEPANE(onepview->onepane)->text->parent; GtkWidget *vs = GTK_SCROLLED_WINDOW(scrollwin)->vscrollbar; GtkAdjustment *adj = GTK_RANGE(vs)->adjustment; if (adj->value > adj->lower) { if (adj->value - adj->page_size > adj->lower) adj->value -= adj->page_size; else adj->value = adj->lower; gtk_signal_emit_by_name(GTK_OBJECT(adj), "value_changed"); } } static void gdiff_onepview_scrolldown(GdiffOnepView *onepview) { GtkWidget *scrollwin = GDIFF_ONEPANE(onepview->onepane)->text->parent; GtkWidget *vs = GTK_SCROLLED_WINDOW(scrollwin)->vscrollbar; GtkAdjustment *adj = GTK_RANGE(vs)->adjustment; if (adj->value < adj->upper) { if (adj->value + adj->page_size < adj->upper) adj->value += adj->page_size; else adj->value = adj->upper; gtk_signal_emit_by_name(GTK_OBJECT(adj), "value_changed"); } } static void gdiff_onepview_set_basepane(GdiffOnepView *onepview, GdiffBasePane *basepane) { g_return_if_fail(onepview != NULL); g_return_if_fail(GDIFF_IS_ONEPVIEW(onepview)); g_return_if_fail(onepview->onepane == NULL); if (basepane) g_return_if_fail(GDIFF_IS_ONEPANE(basepane)); onepview->onepane = basepane; } static void create_onepane(GdiffOnepView *onepview, DiffDir *diffdir, DiffFiles *dfiles) { GtkWidget *onepane; onepane = gdiff_onepane_new(diffdir, dfiles); gdiff_onepview_set_basepane(onepview, GDIFF_BASEPANE(onepane)); gtk_box_pack_start(GTK_BOX(onepview), onepane, TRUE, TRUE, 0); gtk_signal_connect(GTK_OBJECT(onepane), "move_diff", GTK_SIGNAL_FUNC(move_diff_cb), onepview); gtk_widget_show(onepane); } /** * create_overview: * Create GdiffOverview widget. * See "gdiffoverview.[ch]" about GdiffOverview widget. **/ static void create_overview(GdiffOnepView *onepview, DiffFiles *dfiles) { GtkWidget *overview; GdiffOnePane *onepane = GDIFF_ONEPANE(onepview->onepane); DTextMap *dtmap = onepane->dtmap; GtkAdjustment *adj_array[MAX_NUM_COMPARE_FILES]; GdkColor *fg_array[MAX_NUM_COMPARE_FILES]; GdkColor *bg_array[MAX_NUM_COMPARE_FILES]; int n; for (n = 0; n < GDIFF_ONEPVIEW_NUM_FILES(onepview); n++) { adj_array[n] = GTK_TEXT(onepane->text)->vadj; } overview = gdiff_overview_new(GDIFF_ONEPVIEW_NUM_FILES(onepview), adj_array); onepview->overview = GDIFF_OVERVIEW(overview); for (n = 0; n < GDIFF_ONEPVIEW_NUM_FILES(onepview); n++) { fg_array[n] = &PANE_PREF(onepane).diff_bg[n]; bg_array[n] = NULL; } gdiff_overview_set_color(GDIFF_OVERVIEW(overview), fg_array, bg_array); /* initialize overview widget */ if (dtmap->total_nl != 0) { GList *node;/* node of DiffLines list */ for (node = dfiles->dlines_list; node; node = node->next) { const DiffLines *dlines = node->data; gdouble begin_array[MAX_NUM_COMPARE_FILES]; gdouble end_array[MAX_NUM_COMPARE_FILES]; for (n = 0; n < GDIFF_ONEPVIEW_NUM_FILES(onepview); n++) { /* Use local variables for ease to read */ int begin, end, tbegin, tend; begin = dlines->between[n].begin; end = dlines->between[n].end; /* Map to text */ tbegin = dtmap_map_b2t(dtmap, begin); tend = dtmap_map_b2t(dtmap, end); begin_array[n] = (gdouble)tbegin/dtmap->total_nl; end_array[n] = (gdouble)tend/dtmap->total_nl; } gdiff_overview_insert_paintrange(GDIFF_OVERVIEW(overview), begin_array, end_array); } } gtk_box_pack_start(GTK_BOX(onepview), overview, FALSE, FALSE, 0); gtk_widget_show(overview); } /* right-click menu */ static void create_rmenu(GdiffOnepView *onepview) { GdiffOnePane *onepane = GDIFF_ONEPANE(onepview->onepane); GtkWidget *rmenu; /* second argument doesn't matter */ rmenu = rmenu_create(GTK_WIDGET(onepane), GINT_TO_POINTER(0)); gnome_popup_menu_attach(rmenu, onepane->text, onepview); } /** * move_diff_cb: * Callback for "move_diff" signal of GdiffOnePane widget. * "move_diff" itself is handled by GdiffOnePane widget. * GdiffOnepView widget's responsibility is to take care of statusbar. **/ static void move_diff_cb(GdiffOnePane *onepane, MoveDiff mv_diff, gpointer data) { GdiffOnepView *onepview = data; update_statusbar(onepview); } static void update_statusbar(GdiffOnepView *onepview) { GdiffBasePane *onepane = GDIFF_BASEPANE(onepview->onepane); char *sbar_msg = NULL;/* status-bar message */ const char *fnames[MAX_NUM_COMPARE_FILES]; int begins[MAX_NUM_COMPARE_FILES]; int ends[MAX_NUM_COMPARE_FILES]; if (onepane->cur_dlines_node) { const DiffLines *dlines; int n; dlines = onepane->cur_dlines_node->data; for (n = 0; n < GDIFF_ONEPVIEW_NUM_FILES(onepview); n++) { fnames[n] = GDIFF_ONEPVIEW_FILENAME(onepview, n); begins[n] = dlines->between[n].begin; ends[n] = dlines->between[n].end; } sbar_msg = sbar_create_msg(GDIFF_ONEPVIEW_NUM_FILES(onepview), fnames, begins, ends); } if (sbar_msg) { statusbar_update(onepview->gdwin, sbar_msg); g_free(sbar_msg); } }