LLFormat

Reads the design values of a linelist from the format table and applies them. DesignValue answers one value by name. ApplyFormat takes a FormatScope and writes the look that scope stands for onto a Worksheet, a Range, a Shape, a ListObject or a run of Characters. Import and Export move the format table between workbooks, and DesignName says which design the object reads.

THE DESIGN VALUES ARE READ ONCE

DesignValue reads a value from the table the first time it is asked and holds the answer for the life of the object. A caller that edits the format sheet by hand builds a new object to reach the new values, or calls Import, which drops every held answer.

Depends on: CustomTable, Checking, BetterArray

Version: 1.0 (2026-02-09)

Factory

Create #

create

Instantiate an LL format engine for a worksheet

Signature:

Public Function Create(ByVal formatSh As Worksheet, _
                       Optional ByVal designType As String = DEFAULT_DESIGN) As LLFormat

Validates the format worksheet, resolves the design column, and returns a fully initialised LLFormat instance.

Parameters:

  • formatSh: Worksheet. Worksheet containing the format specification table.
  • designType: String. Design column to use. Defaults to DEFAULT_DESIGN.

Returns: LLFormat. A fully initialised LLFormat instance.


Design Lookups

DesignValue #

design-value

Look up a design value or colour from the format table

Signature:

Public Function DesignValue(ByVal labelName As String, _
                             Optional ByVal returnColor As Boolean = True) As Variant

Retrieves either the fill colour (Interior.Color) or the raw cell value for the specified label row under the active design column. Returns a fallback when the label is not found and logs a diagnostic. The answer is cached for the life of the object; see the class @details.

Parameters:

  • labelName: String. Label text stored in the format table.
  • returnColor: Boolean. When True returns Interior.Color; otherwise the raw value. Defaults to True.

Returns: Variant. The colour (Long) or cell value.


Formatting

ApplyFormat #

apply-format

Apply a design-driven format to an Excel object

Signature:

Public Sub ApplyFormat(ByVal formattingObject As Variant, _
                        ByVal scope As Byte, _
                        Optional ByVal nbDecimals As Integer = 0)

Reads style metadata from the format table and applies it to the supplied object according to the given FormatScope constant. The object is sorted ONCE here, by its type, and then handed to the sub that formats that kind of object. Every branch used to open with its own TypeName test and its own Set, 31 times over. An object of the wrong kind for the requested scope still leaves quietly - callers rely on that silence.

Parameters:

  • formattingObject: Variant. The Excel object to format.
  • scope: Byte. FormatScope constant selecting the visual pattern.
  • nbDecimals: Integer. Decimal count for numeric formatting. Defaults to 0.

Import

Import #

import

Import formatting definitions from another worksheet

Signature:

Public Sub Import(ByVal inpsh As Worksheet)

Reads design columns from the source worksheet and merges them into the current format table via CustomTable.Import. Updates the active design name from the source DESIGNTYPE named range.

Parameters:

  • inpsh: Worksheet. Source worksheet containing the format table.

Export

Export #

export

Export the format table to another workbook

Signature:

Public Sub Export(ByVal toWkb As Workbook)

Copies the format table and cell styles to a new worksheet in the destination workbook. When a worksheet with the same name already exists, the call turns into an Import from that sheet.

Parameters:

  • toWkb: Workbook. Destination workbook.

Internal members (not exported)

Cache Management

ResetCaches #

reset-caches

Invalidate all cached references

Signature:

Private Sub ResetCaches()

EnsureFormatReady #

ensure-format-ready

Ensure caches are initialised and the worksheet is set

Signature:

Private Sub EnsureFormatReady()

CachedValue #

cached-value

Read one entry out of a keyed cache

Signature:

Private Function CachedValue(ByVal store As Collection, _
                             ByVal cacheKey As String, _
                             ByRef found As Boolean) As Variant

Parameters:

Returns: Variant. The stored value, or Empty when the key is absent.


StoreCachedValue #

store-cached-value

Add one entry to a keyed cache

Signature:

Private Sub StoreCachedValue(ByVal store As Collection, _
                             ByVal cacheKey As String, _
                             ByVal cacheValue As Variant)

Parameters:


Format Table Access

TableOfSheet #

table-of-sheet

Retrieve the first ListObject of a worksheet

