Skip to content

Commit aec3781

Browse files
implement filter_column, filter_column2 and filter_list
1 parent ef8ebe7 commit aec3781

File tree

2 files changed

+286
-27
lines changed

2 files changed

+286
-27
lines changed

libxlsxwriter/src/worksheet/filter.rs

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
use crate::{Workbook, Worksheet, WorksheetCol, WorksheetRow, XlsxError};
2+
3+
/// And/or operator conditions when using 2 filter rules with `filter_column2`.
4+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
5+
pub enum FilterOperator {
6+
FilterAnd,
7+
FilterOr,
8+
}
9+
10+
impl Default for FilterOperator {
11+
fn default() -> Self {
12+
FilterOperator::FilterAnd
13+
}
14+
}
15+
16+
impl FilterOperator {
17+
pub(crate) fn into_internal(self) -> libxlsxwriter_sys::lxw_filter_operator {
18+
match self {
19+
FilterOperator::FilterAnd => libxlsxwriter_sys::lxw_filter_operator_LXW_FILTER_AND,
20+
FilterOperator::FilterOr => libxlsxwriter_sys::lxw_filter_operator_LXW_FILTER_OR,
21+
}
22+
}
23+
}
24+
25+
/// Criteria used to define an autofilter rule condition.
26+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
27+
pub enum FilterCriteria {
28+
/// Filter cells equal to a value.
29+
EqualTo,
30+
/// Filter cells not equal to a value.
31+
NotEqualTo,
32+
/// Filter cells greater than a value.
33+
GreaterThan,
34+
/// Filter cells less than a value.
35+
LessThan,
36+
/// Filter cells greater than or equal to a value.
37+
GreaterThanOrEqualTo,
38+
/// Filter cells less than or equal to a value.
39+
LessThanOrEqualTo,
40+
/// Filter cells that are blank.
41+
Blanks,
42+
/// Filter cells that are not blank.
43+
NonBlanks,
44+
}
45+
46+
impl Default for FilterCriteria {
47+
fn default() -> Self {
48+
FilterCriteria::EqualTo
49+
}
50+
}
51+
52+
impl FilterCriteria {
53+
pub(crate) fn into_internal(self) -> libxlsxwriter_sys::lxw_filter_criteria {
54+
match self {
55+
FilterCriteria::EqualTo => {
56+
libxlsxwriter_sys::lxw_filter_criteria_LXW_FILTER_CRITERIA_EQUAL_TO
57+
}
58+
FilterCriteria::NotEqualTo => {
59+
libxlsxwriter_sys::lxw_filter_criteria_LXW_FILTER_CRITERIA_NOT_EQUAL_TO
60+
}
61+
FilterCriteria::GreaterThan => {
62+
libxlsxwriter_sys::lxw_filter_criteria_LXW_FILTER_CRITERIA_GREATER_THAN
63+
}
64+
FilterCriteria::LessThan => {
65+
libxlsxwriter_sys::lxw_filter_criteria_LXW_FILTER_CRITERIA_LESS_THAN
66+
}
67+
FilterCriteria::GreaterThanOrEqualTo => {
68+
libxlsxwriter_sys::lxw_filter_criteria_LXW_FILTER_CRITERIA_GREATER_THAN_OR_EQUAL_TO
69+
}
70+
FilterCriteria::LessThanOrEqualTo => {
71+
libxlsxwriter_sys::lxw_filter_criteria_LXW_FILTER_CRITERIA_LESS_THAN_OR_EQUAL_TO
72+
}
73+
FilterCriteria::Blanks => {
74+
libxlsxwriter_sys::lxw_filter_criteria_LXW_FILTER_CRITERIA_BLANKS
75+
}
76+
FilterCriteria::NonBlanks => {
77+
libxlsxwriter_sys::lxw_filter_criteria_LXW_FILTER_CRITERIA_NON_BLANKS
78+
}
79+
}
80+
}
81+
}
82+
83+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Default)]
84+
pub struct FilterRule {
85+
pub criteria: FilterCriteria,
86+
pub value_string: Option<String>,
87+
pub value: Option<f64>,
88+
}
89+
90+
impl FilterRule {
91+
pub(crate) fn into_internal(&self, workbook: &Workbook) -> libxlsxwriter_sys::lxw_filter_rule {
92+
libxlsxwriter_sys::lxw_filter_rule {
93+
criteria: self.criteria.into_internal() as u8,
94+
value_string: workbook.register_option_str(self.value_string.as_deref())
95+
as *mut std::ffi::c_char,
96+
value: self.value.unwrap_or_default(),
97+
}
98+
}
99+
}
100+
101+
impl<'a> Worksheet<'a> {
102+
/// This function allows an autofilter to be added to a worksheet.
103+
///
104+
/// An autofilter is a way of adding drop down lists to the headers of a 2D range of worksheet data.
105+
/// This allows users to filter the data based on simple criteria so that some data is shown and some is hidden.
106+
pub fn autofilter(
107+
&mut self,
108+
first_row: WorksheetRow,
109+
first_col: WorksheetCol,
110+
last_row: WorksheetRow,
111+
last_col: WorksheetCol,
112+
) -> Result<(), XlsxError> {
113+
unsafe {
114+
let result = libxlsxwriter_sys::worksheet_autofilter(
115+
self.worksheet,
116+
first_row,
117+
first_col,
118+
last_row,
119+
last_col,
120+
);
121+
if result == libxlsxwriter_sys::lxw_error_LXW_NO_ERROR {
122+
Ok(())
123+
} else {
124+
Err(XlsxError::new(result))
125+
}
126+
}
127+
}
128+
129+
/// This function can be used to filter columns in a autofilter range based on single rule conditions.
130+
///
131+
/// The `col` parameter is a zero indexed column number and must refer to a column in an existing autofilter created with `autofilter`.
132+
/// It isn't sufficient to just specify the filter condition. You must also hide any rows that don't match the filter condition.
133+
pub fn filter_column(
134+
&mut self,
135+
col: crate::WorksheetCol,
136+
rule: &FilterRule,
137+
) -> Result<(), XlsxError> {
138+
unsafe {
139+
let mut rule_converted = rule.into_internal(self._workbook);
140+
let e = libxlsxwriter_sys::worksheet_filter_column(
141+
self.worksheet,
142+
col,
143+
&mut rule_converted,
144+
);
145+
if e != libxlsxwriter_sys::lxw_error_LXW_NO_ERROR {
146+
return Err(XlsxError::new(e));
147+
}
148+
}
149+
Ok(())
150+
}
151+
152+
/// This function can be used to filter columns in a autofilter range based on two rule conditions.
153+
///
154+
/// It isn't sufficient to just specify the filter condition. You must also hide any rows that don't match the filter condition.
155+
pub fn filter_column2(
156+
&mut self,
157+
col: crate::WorksheetCol,
158+
rule1: &FilterRule,
159+
rule2: &FilterRule,
160+
and_or: FilterOperator,
161+
) -> Result<(), XlsxError> {
162+
unsafe {
163+
let mut rule_converted1 = rule1.into_internal(self._workbook);
164+
let mut rule_converted2 = rule2.into_internal(self._workbook);
165+
let e = libxlsxwriter_sys::worksheet_filter_column2(
166+
self.worksheet,
167+
col,
168+
&mut rule_converted1,
169+
&mut rule_converted2,
170+
and_or.into_internal() as u8,
171+
);
172+
if e != libxlsxwriter_sys::lxw_error_LXW_NO_ERROR {
173+
return Err(XlsxError::new(e));
174+
}
175+
}
176+
Ok(())
177+
}
178+
179+
pub fn filter_list(
180+
&mut self,
181+
col: crate::WorksheetCol,
182+
list: &[&str],
183+
) -> Result<(), XlsxError> {
184+
let mut cstring_helper = crate::CStringHelper::new();
185+
let mut cstr_list: Vec<_> = list
186+
.iter()
187+
.map(|x| cstring_helper.add(x) as *mut std::ffi::c_char)
188+
.collect();
189+
unsafe {
190+
let result = libxlsxwriter_sys::worksheet_filter_list(
191+
self.worksheet,
192+
col,
193+
cstr_list.as_mut_ptr(),
194+
);
195+
if result != libxlsxwriter_sys::lxw_error_LXW_NO_ERROR {
196+
return Err(XlsxError::new(result));
197+
}
198+
}
199+
Ok(())
200+
}
201+
}
202+
203+
#[cfg(test)]
204+
mod test {
205+
use crate::RowColOptions;
206+
207+
use super::*;
208+
209+
fn create_sheet(worksheet: &mut Worksheet) -> Result<(), XlsxError> {
210+
worksheet.write_string(0, 0, "Column A", None)?;
211+
worksheet.write_string(0, 1, "Column B", None)?;
212+
worksheet.write_string(0, 2, "Column C", None)?;
213+
worksheet.write_string(0, 3, "Column D", None)?;
214+
215+
for i in 1..20 {
216+
let value: f64 = i.into();
217+
worksheet.write_number(i, 0, value, None)?;
218+
worksheet.write_number(i, 1, value / 2., None)?;
219+
worksheet.write_string(i, 2, &format!("TEXT{:02}", i), None)?;
220+
worksheet.write_boolean(i, 3, i % 2 == 0, None)?;
221+
}
222+
worksheet.autofilter(0, 0, 19, 3)?;
223+
Ok(())
224+
}
225+
226+
#[test]
227+
fn test_autofilter() -> Result<(), XlsxError> {
228+
let workbook = Workbook::new("test-worksheet_autofilter.xlsx");
229+
// ------------
230+
let mut worksheet1 = workbook.add_worksheet(Some("Sheet 1"))?;
231+
create_sheet(&mut worksheet1)?;
232+
let worksheet1_criteria = FilterRule {
233+
criteria: FilterCriteria::GreaterThan,
234+
value: Some(10.),
235+
value_string: None,
236+
};
237+
worksheet1.filter_column(0, &worksheet1_criteria)?;
238+
let mut hidden_row = RowColOptions {
239+
hidden: 1,
240+
level: 0,
241+
collapsed: 0,
242+
};
243+
for i in 1..=10 {
244+
worksheet1.set_row_opt(i, 13.2, None, &mut hidden_row)?;
245+
}
246+
// ------------
247+
let mut worksheet2 = workbook.add_worksheet(Some("Sheet 2"))?;
248+
create_sheet(&mut worksheet2)?;
249+
let worksheet2_criteria1 = FilterRule {
250+
criteria: FilterCriteria::GreaterThanOrEqualTo,
251+
value: Some(3.),
252+
value_string: None,
253+
};
254+
let worksheet2_criteria2 = FilterRule {
255+
criteria: FilterCriteria::LessThan,
256+
value: Some(5.5),
257+
value_string: None,
258+
};
259+
worksheet2.filter_column2(
260+
1,
261+
&worksheet2_criteria1,
262+
&worksheet2_criteria2,
263+
FilterOperator::FilterAnd,
264+
)?;
265+
for i in 1..20 {
266+
let value: f64 = i.into();
267+
if (value / 2.0) < 3. || 5.5 <= (value / 2.0) {
268+
worksheet2.set_row_opt(i, 13.2, None, &mut hidden_row)?;
269+
}
270+
}
271+
// --------------
272+
let mut worksheet3 = workbook.add_worksheet(Some("Sheet 3"))?;
273+
create_sheet(&mut worksheet3)?;
274+
worksheet3.filter_list(2, &["TEXT02", "TEXT03"])?;
275+
for i in 1..20 {
276+
if i != 2 && i != 3 {
277+
worksheet3.set_row_opt(i, 13.2, None, &mut hidden_row)?;
278+
}
279+
}
280+
281+
workbook.close()?;
282+
Ok(())
283+
}
284+
}

