示例#1
0
void
row_calc_spans (ColRowInfo *ri, int row, Sheet const *sheet)
{
	int left, right, col;
	GnmRange const *merged;
	GnmCell *cell;
	int const last = sheet->cols.max_used;

	row_destroy_span (ri);
	for (col = 0 ; col <= last ; ) {
		cell = sheet_cell_get (sheet, col, row);
		if (cell == NULL) {
			/* skip segments with no cells */
			if (col == COLROW_SEGMENT_START (col) &&
			    NULL == COLROW_GET_SEGMENT (&(sheet->cols), col))
				col = COLROW_SEGMENT_END (col) + 1;
			else
				col++;
			continue;
		}

		/* render as necessary */
		(void)gnm_cell_fetch_rendered_value (cell, TRUE);

		if (gnm_cell_is_merged (cell)) {
			merged = gnm_sheet_merge_is_corner (sheet, &cell->pos);
			if (NULL != merged) {
				col = merged->end.col + 1;
				continue;
			}
		}

		cell_calc_span (cell, &left, &right);
		if (left != right) {
			cell_register_span (cell, left, right);
			col = right + 1;
		} else
			col++;
	}

	ri->needs_respan = FALSE;
}
static void
comment_view_set_bounds (SheetObjectView *sov, double const *coords, gboolean visible)
{
	CommentView *cv = (CommentView *)sov;
	GocPoints *points = goc_points_new (3);
	GocItem *item = GOC_ITEM (GOC_GROUP (sov)->children->data);
	if (visible) {
		SheetObject *so = sheet_object_view_get_so (sov);
		SheetControlGUI const *scg = GNM_SIMPLE_CANVAS (item->canvas)->scg;
		double scale;
		gint64 x, y, dx;
		int far_col;
		GnmRange const *r = gnm_sheet_merge_is_corner (so->sheet,
			&so->anchor.cell_bound.start);

		scale = 1. / item->canvas->pixels_per_unit;

		if (r != NULL)
			far_col = 1 + r->end.col;
		else
			far_col = 1 + so->anchor.cell_bound.start.col;

		/* TODO : This could be optimized using the offsets associated with the visible region */
		/* Add 1 to y because we measure from start, x is measured from end, so
		 * it does not need it */
		y = scg_colrow_distance_get (scg, FALSE, 0, so->anchor.cell_bound.start.row)+ 1;
		points->points[0].y = scale * y;
		points->points[1].y = scale * y;
		points->points[2].y = scale * y + cv->comment_indicator_size;

		dx = cv->comment_indicator_size;
		x = scg_colrow_distance_get (scg, TRUE, 0, far_col);
		points->points[0].x = scale * x - dx;
		points->points[1].x = scale * x;
		points->points[2].x = scale * x;

		goc_item_set (item, "points", points, NULL);
		goc_points_unref (points);
		goc_item_show (GOC_ITEM (sov));
	} else
		goc_item_hide (GOC_ITEM (sov));
}
示例#3
0
/**
 * gnm_cell_combo_view_popdown:
 * @sov: #SheetObjectView
 * @activate_time: event time
 *
 * Open the popup window associated with @sov
 **/
