Commit Graph

13 Commits

Author SHA1 Message Date
Atanas Korchev
609622692e Add culture-aware editing, display, and formula entry to RadzenSpreadsheet
The spreadsheet engine parsed typed input with the invariant culture while
displaying values with the current culture, breaking the edit round-trip on
non-en-US hosts and making comma-decimal entry (10,50) impossible.

Workbook gains a Culture property (defaults to CurrentCulture) which the
component stamps from its inherited Culture parameter. It drives:

- Cell input parsing (CellData type inference), including day-month date
  handling for cultures where the group and date separators collide (de-DE)
- Edit text and display rendering (GetValue, GetValueAsString, GetDisplayText)
- Number format rendering - format codes stay canonical invariant tokens while
  separators, month names, and AM/PM designators follow the culture
- Formula entry and display via the new FormulaLocalizer (Excel FormulaLocal
  semantics: ';' argument separators and ',' decimals in comma-decimal
  cultures, lenient comma acceptance where unambiguous, canonical invariant
  storage)
- Dialog input (data validation, conditional format, filter) via shared
  conversion helpers on SpreadsheetDialogBase

XLSX and CSV files read and write canonical invariant values regardless of
the workbook culture, including autofit column widths. Malformed formulas now
surface as error trees instead of an unhandled lexer exception. Number format
parsing is cached (hard-bounded) since CellView reparsed per render.

Includes localization demos for the Spreadsheet and Document Processing
sections and culture test suites.

Note: headless code on non-en-US hosts now parses string values with the
host culture; set Workbook.Culture explicitly (or to InvariantCulture) for
host-independent processing.
2026-07-08 14:54:55 +03:00
Atanas Korchev
462711f03f Trim comment cruft across Spreadsheet code
Remove narration comments, stale/incorrect comments, and XML doc
comments on private and internal API across the Spreadsheet model,
formula functions, editor, and tools. Keep comments documenting
non-obvious rationale and XML docs on public API.
2026-06-23 10:49:18 +03:00
Atanas Korchev
b05f50782e Route short-lived StringBuilders through StringBuilderCache
Six call sites that build a string once and either return or assign it
now go through the thread-local cache instead of allocating a fresh
StringBuilder on every call:

- NumberFormat.FormatDate
- NumberFormat.FormatNumber (outer builder; the inner thousand-grouping
  builder stays a direct allocation because it is nested inside the
  outer cached one)
- NumberFormat.FormatScientific
- CsvWriter.BuildContent
- Worksheet.InvalidateFormulasReferencing (formula rebuild)
- ColumnRef.ToString — additionally drops the stackalloc<char>;
  appends digits least-significant first then reverses in place via
  the StringBuilder indexer

Sites left as direct 'new StringBuilder()': CsvReader.ParseCsv,
NumberFormatParser.SplitSections / ParseSection, FormulaLexer
ScanTrivia / ScanStringLiteral / ScanNumericLiteral. Each either holds
two parallel builders, reuses one across many fields with Clear, or
has multiple ToString() / return paths that would need try/finally
release plumbing.
2026-06-15 18:45:17 +03:00
Atanas Korchev
031c3a4b8c Extract NumericCoercion helper and fix date conversion drift
Four implementations of 'coerce a cell value to a double' had drifted
across the spreadsheet codebase, with subtle differences:

- AdvancedFilterCriteria.TryCoerceToDouble: handled DateTime via
  ToOADate
- Worksheet.Filter.TryCoerce: did NOT handle DateTime at all (bug —
  date filters silently failed on DateTime-typed cells)
- ConditionalFormatRules.GreaterThanRule.TryGetNumber: did NOT handle
  DateTime explicitly
- NumberFormat.TryGetNumber: handled DateTime via ToNumber (the
  Lotus 1-2-3-compatible variant)

The codebase canonical is ToNumber() — it correctly applies the
phantom-Feb-29-1900 quirk for dates before March 1, 1900. ToOADate
diverged for that pre-1900 range.

Consolidate into NumericCoercion.TryCoerceToDouble. Filter and
ConditionalFormat now correctly handle DateTime. NumberFormat keeps
its CellDataType gate (intentional) but delegates non-string paths
to the shared helper.

