diff --git a/NAMESPACE b/NAMESPACE index daaf73eec..3e6deff24 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -124,6 +124,7 @@ export(wb_remove_named_region) export(wb_remove_row_heights) export(wb_remove_slicer) export(wb_remove_tables) +export(wb_remove_timeline) export(wb_remove_worksheet) export(wb_save) export(wb_set_active_sheet) diff --git a/R/class-workbook-wrappers.R b/R/class-workbook-wrappers.R index 777e7f2d9..594e46ec2 100644 --- a/R/class-workbook-wrappers.R +++ b/R/class-workbook-wrappers.R @@ -508,7 +508,7 @@ wb_add_pivot_table <- function( #' * level: the granularity of the slicer (for timeline 0 = year, 1 = quarter, 2 = month) #' * show_caption: logical if caption should be shown or not #' -#' Removing slicers works on the spreadsheet level. Therefore all slicers are removed from a worksheet. +#' Removing works on the spreadsheet level. Therefore all slicers/timelines are removed from a worksheet. At the moment the drawing reference remains on the spreadsheet. Therefore spreadsheet software that does not handle slicers/timelines will still show the drawing. #' #' @param wb A Workbook object containing a worksheet. #' @param x A `data.frame` that inherits the [`wb_data`][wb_data()] class. @@ -636,6 +636,18 @@ wb_add_timeline <- function( } +#' @rdname wb_add_slicer +#' @export +wb_remove_timeline <- function( + wb, + sheet = current_sheet() +) { + assert_workbook(wb) + wb$clone()$remove_timeline( + sheet = sheet + ) +} + #' Add a formula to a cell range in a worksheet #' #' This function can be used to add a formula to a worksheet. diff --git a/R/class-workbook.R b/R/class-workbook.R index da809d029..8f90f49cb 100644 --- a/R/class-workbook.R +++ b/R/class-workbook.R @@ -2113,19 +2113,21 @@ wbWorkbook <- R6::R6Class( # without choose: filterType = unknown timeline_cache <- read_xml(sprintf( - ' + ' - + %s %s ', uni_name, + st_guid(), timeline, sheet, pivot_table, + cid, selection_xml, bounds_xml ), pointer = FALSE) @@ -2344,6 +2346,48 @@ wbWorkbook <- R6::R6Class( invisible(self) }, + #' @description add pivot table + #' @return The `wbWorkbook` object + remove_timeline = function(sheet = current_sheet()) { + sheet <- private$get_sheet_index(sheet) + + # get indices + timeline_id <- self$worksheets[[sheet]]$relships$timeline + + # skip if nothing to do + if (identical(timeline_id, integer())) return(invisible(self)) + + cache_names <- unname(sapply(xml_attr(self$timelines[timeline_id], "timelines", "timeline"), "[", "cache")) + timeline_names <- unname(sapply(xml_attr(self$timelineCaches, "timelineCacheDefinition"), "[", "name")) + timeline_cache_id <- which(cache_names %in% timeline_names) + + # strings to grep + timeline_xml <- sprintf("timelines/timeline%s.xml", timeline_id) + caches_xml <- sprintf("timelineCaches/timelineCache%s.xml", timeline_cache_id) + + # empty timelines + self$timelines[timeline_id] <- "" + # empty timelineCache + self$timelineCaches[timeline_cache_id] <- "" + + # remove timeline cache relship + self$worksheets[[sheet]]$relships$timeline <- integer() + # remove worksheet relationship + self$worksheets_rels[[sheet]] <- self$worksheets_rels[[sheet]][!grepl(timeline_xml, self$worksheets_rels[[sheet]])] + # remove "x15:timelineRefs" + is_ext_x15 <- grepl("xmlns:x15", self$worksheets[[sheet]]$extLst) + extLst <- xml_rm_child(self$worksheets[[sheet]]$extLst[is_ext_x15], xml_child = "x15:timelineRefs") + self$worksheets[[sheet]]$extLst[is_ext_x15] <- extLst + + # clear workbook.xml.rels + self$workbook.xml.rels <- self$workbook.xml.rels[!grepl(paste0(caches_xml, collapse = "|"), self$workbook.xml.rels)] + + # clear Content_Types + self$Content_Types <- self$Content_Types[!grepl(paste0(c(timeline_xml, caches_xml), collapse = "|"), self$Content_Types)] + + invisible(self) + }, + #' @description Add formula #' @param x x #' @param start_col startCol @@ -2726,15 +2770,16 @@ wbWorkbook <- R6::R6Class( timelinesDir <- dir_create(tmpDir, "xl", "timelines") timelineCachesDir <- dir_create(tmpDir, "xl", "timelineCaches") - timeline <- self$timelines[self$timelines != ""] - for (i in seq_along(timeline)) { + timeline_id <- which(self$timelines != "") + for (i in timeline_id) { write_file( - body = timeline[i], + body = self$timelines[i], fl = file.path(timelinesDir, sprintf("timeline%s.xml", i)) ) } - for (i in seq_along(self$timelineCaches)) { + caches_id <- which(self$timelineCaches != "") + for (i in caches_id) { write_file( body = self$timelineCaches[[i]], fl = file.path(timelineCachesDir, sprintf("timelineCache%s.xml", i)) diff --git a/inst/WORDLIST b/inst/WORDLIST index 828b183c8..025632539 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -50,6 +50,8 @@ SubtotalRow SuperA SuperB Textbox +TimelineStyleDark +TimelineStyleLight TotalCell TrafficLights VARP diff --git a/man/wbWorkbook.Rd b/man/wbWorkbook.Rd index 27e5e1eba..560d8da80 100644 --- a/man/wbWorkbook.Rd +++ b/man/wbWorkbook.Rd @@ -166,6 +166,7 @@ worksheet names.} \item \href{#method-wbWorkbook-add_slicer}{\code{wbWorkbook$add_slicer()}} \item \href{#method-wbWorkbook-remove_slicer}{\code{wbWorkbook$remove_slicer()}} \item \href{#method-wbWorkbook-add_timeline}{\code{wbWorkbook$add_timeline()}} +\item \href{#method-wbWorkbook-remove_timeline}{\code{wbWorkbook$remove_timeline()}} \item \href{#method-wbWorkbook-add_formula}{\code{wbWorkbook$add_formula()}} \item \href{#method-wbWorkbook-add_style}{\code{wbWorkbook$add_style()}} \item \href{#method-wbWorkbook-to_df}{\code{wbWorkbook$to_df()}} @@ -806,6 +807,26 @@ The \code{wbWorkbook} object } } \if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-wbWorkbook-remove_timeline}{}}} +\subsection{Method \code{remove_timeline()}}{ +add pivot table +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{wbWorkbook$remove_timeline(sheet = current_sheet())}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{sheet}}{The name of the sheet} +} +\if{html}{\out{
}} +} +\subsection{Returns}{ +The \code{wbWorkbook} object +} +} +\if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-wbWorkbook-add_formula}{}}} \subsection{Method \code{add_formula()}}{ diff --git a/man/wb_add_slicer.Rd b/man/wb_add_slicer.Rd index 2f8c14070..43a88dee6 100644 --- a/man/wb_add_slicer.Rd +++ b/man/wb_add_slicer.Rd @@ -4,6 +4,7 @@ \alias{wb_add_slicer} \alias{wb_remove_slicer} \alias{wb_add_timeline} +\alias{wb_remove_timeline} \title{Add a slicer/timeline to a pivot table} \usage{ wb_add_slicer( @@ -27,6 +28,8 @@ wb_add_timeline( timeline, params ) + +wb_remove_timeline(wb, sheet = current_sheet()) } \arguments{ \item{wb}{A Workbook object containing a worksheet.} @@ -79,7 +82,7 @@ Possible common \code{params}: \item show_caption: logical if caption should be shown or not } -Removing slicers works on the spreadsheet level. Therefore all slicers are removed from a worksheet. +Removing works on the spreadsheet level. Therefore all slicers/timelines are removed from a worksheet. At the moment the drawing reference remains on the spreadsheet. Therefore spreadsheet software that does not handle slicers/timelines will still show the drawing. } \examples{ # prepare data diff --git a/tests/testthat/test-class-workbook-wrappers.R b/tests/testthat/test-class-workbook-wrappers.R index 65183364f..d300cb010 100644 --- a/tests/testthat/test-class-workbook-wrappers.R +++ b/tests/testthat/test-class-workbook-wrappers.R @@ -420,6 +420,11 @@ test_that("wb_add_timeline() is a wrapper", { expect_wrapper("add_timeline", wb = wb, params = list(x = df, timeline = "date", pivot_table = "pivot1")) }) +test_that("wb_remove_timeline() is a wrapper", { + wb <- wb_workbook()$add_worksheet() + expect_wrapper("remove_timeline", wb = wb) +}) + test_that("wb_add_formula() is a wrapper", { wb <- wb_workbook()$add_worksheet(1) expect_wrapper("add_formula", wb = wb, params = list(sheet = 1, x = "=TODAY()")) diff --git a/tests/testthat/test-write.R b/tests/testthat/test-write.R index bd6cb3901..633206d9f 100644 --- a/tests/testthat/test-write.R +++ b/tests/testthat/test-write.R @@ -692,6 +692,98 @@ test_that("removing slicers works", { }) +test_that("removing timelines works", { + + ### prepare data + df <- data.frame( + AirPassengers = c(AirPassengers), + time = seq(from = as.Date("1949-01-01"), to = as.Date("1960-12-01"), by = "month"), + letters = letters[1:4] + ) + + ### create workbook + wb <- wb_workbook()$ + add_worksheet("pivot")$ + add_worksheet("pivot2")$ + add_worksheet("data")$ + add_data(x = df) + + ### get pivot table data source + df <- wb_data(wb, sheet = "data") + + ### first sheet + # create pivot table + wb$add_pivot_table( + df, + sheet = "pivot", + rows = "time", + cols = "letters", + data = "AirPassengers", + pivot_table = "airpassengers", + params = list( + compact = FALSE, outline = FALSE, compact_data = FALSE, + row_grand_totals = FALSE, col_grand_totals = FALSE) + ) + + # add slicer + wb$add_slicer( + df, + dims = "E1:I7", + sheet = "pivot", + slicer = "letters", + pivot_table = "airpassengers" + ) + + # add timeline + wb$add_timeline( + df, + dims = "E9:I14", + sheet = "pivot", + timeline = "time", + pivot_table = "airpassengers" + ) + + ### second sheet + # create pivot table + wb$add_pivot_table( + df, + sheet = "pivot2", + rows = "time", + cols = "letters", + data = "AirPassengers", + pivot_table = "airpassengers2", + params = list( + compact = FALSE, outline = FALSE, compact_data = FALSE, + row_grand_totals = FALSE, col_grand_totals = FALSE) + ) + + # add slicer + wb$add_slicer( + df, + dims = "E1:I7", + sheet = "pivot2", + slicer = "letters", + pivot_table = "airpassengers2", + params = list(choose = c(letters = 'x %in% c("a", "b")')) + ) + + # add timeline + wb$add_timeline( + df, + dims = "E9:I14", + sheet = "pivot2", + timeline = "time", + pivot_table = "airpassengers2" + ) + + ### remove slicer + wb$remove_timeline(sheet = "pivot") + + temp <- temp_xlsx() + expect_silent(wb$save(temp)) # no warning, all files written as expected + +}) + test_that("writing na.strings = NULL works", { # write na.strings = na_strings()