void
gnm_cell_combo_view_popdown (SheetObjectView *sov, guint32 activate_time)
{
	GocItem		   *view   = GOC_ITEM (sov);
	GnmPane		   *pane   = GNM_PANE (view->canvas);
	SheetControlGUI	   *scg    = pane->simple.scg;
	SheetObject	   *so     = sheet_object_view_get_so (sov);
	Sheet const	   *sheet  = sheet_object_get_sheet (so);
	GtkWidget *frame,  *popup, *list, *container;
	int root_x, root_y;
	gboolean 	make_buttons = FALSE;
	GtkTreePath	  *clip = NULL, *select = NULL;
	GtkWindow *toplevel = wbcg_toplevel (scg_wbcg (scg));
	GdkWindow *popup_window;
	GdkDevice *device;
	GnmRange const *merge;

	popup = gtk_window_new (GTK_WINDOW_POPUP);

	gtk_window_set_type_hint (GTK_WINDOW (popup), GDK_WINDOW_TYPE_HINT_COMBO);
	gtk_window_group_add_window (gtk_window_get_group (toplevel), GTK_WINDOW (popup));
	go_gtk_window_set_transient (toplevel, GTK_WINDOW (popup));
	gtk_window_set_resizable (GTK_WINDOW (popup), FALSE);
	gtk_window_set_decorated (GTK_WINDOW (popup), FALSE);
	gtk_window_set_screen (GTK_WINDOW (popup),
		gtk_widget_get_screen (GTK_WIDGET (toplevel)));

	list = ccombo_create_list (GNM_CCOMBO_VIEW (sov), so, &clip, &select, &make_buttons);

	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (list), FALSE);
	g_object_set_data (G_OBJECT (list), SOV_ID, sov);

	frame = gtk_frame_new (NULL);
	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);

#if 0
	range_dump (&so->anchor.cell_bound, "");
	g_printerr (" : so = %p, view = %p\n", so, view);
#endif
	if (clip != NULL) {
		GtkWidget *sw = gtk_scrolled_window_new (
			gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (list)),
			gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (list)));
		gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
						GTK_POLICY_AUTOMATIC,
						GTK_POLICY_ALWAYS);
		g_object_set_data_full (G_OBJECT (list),
					"clip", clip,
					(GDestroyNotify)gtk_tree_path_free);

		gtk_container_add (GTK_CONTAINER (sw), list);

		/*
		 * Do the sizing in a realize handler as newer versions of
		 * gtk+ give us zero sizes until then.
		 */
		g_signal_connect_after (list, "realize",
					G_CALLBACK (cb_realize_treeview),
					sw);
		container = sw;
	} else
		container = list;

	if (make_buttons) {
		GtkWidget *vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
		GtkWidget *hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);

		GtkWidget *button;
		button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
		g_signal_connect_swapped (button, "clicked",
			G_CALLBACK (cb_ccombo_cancel_button), list);
		gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 6);
		button = gtk_button_new_from_stock (GTK_STOCK_OK);
		g_signal_connect_swapped (button, "clicked",
			G_CALLBACK (cb_ccombo_ok_button), list);
		gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 6);

		gtk_box_pack_start (GTK_BOX (vbox), container, FALSE, TRUE, 6);
		gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 6);
		container = vbox;
	}

	gtk_container_add (GTK_CONTAINER (frame), container);

	/* do the popup */
	gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (pane)),
			       &root_x, &root_y);
	if (sheet->text_is_rtl) {
		GtkAllocation pa;
		gtk_widget_get_allocation (GTK_WIDGET (pane), &pa);
		root_x += pa.width;
		root_x -= scg_colrow_distance_get (scg, TRUE,
			pane->first.col,
			so->anchor.cell_bound.start.col + 1);
	} else
		root_x += scg_colrow_distance_get (scg, TRUE,
			pane->first.col,
			so->anchor.cell_bound.start.col);
	merge = gnm_sheet_merge_is_corner (sheet, &(so->anchor.cell_bound.start));
	gtk_window_move (GTK_WINDOW (popup), root_x,
		root_y + scg_colrow_distance_get
			 (scg, FALSE,
			  pane->first.row,
			  so->anchor.cell_bound.start.row +
			  ((merge == NULL) ? 1 : range_height (merge))));

	gtk_container_add (GTK_CONTAINER (popup), frame);

	g_signal_connect (popup, "key_press_event",
		G_CALLBACK (cb_ccombo_key_press), list);
	g_signal_connect (popup, "button_press_event",
		G_CALLBACK (cb_ccombo_button_press), list);
	g_signal_connect_after (popup, "button_release_event",
		G_CALLBACK (cb_ccombo_button_release), list);
	g_signal_connect (list, "motion_notify_event",
		G_CALLBACK (cb_ccombo_list_motion), list);
	g_signal_connect (list, "button_press_event",
		G_CALLBACK (cb_ccombo_list_button_press), popup);

	gtk_widget_show_all (popup);

	/* after we show the window setup the selection (showing the list
	 * clears the selection) */
	if (select != NULL) {
		gtk_tree_selection_select_path (
			gtk_tree_view_get_selection (GTK_TREE_VIEW (list)),
			select);
		gtk_tree_view_set_cursor (GTK_TREE_VIEW (list),
			select, NULL, FALSE);
		gtk_tree_path_free (select);
	}

	gtk_widget_grab_focus (popup);
	gtk_widget_grab_focus (GTK_WIDGET (list));
	ccombo_focus_change (GTK_WIDGET (list), TRUE);

	popup_window = gtk_widget_get_window (popup);

	device = gtk_get_current_event_device ();
	if (0 == gdk_device_grab (device, popup_window,
	                          GDK_OWNERSHIP_APPLICATION, TRUE,
	                          GDK_BUTTON_PRESS_MASK |
	                          GDK_BUTTON_RELEASE_MASK |
	                          GDK_POINTER_MOTION_MASK,
	                          NULL, activate_time)) {
		if (0 == gdk_device_grab (gdk_device_get_associated_device (device),
		                          popup_window,
		                          GDK_OWNERSHIP_APPLICATION, TRUE,
		                          GDK_KEY_PRESS_MASK |
		                          GDK_KEY_RELEASE_MASK,
		                          NULL, activate_time))
			gtk_grab_add (popup);
		else
			gdk_device_ungrab (device, activate_time);
	}
}
示例#4
0
/**
 * clipboard_paste_region:
 * @cr: The GnmCellRegion to paste.
 * @pt: Where to paste the values.
 * @cc: The context for error handling.
 *
 * Pastes the supplied GnmCellRegion (@cr) into the supplied
 * GnmPasteTarget (@pt).  This operation is not undoable.  It does not auto grow
 * the destination if the target is a singleton.  This is a simple interface to
 * paste a region.
 *
 * returns : TRUE if there was a problem.
 **/
