AnaTabIds

Records the charts of the analysis sheets so an export can draw them again on the sheets it creates, and copies the named ranges those charts read. PrepareSheet builds the tracking worksheet, AddGraphInfo records one chart series and AddGraphFormat the look of one chart, TransferNames copies the named ranges onto an output worksheet, and WriteGraphs draws the charts there.

ONE REGISTRY TABLE

The tracking worksheet holds a single ListObject. Every row carries the scope it belongs to and a kind: a series row describes one chart series, a format row describes the look of one chart. The rows of one chart stay together because they are appended in call order, and the reader starts a new chart when the graph identifier changes.

THE TABLE NAMES COME FROM THE WORKBOOK

Every named range of an analysis table was created by CrossTable through Range.Name, so the workbook already holds it. TransferNames reads the workbook name collection, keeps the names that resolve to a range on the analysis sheet, and creates each one at the same address on the output sheet. The collection is walked once per export and sorted by owning worksheet, because the export asks for four sheets in turn.

Analysis scopes. Each one is a sheet of the generated linelist. This class is the leaf that reads the value, so it owns the enum: AnalysisOutput and LLExporter both name it, and the generated linelist carries this class without carrying AnalysisOutput.

A fifth member used to sit here, standing for the tables-only pass. It was a build stage wearing the type of a scope, and four Select Case blocks that route on a scope had no branch for it. AnalysisOutput owns that enum now, under the name AnalysisBuildStage.

Column positions of the registry table. The headers are written from this enum by PrepareSheet, so one place decides both the layout and every read.

Depends on: Graphs

Version: 2026-07-30

Instantiation

Create #

create

Create a new AnaTabIds instance bound to a tracking worksheet

Signature:

Public Function Create(ByVal idsh As Worksheet, _
                       Optional ByVal check As Boolean = True) As AnaTabIds

Factory method on the predeclared instance. Validates the worksheet reference and, when asked, that the registry table is on the sheet. Pass check as False while the linelist is still being built.

Parameters:

  • idsh: Worksheet. The worksheet hosting the registry table.
  • check: Optional Boolean. When True, calls CheckRequirements. Defaults to True.

Returns: AnaTabIds. A fully initialised tracking instance.

Throws:

  • ProjectError.InvalidArgument When idsh is Nothing.
  • ProjectError.InvalidArgument When check is True and the registry table is missing.

PrepareSheet #

prepare-sheet

Build the registry table on a tracking worksheet

Signature:

Public Sub PrepareSheet(ByVal idsh As Worksheet)

Called on the predeclared instance while the linelist is being built. Writes the header row from RegistryColumnIndex and lists it as REGISTRY_TABLE. A sheet that already carries the table is left as it is, so a second build over the same workbook changes nothing.

Parameters:

  • idsh: Worksheet. The worksheet to prepare.

Throws:

  • ProjectError.InvalidArgument When idsh is Nothing.

Graph Tracking

AddGraphInfo #

add-graph-info

Register a graph series row in the registry

Signature:

Public Sub AddGraphInfo(ByVal scope As Byte, _
                        ByVal graphId As String, _
                        ByVal seriesName As String, _
                        ByVal seriesType As String, _
                        ByVal seriesPos As String, _
                        ByVal seriesLabel As String, _
                        ByVal seriesColumnLabel As String, _
                        ByVal hardCodeLabels As Boolean, _
                        ByVal outRangeAddress As String, _
                        Optional ByVal prefix As String = vbNullString, _
                        Optional ByVal prefixOnly As Boolean = False)

Methods for registering graph series and formatting metadata.

Writes one series row. The rows of one chart have to stay together, and they do because every writer registers the series of a chart one after the other. The two flags are stored as 0 or 1 so they survive a save and reopen.

Parameters:

  • scope: Byte. AnalysisScope value the chart belongs to.
  • graphId: String. Identifier of the chart receiving this series.
  • seriesName: String. Named range name for the series data.
  • seriesType: String. Chart series type (e.g. "line").
  • seriesPos: String. Axis position indicator for the series.
  • seriesLabel: String. Named range name for category labels.
  • seriesColumnLabel: String. Named range name for column header labels.
  • hardCodeLabels: Boolean. When True, labels are written as literals.
  • outRangeAddress: String. Cell address for chart placement on output.
  • prefix: Optional String. Admin-level prefix for spatial graphs. Defaults to vbNullString.
  • prefixOnly: Optional Boolean. When True, only the prefix is used as the label. Defaults to False.