Also fixes DataValidationRule's lingering ToOADate calls so date
validation agrees with date filtering and conditional formatting
for pre-1900 dates, AND collapses 16 empty visit overrides in
FilterCriterionVisitorBase plus removes 50+ lines of trivial Accept
wrappers + dead defensive null guards in StringFilterCriterion.
2026-06-15 18:45:16 +03:00
Atanas Korchev
dc699e9518 Remove noise comments and non-public XML docs from spreadsheet code
Two sweeps over Radzen.Blazor/Documents/Spreadsheet and Radzen.Blazor/Spreadsheet:

- Delete inline `//` comments that merely restate the adjacent code
  (e.g. "// Decrease column count" above `ColumnCount--;`, the "// Parse X"
  labels above the matching ParseX(...) calls). Comments explaining *why*,
  Excel/OOXML quirks, ordering requirements and trade-offs are kept.
- Delete XML doc comments (`///`) on non-public declarations — private/internal
  members and the members of internal types (XlsxWriter/Reader, CsvWriter/Reader,
  the formula lexer/parser, the Functions classes, AutofillCommand, etc.). Docs
  on the public API surface are untouched (the build enforces this via CS1591).

Comment-only changes; no behavior change. Build clean, 1477 spreadsheet tests pass.
2026-06-15 18:45:15 +03:00
Atanas Korchev
79520b2afa Add braces to single-line blocks and expand multi-statement lines 2026-06-15 18:45:05 +03:00
Atanas Korchev
4a70f957c2 Standardize null checks to is null / is not null
Replaced all == null with is null and != null with is not null
across 109 spreadsheet files. The is null pattern uses a direct
reference check that cannot be overridden by operator overloads.
2026-06-15 18:45:05 +03:00
Atanas Korchev
99fd9eb1c9 Extract NumberFormatParser from NumberFormat
NumberFormat.cs (1100 lines) mixed formatting logic with parsing.
Split into:
- NumberFormat.cs (~565 lines) — public API + formatting
- NumberFormatParser.cs (~530 lines) — tokenization + section parsing

Shared types (ParsedFormat, FormatSection, FormatToken, TokenType)
are now internal top-level classes so both can access them.
2026-06-15 18:45:04 +03:00
Atanas Korchev
b1cbf3ef4a Combine triple token iteration into single pass in NumberFormat.ParseSection
Three sequential foreach loops (color extraction, date detection,
number format parsing) merged into one. The isDate flag is checked
inline so number-format fields are skipped for date sections.
2026-06-15 18:45:04 +03:00
Atanas Korchev
ed940153e2 Remove unused cache parameter from NumberFormat.Apply/ApplyWithColor
The Dictionary<string, object> cache parameter was never passed by
any call site. Remove the dead parameter and GetOrParseFormatCode.
2026-06-15 18:45:04 +03:00
Atanas Korchev
d43d792f11 Performance fixes: deduplicate command bases, cache CellMenu, fix O(n²) NumberFormat
- Merge RowCommandBase and ColumnCommandBase into SheetSnapshotCommandBase
- Cache LoadAvailableValues() and ShouldShowBlankOption() in CellMenu
- Fix duplicate GetCurrentTable() call in ShouldShowBlankOption
- Fix O(n²) StringBuilder.Insert(0,...) in NumberFormat thousands separator
- Add error handling to DataCellStore.FetchPageAsync fire-and-forget
2026-06-15 18:45:03 +03:00
Atanas Korchev
24003d100e Cache NumberFormat parsing, use cached FormulaSyntaxTree, deduplicate Apply 2026-06-15 18:45:03 +03:00
Atanas Korchev
5fc3a52908 Move document-layer files to Radzen.Blazor/Documents/Spreadsheet/
137 files with namespace Radzen.Documents.Spreadsheet now live under
Documents/Spreadsheet/ directory, matching their namespace. 76 function
files in Documents/Spreadsheet/Functions/. 27 UI files remain in
Spreadsheet/.
2026-06-15 18:45:03 +03:00