dialog-paste-special.c 9.58 KB
Newer Older
Arturo Espinosa's avatar
Arturo Espinosa committed
1
/*
2 3
 * dialog-paste-special.c: The dialog for selecting non-standard
 *    behaviors when pasting.
Arturo Espinosa's avatar
Arturo Espinosa committed
4 5 6
 *
 * Author:
 *  MIguel de Icaza (miguel@gnu.org)
jpekka's avatar
jpekka committed
7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, see <https://www.gnu.org/licenses/>.
Arturo Espinosa's avatar
Arturo Espinosa committed
20
 */
21
#include <gnumeric-config.h>
22
#include <glib/gi18n-lib.h>
23
#include <gnumeric.h>
24 25
#include <dialogs/dialogs.h>
#include <dialogs/help.h>
Arturo Espinosa's avatar
Arturo Espinosa committed
26

27
#include <wbc-gtk.h>
28 29
#include <gui-util.h>
#include <clipboard.h>
30
#include <selection.h>
31
#include <cmd-edit.h>
32

33

34 35 36 37 38 39 40 41
static char const * const paste_type_group[] = {
	"paste-type-all",
	"paste-type-content",
	"paste-type-as-value",
	"paste-type-formats",
	"paste-type-comments",
	NULL
};
42
static const struct {
43 44 45
	gboolean permit_cell_ops;
	int paste_enum;
} paste_type_group_props[] = {
46
	{TRUE, PASTE_ALL_CELL},
47 48 49 50
	{TRUE, PASTE_CONTENTS},
	{TRUE, PASTE_AS_VALUES},
	{FALSE, PASTE_FORMATS},
	{FALSE, PASTE_COMMENTS},
Arturo Espinosa's avatar
Arturo Espinosa committed
51
};
52
static char const * const cell_operation_group[] = {
Morten Welinder's avatar
Morten Welinder committed
53 54 55 56 57
	"cell-operation-none",
	"cell-operation-add",
	"cell-operation-subtract",
	"cell-operation-multiply",
	"cell-operation-divide",
Arturo Espinosa's avatar
Arturo Espinosa committed
58 59
	NULL
};
60
static const struct {
61 62 63 64 65 66 67 68 69 70 71
	int paste_enum;
} cell_operation_props[] = {
	{0},
	{PASTE_OPER_ADD},
	{PASTE_OPER_SUB},
	{PASTE_OPER_MULT},
	{PASTE_OPER_DIV},
};
static char const * const region_operation_group[] = {
	"region-operation-none",
	"region-operation-transpose",
72 73
	"region-operation-flip-h",
	"region-operation-flip-v",
74 75
	NULL
};
76
static const struct {
77 78 79 80
	int paste_enum;
} region_operation_props[] = {
	{0},
	{PASTE_TRANSPOSE},
81 82
	{PASTE_FLIP_H},
	{PASTE_FLIP_V},
83 84 85
};

typedef struct {
86
	GtkBuilder *gui;
87 88 89 90 91 92 93 94 95 96 97 98 99
	GtkWidget *dialog;
	GtkWidget *ok_button;
	GtkWidget *cancel_button;
	GtkWidget *link_button;
	GtkWidget *help_button;
	char const *help_link;
	Sheet	  *sheet;
	SheetView *sv;
	Workbook  *wb;
	WBCGtk  *wbcg;
} PasteSpecialState;

#define GNM_PASTE_SPECIAL_KEY	"gnm-paste-special"
Arturo Espinosa's avatar
Arturo Espinosa committed
100

101
/* The "Paste Link" button should be grayed-out, unless type "All" is
102 103 104
   selected, cell operation "None" is selected,
   region operation "None" is selected, and "Skip
   Blanks" is not selected.  */