Signature:

Private Function TableOfSheet(ByVal sh As Worksheet) As ListObject

Parameters:

Returns: ListObject. The first table on the sheet.


HeaderOfTable #

header-of-table

Retrieve the header row of a format table

Signature:

Private Function HeaderOfTable(ByVal formatLo As ListObject) As Range

Parameters:

Returns: Range. The header row.


EnsureFormatSheetReady #

ensure-format-sheet-ready

Validate a worksheet as a valid format source

Signature:

Private Sub EnsureFormatSheetReady(ByVal sh As Worksheet, ByRef resolvedDesign As String)

Parameters:


LogInfo #

log-info

Append a diagnostic entry to the internal checking object

Signature:

Private Sub LogInfo(ByVal label As String)

Parameters:


HarvestCollaboratorCheckings #

harvest-collaborator-checkings

Fold what a table adapter filed into this trace

Signature:

Private Sub HarvestCollaboratorCheckings(ByVal collaboratorChecks As Checking)

CustomTable keeps a store of its own, and nobody read it before this line. An import that aborted, or headers the export could not find, was filed and then dropped.

Parameters:


FormatTable #

format-table

Retrieve the first ListObject on the format worksheet

Signature:

Private Function FormatTable() As ListObject

Returns: ListObject. The format table.


HeaderRange #

header-range

Retrieve the header row range of the format table

Signature:

Private Function HeaderRange() As Range

Returns: Range. The header row.


EnsureLabelColumn #

ensure-label-column

Cache the column index of the Label column

Signature:

Private Sub EnsureLabelColumn()

FindColumnIndex #

find-column-index

Find the column index of a named header, or zero when it is absent

Signature:

Private Function FindColumnIndex(ByVal header As Range, ByVal columnName As String) As Long

Parameters:

Returns: Long. The 1-based column index, or 0 when not found.


ColumnExists #

column-exists

Test whether a named column exists in a header range

Signature:

Private Function ColumnExists(ByVal header As Range, ByVal columnName As String) As Boolean

Parameters:

Returns: Boolean. True when the column is found.


ResolveColumnIndex #

resolve-column-index

Find the column index of a named header, raising when it is absent

Signature:

Private Function ResolveColumnIndex(ByVal header As Range, ByVal columnName As String) As Long

Parameters:

Returns: Long. The 1-based column index.


DesignColumnIndex #

design-column-index

Resolve and cache the column index for a design name

Signature:

Private Function DesignColumnIndex(ByVal designName As String) As Long

Parameters:

Returns: Long. The 1-based column index.


LabelRowIndex #

label-row-index

Resolve and cache the row index for a format label

Signature:

Private Function LabelRowIndex(ByVal labelName As String) As Long

The lookup tries an exact match first and then a partial one. Four of the labels this class asks for are stored in the format table with extra words around them - "gap for graphs" sits in "default row height gap for graphs", "dropdown interior color" in "Select dropdown interior color", "time series header font" in "Time series header font color" and "time series header interior" in "Time series header interior color". Partial matching has to stay for those four. The exact pass runs first so that a new row whose label merely CONTAINS an existing one leaves that older row alone.

Parameters:

Returns: Long. The 1-based row index, or 0 when not found.


Public Interface

Wksh #

wksh

Retrieve the worksheet hosting the format table

Signature:

Public Property Get Wksh() As Worksheet

Returns: Worksheet. The host worksheet.


Wksh #

wksh-set

Assign the worksheet backing this formatter

Signature:

Public Property Set Wksh(ByVal sh As Worksheet)

Clears all caches when the worksheet changes.

Parameters:


DesignName #

design-name

Name of the active design column

Signature:

Public Property Get DesignName() As String

Returns: String. The active design name.


DesignName #

design-name-set

Change the active design column

Signature:

Public Property Let DesignName(ByVal design As String)

Resets cached lookups when the design changes.

Parameters:


HasCheckings #

has-checkings

Whether the format object has logged diagnostic messages

Signature:

Public Property Get HasCheckings() As Boolean

Returns: Boolean. True when diagnostic entries exist.


CheckingValues #

checking-values

Retrieve the diagnostic log entries

Signature:

Public Property Get CheckingValues() As Checking

Returns: Checking. The checking instance, or Nothing.


Design Lookups

