Skip to contents

A theme created from nothing starts empty, and a Mergin theme hides a layer by ABSENCE - so an empty theme is a theme that shows nothing. That is #304's second consequence, and it shipped: a Floodplain theme created by a downstream driver held only the three layers its config named, against the donor project's thirty-two, and would have looked correct in the theme list.

Usage

rfp_qgs_theme_create(
  qgs,
  name,
  base,
  add = character(0),
  drop = character(0),
  visible = TRUE,
  force = FALSE,
  backup = TRUE
)

Arguments

qgs

Path to a .qgs project, or a directory holding exactly one.

name

Character. The new theme's name.

base

Character. An existing theme in this project to derive from.

add

Character. Layer names to add, or to make visible if the base already lists them. The groups holding each one it makes visible, and every ancestor of them, are checked in the derived theme if the base does not already check them (#316) - otherwise the layer is listed and draws nothing.

drop

Character. Layer names to remove from the derived theme.

visible

Logical, recycled over add. Default TRUE.

force

Logical. Replace name if it already exists. Default FALSE, because replacing regenerates the preset and anything the new definition does not carry is gone.

backup

Logical. Write <path>.bak before mutating. Default TRUE.

Value

Invisibly, the one-row summary rfp_qgs_theme_set() returns.

Details

Themes are overwhelmingly derived from one another rather than authored, and that is measured rather than asserted. Across the eight themes rfp ships, every one of the seven non-Imagery themes contains all 21 of the layers they share and differs by only four to seven members, with five visibility overrides between them in total. Floodplain - Habitat Lateral is Floodplain with the floodplain products swapped for habitat_lateral; the three Low Detail model themes differ by exactly one streams_* layer each.

Group state, per-class legend state and the preset's own info flags are carried from the base, which is what rfp_qgs_theme_set() regenerating a preset from scratch would otherwise destroy (#121).

Carried is not enough for add (#316). QGIS hides a layer whose group is unchecked, so copying the base's checked groups verbatim buried every added layer that lives outside them - listed, visible="1", drawing nothing, which is the rfp_qgs_theme_layer_add() failure #216 describes, produced by the function that exists to make deriving safe. Measured on the shipped restoration template: add = "Fire Perimeters - Current" onto Land Tenure left /Web Mapping Services unchecked against 14 checked groups. So the groups holding each added visible layer, and every ancestor of them, are derived from the tree and unioned in.

The base's own rows are never modified and nothing is ever unticked, so a derivation that adds only within the base's already-checked groups is unchanged. Checked, not merely present: Land Tenure carries /Other point features as expanded and not checked, so adding FISS obstacles - which that theme already lists, off - stays inside the base's groups and still has one to tick.

Only the layers add makes visible are aimed at. A layer the base already shows from an unchecked group is not sought out - that is the base's own state, and rfp_qgs_theme_layer_add()'s check_groups is where repairing it belongs. But ticking is per group, not per layer, so such a layer is unburied as a side effect when it happens to share a group with an added one. Neither shipped template can show this - both carry zero buried visible entries across every preset - so it is stated rather than tested. drop is deliberately not the mirror either: a group is left checked when its last visible layer goes, because unticking it could hide a layer another preset row still shows.

Examples

qgs <- file.path(tempdir(), "theme_create.qgs")
file.copy(system.file("testdata", "raster_add_fixture.qgs", package = "rfp"),
          qgs, overwrite = TRUE)
#> [1] TRUE
rows <- rfp_qgs_themes(qgs)$layers
base <- rows$theme[[1]]
rfp_qgs_theme_create(qgs, "Derived", base = base,
                     drop = rows$layer[rows$theme == base][[1]],
                     backup = FALSE)
#>  Set 1 theme in /tmp/RtmpfSNDuG/theme_create.qgs
#>  Created "Derived" from "High Detail - Crossings": 2 layers (0 added, 1 dropped)
setdiff(rfp_qgs_theme_names(qgs), unique(rows$theme))
#> [1] "Derived"
unlink(qgs)