From 2069ed947aa1dd5c7c7a76a8c7c053b7c408996a Mon Sep 17 00:00:00 2001 From: omaus Date: Thu, 23 Mar 2023 00:45:52 +0100 Subject: [PATCH] Add deep copy methods to all relevant classes Also finalized ///-comments. --- src/FsSpreadsheet.ExcelIO/FsExtensions.fs | 65 ++++++- src/FsSpreadsheet/Cells/FsCell.fs | 55 +++++- src/FsSpreadsheet/Cells/FsCellsCollection.fs | 168 ++++++++++++---- src/FsSpreadsheet/FsAddress.fs | 24 ++- src/FsSpreadsheet/FsRow.fs | 48 ++++- src/FsSpreadsheet/FsWorkbook.fs | 74 +++++-- src/FsSpreadsheet/FsWorksheet.fs | 191 +++++++++++++++---- src/FsSpreadsheet/Ranges/FsRangeAddress.fs | 50 ++++- src/FsSpreadsheet/Ranges/FsRangeBase.fs | 6 +- src/FsSpreadsheet/Ranges/FsRangeColumn.fs | 12 ++ src/FsSpreadsheet/Tables/FsTable.fs | 17 +- src/FsSpreadsheet/Tables/FsTableField.fs | 15 ++ 12 files changed, 607 insertions(+), 118 deletions(-) diff --git a/src/FsSpreadsheet.ExcelIO/FsExtensions.fs b/src/FsSpreadsheet.ExcelIO/FsExtensions.fs index 03915b89..ef4065b1 100644 --- a/src/FsSpreadsheet.ExcelIO/FsExtensions.fs +++ b/src/FsSpreadsheet.ExcelIO/FsExtensions.fs @@ -6,14 +6,18 @@ open FsSpreadsheet open FsSpreadsheet.ExcelIO open System.IO +/// /// Classes that extend the core FsSpreadsheet library with IO functionalities. +/// [] module FsExtensions = type DataType with - /// Converts a given CellValues to the respective DataType. + /// + /// Converts a given CellValues to the respective DataType. + /// static member ofXlsxCellValues (cellValues : CellValues) = match cellValues with | CellValues.Number -> DataType.Number @@ -32,7 +36,9 @@ module FsExtensions = // let row,col = xlsxCell.CellReference.Value |> CellReference.toIndices // FsCell.create (int row) (int col) v - /// Creates an FsCell on the basis of an XlsxCell. Uses a SharedStringTable if present to get the XlsxCell's value. + /// + /// Creates an FsCell on the basis of an XlsxCell. Uses a SharedStringTable if present to get the XlsxCell's value. + /// static member ofXlsxCell (sst : SharedStringTable option) (xlsxCell : Cell) = let v = Cell.getValue sst xlsxCell let col, row = xlsxCell.CellReference.Value |> CellReference.toIndices @@ -44,7 +50,9 @@ module FsExtensions = type FsTable with + /// /// Returns the FsTable with given FsCellsCollection in the form of an XlsxTable. + /// member self.ToXlsxTable(cells : FsCellsCollection) = let columns = @@ -54,7 +62,9 @@ module FsExtensions = ) Table.create self.Name (StringValue(self.RangeAddress.Range)) columns + /// /// Returns an FsTable with given FsCellsCollection in the form of an XlsxTable. + /// static member toXlsxTable cellsCollection (table : FsTable) = table.ToXlsxTable(cellsCollection) @@ -62,13 +72,16 @@ module FsExtensions = //new(table : Spreadsheet.Table) = // not permitted :( //FsTable(table) + /// /// Takes an XlsxTable and returns an FsTable. static member fromXlsxTable table = let topLeftBoundary, bottomRightBoundary = Table.getArea table |> Table.Area.toBoundaries let ra = FsRangeAddress(FsAddress(topLeftBoundary), FsAddress(bottomRightBoundary)) FsTable(table.Name, ra, table.TotalsRowShown, true) - /// Returns the FsWorksheet associated with the FsTable in a given FsWorkbook. + /// + /// Returns the FsWorksheet associated with the FsTable in a given FsWorkbook. + /// member self.GetWorksheetOfTable(workbook : FsWorkbook) = workbook.GetWorksheets() |> List.find ( @@ -77,14 +90,18 @@ module FsExtensions = |> List.exists (fun t -> t.Name = self.Name) ) - /// Returns the FsWorksheet associated with a given FsTable in an FsWorkbook. + /// + /// Returns the FsWorksheet associated with a given FsTable in an FsWorkbook. + /// static member getWorksheetOfTable workbook (table : FsTable) = table.GetWorksheetOfTable workbook type FsWorksheet with + /// /// Returns the FsWorksheet in the form of an XlsxSpreadsheet. + /// member self.ToXlsxWorksheet() = self.RescanRows() let sheet = Worksheet.empty() @@ -110,11 +127,15 @@ module FsExtensions = sd Worksheet.setSheetData sheetData sheet + /// /// Returns an FsWorksheet in the form of an XlsxSpreadsheet. + /// static member toXlsxWorksheet (fsWorksheet : FsWorksheet) = fsWorksheet.ToXlsxWorksheet() + /// /// Appends the FsTables of this FsWorksheet to a given OpenXmlWorksheetPart in an XlsxWorkbookPart. + /// member self.AppendTablesToWorksheetPart(xlsxlWorkbookPart : DocumentFormat.OpenXml.Packaging.WorkbookPart, xlsxWorksheetPart : DocumentFormat.OpenXml.Packaging.WorksheetPart) = self.Tables |> Seq.iter (fun t -> @@ -122,14 +143,18 @@ module FsExtensions = Table.addTable xlsxlWorkbookPart xlsxWorksheetPart table |> ignore ) + /// /// Appends the FsTables of an FsWorksheet to a given OpenXmlWorksheetPart in an XlsxWorkbookPart. + /// static member appendTablesToWorksheetPart xlsxWorkbookPart xlsxWorksheetPart (fsWorksheet : FsWorksheet) = fsWorksheet.AppendTablesToWorksheetPart(xlsxWorkbookPart, xlsxWorksheetPart) type FsWorkbook with - /// Creates an FsWorkbook from a given Stream to an XlsxFile. + /// + /// Creates an FsWorkbook from a given Stream to an XlsxFile. + /// // TO DO: Ask HLW/TM: is this REALLY the way to go? This is not a constructor! (though it tries to be one) member self.FromXlsxStream (stream : Stream) = let doc = Spreadsheet.fromStream stream false @@ -175,18 +200,24 @@ module FsExtensions = sheets |> Seq.fold (fun wb sheet -> FsWorkbook.addWorksheet sheet wb) (new FsWorkbook()) - /// Creates an FsWorkbook from a given Stream to an XlsxFile. + /// + /// Creates an FsWorkbook from a given Stream to an XlsxFile. + /// static member fromXlsxStream (stream : Stream) = (new FsWorkbook()).FromXlsxStream stream - /// Takes the path to an Xlsx file and returns the FsWorkbook based on its content. + /// + /// Takes the path to an Xlsx file and returns the FsWorkbook based on its content. + /// static member fromXlsxFile (filePath : string) = let sr = new StreamReader(filePath) let wb = FsWorkbook.fromXlsxStream sr.BaseStream sr.Close() wb + /// /// Writes the FsWorkbook into a given MemoryStream. + /// member self.ToStream(stream : MemoryStream) = let doc = Spreadsheet.initEmptyOnStream stream @@ -206,40 +237,58 @@ module FsExtensions = Spreadsheet.close doc + /// /// Writes an FsWorkbook into a given MemoryStream. + /// static member toStream stream (workbook : FsWorkbook) = workbook.ToStream stream + /// /// Returns the FsWorkbook in the form of a byte array. + /// member self.ToBytes() = use memoryStream = new MemoryStream() self.ToStream(memoryStream) memoryStream.ToArray() + /// /// Returns an FsWorkbook in the form of a byte array. + /// static member toBytes (workbook: FsWorkbook) = workbook.ToBytes() + /// /// Writes the FsWorkbook into a binary file at the given path. + /// member self.ToFile(path) = self.ToBytes() |> fun bytes -> File.WriteAllBytes (path, bytes) + /// /// Writes an FsWorkbook into a binary file at the given path. + /// static member toFile path (workbook : FsWorkbook) = workbook.ToFile(path) type Writer = - + + /// /// Writes an FsWorkbook into a given MemoryStream. + /// static member toStream(stream : MemoryStream, workbook : FsWorkbook) = workbook.ToStream(stream) + + /// /// Returns an FsWorkbook in the form of a byte array. + /// static member toBytes(workbook: FsWorkbook) = workbook.ToBytes() + + /// /// Writes an FsWorkbook into a binary file at the given path. + /// static member toFile(path,workbook: FsWorkbook) = workbook.ToFile(path) \ No newline at end of file diff --git a/src/FsSpreadsheet/Cells/FsCell.fs b/src/FsSpreadsheet/Cells/FsCell.fs index b3ace87b..f84fb1cd 100644 --- a/src/FsSpreadsheet/Cells/FsCell.fs +++ b/src/FsSpreadsheet/Cells/FsCell.fs @@ -2,7 +2,9 @@ open System -/// Possible DataTypes used in a FsCell +/// +/// Possible DataTypes used in a FsCell. +/// type DataType = | String | Boolean @@ -10,7 +12,9 @@ type DataType = | Date | Empty + /// /// Returns the proper CellValues case for the given value. + /// static member InferCellValue (value : 'T) = let value = box value match value with @@ -32,7 +36,9 @@ type DataType = | _ -> DataType.String,value.ToString() // Type based on the type XLCell used in ClosedXml +/// /// Creates an FsCell of `DataType` dataType, with value of type `string`, and `FsAddress` address. +/// type FsCell (value : IConvertible, dataType : DataType, address : FsAddress) = // TODO: Maybe save as IConvertible @@ -99,17 +105,23 @@ type FsCell (value : IConvertible, dataType : DataType, address : FsAddress) = with get() = _dataType and internal set(dataType) = _dataType <- dataType + /// /// Gets or sets the columnIndex of the FsCell. + /// member self.ColumnNumber with get() = _columnIndex and set(colI) = _columnIndex <- colI + /// /// Gets or sets the rowIndex of the FsCell. + /// member self.RowNumber with get() = _rowIndex and set(rowI) = _rowIndex <- rowI - /// Gets this FsCell's address, relative to the FsWorksheet. + /// + /// Gets this FsCell's address, relative to the FsWorksheet. + /// /// The FsCell's address. member self.Address with get() = FsAddress(_rowIndex,_columnIndex) @@ -118,25 +130,35 @@ type FsCell (value : IConvertible, dataType : DataType, address : FsAddress) = _columnIndex <- address.ColumnNumber - /// Create an FsCell from given rowNumber, colNumber, and value. Infers the DataType. + /// + /// Create an FsCell from given rowNumber, colNumber, and value. Infers the DataType. + /// static member create (rowNumber : int) (colNumber : int) value = let dataT, value = DataType.InferCellValue value FsCell(value, dataT, FsAddress(rowNumber, colNumber)) - /// Creates an empty FsCell. + /// + /// Creates an empty FsCell. + /// static member createEmpty () = FsCell("", DataType.Empty, FsAddress(0,0)) - /// Creates an FsCell with the given FsAdress and value. Inferes the DataType. + /// + /// Creates an FsCell with the given FsAdress and value. Inferes the DataType. + /// static member createWithAdress (adress : FsAddress) value = let dataT, value = DataType.InferCellValue value FsCell(value, dataT, adress) - /// Creates an empty FsCell with a given FsAddress. + /// + /// Creates an empty FsCell with a given FsAddress. + /// static member createEmptyWithAdress (adress : FsAddress) = FsCell("", DataType.Empty, adress) - /// Creates an FsCell with the given DataType, rowNumber, colNumber, and value. + /// + /// Creates an FsCell with the given DataType, rowNumber, colNumber, and value. + /// static member createWithDataType (dataType : DataType) (rowNumber : int) (colNumber : int) value = FsCell(value, dataType, FsAddress(rowNumber, colNumber)) @@ -167,7 +189,9 @@ type FsCell (value : IConvertible, dataType : DataType, address : FsAddress) = self.DataType <- otherCell.DataType self.Value <- otherCell.Value + /// /// Copies DataType and Value from this FsCell to a given one and replaces theirs. + /// member self.CopyTo(target : FsCell) = target.DataType <- self.DataType target.Value <- self.Value @@ -175,11 +199,26 @@ type FsCell (value : IConvertible, dataType : DataType, address : FsAddress) = /// /// Copies and replaces DataType and Value from a source FsCell into a target FsCell. Returns the target cell. /// - static member copy (sourceCell : FsCell) (targetCell : FsCell) = + static member copyFromTo (sourceCell : FsCell) (targetCell : FsCell) = targetCell.DataType <- sourceCell.DataType targetCell.Value <- sourceCell.Value targetCell + /// + /// Creates a deep copy of this FsCell. + /// + member self.Copy() = + let value = self.Value + let dt = self.DataType + let addr = self.Address.Copy() + FsCell(value, dt, addr) + + /// + /// Returns a deep copy of a given FsCell. + /// + static member copy (cell : FsCell) = + cell.Copy() + /// /// Gets the cell's value converted to the T type. /// FsSpreadsheet will try to convert the current value to type 'T. diff --git a/src/FsSpreadsheet/Cells/FsCellsCollection.fs b/src/FsSpreadsheet/Cells/FsCellsCollection.fs index 92acdb35..4c915467 100644 --- a/src/FsSpreadsheet/Cells/FsCellsCollection.fs +++ b/src/FsSpreadsheet/Cells/FsCellsCollection.fs @@ -3,6 +3,7 @@ open System.Collections.Generic open System.Linq + module Dictionary = let tryGet (k : 'Key) (dict : Dictionary<'Key,'Value>) = @@ -12,7 +13,6 @@ module Dictionary = else None - type FsCellsCollection() = // --------- @@ -51,6 +51,19 @@ type FsCellsCollection() = // METHODS // ------- + /// + /// Creates a deep copy of the FsCellsCollection. + /// + member this.Copy() = + let cells = this.GetCells() |> Seq.map (fun (c : FsCell) -> c.Copy()) + FsCellsCollection.createFromCells cells + + /// + /// Returns a deep copy of a given FsCellsCollection. + /// + static member copy (cellsCollection : FsCellsCollection) = + cellsCollection.Copy() + /// static member private IncrementUsage(dictionary : Dictionary, key : int32) = @@ -75,10 +88,14 @@ type FsCellsCollection() = | None -> false - /// Creates an FsCellsCollection from the given FsCells. + /// + /// Creates an FsCellsCollection from the given FsCells. + /// /// Derives row- and columnIndices from the FsAddress of the FsCells. static member createFromCells (cells : seq) = - FsCellsCollection().Add cells + let fcc = FsCellsCollection() + fcc.Add cells + fcc // TO DO: Must create deep copy methods for ALL other objects in it first, and call them here. ///// Creates and returns a deep copy of the FsCellsCollection. @@ -88,11 +105,15 @@ type FsCellsCollection() = // let newCells = // create deep copy here // newCellsColl.Add cells - ///// Creates and returns a deep copy of an FsCellsCollection. + ///// + ///// Creates and returns a deep copy of an FsCellsCollection. + ///// //static member copy (cellsCollection : FsCellsCollection) = // cellsCollection.Copy() - /// Empties the whole FsCellsCollection. + /// + /// Empties the whole FsCellsCollection. + /// member this.Clear() = _count <- 0; @@ -110,7 +131,9 @@ type FsCellsCollection() = // Add(sheetPoint.Row, sheetPoint.Column, cell); //} - /// Adds an FsCell of given rowIndex and columnIndex to the FsCellsCollection. + /// + /// Adds an FsCell of given rowIndex and columnIndex to the FsCellsCollection. + /// member this.Add(row : int32, column : int32, cell : FsCell) = _count <- _count + 1 @@ -137,40 +160,53 @@ type FsCellsCollection() = | None -> () - this - - /// Adds an FsCell of given rowIndex and columnIndex to an FsCellsCollection. + /// + /// Adds an FsCell of given rowIndex and columnIndex to an FsCellsCollection. + /// static member addCellWithIndeces rowIndex colIndex (cell : FsCell) (cellsCollection : FsCellsCollection) = cellsCollection.Add(rowIndex, colIndex, cell) - /// Adds an FsCell to the FsCellsCollection. + /// + /// Adds an FsCell to the FsCellsCollection. + /// /// Derives row- and columnIndex from the FsAddress of the FsCell. member this.Add(cell : FsCell) = this.Add(cell.Address.RowNumber, cell.Address.ColumnNumber, cell) - /// Adds an FsCell to an FsCellsCollection. + /// + /// Adds an FsCell to an FsCellsCollection. + /// /// Derives row- and columnIndex from the FsAddress of the FsCell. static member addCell (cell : FsCell) (cellsCollection : FsCellsCollection) = cellsCollection.Add(cell) + cellsCollection - /// Adds FsCells to the FsCellsCollection. + /// + /// Adds FsCells to the FsCellsCollection. + /// /// Derives row- and columnIndeces from the FsAddress of the FsCells. member this.Add(cells : seq) = cells |> Seq.iter (this.Add >> ignore) - this - /// Adds FsCells to an FsCellsCollection. + /// + /// Adds FsCells to an FsCellsCollection. + /// /// Derives row- and columnIndeces from the FsAddress of the FsCells. static member addCells (cells : seq) (cellsCollection : FsCellsCollection) = cellsCollection.Add cells + cellsCollection - /// Checks if an FsCell exists at given row- and columnIndex. + /// + /// Checks if an FsCell exists at given row- and columnIndex. + /// member this.ContainsCellAt(rowIndex, colIndex) = match Dictionary.tryGet rowIndex _rowsCollection with | Some colsCollection -> colsCollection.ContainsKey colIndex | None -> false - /// Checks if an FsCell exists at given row- and columnIndex of a given FsCellsCollection. + /// + /// Checks if an FsCell exists at given row- and columnIndex of a given FsCellsCollection. + /// static member containsCellAt rowIndex colIndex (cellsCollection : FsCellsCollection) = cellsCollection.ContainsCellAt(rowIndex, colIndex) @@ -179,7 +215,9 @@ type FsCellsCollection() = // Remove(sheetPoint.Row, sheetPoint.Column); //} + /// /// Removes an FsCell of given rowIndex and columnIndex from the FsCellsCollection. + /// member this.RemoveCellAt(row : int32, column : int32) = _count <- _count - 1 @@ -218,11 +256,16 @@ type FsCellsCollection() = | None -> () + /// /// Removes an FsCell of given rowIndex and columnIndex from an FsCellsCollection. + /// static member removeCellAt rowIndex colIndex (cellsCollection : FsCellsCollection) = cellsCollection.RemoveCellAt(rowIndex, colIndex) + cellsCollection - /// Removes the value of an FsCell at given row- and columnIndex if it exists from the FsCollection. + /// + /// Removes the value of an FsCell at given row- and columnIndex if it exists from the FsCollection. + /// /// Does nothing if the row or column of given index does not exist. /// if columnIndex is null. member this.TryRemoveValueAt(rowIndex, colIndex) = @@ -231,15 +274,19 @@ type FsCellsCollection() = try (colsCollection.Item colIndex).Value <- "" with _ -> () | None -> () - this - /// Removes the value of an FsCell at given row- and columnIndex if it exists from a given FsCollection. + /// + /// Removes the value of an FsCell at given row- and columnIndex if it exists from a given FsCollection. + /// /// Does nothing if the row or column of given index does not exist. /// Throws `System.ArgumentNullException` if columnIndex is null. static member tryRemoveValueAt rowIndex colIndex (cellsCollection : FsCellsCollection) = cellsCollection.TryRemoveValueAt(rowIndex, colIndex) + cellsCollection - /// Removes the value of an FsCell at given row- and columnIndex from the FsCollection. + /// + /// Removes the value of an FsCell at given row- and columnIndex from the FsCollection. + /// /// if rowIndex or columnIndex is null. /// if row or column at the given index does not exist. member this.RemoveValueAt(rowIndex, colIndex) = @@ -248,23 +295,31 @@ type FsCellsCollection() = .Item(colIndex) .Value <- "" - /// Removes the value of an FsCell at given row- and columnIndex from a given FsCollection. + /// + /// Removes the value of an FsCell at given row- and columnIndex from a given FsCollection. + /// /// if rowIndex or columnIndex is null. /// if row or column at the given index does not exist. static member removeValueAt rowIndex colIndex (cellsCollection : FsCellsCollection) = cellsCollection.RemoveValueAt(rowIndex, colIndex) + cellsCollection + /// /// Returns all FsCells of the FsCellsCollection. + /// member this.GetCells() = - _rowsCollection.Values |> Seq.collect (fun columnsCollection -> columnsCollection.Values) + /// /// Returns all FsCells of the FsCellsCollection. + /// static member getCells (cellsCollection : FsCellsCollection) = cellsCollection.GetCells() + /// /// Returns the FsCells from given rowStart to rowEnd and columnStart to columnEnd and fulfilling the predicate. + /// member this.GetCells(rowStart : int32, columnStart : int32, rowEnd : int32, columnEnd : int32, predicate : FsCell -> bool) = let finalRow = if rowEnd > _maxRowUsed then _maxRowUsed else rowEnd @@ -282,46 +337,59 @@ type FsCellsCollection() = | None -> () } + /// /// Returns the FsCells from an FsCellsCollection with given rowStart to rowEnd and columnStart to columnEnd and fulfilling the predicate. + /// static member filterCellsFromTo rowStart columnStart rowEnd columnEnd (predicate : FsCell -> bool) (cellsCollection : FsCellsCollection) = cellsCollection.GetCells(rowStart, columnStart, rowEnd, columnEnd, predicate) + /// /// Returns the FsCells from given startAddress to lastAddress and fulfilling the predicate. + /// member this.GetCells(startAddress : FsAddress, lastAddress : FsAddress, predicate : FsCell -> bool) = this.GetCells(startAddress.RowNumber,startAddress.ColumnNumber,lastAddress.RowNumber,lastAddress.ColumnNumber, predicate) + /// /// Returns the FsCells from an FsCellsCollection with given startAddress to lastAddress and fulfilling the predicate. + /// static member filterCellsFromToAddress startAddress lastAddress (predicate : FsCell -> bool) (cellsCollection : FsCellsCollection) = cellsCollection.GetCells(startAddress, lastAddress, predicate) + /// /// Returns the FsCells from given rowStart to rowEnd and columnStart to columnEnd. + /// member this.GetCells(rowStart : int32, columnStart : int32, rowEnd : int32, columnEnd : int32) = + let finalRow = if rowEnd > _maxRowUsed then _maxRowUsed else rowEnd + let finalColumn = if columnEnd > _maxColumnUsed then _maxColumnUsed else columnEnd + seq { + for ro = rowStart to finalRow do - let finalRow = if rowEnd > _maxRowUsed then _maxRowUsed else rowEnd - let finalColumn = if columnEnd > _maxColumnUsed then _maxColumnUsed else columnEnd - seq { - for ro = rowStart to finalRow do - - match Dictionary.tryGet ro _rowsCollection with - | Some columnsCollection -> - for co = columnStart to finalColumn do - match Dictionary.tryGet co columnsCollection with - | Some cell -> - yield cell - | _ -> () - | None -> () - } + match Dictionary.tryGet ro _rowsCollection with + | Some columnsCollection -> + for co = columnStart to finalColumn do + match Dictionary.tryGet co columnsCollection with + | Some cell -> + yield cell + | _ -> () + | None -> () + } + /// /// Returns the FsCells from an FsCellsCollection with given rowStart to rowEnd and columnStart to columnEnd. + /// static member getCellsFromTo rowStart columnStart rowEnd columnEnd (cellsCollection : FsCellsCollection) = cellsCollection.GetCells(rowStart, columnStart, rowEnd, columnEnd) + /// /// Returns the FsCells from given startAddress to lastAddress. + /// member this.GetCells(startAddress : FsAddress, lastAddress : FsAddress) = this.GetCells(startAddress.RowNumber,startAddress.ColumnNumber,lastAddress.RowNumber,lastAddress.ColumnNumber) + /// /// Returns the FsCells from an FsCellsCollection with given startAddress to lastAddress. + /// static member getCellsFromToAddress startAddress lastAddress (cellsCollection : FsCellsCollection) = cellsCollection.GetCells(startAddress, lastAddress) @@ -458,7 +526,9 @@ type FsCellsCollection() = // } //} + /// /// Returns the FsCell at given rowIndex and columnIndex if it exists. Otherwise returns None. + /// member this.TryGetCell(row : int32, column : int32) = if (row > _maxRowUsed || column > _maxColumnUsed) then @@ -472,7 +542,9 @@ type FsCellsCollection() = | None -> None | None -> None + /// /// Returns the FsCell from an FsCellsCollection at given rowIndex and columnIndex if it exists. Otherwise returns None. + /// static member tryGetCell rowIndex colIndex (cellsCollection : FsCellsCollection) = cellsCollection.TryGetCell(rowIndex, colIndex) @@ -588,23 +660,33 @@ type FsCellsCollection() = // return 0; //} + /// /// Returns all FsCells in the given columnIndex. + /// member this.GetCellsInColumn(colIndex) = this.GetCells(1, colIndex, _maxRowUsed, colIndex) + /// /// Returns all FsCells in an FsCellsCollection with the given columnIndex. + /// static member getCellsInColumn colIndex (cellsCollection : FsCellsCollection) = cellsCollection.GetCellsInColumn colIndex + /// /// Returns all FsCells in the given rowIndex. + /// member this.GetCellsInRow(rowIndex) = this.GetCells(rowIndex, 1, rowIndex, _maxColumnUsed) + /// /// Returns all FsCells in an FsCellsCollection with the given rowIndex. + /// static member getCellsInRow rowIndex (cellsCollection : FsCellsCollection) = cellsCollection.GetCellsInRow rowIndex - /// Returns the upper left corner of the FsCellsCollection. + /// + /// Returns the upper left corner of the FsCellsCollection. + /// member this.GetFirstAddress() = try let minRow = _rowsCollection.Keys |> Seq.min @@ -615,15 +697,21 @@ type FsCellsCollection() = FsAddress(minRow, minCol) with :? System.ArgumentException -> FsAddress(0, 0) - /// Returns the upper left corner of a given FsCellsCollection. + /// + /// Returns the upper left corner of a given FsCellsCollection. + /// static member getFirstAddress (cells : FsCellsCollection) = cells.GetFirstAddress() - /// Returns the lower right corner of the FsCellsCollection. + /// + /// Returns the lower right corner of the FsCellsCollection. + /// member this.GetLastAddress() = FsAddress(this.MaxRowNumber, this.MaxColumnNumber) - /// Returns the lower right corner of a given FsCellsCollection. + /// + /// Returns the lower right corner of a given FsCellsCollection. + /// static member getLastAddress (cells : FsCellsCollection) = cells.GetLastAddress() diff --git a/src/FsSpreadsheet/FsAddress.fs b/src/FsSpreadsheet/FsAddress.fs index b36ef12d..e7f28c53 100644 --- a/src/FsSpreadsheet/FsAddress.fs +++ b/src/FsSpreadsheet/FsAddress.fs @@ -127,12 +127,32 @@ type FsAddress(rowNumber : int, columnNumber : int, fixedRow : bool, fixedColumn member this.LOL () = 1 //let mutable _address = address - /// Updates the row- and columnIndex respective to the given indices. + /// + /// Creates a deep copy of the FsAddress. + /// + member this.Copy() = + let colNo = this.ColumnNumber + let rowNo = this.RowNumber + let fixRow = this.FixedRow + let fixedCol = this.FixedColumn + FsAddress(rowNo, colNo, fixRow, fixedCol) + + /// + /// Returns a deep copy of the given FsAddress. + /// + static member copy (address : FsAddress) = + address.Copy() + + /// + /// Updates the row- and columnIndex respective to the given indices. + /// member self.UpdateIndices(rowIndex,colIndex) = _columnNumber <- colIndex _rowNumber <- rowIndex - /// Updates the row- and columnIndex of a given FsAddress respective to the given indices. + /// + /// Updates the row- and columnIndex of a given FsAddress respective to the given indices. + /// static member updateIndices rowIndex colIndex (address : FsAddress) = address.UpdateIndices(rowIndex, colIndex) address diff --git a/src/FsSpreadsheet/FsRow.fs b/src/FsSpreadsheet/FsRow.fs index 3c7f2e58..061e2b74 100644 --- a/src/FsSpreadsheet/FsRow.fs +++ b/src/FsSpreadsheet/FsRow.fs @@ -1,7 +1,9 @@ namespace FsSpreadsheet // Type based on the type XLRow used in ClosedXml -/// Creates an FsRow from the given FsRangeAddress, consisting of FsCells within a given FsCellsCollection, and a styleValue. +/// +/// Creates an FsRow from the given FsRangeAddress, consisting of FsCells within a given FsCellsCollection, and a styleValue. +/// /// The FsCellsCollection must only cover 1 row! /// if given FsCellsCollection has more than 1 row. type FsRow (rangeAddress : FsRangeAddress, cells : FsCellsCollection, styleValue)= @@ -12,7 +14,9 @@ type FsRow (rangeAddress : FsRangeAddress, cells : FsCellsCollection, styleValue new () = FsRow (FsRangeAddress(FsAddress(0,0),FsAddress(0,0)),FsCellsCollection(),null) - /// Create an FsRow from a given FsCellsCollection and an rowIndex. + /// + /// Create an FsRow from a given FsCellsCollection and an rowIndex. + /// /// The appropriate range of the cells (i.e. minimum colIndex and maximum colIndex) is derived from the FsCells with the matching rowIndex. new (index, (cells : FsCellsCollection)) = let minColIndex = (cells.GetCellsInRow index |> Seq.minBy (fun c -> c.Address.ColumnNumber)).Address.ColumnNumber @@ -28,7 +32,9 @@ type FsRow (rangeAddress : FsRangeAddress, cells : FsCellsCollection, styleValue member self.Cells = base.Cells(cells) - /// The index of the FsRow. + /// + /// The index of the FsRow. + /// member self.Index with get() = self.RangeAddress.FirstAddress.RowNumber and set(i) = @@ -40,11 +46,31 @@ type FsRow (rangeAddress : FsRangeAddress, cells : FsCellsCollection, styleValue // METHODS // ------- - /// Returns the index of the given FsRow. + /// + /// Creates a deep copy of this FsRow. + /// + member self.Copy() = + let ra = self.RangeAddress.Copy() + let cells = self.Cells |> Seq.map (fun c -> c.Copy()) + let fcc = FsCellsCollection() + fcc.Add cells + FsRow(ra, fcc, null) + + /// + /// Returns a deep copy of a given FsRow. + /// + static member copy (row : FsRow) = + row.Copy() + + /// + /// Returns the index of the given FsRow. + /// static member getIndex (row : FsRow) = row.Index - /// Returns the FsCell at columnIndex. + /// + /// Returns the FsCell at columnIndex. + /// member self.Cell(columnIndex) = base.Cell(FsAddress(1,columnIndex),cells) @@ -58,18 +84,24 @@ type FsRow (rangeAddress : FsRangeAddress, cells : FsCellsCollection, styleValue // _cells <- List.append _cells [cell] // cell - /// Returns the FsCell at the given columnIndex from an FsRow. + /// + /// Returns the FsCell at the given columnIndex from an FsRow. + /// static member getCellAt colIndex (row : FsRow) = row.Cell(colIndex) + /// /// 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. + /// member this.InsertValueAt(colIndex, (value : 'a)) = let cell = FsCell(value) cells.Add(int32 this.Index, int32 colIndex, cell) - /// Adds a value at the given row- and columnIndex to FsRow using. + /// + /// Adds a value at the given row- and columnIndex to FsRow using. /// - /// If a cell exists in the given position, shoves it to the right. + /// If a cell exists in the given position, shoves it to the right. + /// static member insertValueAt colIndex value (row : FsRow) = row.InsertValueAt(colIndex, value) |> ignore row diff --git a/src/FsSpreadsheet/FsWorkbook.fs b/src/FsSpreadsheet/FsWorkbook.fs index c327575b..c40ff87b 100644 --- a/src/FsSpreadsheet/FsWorkbook.fs +++ b/src/FsSpreadsheet/FsWorkbook.fs @@ -1,7 +1,9 @@ namespace FsSpreadsheet -/// Creates an empty FsWorkbook. +/// +/// Creates an empty FsWorkbook. +/// type FsWorkbook() = let mutable _worksheets = [] @@ -18,19 +20,39 @@ type FsWorkbook() = // ------- // METHODS // ------- + + /// + /// Creates a deep copy of this FsWorkbook. + /// + member self.Copy() = + let shts = self.GetWorksheets() |> List.map (fun (s : FsWorksheet) -> s.Copy()) + let wb = new FsWorkbook() + wb.AddWorksheets shts + + /// + /// Returns a deep copy of a given FsWorkbook. + /// + static member copy (workbook : FsWorkbook) = + workbook.Copy() + /// /// Adds an FsWorksheet with given name. + /// member self.AddWorksheet(name : string) = let sheet = FsWorksheet name _worksheets <- List.append _worksheets [sheet] sheet /// Adds an FsWorksheet with given name to an FsWorkbook. + /// static member addWorksheetWithName (name : string) (workbook : FsWorkbook) = workbook.AddWorksheet name |> ignore workbook + + /// /// Adds a given FsWorksheet. + /// member self.AddWorksheet(sheet : FsWorksheet) = if _worksheets |> List.exists (fun ws -> ws.Name = sheet.Name) then failwithf "Could not add worksheet with name \"%s\" to workbook as it already contains a worksheet with the same name" sheet.Name @@ -38,49 +60,69 @@ type FsWorkbook() = _worksheets <- List.append _worksheets [sheet] sheet + /// /// Adds an FsWorksheet to an FsWorkbook. + /// static member addWorksheet (sheet : FsWorksheet) (workbook : FsWorkbook) = workbook.AddWorksheet sheet |> ignore workbook - /// Adds a collection of FsWorksheets to the FsWorkbook. + /// + /// Adds a collection of FsWorksheets to the FsWorkbook. + /// member self.AddWorksheets(sheets : seq) = sheets |> Seq.iter (self.AddWorksheet >> ignore) self - /// Adds a collection of FsWorksheets to an FsWorkbook. + /// + /// Adds a collection of FsWorksheets to an FsWorkbook. + /// static member addWorksheets sheets (workbook : FsWorkbook) = workbook.AddWorksheets sheets + /// /// Returns all FsWorksheets. + /// member self.GetWorksheets() = _worksheets + /// /// Returns all FsWorksheets. + /// static member getWorksheets (workbook : FsWorkbook) = workbook.GetWorksheets() - /// Returns the FsWorksheet with the given name if it exists in the FsWorkbook. Else returns None. + /// + /// Returns the FsWorksheet with the given name if it exists in the FsWorkbook. Else returns None. + /// member self.TryGetWorksheetByName(sheetName) = _worksheets |> List.tryFind (fun w -> w.Name = sheetName) - /// Returns the FsWorksheet with the given name if it exists in a given FsWorkbook. Else returns None. + /// + /// Returns the FsWorksheet with the given name if it exists in a given FsWorkbook. Else returns None. + /// static member tryGetWorksheetByName sheetName (workbook : FsWorkbook) = workbook.TryGetWorksheetByName sheetName - /// Returns the FsWorksheet with the given name. + /// + /// Returns the FsWorksheet with the given name. + /// /// if FsWorksheet with given name is not present in the FsWorkkbook. member self.GetWorksheetByName(sheetName) = try (self.TryGetWorksheetByName sheetName).Value with _ -> failwith $"FsWorksheet with name {sheetName} is not present in the FsWorkbook." - /// Returns the FsWorksheet with the given name from an FsWorkbook. + /// + /// Returns the FsWorksheet with the given name from an FsWorkbook. + /// /// if FsWorksheet with given name is not present in the FsWorkkbook. static member getWorksheetByName sheetName (workbook : FsWorkbook) = workbook.GetWorksheetByName sheetName - /// Removes an FsWorksheet with given name. + /// + /// Removes an FsWorksheet with given name. + /// /// if FsWorksheet with given name is not present in the FsWorkkbook. member self.RemoveWorksheet(name : string) = let filteredWorksheets = @@ -90,27 +132,37 @@ type FsWorkbook() = _worksheets <- filteredWorksheets self + /// /// Removes an FsWorksheet with given name from an FsWorkbook. + /// static member removeWorksheetByName (name : string) (workbook : FsWorkbook) = workbook.RemoveWorksheet name |> ignore workbook - /// Removes a given FsWorksheet. + /// + /// Removes a given FsWorksheet. + /// /// if FsWorksheet with given name is not present in the FsWorkkbook. member self.RemoveWorksheet(sheet : FsWorksheet) = self.RemoveWorksheet(sheet.Name) |> ignore self + /// /// Removes a given FsWorksheet from an FsWorkbook. + /// static member removeWorksheet (sheet : FsWorksheet) (workbook : FsWorkbook) = workbook.RemoveWorksheet sheet |> ignore workbook - /// Returns all FsTables from the FsWorkbook. + /// + /// Returns all FsTables from the FsWorkbook. + /// member self.GetTables() = self.GetWorksheets() |> List.collect (fun s -> s.Tables) - /// Returns all FsTables from an FsWorkbook. + /// + /// Returns all FsTables from an FsWorkbook. + /// static member getTables (workbook : FsWorkbook) = workbook.GetTables() \ No newline at end of file diff --git a/src/FsSpreadsheet/FsWorksheet.fs b/src/FsSpreadsheet/FsWorksheet.fs index c20b534d..0d65c54e 100644 --- a/src/FsSpreadsheet/FsWorksheet.fs +++ b/src/FsSpreadsheet/FsWorksheet.fs @@ -1,7 +1,9 @@ namespace FsSpreadsheet // Type based on the type XLWorksheet used in ClosedXml +/// /// Creates an FsWorksheet with the given name, FsRows, FsTables, and FsCellsCollection. +/// type FsWorksheet (name, fsRows, fsTables, fsCellsCollection) = let mutable _name = name @@ -12,11 +14,15 @@ type FsWorksheet (name, fsRows, fsTables, fsCellsCollection) = let mutable _cells : FsCellsCollection = fsCellsCollection + /// /// Creates an empty FsWorksheet. + /// new () = FsWorksheet("") + /// /// Creates an empty FsWorksheet with the given name. + /// new (name) = FsWorksheet(name, [], [], FsCellsCollection()) @@ -35,20 +41,28 @@ type FsWorksheet (name, fsRows, fsTables, fsCellsCollection) = // PROPERTIES // ---------- + /// /// The name of the FsWorksheet. + /// member self.Name with get() = _name and set(name) = _name <- name + /// /// The FsCellCollection of the FsWorksheet. + /// member self.CellCollection with get () = _cells + /// /// The FsTables of the FsWorksheet. + /// member self.Tables with get() = _tables + /// /// The FsRows of the FsWorksheet. + /// member self.Rows with get () = _rows @@ -57,24 +71,33 @@ type FsWorksheet (name, fsRows, fsTables, fsCellsCollection) = // METHODS // ------- + /// /// Returns a copy of the FsWorksheet. + /// member self.Copy() = - let newSheet = FsWorksheet(self.Name) - self.Tables - |> List.iter ( - fun t -> - newSheet.Table(t.Name, t.RangeAddress, t.ShowHeaderRow) - |> ignore - ) - for row in (self.Rows) do - let (newRow : FsRow) = newSheet.Row(row.Index) - for cell in row.Cells do - let newCell = newRow.Cell(cell.Address,newSheet.CellCollection) - newCell.SetValueAs(cell.Value) - |> ignore - newSheet - + let fcc = self.CellCollection.Copy() + let nam = self.Name + let rws = self.Rows |> List.map (fun r -> r.Copy()) + let tbs = self.Tables |> List.map (fun t -> t.Copy()) + FsWorksheet(nam, rws, tbs, fcc) + //let newSheet = FsWorksheet(self.Name) + //self.Tables + //|> List.iter ( + // fun t -> + // newSheet.Table(t.Name, t.RangeAddress, t.ShowHeaderRow) + // |> ignore + //) + //for row in (self.Rows) do + // let (newRow : FsRow) = newSheet.Row(row.Index) + // for cell in row.Cells do + // let newCell = newRow.Cell(cell.Address,newSheet.CellCollection) + // newCell.SetValueAs(cell.Value) + // |> ignore + //newSheet + + /// /// Returns a copy of a given FsWorksheet. + /// static member copy (sheet : FsWorksheet) = sheet.Copy() @@ -83,7 +106,9 @@ type FsWorksheet (name, fsRows, fsTables, fsCellsCollection) = // Row(s) // ------ - /// Returns the FsRow at the given index. If it does not exist, it is created and appended first. + /// + /// Returns the FsRow at the given index. If it does not exist, it is created and appended first. + /// member self.Row(rowIndex) = match _rows |> List.tryFind (fun row -> row.Index = rowIndex) with | Some row -> @@ -93,38 +118,52 @@ type FsWorksheet (name, fsRows, fsTables, fsCellsCollection) = _rows <- List.append _rows [row] row - /// Returns the FsRow at the given FsRangeAddress. If it does not exist, it is created and appended first. + /// + /// Returns the FsRow at the given FsRangeAddress. If it does not exist, it is created and appended first. + /// member self.Row(rangeAddress : FsRangeAddress) = if rangeAddress.FirstAddress.RowNumber <> rangeAddress.LastAddress.RowNumber then failwithf "Row may not have a range address spanning over different row indices" self.Row(rangeAddress.FirstAddress.RowNumber).RangeAddress <- rangeAddress + /// /// Appends an FsRow to an FsWorksheet if the rowIndex is not already taken. + /// static member appendRow (row : FsRow) (sheet : FsWorksheet) = sheet.Row(row.Index) |> ignore sheet + /// /// Returns the FsRows of a given FsWorksheet. + /// static member getRows (sheet : FsWorksheet) = sheet.Rows + /// /// Returns the FsRow at the given rowIndex of an FsWorksheet. + /// static member getRowAt rowIndex sheet = FsWorksheet.getRows sheet // to do: getIndex |> Seq.find (FsRow.getIndex >> (=) rowIndex) + /// /// Returns the FsRow at the given rowIndex of an FsWorksheet if it exists, else returns None. + /// static member tryGetRowAt rowIndex (sheet : FsWorksheet) = sheet.Rows |> Seq.tryFind (FsRow.getIndex >> (=) rowIndex) + /// /// Returns the FsRow matching or exceeding the given rowIndex if it exists, else returns None. + /// static member tryGetRowAfter rowIndex (sheet : FsWorksheet) = sheet.Rows |> List.tryFind (fun r -> r.Index >= rowIndex) + /// /// Inserts an FsRow into the FsWorksheet before a reference FsRow. + /// member self.InsertBefore(row : FsRow, refRow : FsRow) = _rows |> List.iter ( @@ -135,51 +174,71 @@ type FsWorksheet (name, fsRows, fsTables, fsCellsCollection) = self.Row(row.Index) |> ignore self + /// /// Inserts an FsRow into the FsWorksheet before a reference FsRow. + /// static member insertBefore row (refRow : FsRow) (sheet : FsWorksheet) = sheet.InsertBefore(row, refRow) + /// /// Returns true if the FsWorksheet contains an FsRow with the given rowIndex. + /// member self.ContainsRowAt(rowIndex) = self.Rows |> List.exists (fun t -> t.Index = rowIndex) + /// /// Returns true if the FsWorksheet contains an FsRow with the given rowIndex. + /// static member containsRowAt rowIndex (sheet : FsWorksheet) = sheet.ContainsRowAt rowIndex + /// /// Returns the number of FsRows contained in the FsWorksheet. + /// static member countRows (sheet : FsWorksheet) = sheet.Rows.Length + /// /// Removes the FsRow at the given rowIndex. + /// member self.RemoveRowAt(rowIndex) = let newRows = _rows |> List.filter (fun r -> r.Index <> rowIndex) _rows <- newRows + /// /// Removes the FsRow at a given rowIndex of an FsWorksheet. + /// static member removeRowAt rowIndex (sheet : FsWorksheet) = sheet.RemoveRowAt(rowIndex) sheet + /// /// Removes the FsRow at a given rowIndex of the FsWorksheet if the FsRow exists. + /// member self.TryRemoveAt(rowIndex) = if self.ContainsRowAt rowIndex then self.RemoveRowAt rowIndex self + /// /// Removes the FsRow at a given rowIndex of an FsWorksheet if the FsRow exists. + /// static member tryRemoveAt rowIndex sheet = if FsWorksheet.containsRowAt rowIndex sheet then sheet.RemoveRowAt rowIndex + /// /// Sorts the FsRows by their rowIndex. + /// member self.SortRows() = _rows <- _rows |> List.sortBy (fun r -> r.Index) + /// /// Applies function f to all FsRows and returns the modified FsWorksheet. + /// member self.MapRowsInPlace(f : FsRow -> FsRow) = let indeces = self.Rows |> List.map (fun r -> r.Index) indeces @@ -187,7 +246,9 @@ type FsWorksheet (name, fsRows, fsTables, fsCellsCollection) = |> fun res -> _rows <- res self + /// /// Applies function f in a given FsWorksheet to all FsRows and returns the modified FsWorksheet. + /// static member mapRowsInPlace (f : FsRow -> FsRow) (sheet : FsWorksheet) = sheet.MapRowsInPlace f @@ -204,35 +265,47 @@ type FsWorksheet (name, fsRows, fsTables, fsCellsCollection) = // ) // newWs.Tables <- sheet.Tables + /// /// Returns the highest index of any FsRow. + /// member self.GetMaxRowIndex() = try self.Rows |> List.maxBy (fun r -> r.Index) with :? System.ArgumentException -> failwith "The FsWorksheet has no FsRows." + /// /// Returns the highest index of any FsRow in a given FsWorksheet. + /// static member getMaxRowIndex (sheet : FsWorksheet) = sheet.GetMaxRowIndex() + /// /// Gets the string values of the FsRow at the given 1-based rowIndex. + /// member self.GetRowValuesAt(rowIndex) = if self.ContainsRowAt rowIndex then self.Row(rowIndex).Cells |> Seq.map (fun c -> c.Value) else Seq.empty + /// /// Gets the string values of the FsRow at the given 1-based rowIndex of a given FsWorksheet. + /// static member getRowValuesAt rowIndex (sheet : FsWorksheet) = sheet.GetRowValuesAt rowIndex + /// /// Gets the string values at the given 1-based rowIndex of the FsRow if it exists, else returns None. + /// member self.TryGetRowValuesAt(rowIndex) = if self.ContainsRowAt rowIndex then Some (self.GetRowValuesAt rowIndex) else None + /// /// Takes an FsWorksheet and gets the string values at the given 1-based rowIndex of the FsRow if it exists, else returns None. + /// static member tryGetRowValuesAt rowIndex (sheet : FsWorksheet) = sheet.TryGetRowValuesAt rowIndex @@ -249,7 +322,9 @@ type FsWorksheet (name, fsRows, fsTables, fsCellsCollection) = // TO DO (later) //static member tryGetIndexedRowValuesAt rowIndex sheet = + /// /// Checks the cell collection and recreate the whole set of rows, so that all cells are placed in a row + /// member self.RescanRows() = let rows = _rows |> Seq.map (fun r -> r.Index,r) |> Map.ofSeq _cells.GetCells() @@ -274,7 +349,9 @@ type FsWorksheet (name, fsRows, fsTables, fsCellsCollection) = // Table(s) // -------- + /// /// Returns the FsTable with the given tableName, rangeAddress, and showHeaderRow parameters. If it does not exist yet, it gets created and appended first. + /// // TO DO: Ask HLW: Is this really a good name for the method? member self.Table(tableName,rangeAddress,showHeaderRow) = match _tables |> List.tryFind (fun table -> table.Name = name) with @@ -285,15 +362,21 @@ type FsWorksheet (name, fsRows, fsTables, fsCellsCollection) = _tables <- List.append _tables [table] table + /// /// Returns the FsTable with the given tableName and rangeAddress parameters. If it does not exist yet, it gets created first. ShowHeaderRow is true by default. + /// member self.Table(tableName,rangeAddress) = self.Table(tableName,rangeAddress,true) - /// Returns the FsTable of the given name from an FsWorksheet if it exists. Else returns None. + /// + /// Returns the FsTable of the given name from an FsWorksheet if it exists. Else returns None. + /// static member tryGetTableByName tableName (sheet : FsWorksheet) = sheet.Tables |> List.tryFind (fun t -> t.Name = tableName) - /// Returns the FsTable of the given name from an FsWorksheet. + /// + /// Returns the FsTable of the given name from an FsWorksheet. + /// static member getTableByName tableName (sheet : FsWorksheet) = try (sheet.Tables |> List.tryFind (fun t -> t.Name = tableName)).Value with _ -> failwith $"FsTable with name {tableName} is not presen in the FsWorksheet {sheet.Name}." @@ -302,7 +385,9 @@ type FsWorksheet (name, fsRows, fsTables, fsCellsCollection) = // TO DO: getTableByRangeAddress - /// Adds an FsTable to the FsWorksheet if an FsTable with the same name is not already attached. + /// + /// Adds an FsTable to the FsWorksheet if an FsTable with the same name is not already attached. + /// // TO DO: Ask HLW: rather printfn or failwith? member self.AddTable(table : FsTable) = if self.Tables |> List.exists (fun t -> t.Name = table.Name) then @@ -310,17 +395,23 @@ type FsWorksheet (name, fsRows, fsTables, fsCellsCollection) = else _tables <- List.append _tables [table] self - /// Adds an FsTable to the FsWorksheet if an FsTable with the same name is not already attached. + /// + /// Adds an FsTable to the FsWorksheet if an FsTable with the same name is not already attached. + /// static member addTable table (sheet : FsWorksheet) = sheet.AddTable table - /// Adds a list of FsTables to the FsWorksheet. All FsTables with a name already present in the FsWorksheet are not attached. + /// + /// Adds a list of FsTables to the FsWorksheet. All FsTables with a name already present in the FsWorksheet are not attached. + /// // TO DO: Ask HLW: rather printfn or failwith? member self.AddTables(tables) = tables |> List.iter (self.AddTable >> ignore) self - /// Adds a list of FsTables to an FsWorksheet. All FsTables with a name already present in the FsWorksheet are not attached. + /// + /// Adds a list of FsTables to an FsWorksheet. All FsTables with a name already present in the FsWorksheet are not attached. + /// static member addTables tables (sheet : FsWorksheet) = sheet.AddTables tables @@ -329,49 +420,66 @@ type FsWorksheet (name, fsRows, fsTables, fsCellsCollection) = // Cell(s) // ------- + /// /// Returns the FsCell at the given row- and columnIndex if the FsCell exists, else returns None. + /// member self.TryGetCellAt(rowIndex, colIndex) = self.CellCollection.TryGetCell(rowIndex, colIndex) + /// /// Returns the FsCell at the given row- and columnIndex of a given FsWorksheet if the FsCell exists, else returns None. + /// static member tryGetCellAt rowIndex colIndex (sheet : FsWorksheet) = sheet.TryGetCellAt(rowIndex, colIndex) + /// /// Returns the FsCell at the given row- and columnIndex. + /// member self.GetCellAt(rowIndex, colIndex) = self.TryGetCellAt(rowIndex, colIndex).Value + /// /// Returns the FsCell at the given row- and columnIndex of a given FsWorksheet. + /// static member getCellAt rowIndex colIndex (sheet : FsWorksheet) = sheet.GetCellAt(rowIndex, colIndex) - + /// /// Adds a FsCell to the FsWorksheet. !Exception if cell address already exists! + /// member self.AddCell (cell:FsCell) = self.CellCollection.Add cell |> ignore self + /// /// Adds a sequence of FsCells to the FsWorksheet. !Exception if cell address already exists! + /// member self.AddCells (cells:seq) = self.CellCollection.Add cells |> ignore self + /// /// Adds a value at the given row- and columnIndex to the FsWorksheet. /// /// If a cell exists at the given postion, it is shoved to the right. + /// member self.InsertValueAt(value : 'a, rowIndex, colIndex)= let cell = FsCell(value) self.CellCollection.Add(int32 rowIndex, int32 colIndex, cell) + /// /// Adds a value at the given row- and columnIndex to a given FsWorksheet. /// /// If an FsCell exists at the given position, it is shoved to the right. + /// static member insertValueAt (value : 'a) rowIndex colIndex (sheet : FsWorksheet)= sheet.InsertValueAt(value, rowIndex, colIndex) + /// /// Adds a value at the given row- and columnIndex. /// /// If an FsCell exists at the given position, overwrites it. + /// member self.SetValueAt(value : 'a, rowIndex, colIndex) = match self.CellCollection.TryGetCell(rowIndex, colIndex) with | Some c -> @@ -381,55 +489,68 @@ type FsWorksheet (name, fsRows, fsTables, fsCellsCollection) = self.CellCollection.Add(rowIndex, colIndex, value) |> ignore self + /// /// Adds a value at the given row- and columnIndex of a given FsWorksheet. /// /// If an FsCell exists at the given position, it is overwritten. + /// static member setValueAt (value : 'a) rowIndex colIndex (sheet : FsWorksheet) = sheet.SetValueAt(value, rowIndex, colIndex) + /// /// Removes the value at the given row- and columnIndex from the FsWorksheet. + /// member self.RemoveCellAt(rowIndex, colIndex) = self.CellCollection.RemoveCellAt(int32 rowIndex, int32 colIndex) self + /// /// Removes the value at the given row- and columnIndex from an FsWorksheet. + /// static member removeCellAt rowIndex colIndex (sheet : FsWorksheet) = sheet.RemoveCellAt(rowIndex, colIndex) - /// Removes the value of an FsCell at given row- and columnIndex if it exists from the FsCollection. + /// + /// Removes the value of an FsCell at given row- and columnIndex if it exists from the FsCollection. + /// /// Does nothing if the row or column of given index does not exist. /// if columnIndex is null. member self.TryRemoveValueAt(rowIndex, colIndex) = self.CellCollection.TryRemoveValueAt(rowIndex, colIndex) - /// Removes the value of an FsCell at given row- and columnIndex if it exists from the FsCollection of a given FsWorksheet. + /// + /// Removes the value of an FsCell at given row- and columnIndex if it exists from the FsCollection of a given FsWorksheet. + /// /// Does nothing if the row or column of given index does not exist. /// if columnIndex is null. static member tryRemoveValueAt rowIndex colIndex (sheet : FsWorksheet) = sheet.TryRemoveValueAt(rowIndex, colIndex) - /// Removes the value of an FsCell at given row- and columnIndex from the FsCollection. + /// + /// Removes the value of an FsCell at given row- and columnIndex from the FsCollection. + /// /// if rowIndex or columnIndex is null. /// if row or column at the given index does not exist. member self.RemoveValueAt(rowIndex, colIndex) = self.CellCollection.RemoveValueAt(rowIndex, colIndex) - /// Removes the value of an FsCell at given row- and columnIndex from the FsCollection of a given FsWorksheet. + /// + /// Removes the value of an FsCell at given row- and columnIndex from the FsCollection of a given FsWorksheet. + /// /// if rowIndex or columnIndex is null. /// if row or column at the given index does not exist. static member removeValueAt rowIndex colIndex (sheet : FsWorksheet) = sheet.RemoveValueAt(rowIndex, colIndex) - - // ########################## - // Static member - // Adds a FsCell to the FsWorksheet. !Exception if cell address already exists! + /// + /// Adds a FsCell to the FsWorksheet. !Exception if cell address already exists! + /// static member addCell (cell:FsCell) (sheet :FsWorksheet) = sheet.AddCell cell - // ########################## - // Static member - // Adds a sequence of FsCells to the FsWorksheet. !Exception if cell address already exists! + /// + /// Adds a sequence of FsCells to the FsWorksheet. !Exception if cell address already exists! + /// static member addCells (cell:seq) (sheet :FsWorksheet) = sheet.AddCells cell diff --git a/src/FsSpreadsheet/Ranges/FsRangeAddress.fs b/src/FsSpreadsheet/Ranges/FsRangeAddress.fs index 480516ca..0aee0d44 100644 --- a/src/FsSpreadsheet/Ranges/FsRangeAddress.fs +++ b/src/FsSpreadsheet/Ranges/FsRangeAddress.fs @@ -1,95 +1,127 @@ namespace rec FsSpreadsheet // Helper functions for working with "A1:A1"-style table areas. +/// /// The areas marks the area in which the table lies. +/// module Range = + /// /// Given A1-based top left start and bottom right end indices, returns a "A1:A1"-style area- + /// let ofBoundaries fromCellReference toCellReference = sprintf "%s:%s" fromCellReference toCellReference + /// /// Given a "A1:A1"-style area, returns A1-based cell start and end cellReferences. + /// let toBoundaries (area : string) = area.Split ':' |> fun a -> a.[0], a.[1] + /// /// Gets the right boundary of the area. + /// let rightBoundary (area : string) = toBoundaries area |> snd |> CellReference.toIndices |> fst + /// /// Gets the left boundary of the area. + /// let leftBoundary (area : string) = toBoundaries area |> fst |> CellReference.toIndices |> fst + /// /// Gets the Upper boundary of the area. + /// let upperBoundary (area : string) = toBoundaries area |> fst |> CellReference.toIndices |> snd + /// /// Gets the lower boundary of the area. + /// let lowerBoundary (area : string) = toBoundaries area |> snd |> CellReference.toIndices |> snd + /// /// Moves both start and end of the area by the given amount (positive amount moves area to right and vice versa). + /// let moveHorizontal amount (area : string) = area |> toBoundaries |> fun (f,t) -> CellReference.moveHorizontal amount f, CellReference.moveHorizontal amount t ||> ofBoundaries + /// /// Moves both start and end of the area by the given amount (positive amount moves area to right and vice versa). + /// let moveVertical amount (area : string) = area |> toBoundaries |> fun (f,t) -> CellReference.moveHorizontal amount f, CellReference.moveHorizontal amount t ||> ofBoundaries + /// /// Extends the right boundary of the area by the given amount (positive amount increases area to right and vice versa). + /// let extendRight amount (area : string) = area |> toBoundaries |> fun (f,t) -> f, CellReference.moveHorizontal amount t ||> ofBoundaries + /// /// Extends the left boundary of the area by the given amount (positive amount decreases the area to left and vice versa). + /// let extendLeft amount (area : string) = area |> toBoundaries |> fun (f,t) -> CellReference.moveHorizontal amount f, t ||> ofBoundaries + /// /// Returns true if the column index of the reference exceeds the right boundary of the area. + /// let referenceExceedsAreaRight reference area = (reference |> CellReference.toIndices |> fst) > (area |> rightBoundary) + /// /// Returns true if the column index of the reference exceeds the left boundary of the area. + /// let referenceExceedsAreaLeft reference area = (reference |> CellReference.toIndices |> fst) < (area |> leftBoundary) + /// /// Returns true if the column index of the reference exceeds the upper boundary of the area. + /// let referenceExceedsAreaAbove reference area = (reference |> CellReference.toIndices |> snd) > (area |> upperBoundary) + /// /// Returns true if the column index of the reference exceeds the lower boundary of the area. + /// let referenceExceedsAreaBelow reference area = (reference |> CellReference.toIndices |> snd) < (area |> lowerBoundary ) + /// /// Returns true if the reference does not lie in the boundary of the area. + /// let referenceExceedsArea reference area = referenceExceedsAreaRight reference area || @@ -99,7 +131,9 @@ module Range = || referenceExceedsAreaBelow reference area + /// /// Returns true if the A1:A1-style area is of correct format. + /// let isCorrect area = try let hor = leftBoundary area <= rightBoundary area @@ -109,7 +143,7 @@ module Range = if not ver then printfn "Lower area boundary must be higher or equal to upper area boundary." hor && ver - + with | err -> printfn "Area \"%s\" could not be parsed: %s" area err.Message @@ -126,6 +160,18 @@ type FsRangeAddress(firstAddress : FsAddress, lastAddress : FsAddress) = let firstAdress,lastAddress = Range.toBoundaries rangeAddress FsRangeAddress(FsAddress(firstAdress),FsAddress(lastAddress)) + /// + /// Creates a deep copy of this FsRangeAddress. + /// + member self.Copy() = + FsRangeAddress(self.Range) + + /// + /// Returns a deep copy of a given FsRangeAddress. + /// + static member copy (rangeAddress : FsRangeAddress) = + rangeAddress.Copy() + member self.Extend (address : FsAddress) = if address.RowNumber < _firstAddress.RowNumber then _firstAddress.RowNumber <- address.RowNumber @@ -139,7 +185,7 @@ type FsRangeAddress(firstAddress : FsAddress, lastAddress : FsAddress) = if address.ColumnNumber > _lastAddress.ColumnNumber then _lastAddress.ColumnNumber <- address.ColumnNumber - member self.Normalize () = + member self.Normalize() = let firstRow,lastRow = if firstAddress.RowNumber < lastAddress.RowNumber then diff --git a/src/FsSpreadsheet/Ranges/FsRangeBase.fs b/src/FsSpreadsheet/Ranges/FsRangeBase.fs index d4cb4fba..4f3eedf9 100644 --- a/src/FsSpreadsheet/Ranges/FsRangeBase.fs +++ b/src/FsSpreadsheet/Ranges/FsRangeBase.fs @@ -64,7 +64,7 @@ type FsRangeBase (rangeAddress : FsRangeAddress, styleValue) = // && column.StyleValue != Worksheet.StyleValue) // styleValue = column.StyleValue; //} - let absoluteAddress = new FsAddress(absRow,absColumn,cellAddressInRange.FixedRow,cellAddressInRange.FixedColumn); + let absoluteAddress = new FsAddress(absRow, absColumn, cellAddressInRange.FixedRow, cellAddressInRange.FixedColumn); // If the default style for this range base is empty, but the worksheet // has a default style, use the worksheet's default style @@ -76,10 +76,10 @@ type FsRangeBase (rangeAddress : FsRangeAddress, styleValue) = newCell member self.Cells(cells : FsCellsCollection) = - cells.GetCells(self.RangeAddress.FirstAddress,self.RangeAddress.LastAddress) + cells.GetCells(self.RangeAddress.FirstAddress, self.RangeAddress.LastAddress) member self.Cells(cells : FsCellsCollection, predicate : FsCell -> bool) = - cells.GetCells(self.RangeAddress.FirstAddress,self.RangeAddress.LastAddress, predicate) + cells.GetCells(self.RangeAddress.FirstAddress, self.RangeAddress.LastAddress, predicate) member self.ColumnCount() = _rangeAddress.LastAddress.ColumnNumber - _rangeAddress.FirstAddress.ColumnNumber + 1; diff --git a/src/FsSpreadsheet/Ranges/FsRangeColumn.fs b/src/FsSpreadsheet/Ranges/FsRangeColumn.fs index 2f7e8de9..a2e425c6 100644 --- a/src/FsSpreadsheet/Ranges/FsRangeColumn.fs +++ b/src/FsSpreadsheet/Ranges/FsRangeColumn.fs @@ -31,6 +31,18 @@ type FsRangeColumn(rangeAddress) = static member fromRangeAddress (rangeAddress : FsRangeAddress) = FsRangeColumn rangeAddress + /// + /// Creates a deep copy of this FsRangeColumn. + /// + member self.Copy() = + FsRangeColumn(self.RangeAddress.Copy()) + + /// + /// Returns a deep copy of a given FsRangeColumn. + /// + static member copy (rangeColumn : FsRangeColumn) = + rangeColumn.Copy() + [] module Enhancements = diff --git a/src/FsSpreadsheet/Tables/FsTable.fs b/src/FsSpreadsheet/Tables/FsTable.fs index 7e9eb887..edb3c6a9 100644 --- a/src/FsSpreadsheet/Tables/FsTable.fs +++ b/src/FsSpreadsheet/Tables/FsTable.fs @@ -427,4 +427,19 @@ type FsTable (name : string, rangeAddress, showTotalsRow, showHeaderRow) = static member getDataCellsOfColumnIndex cellsCollection (colIndex : int) (table : FsTable) = table.GetDataCellsOfColumn(cellsCollection, colIndex) - // TO DO: add equivalents of the other methods regarding header cell for data cells. \ No newline at end of file + // TO DO: add equivalents of the other methods regarding header cell for data cells. + + /// + /// Creates a deep copy of this FsTable. + /// + member this.Copy() = + let ra = this.RangeAddress.Copy() + let nam = this.Name + let shr = this.ShowHeaderRow + FsTable(nam, ra, false, shr) + + /// + /// Returns a deep copy of a given FsTable. + /// + static member copy (table : FsTable) = + table.Copy() \ No newline at end of file diff --git a/src/FsSpreadsheet/Tables/FsTableField.fs b/src/FsSpreadsheet/Tables/FsTableField.fs index e1d634e5..ebd1c68c 100644 --- a/src/FsSpreadsheet/Tables/FsTableField.fs +++ b/src/FsSpreadsheet/Tables/FsTableField.fs @@ -91,6 +91,21 @@ type FsTableField (name : string, index : int, column : FsRangeColumn, totalsRow tableField.SetName(name, cellsCollection, showHeaderRow) tableField + /// + /// Creates a deep copy of this FsTableField. + /// + member this.Copy() = + let col = this.Column.Copy() + let ind = this.Index + let nam = this.Name + FsTableField(nam, ind, col, null, null) + + /// + /// Returns a deep copy of a given FsTableField. + /// + static member copy (tableField : FsTableField) = + tableField.Copy() + /// /// Returns the header cell (taken from a given FsCellsCollection) for the FsTableField if `showHeaderRow` is true. Else fails. ///