AnalysisBaseFontSize #

analysis-base-font-size

Base font size used by the analysis format scopes

Signature:

Private Function AnalysisBaseFontSize() As Variant

Returns: Variant. The design font size, or 11 when the design cell is blank.


Drawing Helpers

DrawLines #

draw-lines

Draw border lines around a range

Signature:

Private Sub DrawLines(ByVal rng As Range, _
                      Optional At As String = "All", _
                      Optional weight As Integer = xlHairline, _
                      Optional line As Integer = xlContinuous, _
                      Optional color As Variant = vbBlack)

Parameters:


DrawBorder #

draw-border

Draw a rectangular border around a range

Signature:

Private Sub DrawBorder(ByVal rng As Range, Optional weight As Integer = xlThin, _
                       Optional color As Variant = vbBlack, _
                       Optional line As Long = xlContinuous)

Writes the four properties in the SAME order as DrawLines. Several scopes called DrawLines four times, once per edge, and now call this sub once. With line:=xlDouble the LineStyle write is what settles the final weight, so a different order would make those frames come out heavier.

Parameters:


FormatRange #

format-range

Apply fill, font, alignment, and number format to a range

Signature:

Private Sub FormatRange(ByVal rng As Range, _
                        Optional ByVal fillValue As String = "", _
                        Optional ByVal interiorColor As Variant = "", _
                        Optional ByVal fontColor As Variant = "", _
                        Optional ByVal isBold As Boolean = False, _
                        Optional ByVal Horiz As Integer = xlHAlignCenter, _
                        Optional ByVal Verti As Integer = xlVAlignCenter, _
                        Optional ByVal FontSize As Double = 0, _
                        Optional ByVal NumFormat As String = "", _
                        Optional ByVal wrap As String = vbNullString)

The Variant arguments are compared against vbNullString to mean "leave this property alone". That works because VBA sorts every number below every string, and several scopes pass vbNullString on purpose to skip a property.

Parameters:


FormatCharacters #

format-characters

Apply font styling to a Characters object

Signature:

Private Sub FormatCharacters(ByVal Char As Characters, _
                             Optional ByVal fontColor As Variant = "", _
                             Optional ByVal isBold As Boolean = False, _
                             Optional ByVal FontSize As Double = 0)

Parameters:


FormatShape #

format-shape

Apply fill and font styling to a Shape object

Signature:

Private Sub FormatShape(ByVal shp As Shape, _
                        Optional ByVal fontColor As Variant = vbNullString, _
                        Optional ByVal interiorColor As Variant = vbNullString, _
                        Optional ByVal isBold As Boolean = False, _
                        Optional ByVal FontSize As Double = 0)

Parameters:


RemoveGridLines #

remove-gridlines

Hide gridlines on a worksheet

Signature:

Private Sub RemoveGridLines(ByVal sh As Worksheet, Optional DisplayZeros As Boolean = False)

Parameters:


PreparePrintSheet #

prepare-print-sheet

Configure page setup for printing a worksheet

Signature:

Private Sub PreparePrintSheet(ByVal sh As Worksheet)

Parameters:


Formatting

ApplyWorksheetFormat #

apply-worksheet-format

Apply the worksheet-level format scopes

Signature:

Private Sub ApplyWorksheetFormat(ByVal sh As Worksheet, ByVal scope As Byte)

Parameters:


ApplyCharactersFormat #

apply-characters-format

Apply the label format scopes to a Characters object

Signature:

Private Sub ApplyCharactersFormat(ByVal Char As Characters, ByVal scope As Byte)

Parameters:


ApplyShapeFormat #

apply-shape-format

Apply the button format scopes to a Shape

Signature:

Private Sub ApplyShapeFormat(ByVal shp As Shape, ByVal scope As Byte)

Parameters:


ApplyListObjectFormat #

apply-listobject-format

Apply the entry table format scopes to a ListObject

Signature:

Private Sub ApplyListObjectFormat(ByVal tableObject As ListObject, ByVal scope As Byte)

Parameters:


FormatMissingLook #

format-missing-look

The shared look of the missing and one-cell analysis scopes

Signature:

Private Sub FormatMissingLook(ByVal rng As Range, _
                              ByVal horizAlign As Long, _
                              ByVal drawInsideLines As Boolean)