Arturo Espinosa's avatar
Arturo Espinosa committed
105
static void
106
paste_link_set_sensitive (PasteSpecialState *state)
Arturo Espinosa's avatar
Arturo Espinosa committed
107
{
108
	gboolean sensitive =
Morten Welinder's avatar
Morten Welinder committed
109
		(!gtk_toggle_button_get_active
Morten Welinder's avatar
Morten Welinder committed
110
		 (GTK_TOGGLE_BUTTON (go_gtk_builder_get_widget (state->gui,"skip-blanks")))
111 112 113
		 && 0 == gnm_gui_group_value (state->gui, paste_type_group)
		 && 0 == gnm_gui_group_value (state->gui, cell_operation_group)
		 && 0 == gnm_gui_group_value (state->gui, region_operation_group));
114 115
	gtk_widget_set_sensitive (state->link_button, sensitive);
}
Arturo Espinosa's avatar
Arturo Espinosa committed
116

117 118 119
static void
skip_blanks_set_sensitive (PasteSpecialState *state)
{
Morten Welinder's avatar
Morten Welinder committed
120
	GtkWidget *button = go_gtk_builder_get_widget (state->gui,"skip-blanks");
121
	gboolean sensitive =
122 123
		(3 > gnm_gui_group_value (state->gui, paste_type_group)
		 && 0 == gnm_gui_group_value (state->gui, cell_operation_group));
124 125 126
	gtk_widget_set_sensitive (button, sensitive);
}

127 128 129
static void
dont_change_formulae_set_sensitive (PasteSpecialState *state)
{
Morten Welinder's avatar
Morten Welinder committed
130
	GtkWidget *button = go_gtk_builder_get_widget (state->gui,"dont-change-formulae");
131
	gboolean sensitive =
132 133
		(2 > gnm_gui_group_value (state->gui, paste_type_group)
		 && 0 == gnm_gui_group_value (state->gui, cell_operation_group));
134 135 136
	gtk_widget_set_sensitive (button, sensitive);
}

137 138 139 140
static void
cb_destroy (PasteSpecialState *state)
{
	if (state->gui != NULL)
141
		g_object_unref (state->gui);
142 143
	wbcg_edit_finish (state->wbcg, WBC_EDIT_REJECT, NULL);
	g_free (state);
Arturo Espinosa's avatar
Arturo Espinosa committed
144 145
}

146
static void
147
dialog_paste_special_type_toggled_cb (GtkWidget *button, PasteSpecialState *state)
148
{
149
	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) {
150
		int i = gnm_gui_group_value (state->gui, paste_type_group);
151 152 153
		char const * const *group;
		gboolean permit_cell_ops = paste_type_group_props[i].permit_cell_ops;

Morten Welinder's avatar
Morten Welinder committed
154
		for (group = cell_operation_group; *group != NULL; group++)
Morten Welinder's avatar
Morten Welinder committed
155
			gtk_widget_set_sensitive (go_gtk_builder_get_widget (state->gui,*group),
156 157
						  permit_cell_ops);
		paste_link_set_sensitive (state);
Morten Welinder's avatar
Morten Welinder committed
158 159
		skip_blanks_set_sensitive (state);
		dont_change_formulae_set_sensitive (state);
160
	}
161 162
}

163
static void
164
dialog_paste_special_cell_op_toggled_cb (GtkWidget *button, PasteSpecialState *state)
165
{
166
	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) {
Morten Welinder's avatar
Morten Welinder committed
167 168 169
		paste_link_set_sensitive (state);
		skip_blanks_set_sensitive (state);
		dont_change_formulae_set_sensitive (state);
170
	}
171 172 173
}

static void
174
dialog_paste_special_region_op_toggled_cb (GtkWidget *button, PasteSpecialState *state)
175
{
176
	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) {
Morten Welinder's avatar
Morten Welinder committed
177
		paste_link_set_sensitive (state);
178
	}
179 180
}
static void
181
dialog_paste_special_skip_blanks_toggled_cb (GtkWidget *button, PasteSpecialState *state)
182
{
Morten Welinder's avatar
Morten Welinder committed
183
		paste_link_set_sensitive (state);
184 185 186
}

static void
187 188
cb_tool_cancel_clicked (G_GNUC_UNUSED GtkWidget *button,
			PasteSpecialState *state)
189
{
190 191 192 193 194 195 196 197 198
	gtk_widget_destroy (state->dialog);
	return;
}

