Skip to content

Commit

Permalink
Merge pull request #62 from CSBiology/feature-moreFsRowFun-#61
Browse files Browse the repository at this point in the history
#61 Add functionality for `FsRow`
  • Loading branch information
omaus authored Aug 10, 2023
2 parents a861d95 + ac14e0d commit 39d270a
Show file tree
Hide file tree
Showing 16 changed files with 835 additions and 557 deletions.
1,033 changes: 543 additions & 490 deletions playground.fsx

Large diffs are not rendered by default.

108 changes: 92 additions & 16 deletions src/FsSpreadsheet/FsRow.fs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
namespace FsSpreadsheet


open System.Collections.Generic
open System.Collections

open Fable.Core


// Type based on the type XLRow used in ClosedXml
/// <summary>
/// Creates an FsRow from the given FsRangeAddress, consisting of FsCells within a given FsCellsCollection, and a styleValue.
Expand All @@ -24,7 +27,7 @@ type FsRow (rangeAddress : FsRangeAddress, cells : FsCellsCollection)=
static member empty() = FsRow (FsRangeAddress(FsAddress(0,0),FsAddress(0,0)),FsCellsCollection())

/// <summary>
/// Create an FsRow from a given FsCellsCollection and an rowIndex.
/// Creates an FsRow from a given FsCellsCollection and an rowIndex.
/// </summary>
/// <remarks>The appropriate range of the cells (i.e. minimum colIndex and maximum colIndex) is derived from the FsCells with the matching rowIndex.</remarks>
static member createAt(index, (cells : FsCellsCollection)) =
Expand All @@ -51,17 +54,29 @@ type FsRow (rangeAddress : FsRangeAddress, cells : FsCellsCollection)=
// ----------

/// The associated FsCells.
member self.Cells =
member this.Cells =
base.Cells(cells)

/// <summary>
/// The index of the FsRow.
/// </summary>
member self.Index
with get() = self.RangeAddress.FirstAddress.RowNumber
member this.Index
with get() = this.RangeAddress.FirstAddress.RowNumber
and set(i) =
self.RangeAddress.FirstAddress.RowNumber <- i
self.RangeAddress.LastAddress.RowNumber <- i
this.RangeAddress.FirstAddress.RowNumber <- i
this.RangeAddress.LastAddress.RowNumber <- i

/// <summary>
/// The number of the lowest column index of the FsRow where an FsCell exists.
/// </summary>
member this.MinColIndex
with get() = this.RangeAddress.FirstAddress.ColumnNumber

/// <summary>
/// The number of the highest column index of the FsRow where an FsCell exists.
/// </summary>
member this.MaxColIndex
with get() = this.RangeAddress.LastAddress.ColumnNumber


// -------
Expand All @@ -71,9 +86,9 @@ type FsRow (rangeAddress : FsRangeAddress, cells : FsCellsCollection)=
/// <summary>
/// Creates a deep copy of this FsRow.
/// </summary>
member self.Copy() =
let ra = self.RangeAddress.Copy()
let cells = self.Cells |> Seq.map (fun c -> c.Copy())
member this.Copy() =
let ra = this.RangeAddress.Copy()
let cells = this.Cells |> Seq.map (fun c -> c.Copy())
let fcc = FsCellsCollection()
fcc.Add cells
FsRow(ra, fcc)
Expand All @@ -89,20 +104,50 @@ type FsRow (rangeAddress : FsRangeAddress, cells : FsCellsCollection)=
/// </summary>
static member getIndex (row : FsRow) =
row.Index


/// <summary>
/// Checks if there is an FsCell at given column index.
/// </summary>
/// <param name="colIndex">The number of the column where the presence of an FsCell shall be checked.</param>
member this.HasCellAt(colIndex) =
this.Cells
|> Seq.exists (fun c -> c.ColumnNumber = colIndex)

/// <summary>
/// Checks if there is an FsCell at given column index of a given FsRow.
/// </summary>
/// <param name="colIndex">The number of the column where the presence of an FsCell shall be checked.</param>
static member hasCellAt colIndex (row : FsRow) =
row.HasCellAt colIndex

