1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2007 Free Software Foundation
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include <gtksheet/gtksheet.h>
20 #include "clipboard.h"
21 #include <data/case.h>
22 #include "psppire-data-store.h"
23 #include <data/casereader.h>
24 #include <data/case-map.h>
25 #include <libpspp/alloc.h>
26 #include <data/casewriter.h>
27 #include <data/format.h>
28 #include <data/data-out.h>
32 /* A casereader and dictionary holding the data currently in the clip */
33 static struct casereader *clip_datasheet = NULL;
34 struct dictionary *clip_dict = NULL;
39 static void data_sheet_update_clipboard (GtkSheet *);
41 /* Set the clip according to the currently
42 selected range in the data sheet */
44 data_sheet_set_clip (GtkSheet *sheet)
47 struct casewriter *writer ;
50 struct case_map *map = NULL;
54 ds = PSPPIRE_DATA_STORE (gtk_sheet_get_model (sheet));
56 gtk_sheet_get_selected_range (sheet, &range);
58 /* If nothing selected, then use active cell */
59 if ( range.row0 < 0 || range.col0 < 0 )
62 gtk_sheet_get_active_cell (sheet, &row, &col);
64 range.row0 = range.rowi = row;
65 range.col0 = range.coli = col;
68 /* The sheet range can include cells that do not include data.
69 Exclude them from the range. */
70 max_rows = psppire_data_store_get_case_count (ds);
71 if (range.rowi >= max_rows)
75 range.rowi = max_rows - 1;
77 max_columns = dict_get_var_cnt (ds->dict->dict);
78 if (range.coli >= max_columns)
82 range.coli = max_columns - 1;
85 g_return_if_fail (range.rowi >= range.row0);
86 g_return_if_fail (range.row0 >= 0);
87 g_return_if_fail (range.coli >= range.col0);
88 g_return_if_fail (range.col0 >= 0);
90 /* Destroy any existing clip */
93 casereader_destroy (clip_datasheet);
94 clip_datasheet = NULL;
99 dict_destroy (clip_dict);
103 /* Construct clip dictionary. */
104 clip_dict = dict_create ();
105 for (i = range.col0; i <= range.coli; i++)
107 const struct variable *old = dict_get_var (ds->dict->dict, i);
108 dict_clone_var_assert (clip_dict, old, var_get_name (old));
111 /* Construct clip data. */
112 map = case_map_by_name (ds->dict->dict, clip_dict);
113 writer = autopaging_writer_create (dict_get_next_value_idx (clip_dict));
114 for (i = range.row0; i <= range.rowi ; ++i )
118 if (psppire_case_file_get_case (ds->case_file, i, &old))
122 case_map_execute (map, &old, &new);
124 casewriter_write (writer, &new);
127 casewriter_force_error (writer);
129 case_map_destroy (map);
131 clip_datasheet = casewriter_make_reader (writer);
133 data_sheet_update_clipboard (sheet);
143 /* Perform data_out for case CC, variable V, appending to STRING */
145 data_out_g_string (GString *string, const struct variable *v,
146 const struct ccase *cc)
150 const struct fmt_spec *fs = var_get_print_format (v);
151 const union value *val = case_data (cc, v);
152 buf = xzalloc (fs->w);
154 data_out (val, fs, buf);
156 g_string_append_len (string, buf, fs->w);
167 const size_t val_cnt = casereader_get_value_cnt (clip_datasheet);
168 const casenumber case_cnt = casereader_get_case_cnt (clip_datasheet);
170 string = g_string_sized_new (10 * val_cnt * case_cnt);
172 for (r = 0 ; r < case_cnt ; ++r )
176 if ( ! casereader_peek (clip_datasheet, r, &cc))
178 g_warning ("Clipboard seems to have inexplicably shrunk");
182 for (c = 0 ; c < val_cnt ; ++c)
184 const struct variable *v = dict_get_var (clip_dict, c);
185 data_out_g_string (string, v, &cc);
186 if ( c < val_cnt - 1 )
187 g_string_append (string, "\t");
191 g_string_append (string, "\n");
206 const size_t val_cnt = casereader_get_value_cnt (clip_datasheet);
207 const casenumber case_cnt = casereader_get_case_cnt (clip_datasheet);
209 /* Guestimate the size needed */
210 string = g_string_sized_new (20 * val_cnt * case_cnt);
212 g_string_append (string, "<table>\n");
213 for (r = 0 ; r < case_cnt ; ++r )
217 if ( ! casereader_peek (clip_datasheet, r, &cc))
219 g_warning ("Clipboard seems to have inexplicably shrunk");
222 g_string_append (string, "<tr>\n");
224 for (c = 0 ; c < val_cnt ; ++c)
226 const struct variable *v = dict_get_var (clip_dict, c);
227 g_string_append (string, "<td>");
228 data_out_g_string (string, v, &cc);
229 g_string_append (string, "</td>\n");
232 g_string_append (string, "</tr>\n");
236 g_string_append (string, "</table>\n");
244 clipboard_get_cb (GtkClipboard *clipboard,
245 GtkSelectionData *selection_data,
249 GString *string = NULL;
253 case SELECT_FMT_TEXT:
254 string = clip_to_text ();
256 case SELECT_FMT_HTML:
257 string = clip_to_html ();
260 g_assert_not_reached ();
263 gtk_selection_data_set (selection_data, selection_data->target,
265 (const guchar *) string->str, string->len);
267 g_string_free (string, TRUE);
271 clipboard_clear_cb (GtkClipboard *clipboard,
274 dict_destroy (clip_dict);
277 casereader_destroy (clip_datasheet);
278 clip_datasheet = NULL;
284 data_sheet_update_clipboard (GtkSheet *sheet)
286 static const GtkTargetEntry targets[] = {
287 { "UTF8_STRING", 0, SELECT_FMT_TEXT },
288 { "STRING", 0, SELECT_FMT_TEXT },
289 { "TEXT", 0, SELECT_FMT_TEXT },
290 { "COMPOUND_TEXT", 0, SELECT_FMT_TEXT },
291 { "text/plain;charset=utf-8", 0, SELECT_FMT_TEXT },
292 { "text/plain", 0, SELECT_FMT_TEXT },
293 { "text/html", 0, SELECT_FMT_HTML }
296 GtkClipboard *clipboard =
297 gtk_widget_get_clipboard (GTK_WIDGET (sheet),
298 GDK_SELECTION_CLIPBOARD);
300 if (!gtk_clipboard_set_with_owner (clipboard, targets,
301 G_N_ELEMENTS (targets),
302 clipboard_get_cb, clipboard_clear_cb,
304 clipboard_clear_cb (clipboard, sheet);