static void
cb_tool_ok_clicked (G_GNUC_UNUSED GtkWidget *button,
			PasteSpecialState *state)
{
	int result;
199 200
	int paste_type = gnm_gui_group_value (state->gui, paste_type_group);
	int region_op_type = gnm_gui_group_value (state->gui, region_operation_group);
Morten Welinder's avatar
Morten Welinder committed
201

Morten Welinder's avatar
Morten Welinder committed
202
	result = paste_type_group_props[paste_type].paste_enum
203 204 205
		| region_operation_props[region_op_type].paste_enum;

	if (paste_type_group_props[paste_type].permit_cell_ops) {
206
		int cell_op_type = gnm_gui_group_value (state->gui, cell_operation_group);
207
		result |= cell_operation_props[cell_op_type].paste_enum;
208
	}
209

Morten Welinder's avatar
Morten Welinder committed
210
	if (gtk_toggle_button_get_active
Morten Welinder's avatar
Morten Welinder committed
211
	    (GTK_TOGGLE_BUTTON (go_gtk_builder_get_widget (state->gui,"skip-blanks"))))
212
		result |= PASTE_SKIP_BLANKS;
Morten Welinder's avatar
Morten Welinder committed
213
	if (gtk_toggle_button_get_active
Morten Welinder's avatar
Morten Welinder committed
214
	    (GTK_TOGGLE_BUTTON (go_gtk_builder_get_widget (state->gui,"dont-change-formulae"))))
215
		result |= PASTE_EXPR_LOCAL_RELOCATE;
216

217 218 219 220 221 222 223
	if (gtk_toggle_button_get_active
	    (GTK_TOGGLE_BUTTON (go_gtk_builder_get_widget (state->gui,"row-heights"))))
		result |= PASTE_ROW_HEIGHTS;
	if (gtk_toggle_button_get_active
	    (GTK_TOGGLE_BUTTON (go_gtk_builder_get_widget (state->gui,"column-widths"))))
		result |= PASTE_COLUMN_WIDTHS;

Morten Welinder's avatar
Morten Welinder committed
224
	cmd_paste_to_selection (GNM_WBC (state->wbcg), state->sv, result);
225 226 227 228 229 230 231 232
	gtk_widget_destroy (state->dialog);
	return;
}

static void
cb_tool_paste_link_clicked (G_GNUC_UNUSED GtkWidget *button,
			PasteSpecialState *state)
{
Morten Welinder's avatar
Morten Welinder committed
233
	cmd_paste_to_selection (GNM_WBC (state->wbcg), state->sv, PASTE_LINK);
234 235
	gtk_widget_destroy (state->dialog);
	return;
236 237
}

