From c471256ad9f773abd01fe512aa7c1bfaf44e075c Mon Sep 17 00:00:00 2001 From: Jan Marvin Garbuszus Date: Sat, 30 Nov 2024 11:26:02 +0100 Subject: [PATCH] [misc] extend bookview handling (#1193) --- NAMESPACE | 2 + NEWS.md | 1 + R/class-workbook-wrappers.R | 39 +++++++++++- R/class-workbook.R | 59 ++++++++++++++++++- inst/WORDLIST | 1 + man/wbWorkbook.Rd | 39 +++++++++++- man/wb_set_bookview.Rd | 35 ++++++++++- tests/testthat/test-class-workbook-wrappers.R | 12 +++- tests/testthat/test-class-workbook.R | 43 ++++++++++++++ 9 files changed, 222 insertions(+), 9 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index dea2f2ad0..6afe574bf 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -93,6 +93,7 @@ export(wb_get_active_sheet) export(wb_get_base_colors) export(wb_get_base_colours) export(wb_get_base_font) +export(wb_get_bookview) export(wb_get_cell_style) export(wb_get_comment) export(wb_get_creators) @@ -116,6 +117,7 @@ export(wb_page_setup) export(wb_protect) export(wb_protect_worksheet) export(wb_read) +export(wb_remove_bookview) export(wb_remove_col_widths) export(wb_remove_comment) export(wb_remove_conditional_formatting) diff --git a/NEWS.md b/NEWS.md index d0993ba4a..8f42b4fbf 100644 --- a/NEWS.md +++ b/NEWS.md @@ -6,6 +6,7 @@ * Make non consecutive equal sized dims behave similar to non equal sized non consecutive dims. This makes `dims = "A1:A5,C1:D5"` behave similar to `dims = "A1,C1:D1,A2:A5,C2:D5"`. * Improvements to the internal C++ code in `wb_add_data()` to avoid string copies. [1184](https://github.com/JanMarvin/openxlsx2/pull/1184) This is a continuation of work started in [1177](https://github.com/JanMarvin/openxlsx2/pull/1177) to speedup `wb_add_data()`/`wb_add_data_table()`. +* Extend the `bookview` handling. It is now possible to add more than one `bookview` using `wb_set_bookview(use_view = 2L)` and to remove additional `bookview`s with `wb_remove_bookview()`. Available `bookview`s can be inspected with `wb_get_bookview()`. ## Fixes diff --git a/R/class-workbook-wrappers.R b/R/class-workbook-wrappers.R index 19a05ec1c..a6a26fd6c 100644 --- a/R/class-workbook-wrappers.R +++ b/R/class-workbook-wrappers.R @@ -1666,8 +1666,25 @@ wb_set_base_colours <- wb_set_base_colors wb_get_base_colours <- wb_get_base_colors -#' Set the workbook position, size and filter -#' +#' Get and Set the workbook position, size and filter +#' @name wb_set_bookview +#' @return A data frame with the bookview properties +#' @export +wb_get_bookview <- function(wb) { + assert_workbook(wb) + wb$get_bookview() +} + +#' @name wb_set_bookview +#' @param remove_view You can remove views using index positions. This will only remove the view wont apply modifications. +#' @return The Workbook object +#' @export +wb_remove_bookview <- function(wb, remove_view = NULL) { + assert_workbook(wb) + wb$clone()$remove_bookview(remove_view = remove_view) +} + +#' @rdname wb_set_bookview #' @param wb A [wbWorkbook] object #' @param active_tab activeTab #' @param auto_filter_date_grouping autoFilterDateGrouping @@ -1682,8 +1699,24 @@ wb_get_base_colours <- wb_get_base_colors #' @param window_width windowWidth #' @param x_window xWindow #' @param y_window yWindow +#' @param use_view Which view to modify. Default is `1` (the first view). #' @param ... additional arguments #' @return The Workbook object +#' @examples +#' wb <- wb_workbook() %>% wb_add_worksheet() +#' +#' # set the first and second bookview (horizontal split) +#' wb <- wb %>% +#' wb_set_bookview(window_height = 17600, window_width = 15120, x_window = 15120, y_window = 760) %>% +#' wb_set_bookview(window_height = 17600, window_width = 15040, x_window = 0, y_window = 760, use_view = 2) +#' +#' wb %>% wb_get_bookview() +#' +#' # remove the first view +#' wb %>% wb_remove_bookview(remove_view = 1) %>% wb_get_bookview() +#' +#' # keep only the first view +#' wb %>% wb_remove_bookview(remove_view = -1) %>% wb_get_bookview() #' @export wb_set_bookview <- function( wb, @@ -1700,6 +1733,7 @@ wb_set_bookview <- function( window_width = NULL, x_window = NULL, y_window = NULL, + use_view = 1L, ... ) { assert_workbook(wb) @@ -1717,6 +1751,7 @@ wb_set_bookview <- function( window_width = window_width, x_window = x_window, y_window = y_window, + use_view = use_view, ... = ... ) } diff --git a/R/class-workbook.R b/R/class-workbook.R index 574aed8c4..fa2bd84a4 100644 --- a/R/class-workbook.R +++ b/R/class-workbook.R @@ -4239,7 +4239,46 @@ wbWorkbook <- R6::R6Class( ### book views ---- - #' @description Set the book views + #' @description Get the book views + #' @return A dataframe with the bookview properties + get_bookview = function() { + wbv <- self$workbook$bookViews + if (is.null(wbv)) { + wbv <- xml_node_create("workbookView") + } else { + wbv <- xml_node(wbv, "bookViews", "workbookView") + } + rbindlist(xml_attr(wbv, "workbookView")) + }, + + #' @description Get the book views + #' @param remove_view remove_view + #' @return The `wbWorkbook` object + remove_bookview = function(remove_view = NULL) { + + wbv <- self$workbook$bookViews + + if (is.null(wbv)) { + return(invisible(self)) + } else { + wbv <- xml_node(wbv, "bookViews", "workbookView") + } + + if (!is.null(remove_view)) { + if (!is.integer(remove_view)) remove_view <- as.integer(remove_view) + # if there are three views, and 2 is removed, the indices are + # now 1, 2 and not 1, 3. removing -1 keeps only the first view + wbv <- wbv[-remove_view] + } + + self$workbook$bookViews <- xml_node_create( + "bookViews", + xml_children = wbv + ) + + invisible(self) + }, + #' @param active_tab activeTab #' @param auto_filter_date_grouping autoFilterDateGrouping #' @param first_sheet firstSheet @@ -4253,6 +4292,7 @@ wbWorkbook <- R6::R6Class( #' @param window_width windowWidth #' @param x_window xWindow #' @param y_window yWindow + #' @param use_view use_view #' @return The `wbWorkbook` object set_bookview = function( active_tab = NULL, @@ -4268,6 +4308,7 @@ wbWorkbook <- R6::R6Class( window_width = NULL, x_window = NULL, y_window = NULL, + use_view = 1L, ... ) { @@ -4281,8 +4322,20 @@ wbWorkbook <- R6::R6Class( wbv <- xml_node(wbv, "bookViews", "workbookView") } - wbv <- xml_attr_mod( - wbv, + if (use_view > length(wbv)) { + if (use_view == length(wbv) + 1L) { + wbv <- c(wbv, xml_node_create("workbookView")) + } else { + msg <- paste0( + "There is more than one workbook view missing.", + " Available: ", length(wbv), ". Requested: ", use_view + ) + stop(msg, call. = FALSE) + } + } + + wbv[use_view] <- xml_attr_mod( + wbv[use_view], xml_attributes = c( activeTab = as_xml_attr(active_tab), autoFilterDateGrouping = as_xml_attr(auto_filter_date_grouping), diff --git a/inst/WORDLIST b/inst/WORDLIST index e6e023f91..abc7229d9 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -64,6 +64,7 @@ autocompletion bandedCols bandedRows blankRow +bookview bool calcChain calculatedColumn diff --git a/man/wbWorkbook.Rd b/man/wbWorkbook.Rd index 6bb343ad1..ba49659d2 100644 --- a/man/wbWorkbook.Rd +++ b/man/wbWorkbook.Rd @@ -186,6 +186,8 @@ worksheet names.} \item \href{#method-wbWorkbook-get_base_colours}{\code{wbWorkbook$get_base_colours()}} \item \href{#method-wbWorkbook-set_base_colors}{\code{wbWorkbook$set_base_colors()}} \item \href{#method-wbWorkbook-set_base_colours}{\code{wbWorkbook$set_base_colours()}} +\item \href{#method-wbWorkbook-get_bookview}{\code{wbWorkbook$get_bookview()}} +\item \href{#method-wbWorkbook-remove_bookview}{\code{wbWorkbook$remove_bookview()}} \item \href{#method-wbWorkbook-set_bookview}{\code{wbWorkbook$set_bookview()}} \item \href{#method-wbWorkbook-get_sheet_names}{\code{wbWorkbook$get_sheet_names()}} \item \href{#method-wbWorkbook-set_sheet_names}{\code{wbWorkbook$set_sheet_names()}} @@ -1389,10 +1391,42 @@ The \code{wbWorkbook} object } } \if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-wbWorkbook-get_bookview}{}}} +\subsection{Method \code{get_bookview()}}{ +Get the book views +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{wbWorkbook$get_bookview()}\if{html}{\out{
}} +} + +\subsection{Returns}{ +A dataframe with the bookview properties +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-wbWorkbook-remove_bookview}{}}} +\subsection{Method \code{remove_bookview()}}{ +Get the book views +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{wbWorkbook$remove_bookview(remove_view = NULL)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{remove_view}}{remove_view} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +The \code{wbWorkbook} object +} +} +\if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-wbWorkbook-set_bookview}{}}} \subsection{Method \code{set_bookview()}}{ -Set the book views \subsection{Usage}{ \if{html}{\out{
}}\preformatted{wbWorkbook$set_bookview( active_tab = NULL, @@ -1408,6 +1442,7 @@ Set the book views window_width = NULL, x_window = NULL, y_window = NULL, + use_view = 1L, ... )}\if{html}{\out{
}} } @@ -1441,6 +1476,8 @@ Set the book views \item{\code{y_window}}{yWindow} +\item{\code{use_view}}{use_view} + \item{\code{...}}{additional arguments} } \if{html}{\out{}} diff --git a/man/wb_set_bookview.Rd b/man/wb_set_bookview.Rd index eeda87dcf..3c671bf68 100644 --- a/man/wb_set_bookview.Rd +++ b/man/wb_set_bookview.Rd @@ -2,8 +2,14 @@ % Please edit documentation in R/class-workbook-wrappers.R \name{wb_set_bookview} \alias{wb_set_bookview} -\title{Set the workbook position, size and filter} +\alias{wb_get_bookview} +\alias{wb_remove_bookview} +\title{Get and Set the workbook position, size and filter} \usage{ +wb_get_bookview(wb) + +wb_remove_bookview(wb, remove_view = NULL) + wb_set_bookview( wb, active_tab = NULL, @@ -19,12 +25,15 @@ wb_set_bookview( window_width = NULL, x_window = NULL, y_window = NULL, + use_view = 1L, ... ) } \arguments{ \item{wb}{A \link{wbWorkbook} object} +\item{remove_view}{You can remove views using index positions. This will only remove the view wont apply modifications.} + \item{active_tab}{activeTab} \item{auto_filter_date_grouping}{autoFilterDateGrouping} @@ -51,11 +60,33 @@ wb_set_bookview( \item{y_window}{yWindow} +\item{use_view}{Which view to modify. Default is \code{1} (the first view).} + \item{...}{additional arguments} } \value{ +A data frame with the bookview properties + +The Workbook object + The Workbook object } \description{ -Set the workbook position, size and filter +Get and Set the workbook position, size and filter +} +\examples{ + wb <- wb_workbook() \%>\% wb_add_worksheet() + + # set the first and second bookview (horizontal split) + wb <- wb \%>\% + wb_set_bookview(window_height = 17600, window_width = 15120, x_window = 15120, y_window = 760) \%>\% + wb_set_bookview(window_height = 17600, window_width = 15040, x_window = 0, y_window = 760, use_view = 2) + + wb \%>\% wb_get_bookview() + + # remove the first view + wb \%>\% wb_remove_bookview(remove_view = 1) \%>\% wb_get_bookview() + + # keep only the first view + wb \%>\% wb_remove_bookview(remove_view = -1) \%>\% wb_get_bookview() } diff --git a/tests/testthat/test-class-workbook-wrappers.R b/tests/testthat/test-class-workbook-wrappers.R index 1caf39a06..374333c81 100644 --- a/tests/testthat/test-class-workbook-wrappers.R +++ b/tests/testthat/test-class-workbook-wrappers.R @@ -205,13 +205,23 @@ test_that("wb_get_base_color() is a wrapper", { expect_wrapper("get_base_colours", wb = wb) }) -# wb_set_bookview() ----------------------------------------------------------- +# wb_get_bookview(),wb_remove_bookview(), wb_set_bookview() ------------------- + +test_that("wb_get_bookview() is a wrapper", { + expect_wrapper("get_bookview") +}) test_that("wb_set_bookview() is a wrapper", { params <- list(activeTab = "1") expect_wrapper("set_bookview", params = params) }) +test_that("wb_remove_bookview() is a wrapper", { + wb <- wb_workbook()$add_worksheet()$set_bookview() + params <- list(remove_view = 1L) + expect_wrapper("remove_bookview", params = params) +}) + # wb_set_header_footer() ------------------------------------------------------ test_that("wb_set_header_footer() is a wrapper", { diff --git a/tests/testthat/test-class-workbook.R b/tests/testthat/test-class-workbook.R index 809d11943..6b81c0ea0 100644 --- a/tests/testthat/test-class-workbook.R +++ b/tests/testthat/test-class-workbook.R @@ -1249,3 +1249,46 @@ test_that("handling mips in docMetadata works", { wb <- wb_load(tmp) expect_equal(xml, wb$docMetadata) }) + +test_that("using and removing secondary bookviews works", { + wb <- wb_workbook() %>% wb_add_worksheet() + + # set the first and second bookview (horizontal split) + wb <- wb %>% + wb_set_bookview(window_height = 17600, window_width = 15120, x_window = 15120, y_window = 760) %>% + wb_set_bookview(window_height = 17600, window_width = 15040, x_window = 0, y_window = 760, use_view = 2) + + exp <- structure( + list(windowHeight = c("17600", "17600"), windowWidth = c("15120", "15040"), + xWindow = c("15120", "0"), yWindow = c("760", "760")), + row.names = c(NA, 2L), class = "data.frame") + got <- wb %>% wb_get_bookview() + expect_equal(exp, got) + + # remove the first view + exp <- structure( + list(windowHeight = c("17600"), windowWidth = c("15040"), + xWindow = c("0"), yWindow = c("760")), + row.names = c(NA, 1L), class = "data.frame") + got <- wb %>% wb_remove_bookview(remove_view = 1) %>% wb_get_bookview() + expect_equal(exp, got) + + # keep only the first view + exp <- structure( + list(windowHeight = c("17600"), windowWidth = c("15120"), + xWindow = c("15120"), yWindow = c("760")), + row.names = c(NA, 1L), class = "data.frame") + got <- wb %>% wb_remove_bookview(remove_view = -1) %>% wb_get_bookview() + expect_equal(exp, got) + + wb <- wb_workbook() %>% wb_add_worksheet() + exp <- structure(list(), row.names = c(NA, 1L), names = character(0), class = "data.frame") + got <- wb %>% wb_remove_bookview(remove_view = 1) %>% wb_get_bookview() + expect_equal(exp, got) + + expect_error( + wb <- wb_workbook() %>% wb_add_worksheet() %>% wb_set_bookview(use_view = 3), + "There is more than one workbook view missing. Available: 1. Requested: 3" + ) + +})