Throws:

  • ProjectError.InvalidArgument When the scope is unknown.

AddGraphFormat #

add-graph-format

Register the look of one chart in the registry

Signature:

Public Sub AddGraphFormat(ByVal scope As Byte, _
                          ByVal graphId As String, _
                          ByVal catTitle As String, _
                          ByVal valuesTitle As String, _
                          ByVal hardCodeLabels As Boolean, _
                          Optional ByVal heightFactor As Long = 1, _
                          Optional ByVal plotTitle As String = vbNullString)

Writes one format row, found again by the graph identifier when the chart has all its series.

Parameters:

  • scope: Byte. AnalysisScope value the chart belongs to.
  • graphId: String. Identifier of the chart to format.
  • catTitle: String. Category (X) axis title.
  • valuesTitle: String. Value (Y) axis title.
  • hardCodeLabels: Boolean. When True, axis labels are written as literals.
  • heightFactor: Optional Long. Multiplier for chart height. Defaults to 1.
  • plotTitle: Optional String. Chart title. Defaults to vbNullString.

Throws:

  • ProjectError.InvalidArgument When the scope is unknown.

Name Transfer

TransferNames #

transfer-names

Recreate every named range of an analysis sheet on the output sheet

Signature:

Public Sub TransferNames(ByVal inpsh As Worksheet, ByVal outsh As Worksheet)

Copying the named ranges of an analysis sheet to the output sheet.

A chart reads its values and its labels through named ranges, so the output sheet needs the same names at the same addresses. The names are read from the workbook collection: every one of them was created on the analysis sheet by the table builder, which is why nothing has to be stored to find them again. A name holding a value has no range behind it, so it is skipped, and so is a name that no longer resolves.

Parameters:

  • inpsh: Worksheet. The analysis sheet the names live on.
  • outsh: Worksheet. The sheet the names are recreated on.

Throws:

  • ProjectError.InvalidArgument When either worksheet is Nothing.

Graph Writing

WriteGraphs #

write-graphs

Recreate the named ranges and the charts of one scope

Signature:

Public Sub WriteGraphs(ByVal outsh As Worksheet, ByVal scope As Byte, _
                       ByVal inpsh As Worksheet)

Drawing the tracked charts on an output worksheet.

Copies the named ranges of the analysis sheet first, because a chart cannot read a series before its name exists. Then walks the series rows of the scope in registry order and starts a new chart every time the graph identifier changes. Each chart is formatted once it holds all its series.

Parameters:

  • outsh: Worksheet. The output worksheet receiving the charts.
  • scope: Byte. AnalysisScope value selecting the registry rows.
  • inpsh: Worksheet. The analysis sheet the names are copied from. The caller holds it already, which is why it is passed in.

Remarks:

  • Application.GoTo scrolls to the chart position, which some Excel versions need for correct chart placement. It also means the output sheet has to be selectable.

Throws:

  • ProjectError.InvalidArgument When a worksheet is Nothing or the scope is unknown.

Internal members (not exported)

Internal Properties

Seal #

seal

Seal the instance against further setup writes.

Signature:

Public Sub Seal()

Factory-support properties for construction and worksheet access.


GuardNotSealed #

guard-not-sealed

Guard a setup setter against post-creation writes.

Signature:

Private Sub GuardNotSealed(ByVal propName As String)

Parameters:


Wksh #

wksh-set

Assign the tracking worksheet

Signature:

Public Property Set Wksh(ByVal sh As Worksheet)

Parameters:


Wksh #

wksh

Tracking worksheet reference

Signature:

Public Property Get Wksh() As Worksheet

Returns: Worksheet. The bound tracking worksheet.


Registry Access

RegistryHeaders #

registry-headers

The header row of the registry table, in column order

Signature:

Private Function RegistryHeaders() As Variant

The one table every read and every write goes through.

Returns: Variant. A zero-based array of REGISTRY_COLUMN_COUNT header names.


Registry #

registry

Resolve the registry table, held after the first read

Signature:

Private Property Get Registry() As ListObject

Returns: ListObject. The registry table of the tracking worksheet.

Throws:


RegistryValues #

registry-values

Read the whole registry table into memory

Signature:

Private Function RegistryValues() As Variant

One read serves the whole walk of one scope. A table with no rows answers Empty, which the callers test with IsEmpty.

Returns: Variant. A two-dimensional array of the data rows, or Empty.


AppendRow #

append-row

Append one row to the registry table in a single write