gboolean
clipboard_paste_region (GnmCellRegion const *cr,
			GnmPasteTarget const *pt,
			GOCmdContext *cc)
{
	int repeat_horizontal, repeat_vertical, clearFlags;
	int dst_cols, dst_rows, src_cols, src_rows;
	int i, j;
	GSList *ptr;
	GnmRange const *r;
	gboolean has_contents, adjust_merges = TRUE;
	struct paste_cell_data dat;
	GnmRange const *merge_src;

	g_return_val_if_fail (pt != NULL, TRUE);
	g_return_val_if_fail (cr != NULL, TRUE);

	/* we do not need any of this fancy stuff when pasting a simple object */
	if (cr->cell_content == NULL &&
	    cr->styles == NULL &&
	    cr->merged == NULL &&
	    cr->objects != NULL) {
		if (pt->paste_flags & (PASTE_COMMENTS | PASTE_OBJECTS))
			for (ptr = cr->objects; ptr; ptr = ptr->next)
				paste_object (pt, ptr->data,
					pt->range.start.col, pt->range.start.row);
		return FALSE;
	}

	r = &pt->range;
	dst_cols = range_width (r);
	dst_rows = range_height (r);
	src_cols = cr->cols;
	src_rows = cr->rows;



	/* If the source is a single cell or a single merge */
	/* Treat a target of a single merge specially, don't split the merge */
	if ((src_cols == 1 && src_rows == 1) ||
	    (g_slist_length (cr->merged) == 1 &&
	     (NULL != (merge_src = cr->merged->data)) &&
	     range_height (merge_src) == cr->rows &&
	     range_width (merge_src) == cr->cols)) {
		GnmRange const *merge = gnm_sheet_merge_is_corner (pt->sheet, &r->start);
		if (merge != NULL && range_equal (r, merge)) {
			dst_cols = dst_rows = 1;
			adjust_merges = FALSE;
			src_cols = 1;
			src_rows = 1;
		}
	/* Apparently links do not supercede merges */
	} else if (pt->paste_flags & PASTE_LINK)
		adjust_merges = FALSE;

	has_contents = pt->paste_flags & (PASTE_CONTENTS|PASTE_AS_VALUES|PASTE_LINK);

	if (pt->paste_flags & PASTE_TRANSPOSE) {
		int tmp = src_cols;
		src_cols = src_rows;
		src_rows = tmp;
	}

	if (cr->not_as_contents && (pt->paste_flags & PASTE_CONTENTS)) {
		go_cmd_context_error_invalid (cc,
					_("Unable to paste"),
					_("Contents can only be pasted by value or by link."));
		return TRUE;
	}

	/* calculate the tiling */
	repeat_horizontal = dst_cols/src_cols;
	if (repeat_horizontal * src_cols != dst_cols) {
		char *msg = g_strdup_printf (
			_("destination does not have an even multiple of source columns (%d vs %d)\n\n"
			  "Try selecting a single cell or an area of the same shape and size."),
			dst_cols, src_cols);
		go_cmd_context_error_invalid (cc, _("Unable to paste"), msg);
		g_free (msg);
		return TRUE;
	}

	repeat_vertical = dst_rows/src_rows;
	if (repeat_vertical * src_rows != dst_rows) {
		char *msg = g_strdup_printf (
			_("destination does not have an even multiple of source rows (%d vs %d)\n\n"
			  "Try selecting a single cell or an area of the same shape and size."),
			dst_rows, src_rows);
		go_cmd_context_error_invalid (cc, _("Unable to paste"), msg);
		g_free (msg);
		return TRUE;
	}

	if ((pt->range.start.col + dst_cols) > gnm_sheet_get_max_cols (pt->sheet) ||
	    (pt->range.start.row + dst_rows) > gnm_sheet_get_max_rows (pt->sheet)) {
		go_cmd_context_error_invalid (cc,
					_("Unable to paste"),
					_("result passes the sheet boundary"));
		return TRUE;
	}

	clearFlags = 0;
	/* clear the region where we will paste */
	if (has_contents)
		clearFlags = CLEAR_VALUES | CLEAR_NORESPAN;

	if (pt->paste_flags & PASTE_COMMENTS)
		clearFlags |= CLEAR_COMMENTS;

	/* No need to clear the formats.  We will paste over top of these. */
	/* if (pt->paste_flags & PASTE_FORMATS) clearFlags |= CLEAR_FORMATS; */

	if (pt->paste_flags & (PASTE_OPER_MASK | PASTE_SKIP_BLANKS))
		clearFlags = 0;

	/* remove merged regions even for operations, or blanks */
	if (has_contents && adjust_merges)
		clearFlags |= CLEAR_MERGES;

	if (clearFlags != 0) {
		int const dst_col = pt->range.start.col;
		int const dst_row = pt->range.start.row;
		sheet_clear_region (pt->sheet,
				    dst_col, dst_row,
				    dst_col + dst_cols - 1,
				    dst_row + dst_rows - 1,
				    clearFlags, cc);
	}

	dat.translate_dates = cr->date_conv &&
		!go_date_conv_equal (cr->date_conv, workbook_date_conv (pt->sheet->workbook));

	for (i = 0; i < repeat_horizontal ; i++)
		for (j = 0; j < repeat_vertical ; j++) {
			int const left = i * src_cols + pt->range.start.col;
			int const top = j * src_rows + pt->range.start.row;

			dat.top_left.col = left;
			dat.top_left.row = top;
			dat.rinfo.reloc_type = GNM_EXPR_RELOCATE_MOVE_RANGE;
			dat.rinfo.origin_sheet = dat.rinfo.target_sheet = pt->sheet;
			if (pt->paste_flags & PASTE_EXPR_LOCAL_RELOCATE) {
				dat.rinfo.origin.start = cr->base;
				dat.rinfo.origin.end.col = cr->base.col + cr->cols - 1;
				dat.rinfo.origin.end.row = cr->base.row + cr->rows - 1;
				dat.rinfo.col_offset = left - cr->base.col;
				dat.rinfo.row_offset = top - cr->base.row;
			} else {
				dat.rinfo.origin = pt->range;
				dat.rinfo.col_offset = 0;
				dat.rinfo.row_offset = 0;
			}

			/* Move the styles on here so we get correct formats before recalc */
			if (pt->paste_flags & PASTE_FORMATS) {
				if (pt->paste_flags & PASTE_TRANSPOSE)
					sheet_style_set_list (pt->sheet, &dat.top_left,
							      cr->styles,
							      (sheet_style_set_list_cb_t)
							      range_transpose,
							      &dat.top_left);
				else if (pt->paste_flags & PASTE_FLIP_H) {
					int data = 2 * left + src_cols - 1;
					sheet_style_set_list (pt->sheet, &dat.top_left,
							      cr->styles,
							      (sheet_style_set_list_cb_t)
							      range_flip_h, &data);
				} else if (pt->paste_flags & PASTE_FLIP_V) {
					int data = 2 * top + src_rows - 1;
					sheet_style_set_list (pt->sheet, &dat.top_left,
							      cr->styles,
							      (sheet_style_set_list_cb_t)
							      range_flip_v, &data);
				} else
					sheet_style_set_list (pt->sheet, &dat.top_left,
							      cr->styles, NULL, NULL);
			}
			if (has_contents && !(pt->paste_flags & PASTE_DONT_MERGE)) {
				for (ptr = cr->merged; ptr != NULL ; ptr = ptr->next) {
					GnmRange tmp = *((GnmRange const *)ptr->data);
					if (pt->paste_flags & PASTE_TRANSPOSE) {
						int x;
						x = tmp.start.col; tmp.start.col = tmp.start.row;  tmp.start.row = x;
						x = tmp.end.col; tmp.end.col = tmp.end.row;  tmp.end.row = x;
					}
					if (!range_translate (&tmp, pt->sheet, left, top))
						gnm_sheet_merge_add (pt->sheet, &tmp, TRUE, cc);
				}
			}

			if (has_contents && (pt->paste_flags & PASTE_LINK)) {
				paste_link (pt, top, left, cr);
				continue;
			}

			if (has_contents && NULL != cr->cell_content) {
				dat.pt = pt;
				dat.cr = cr;
				g_hash_table_foreach (cr->cell_content,
					(GHFunc)cb_paste_cell, &dat);
			}

			if (pt->paste_flags & (PASTE_COMMENTS | PASTE_OBJECTS))
				for (ptr = cr->objects; ptr; ptr = ptr->next)
					paste_object (pt, ptr->data, left, top);
		}

	if (!(pt->paste_flags & PASTE_NO_RECALC)) {
		if (has_contents) {
			sheet_region_queue_recalc (pt->sheet, r);
			sheet_flag_status_update_range (pt->sheet, r);
		} else
			sheet_flag_style_update_range (pt->sheet, r);

		sheet_range_calc_spans (pt->sheet, r,
					(pt->paste_flags & PASTE_FORMATS) ? GNM_SPANCALC_RE_RENDER : GNM_SPANCALC_RENDER);
		if (pt->paste_flags & PASTE_UPDATE_ROW_HEIGHT)
			rows_height_update (pt->sheet, &pt->range, FALSE);
		sheet_redraw_all (pt->sheet, FALSE);
	}

	return FALSE;
}