238
void
239
dialog_paste_special (WBCGtk *wbcg)
Arturo Espinosa's avatar
Arturo Espinosa committed
240
{
241
	PasteSpecialState *state;
242
	GtkBuilder *gui;
243
	char const * const *group;
244

Morten Welinder's avatar
Morten Welinder committed
245
	if (gnm_dialog_raise_if_exists (wbcg, GNM_PASTE_SPECIAL_KEY))
246
		return;
247
	gui = gnm_gtk_builder_load ("res:ui/paste-special.ui", NULL, GO_CMD_CONTEXT (wbcg));
248 249
	if (gui == NULL)
		return;
250 251 252

	state = g_new0 (PasteSpecialState, 1);
	state->wbcg   = wbcg;
253
	state->gui    = gui;
Morten Welinder's avatar
Morten Welinder committed
254
	state->dialog =  go_gtk_builder_get_widget (state->gui, "paste-special");
255
	state->sheet = wbcg_cur_sheet (wbcg);
Morten Welinder's avatar
Morten Welinder committed
256
	state->sv = wb_control_cur_sheet_view (GNM_WBC (wbcg));
257

258
	g_return_if_fail (state->dialog != NULL);
259

Morten Welinder's avatar
Morten Welinder committed
260
	state->link_button = go_gtk_builder_get_widget (state->gui,"paste-link_button");
261 262 263
	g_signal_connect (G_OBJECT (state->link_button),
			  "clicked",
			  G_CALLBACK (cb_tool_paste_link_clicked), state);
Morten Welinder's avatar
Morten Welinder committed
264
	state->help_button = go_gtk_builder_get_widget (state->gui, "help_button");
Morten Welinder's avatar
Morten Welinder committed
265
	gnm_init_help_button (state->help_button, GNUMERIC_HELP_LINK_PASTE_SPECIAL);
Morten Welinder's avatar
Morten Welinder committed
266
	state->cancel_button = go_gtk_builder_get_widget (state->gui, "cancel_button");
267 268 269
	g_signal_connect (G_OBJECT (state->cancel_button),
			  "clicked",
			  G_CALLBACK (cb_tool_cancel_clicked), state);
Morten Welinder's avatar
Morten Welinder committed
270
	state->ok_button = go_gtk_builder_get_widget (state->gui, "ok_button");
271 272 273
	g_signal_connect (G_OBJECT (state->ok_button),
			  "clicked",
			  G_CALLBACK (cb_tool_ok_clicked), state);
Morten Welinder's avatar
Morten Welinder committed
274

275

Morten Welinder's avatar
Morten Welinder committed
276
	for (group = paste_type_group; *group != NULL; group++)
Morten Welinder's avatar
Morten Welinder committed
277
		g_signal_connect_after (go_gtk_builder_get_widget (state->gui,*group),
278 279
					"toggled",
					G_CALLBACK (dialog_paste_special_type_toggled_cb), state);
Morten Welinder's avatar
Morten Welinder committed
280
	for (group = cell_operation_group; *group != NULL; group++)
Morten Welinder's avatar
Morten Welinder committed
281
		g_signal_connect_after (go_gtk_builder_get_widget (state->gui,*group),
282 283
					"toggled",
					G_CALLBACK (dialog_paste_special_cell_op_toggled_cb), state);
Morten Welinder's avatar
Morten Welinder committed
284
	for (group = region_operation_group; *group != NULL; group++)
Morten Welinder's avatar
Morten Welinder committed
285
		g_signal_connect_after (go_gtk_builder_get_widget (state->gui,*group),
286 287
					"toggled",
					G_CALLBACK (dialog_paste_special_region_op_toggled_cb), state);
Morten Welinder's avatar
Morten Welinder committed
288
	g_signal_connect_after (go_gtk_builder_get_widget (state->gui, "skip-blanks"),
289 290
				"toggled",
				G_CALLBACK (dialog_paste_special_skip_blanks_toggled_cb), state);
Morten Welinder's avatar
Morten Welinder committed
291
	paste_link_set_sensitive (state);
292

293 294 295 296 297 298 299
	gtk_toggle_button_set_active
		(GTK_TOGGLE_BUTTON (go_gtk_builder_get_widget (state->gui,"column-widths")),
		 sv_is_full_colrow_selected (state->sv, TRUE, -1));
	gtk_toggle_button_set_active
		(GTK_TOGGLE_BUTTON (go_gtk_builder_get_widget (state->gui,"row-heights")),
		 sv_is_full_colrow_selected (state->sv, FALSE, -1));

300 301
	gnm_dialog_setup_destroy_handlers (GTK_DIALOG (state->dialog), wbcg,
					   GNM_DIALOG_DESTROY_SHEET_REMOVED);
Arturo Espinosa's avatar
Arturo Espinosa committed
302

Morten Welinder's avatar
Morten Welinder committed
303
	gnm_keyed_dialog (wbcg, GTK_WINDOW (state->dialog),
304
			       GNM_PASTE_SPECIAL_KEY);
Arturo Espinosa's avatar
Arturo Espinosa committed
305

306
	wbc_gtk_attach_guru (state->wbcg, state->dialog);
307
	g_object_set_data_full (G_OBJECT (state->dialog),
308 309 310 311
				"state", state,
				(GDestroyNotify) cb_destroy);

	gtk_widget_show (state->dialog);
Arturo Espinosa's avatar
Arturo Espinosa committed
312
}