libxlsxwriter/src/worksheet/mod.rs

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
mod filter;
12
mod table;
23
mod validation;
34

45
use super::{convert_bool, Chart, Format, FormatColor, Workbook, XlsxError};
56
use std::ffi::CString;
67
use std::os::raw::c_char;
78

9+
pub use filter::*;
810
pub use table::*;
911
pub use validation::*;
1012

@@ -1308,33 +1310,6 @@ impl<'a> Worksheet<'a> {
13081310
}
13091311
}
13101312

1311-
/// This function allows an autofilter to be added to a worksheet.
1312-
///
1313-
/// An autofilter is a way of adding drop down lists to the headers of a 2D range of worksheet data.
1314-
/// This allows users to filter the data based on simple criteria so that some data is shown and some is hidden.
1315-
pub fn autofilter(
1316-
&mut self,
1317-
first_row: WorksheetRow,
1318-
first_col: WorksheetCol,
1319-
last_row: WorksheetRow,
1320-
last_col: WorksheetCol,
1321-
) -> Result<(), XlsxError> {
1322-
unsafe {
1323-
let result = libxlsxwriter_sys::worksheet_autofilter(
1324-
self.worksheet,
1325-
first_row,
1326-
first_col,
1327-
last_row,
1328-
last_col,
1329-
);
1330-
if result == libxlsxwriter_sys::lxw_error_LXW_NO_ERROR {
1331-
Ok(())
1332-
} else {
1333-
Err(XlsxError::new(result))
1334-
}
1335-
}
1336-
}
1337-
13381313
pub fn activate(&mut self) {
13391314
unsafe {
13401315
libxlsxwriter_sys::worksheet_activate(self.worksheet);

0 commit comments

Comments
 (0)