/// <summary>
/// Returns the FsCell at columnIndex.
/// Returns the FsCell at columnIndex if it exists. Else creates an empty FsCell at that position.
/// </summary>
member this.Item (columnIndex) =
member this.Item(columnIndex) =
// use FsRangeBase call with colindex 1
base.Cell(FsAddress(1,columnIndex),cells)
base.Cell(FsAddress(1,columnIndex),cells)

/// <summary>
/// Returns the FsCell at the given columnIndex from an FsRow.
/// Returns the FsCell at the given columnIndex from an FsRow if it exists. Else creates an ampty FsCell at that position.
/// </summary>
static member item colIndex (row : FsRow) =
row.Item(colIndex)

/// <summary>
/// Returns the FsCell at the given columnIndex if it exists. Else returns None.
/// </summary>
/// <param name="colIndex">The number of the column where the FsCell shall be retrieved.</param>
member this.TryItem(colIndex) =
if this.HasCellAt colIndex then Some this[colIndex]
else None

/// <summary>

Check warning on line 144 in src/FsSpreadsheet/FsRow.fs

View workflow job for this annotation

GitHub Actions / build-and-deploy-docs

This XML comment is incomplete: no documentation for parameter 'row'

Check warning on line 144 in src/FsSpreadsheet/FsRow.fs

View workflow job for this annotation

GitHub Actions / build-and-test-linux

This XML comment is incomplete: no documentation for parameter 'row'

Check warning on line 144 in src/FsSpreadsheet/FsRow.fs

View workflow job for this annotation

GitHub Actions / build-and-test-windows

This XML comment is incomplete: no documentation for parameter 'row'
/// Returns the FsCell at the given columnIndex if it exists in the given FsRow. Else returns None.
/// </summary>
/// <param name="colIndex">The number of the column where the FsCell shall be retrieved.</param>
static member tryItem colIndex (row: FsRow) =
row.TryItem colIndex

/// <summary>
/// Inserts the value at columnIndex as an FsCell. If there is an FsCell at the position, this FsCells and all the ones right to it are shifted to the right.
/// </summary>
Expand All @@ -119,8 +164,39 @@ type FsRow (rangeAddress : FsRangeAddress, cells : FsCellsCollection)=
row.InsertValueAt(colIndex, value) |> ignore
row

//member self.SortCells() = _cells <- _cells |> List.sortBy (fun c -> c.WorksheetColumn)
//member this.SortCells() = _cells <- _cells |> List.sortBy (fun c -> c.WorksheetColumn)

// TO DO (later)
///// Takes an FsCellsCollection and creates an FsRow from the given rowIndex and the cells in the FsCellsCollection that share the same rowIndex.
//static member fromCellsCollection rowIndex (cellsCollection : FsCellsCollection) =
//static member fromCellsCollection rowIndex (cellsCollection : FsCellsCollection) =

/// <summary>
/// Transforms the FsRow into a dense FsRow.
///
/// FsRows are sparse by default. This means there are no FsCells present between positions with that are filled with FsCells. In dense FsRows, such "empty positions" are then filled with empty FsCells.
/// </summary>
member this.ToDenseRow() =
for i = this.MinColIndex to this.MaxColIndex do
ignore this[i]

/// <summary>
/// Transforms the given FsRow into a dense FsRow.
///
/// FsRows are sparse by default. This means there are no FsCells present between positions with that are filled with FsCells. In dense FsRows, such "empty positions" are then filled with empty FsCells.
/// </summary>
/// <param name="row">The FsRow that gets transformed into a dense FsRow.</param>
/// <remarks>This is an in-place operation.</remarks>
static member toDenseRow (row : FsRow) =
row.ToDenseRow()
row