Six scopes share this block: the same two design colours, the same FormatRange call apart from the horizontal alignment, and the same double frame around the cells.

Parameters:


FormatSectionBody #

format-section-body

The shared tail of the section and sub-section scopes

Signature:

Private Sub FormatSectionBody(ByVal rng As Range, _
                              ByVal interiorColorValue As Variant, _
                              ByVal fontColorValue As Variant, _
                              ByVal fontSizeValue As Variant)

Parameters:


ApplyRangeFormat #

apply-range-format

Apply every range-level format scope

Signature:

Private Sub ApplyRangeFormat(ByVal baseRng As Range, _
                             ByVal scope As Byte, _
                             ByVal nbDecimals As Integer)

baseRng always holds the range the caller passed. rng is the working range and several scopes move it, so anything that has to measure from the original reads baseRng.

Parameters:


Export

ResolveWorksheet #

resolve-worksheet

Look up a worksheet by name without raising errors

Signature:

Private Function ResolveWorksheet(ByVal targetWorkbook As Workbook, ByVal sheetName As String) As Worksheet

Returns: Worksheet. The found worksheet, or Nothing.


ResolveFormatTable #

resolve-format-table

Locate a ListObject on the target sheet by name or index

Signature:

Private Function ResolveFormatTable(ByVal targetSheet As Worksheet, ByVal preferredName As String) As ListObject

Returns: ListObject. The found table, or Nothing.


CopyFormatTableStyles #

copy-format-table-styles

Copy cell-level styles between two format tables

Signature:

Private Sub CopyFormatTableStyles(ByVal sourceTable As ListObject, ByVal targetTable As ListObject)

Block at a time. Excel answers Null for a property whose value varies across a range, so a block styled the same all the way down takes six writes for the whole block, and a mixed block falls back to the cell loop. The header row is taken on its own, because it carries its own styling and would make every column read as mixed. The limit of this: the design columns hold a different colour on every row, which is the whole point of the format table, so those columns are still walked cell by cell. VBA offers a block format copy only through the clipboard. Copy plus PasteSpecial xlPasteFormats would do the whole table in one step, and the clipboard is the least reliable path on Mac Excel, so this code stays off it.


CopyStyles #

copy-styles

Copy the styles of one block, in one step when the block allows it

Signature:

Private Sub CopyStyles(ByVal sourceBlock As Range, ByVal targetBlock As Range)

Parameters:


CopyStylesAsBlock #

copy-styles-as-block

Copy a block of styles in a single write when the block is uniform

Signature:

Private Function CopyStylesAsBlock(ByVal sourceBlock As Range, _
                                   ByVal targetBlock As Range) As Boolean

Excel answers Null for a property whose value varies across a range, so reading the six properties off the whole block is both the test and the read.

Parameters:

Returns: Boolean. True when the whole block was copied in one step.


CopyStylesByCell #

copy-styles-by-cell

Copy a block of styles cell by cell

Signature:

Private Sub CopyStylesByCell(ByVal sourceBlock As Range, ByVal targetBlock As Range)

Both blocks are walked with a single Cells index, so the same loop serves a one-row block and a one-column block. Each cell fetches its Interior and its Font once, then takes three properties off each.

Parameters:


EnsureDesignTypeRange #

ensure-design-type-range

Create the DESIGNTYPE named range on the target sheet

Signature:

Private Sub EnsureDesignTypeRange(ByVal sourceSheet As Worksheet, _
                                  ByVal targetSheet As Worksheet, _
                                  ByVal targetTable As ListObject)

NamedRange #

named-range

Retrieve a worksheet-scoped named range, or Nothing when it is absent

Signature:

Private Function NamedRange(ByVal sh As Worksheet, ByVal rngName As String) As Range

Parameters:

Returns: Range. The named range, or Nothing.


ThrowError #

throw-error

Raise a typed project error

Signature:

Private Sub ThrowError(ByVal errNumber As ProjectError, ByVal errorMessage As String)

Seal #

seal

Seal the instance so setup setters can no longer be written

Signature:

Public Sub Seal()

GuardNotSealed #

guard-not-sealed

Guard a setup setter against writes after sealing

Signature:

Private Sub GuardNotSealed(ByVal propName As String)

Parameters:


Used in (27 file(s))