
Create a map theme from another one, plus a delta
Source:R/rfp_qgs_theme_create.R
rfp_qgs_theme_create.RdA 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.
Arguments
- qgs
Path to a
.qgsproject, 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. DefaultTRUE.- force
Logical. Replace
nameif it already exists. DefaultFALSE, because replacing regenerates the preset and anything the new definition does not carry is gone.- backup
Logical. Write
<path>.bakbefore mutating. DefaultTRUE.
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)