Code cleanups.
[gnumeric.git] / src / tools / filter.c
blob4ea029c5f9d5cddfac686128c245099d18cbb287
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /*
4 * filter.c:
6 * Author:
7 * Jukka-Pekka Iivonen <jiivonen@hutcs.cs.hut.fi>
9 * (C) Copyright 2000, 2001, 2002 by Jukka-Pekka Iivonen <iivonen@iki.fi>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, see <https://www.gnu.org/licenses/>.
25 #include <gnumeric-config.h>
26 #include <glib/gi18n-lib.h>
27 #include <gnumeric.h>
29 #include <sheet.h>
30 #include <sheet-filter.h>
31 #include <workbook-control.h>
32 #include <cell.h>
33 #include <ranges.h>
34 #include <value.h>
35 #include <selection.h>
36 #include <criteria.h>
38 #include "filter.h"
39 #include "analysis-tools.h"
41 static void
42 filter (data_analysis_output_t *dao, Sheet *sheet, GSList *rows,
43 gint input_col_b, gint input_col_e, gint input_row_b, gint input_row_e)
45 GnmCell *cell;
46 int i, r=0;
48 if (dao->type == InPlaceOutput) {
49 sheet->has_filtered_rows = TRUE;
50 colrow_set_visibility (sheet, FALSE,
51 FALSE, input_row_b+1, input_row_e);
52 for (i=input_row_b; i<=input_row_e; i++) {
53 ColRowInfo *ri = sheet_row_fetch (sheet, i);
54 ri->in_advanced_filter = TRUE;
56 while (rows != NULL) {
57 const gint *row = rows->data;
58 colrow_set_visibility (sheet, FALSE, TRUE, *row, *row);
59 rows = rows->next;
61 sheet_redraw_all (sheet, TRUE);
62 /* FIXME: what happens if we just have hidden the selection? */
64 } else {
65 for (i=input_col_b; i<=input_col_e; i++) {
66 cell = sheet_cell_get (sheet, i, input_row_b);
67 if (cell == NULL)
68 dao_set_cell (dao, i - input_col_b, r, NULL);
69 else {
70 GnmValue *value = value_dup (cell->value);
71 dao_set_cell_value (dao, i - input_col_b, r,
72 value);
75 ++r;
77 while (rows != NULL) {
78 const gint *row = rows->data;
79 for (i=input_col_b; i<=input_col_e; i++) {
80 cell = sheet_cell_get (sheet, i, *row);
81 if (cell == NULL)
82 dao_set_cell (dao, i - input_col_b, r,
83 NULL);
84 else {
85 GnmValue *value =
86 value_dup (cell->value);
87 dao_set_cell_value (dao,
88 i - input_col_b, r,
89 value);
92 ++r;
93 rows = rows->next;
99 * Advanced Filter tool.
101 gint
102 advanced_filter (WorkbookControl *wbc,
103 data_analysis_output_t *dao,
104 GnmValue *database,
105 GnmValue *criteria,
106 gboolean unique_only_flag)
108 GSList *crit, *rows;
109 GnmEvalPos ep;
110 GnmRange r, s;
111 SheetView *sv;
112 Sheet *sheet = criteria->v_range.cell.a.sheet;
114 /* I don't like this -- minimal fix for now. 509427. */
115 if (!VALUE_IS_CELLRANGE (criteria))
116 return analysis_tools_invalid_field;
118 crit = parse_database_criteria (
119 eval_pos_init_sheet (&ep, wb_control_cur_sheet (wbc)),
120 database, criteria);
122 if (crit == NULL)
123 return analysis_tools_invalid_field;
125 rows = find_rows_that_match (sheet,
126 database->v_range.cell.a.col,
127 database->v_range.cell.a.row + 1,
128 database->v_range.cell.b.col,
129 database->v_range.cell.b.row,
130 crit, unique_only_flag);
132 free_criterias (crit);
134 if (rows == NULL)
135 return analysis_tools_no_records_found;
137 dao_prepare_output (wbc, dao, _("Filtered"));
139 filter (dao, sheet, rows,
140 database->v_range.cell.a.col,
141 database->v_range.cell.b.col, database->v_range.cell.a.row,
142 database->v_range.cell.b.row);
144 g_slist_free_full (rows, (GDestroyNotify)g_free);
146 sv = sheet_get_view (sheet, wb_control_view (wbc));
147 s = r = *(selection_first_range (sv, NULL, NULL));
148 r.end.row = r.start.row;
149 sv_selection_reset (sv);
150 sv_selection_add_range (sv, &r);
151 sv_selection_add_range (sv, &s);
153 wb_control_menu_state_update (wbc, MS_FILTER_STATE_CHANGED);
155 return analysis_tools_noerr;
158 static gboolean
159 cb_show_all (GnmColRowIter const *iter, Sheet *sheet)
161 if (iter->cri->in_advanced_filter) {
162 ColRowInfo *ri = sheet_row_fetch (sheet, iter->pos);
163 if (!iter->cri->visible)
164 colrow_set_visibility (sheet, FALSE, TRUE,
165 iter->pos, iter->pos);
166 ri->in_advanced_filter = FALSE;
168 return FALSE;
171 void
172 filter_show_all (WorkbookControl *wbc)
174 Sheet *sheet = wb_control_cur_sheet (wbc);
176 /* FIXME: This is slow. We should probably have a linked list
177 * containing the filtered rows in the sheet structure. */
178 sheet_colrow_foreach (sheet, FALSE, 0, -1,
179 (ColRowHandler) cb_show_all, sheet);
180 sheet->has_filtered_rows = FALSE;
181 sheet_redraw_all (sheet, TRUE);
183 wb_control_menu_state_update (wbc, MS_FILTER_STATE_CHANGED);
186 static gboolean
187 analysis_tool_advanced_filter_engine_run (data_analysis_output_t *dao,
188 analysis_tools_data_advanced_filter_t *info)
190 GnmRange range;
191 char *name;
192 GnmValue *database = info->base.range_1;
193 GnmValue *criteria = info->base.range_2;
194 gint err = analysis_tools_noerr;
195 GSList *crit, *rows;
196 GnmEvalPos ep;
198 dao_set_italic (dao, 0, 0, 0, 2);
199 set_cell_text_col (dao, 0, 0, _("/Advanced Filter:"
200 "/Source Range:"
201 "/Criteria Range:"));
202 range_init_value (&range, database);
203 name = global_range_name (database->v_range.cell.a.sheet, &range);
204 dao_set_cell (dao, 1, 1, name);
205 g_free (name);
206 range_init_value (&range, criteria);
207 name = global_range_name (criteria->v_range.cell.a.sheet, &range);
208 dao_set_cell (dao, 1, 2, name);
209 g_free (name);
211 dao->offset_row = 3;
213 crit = parse_database_criteria (
214 eval_pos_init_sheet (&ep, wb_control_cur_sheet (info->base.wbc)),
215 database, criteria);
217 if (crit == NULL) {
218 err = analysis_tools_invalid_field;
219 goto finish;
222 rows = find_rows_that_match (database->v_range.cell.a.sheet,
223 database->v_range.cell.a.col,
224 database->v_range.cell.a.row + 1,
225 database->v_range.cell.b.col,
226 database->v_range.cell.b.row,
227 crit, info->unique_only_flag);
229 free_criterias (crit);
231 if (rows == NULL) {
232 err = analysis_tools_no_records_found;
233 goto finish;
236 filter (dao, database->v_range.cell.a.sheet, rows,
237 database->v_range.cell.a.col,
238 database->v_range.cell.b.col, database->v_range.cell.a.row,
239 database->v_range.cell.b.row);
241 g_slist_free_full (rows, (GDestroyNotify)g_free);
243 finish:
244 if (err != analysis_tools_noerr) {
245 dao_set_merge (dao, 0,0, 1, 0);
246 if (err == analysis_tools_no_records_found)
247 dao_set_cell (dao, 0, 0, _("No matching records were found."));
248 else if (err == analysis_tools_invalid_field)
249 dao_set_cell (dao, 0, 0, _("The given criteria are invalid."));
250 else
251 dao_set_cell_printf (dao, 0, 0,
252 _("An unexpected error has occurred: "
253 "%d."), err);
256 dao_redraw_respan (dao);
258 return analysis_tools_noerr;
262 gboolean
263 analysis_tool_advanced_filter_engine (G_GNUC_UNUSED GOCmdContext *gcc, data_analysis_output_t *dao, gpointer specs,
264 analysis_tool_engine_t selector, gpointer result)
266 analysis_tools_data_advanced_filter_t *info = specs;
267 switch (selector) {
268 case TOOL_ENGINE_UPDATE_DESCRIPTOR:
269 return (dao_command_descriptor (dao, _("Advanced Filter (%s)"), result)
270 == NULL);
271 case TOOL_ENGINE_UPDATE_DAO: {
272 int rows, cols;
273 rows = info->base.range_1->v_range.cell.b.row
274 - info->base.range_1->v_range.cell.a.row + 1;
275 cols = info->base.range_1->v_range.cell.b.col
276 - info->base.range_1->v_range.cell.a.col + 1;
277 if (cols < 2)
278 cols = 2;
279 dao_adjust (dao, cols, 3 + rows);
280 return FALSE;
282 case TOOL_ENGINE_CLEAN_UP:
283 return analysis_tool_generic_b_clean (specs);
284 case TOOL_ENGINE_LAST_VALIDITY_CHECK:
285 return FALSE;
286 case TOOL_ENGINE_PREPARE_OUTPUT_RANGE:
287 dao_prepare_output (NULL, dao, _("Advanced Filter"));
288 return FALSE;
289 case TOOL_ENGINE_FORMAT_OUTPUT_RANGE:
290 return dao_format_output (dao, _("Advanced Filter"));
291 case TOOL_ENGINE_PERFORM_CALC:
292 default:
293 return analysis_tool_advanced_filter_engine_run (dao, info);
295 return TRUE; /* We shouldn't get here */