mirror of
https://github.com/storytold/gridcraft.git
synced 2026-11-03 17:16:14 -06:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb840345df | ||
|
|
3bc364e712 |
@@ -168,19 +168,6 @@ fn filters_and_report_filter_rows() {
|
||||
assert!(s.execute("pivot.filter", json!({"field": "Product", "selected": []})).is_err());
|
||||
}
|
||||
|
||||
/// A selection of the most labels allowed (100,000) is looked up once per record, not scanned: the
|
||||
/// report still filters case-insensitively.
|
||||
#[test]
|
||||
fn a_huge_filter_selection_is_matched_through_a_set() {
|
||||
let mut s = sales();
|
||||
s.execute("insert.pivotTable", json!({"rows": ["Product"], "values": ["Sales"], "filters": ["Region"]})).unwrap();
|
||||
let mut selected: Vec<String> = (0..99_999).map(|i| format!("Region {i}")).collect();
|
||||
selected.push("EAST".into());
|
||||
s.execute("pivot.filter", json!({"field": "Region", "selected": selected})).unwrap();
|
||||
let gt = find_row(&s, "Grand Total").unwrap();
|
||||
assert_eq!(val(&s, &CellRef::new(gt, 1).a1()), Value::Number(415.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn show_values_as() {
|
||||
let mut s = sales();
|
||||
|
||||
@@ -77,8 +77,6 @@ struct AggregateInput<'a> {
|
||||
extra: &'a [usize],
|
||||
filters: &'a [(usize, &'a PivotFilter, PivotDateGroup, bool)],
|
||||
filter_fmts: &'a [String],
|
||||
/// Each filter's selected labels, ASCII-lowercased, so a record's test is one probe.
|
||||
filter_sets: &'a [Option<HashSet<String>>],
|
||||
row_fmts: &'a [String],
|
||||
col_fmts: &'a [String],
|
||||
empty: bool,
|
||||
@@ -101,10 +99,10 @@ fn aggregate_record(
|
||||
ri: usize,
|
||||
rec: &[Value],
|
||||
) -> Result<(), String> {
|
||||
for (((c, _, group, _), fmt), selected) in input.filters.iter().zip(input.filter_fmts).zip(input.filter_sets) {
|
||||
if let Some(selected) = selected {
|
||||
for ((c, field, group, _), fmt) in input.filters.iter().zip(input.filter_fmts) {
|
||||
if let Some(selected) = &field.selected {
|
||||
let label = item_label(input.wb, rec.get(*c).unwrap_or(&Value::Empty), *group, fmt);
|
||||
if !selected.contains(&label.to_ascii_lowercase()) {
|
||||
if !selected.iter().any(|value| value.eq_ignore_ascii_case(&label)) {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
@@ -477,8 +475,6 @@ pub(super) fn compute_from(wb: &Workbook, pt: &PivotTable, src: &Source, mut pro
|
||||
|
||||
// ---- aggregate
|
||||
let filter_fmts: Vec<String> = filters.iter().map(|f| fmt_of(f.0)).collect();
|
||||
let filter_sets: Vec<Option<HashSet<String>>> =
|
||||
filters.iter().map(|(_, field, _, _)| field.selected.as_ref().map(|s| s.iter().map(|v| v.to_ascii_lowercase()).collect())).collect();
|
||||
let row_fmts: Vec<String> = rows.iter().map(|(c, _)| fmt_of(*c)).collect();
|
||||
let col_fmts: Vec<String> = cols.iter().map(|(c, _)| fmt_of(*c)).collect();
|
||||
let aggregate = aggregate_source(
|
||||
@@ -492,7 +488,6 @@ pub(super) fn compute_from(wb: &Workbook, pt: &PivotTable, src: &Source, mut pro
|
||||
extra: &extra,
|
||||
filters: &filters,
|
||||
filter_fmts: &filter_fmts,
|
||||
filter_sets: &filter_sets,
|
||||
row_fmts: &row_fmts,
|
||||
col_fmts: &col_fmts,
|
||||
empty,
|
||||
|
||||
@@ -375,7 +375,7 @@ pub fn formula_refs(text: &str) -> Vec<(usize, usize, RangeRef, Option<String>,
|
||||
let offset = text.len() - body.len();
|
||||
let Ok(toks) = gridcraft_engine::formula::lexer::tokenize(body) else { return vec![] };
|
||||
let mut out: Vec<(usize, usize, RangeRef, Option<String>, usize)> = Vec::new();
|
||||
let mut seen: Vec<String> = Vec::new();
|
||||
let mut seen: std::collections::HashMap<String, usize> = std::collections::HashMap::new();
|
||||
let mut i = 0;
|
||||
while i < toks.len() {
|
||||
use gridcraft_engine::formula::lexer::Tok;
|
||||
@@ -407,13 +407,8 @@ pub fn formula_refs(text: &str) -> Vec<(usize, usize, RangeRef, Option<String>,
|
||||
continue;
|
||||
};
|
||||
let key = body.get(start..end).unwrap_or("").replace('$', "").to_ascii_uppercase();
|
||||
let idx = match seen.iter().position(|k| *k == key) {
|
||||
Some(k) => k,
|
||||
None => {
|
||||
seen.push(key);
|
||||
seen.len() - 1
|
||||
}
|
||||
};
|
||||
let next = seen.len();
|
||||
let idx = *seen.entry(key).or_insert(next);
|
||||
out.push((start + offset, end + offset, range, sheet, idx % REF_COLOR_COUNT));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -278,6 +278,9 @@ fn paint_cell_decorations(q: &QuadrantPaint<'_>, c: CellRef, rect: Rect, lk: &Lo
|
||||
false
|
||||
}
|
||||
|
||||
/// Most repeats of a fill character laid out in one cell.
|
||||
const MAX_FILL_REPEATS: usize = 8192;
|
||||
|
||||
fn paint_data_bar(p: &egui::Painter, rect: Rect, frac: f32, rgb: [u8; 3], gradient: bool) {
|
||||
let bar = Rect::from_min_size(pos2(rect.left() + 2.0, rect.top() + 2.0), vec2((rect.width() - 4.0) * frac, rect.height() - 4.0));
|
||||
let col = theme::color32(rgb);
|
||||
@@ -432,7 +435,8 @@ fn paint_cell(q: &QuadrantPaint<'_>, painted: &(CellRef, Rect, Look, Option<CfLo
|
||||
{
|
||||
let base_w = w;
|
||||
let cw = p.layout_no_wrap(ch.to_string(), font.clone(), color).size().x.max(1.0);
|
||||
let n = (((avail_w - 2.0 * pad) - base_w) / cw).floor().max(0.0) as usize;
|
||||
// A merged cell's width counts offscreen columns: no screen shows more repeats than this.
|
||||
let n = ((((avail_w - 2.0 * pad) - base_w) / cw).floor().max(0.0) as usize).min(MAX_FILL_REPEATS);
|
||||
let mut s = first_line.clone();
|
||||
if first_line.is_char_boundary(pos) {
|
||||
s.insert_str(pos, &ch.to_string().repeat(n));
|
||||
|
||||
Reference in New Issue
Block a user