/// <summary>
/// Takes a given FsRow and returns a new dense FsRow from it.
///
/// FsRows are sparse by default. This means there are no FsCells present between positions with that are filled with FsCells. In dense FsRows, such "empty positions" are then filled with empty FsCells.
/// </summary>
/// <param name="row">The FsRow that whose copy gets transformed into a dense FsRow.</param>
static member createDenseRowOf (row : FsRow) =
let newRow = row.Copy()
newRow.ToDenseRow()
newRow
40 changes: 27 additions & 13 deletions src/FsSpreadsheet/Ranges/FsRangeBase.fs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace FsSpreadsheet


[<AbstractClass>][<AllowNullLiteral>]
type FsRangeBase (rangeAddress : FsRangeAddress) =
//: XLStylizedBase, IXLRangeBase, IXLStylized
Expand All @@ -17,13 +18,13 @@ type FsRangeBase (rangeAddress : FsRangeAddress) =

//abstract member OnRangeAddressChanged : FsRangeAddress*FsRangeAddress -> unit

//default self.OnRangeAddressChanged (oldAddress, newAddress) =
//default this.OnRangeAddressChanged (oldAddress, newAddress) =

// Worksheet.RellocateRange(RangeType, oldAddress, newAddress);

member self.Extend(address : FsAddress) = _rangeAddress.Extend(address)
member this.Extend(address : FsAddress) = _rangeAddress.Extend(address)

member self.RangeAddress
member this.RangeAddress
with get () = _rangeAddress
and set (rangeAdress) =
if rangeAdress <> _rangeAddress then
Expand All @@ -32,10 +33,10 @@ type FsRangeBase (rangeAddress : FsRangeAddress) =
//OnRangeAddressChanged(oldAddress, _rangeAddress);

// TO DO: add description – important and complex function
member self.Cell(cellAddressInRange : FsAddress, cells : FsCellsCollection) =
member this.Cell(cellAddressInRange : FsAddress, cells : FsCellsCollection) =

let absRow = cellAddressInRange.RowNumber + self.RangeAddress.FirstAddress.RowNumber - 1;
let absColumn = cellAddressInRange.ColumnNumber + self.RangeAddress.FirstAddress.ColumnNumber - 1;
let absRow = cellAddressInRange.RowNumber + this.RangeAddress.FirstAddress.RowNumber - 1;
let absColumn = cellAddressInRange.ColumnNumber + this.RangeAddress.FirstAddress.ColumnNumber - 1;

if (absRow <= 0 || absRow > 1048576) then
failwithf "Row number must be between 1 and %i" cells.MaxRowNumber
Expand Down Expand Up @@ -67,13 +68,26 @@ type FsRangeBase (rangeAddress : FsRangeAddress) =
// has a default style, use the worksheet's default style
let newCell = FsCell.createEmptyWithAdress absoluteAddress

self.Extend(absoluteAddress)
this.Extend(absoluteAddress)

cells.Add(absRow, absColumn, newCell) |> ignore
newCell

member self.Cells(cells : FsCellsCollection) =
cells.GetCells(self.RangeAddress.FirstAddress, self.RangeAddress.LastAddress)

member self.ColumnCount() =
_rangeAddress.LastAddress.ColumnNumber - _rangeAddress.FirstAddress.ColumnNumber + 1;

/// <summary>
/// Returns the FsCells of this FsRangeBase with the given FsCellsCollection.
/// </summary>
/// <param name="cells">The FsCellsCollection where the FsCells are retrieved from.</param>
member this.Cells(cells : FsCellsCollection) =
cells.GetCells(this.RangeAddress.FirstAddress, this.RangeAddress.LastAddress)

/// <summary>
/// The number of columns in the FsRangeBase.
/// </summary>
member this.ColumnCount() =
_rangeAddress.LastAddress.ColumnNumber - _rangeAddress.FirstAddress.ColumnNumber + 1

/// <summary>
/// The number of rows in the FsRangeBase.
/// </summary>
member this.RowCount() =
_rangeAddress.LastAddress.RowNumber - _rangeAddress.FirstAddress.RowNumber + 1
Loading

0 comments on commit 39d270a

Please sign in to comment.