Signature:

Private Sub AppendRow(ByRef fields As Variant)

The tracking worksheet holds this one table and nothing else, so growing the table over the cells below it is safe. A freshly built table carries one blank row and the first entry goes into it.

Parameters:


ValidateScope #

validate-scope

Refuse a scope this class cannot route

Signature:

Private Sub ValidateScope(ByVal scope As Byte)

Parameters:

Throws:


Graph Tracking

EmptyRow #

empty-row

A registry row with every column blank

Signature:

Private Function EmptyRow() As Variant

Returns: Variant. A one-based array of REGISTRY_COLUMN_COUNT empty strings.


Name Transfer

SheetNames #

sheet-names

The tracked names of one worksheet, name and address

Signature:

Private Function SheetNames(ByVal inpsh As Worksheet) As Collection

Answers from the bucket built on the first call. The export asks for four sheets in turn and the workbook name collection holds thousands of entries, so it is walked once.

Parameters:

Returns: Collection. Array(simple name, address) entries, empty when the sheet carries no name.


BuildNameBuckets #

build-name-buckets

Walk the workbook names once and bucket them by owning worksheet

Signature:

Private Sub BuildNameBuckets(ByVal wkb As Workbook)

The owning sheet is read off RefersToRange. An analysis sheet name is translated and can carry spaces and apostrophes, which makes the RefersTo text a poor thing to match on. A name that holds a value has no range behind it and raises, which is how the two are told apart.

Parameters:


SimpleName #

simple-name

The name without its worksheet qualifier

Signature:

Private Function SimpleName(ByVal fullName As String) As String

A worksheet-scoped name reads as "Sheet name!LOCAL_NAME". The output sheet gets the part after the separator.

Parameters:

Returns: String. The name with no qualifier.


Graph Writing

IsSeriesRow #

is-series-row

Test whether a registry row describes a series of this scope

Signature:

Private Function IsSeriesRow(ByRef values As Variant, ByVal rowIndex As Long, _
                             ByVal scope As Byte) As Boolean

Parameters:

Returns: Boolean. True for a series row of that scope.


AddSeries #

add-series

Read one series row and add it to a chart

Signature:

Private Sub AddSeries(ByVal gr As Graphs, ByRef values As Variant, _
                      ByVal rowIndex As Long)

Parameters:


ApplyFormat #

apply-format

Apply the format row of one chart

Signature:

Private Sub ApplyFormat(ByVal gr As Graphs, ByRef values As Variant, _
                        ByVal scope As Byte, ByVal graphId As String)

Finds the format row of the graph identifier inside the scope. A chart with no format row keeps the chart defaults.

Parameters:


FormatRowIndex #

format-row-index

Locate the format row of one chart

Signature:

Private Function FormatRowIndex(ByRef values As Variant, ByVal scope As Byte, _
                                ByVal graphId As String) As Long

Parameters:

Returns: Long. The row index, or 0 when the chart has no format row.


Typed Reads

ReadBoolean #

read-boolean

Read a stored flag

Signature:

Private Function ReadBoolean(ByVal value As Variant) As Boolean

Turning a stored cell value back into a typed value, with no silent trap.

The writers store a flag as 0 or 1, so the numeric arm answers every value this class has ever written. The text arms cover a value typed by hand into the sheet, and anything else answers False.

Parameters:

Returns: Boolean. The stored flag.


ReadLong #

read-long

Read a stored whole number

Signature:

Private Function ReadLong(ByVal value As Variant, ByVal defaultValue As Long) As Long

Parameters:

Returns: Long. The stored number, or the default.


Validation

LoExists #

lo-exists

Check whether a ListObject exists on a worksheet

Signature:

Private Function LoExists(ByVal sh As Worksheet, ByVal loName As String) As Boolean

Existence checks and factory validation.

Parameters:

Returns: Boolean. True when the ListObject exists.


CheckRequirements #

check-requirements

Validate the tracking worksheet infrastructure

Signature:

Private Sub CheckRequirements(ByVal sh As Worksheet)

Checks that the registry table is on the sheet. The export passes the sheet it copies from, so no analysis sheet name is looked up here.

Parameters:

Throws:


Error Handling

ThrowError #

throw-error

Raise a ProjectError-based exception

Signature:

Private Sub ThrowError(ByVal errNumber As Long, ByVal message As String)

Wrapper around Err.Raise that standardises the source to CLASS_NAME.

Parameters:

Throws:


Used in (6 file(s))