LinelistSpecs
Modern facade that wraps a specifications workbook and exposes lazy-loaded, cached accessors for every collaborator object (dictionary, choices, translations, geo, analysis, passwords, format, exports, formulas). Provides lifecycle orchestration methods for importing data from external setup workbooks, preparing the dictionary with preserved sheet names, exporting specifications to a destination linelist workbook, and surfacing user-facing error dialogs. Uses a PredeclaredId factory pattern so callers construct instances via LinelistSpecs.Create(workbook) and receive an ILinelistSpecs interface reference.
Depends on: ILLdictionary, ILLChoices, ILLTranslation, IDesignerTranslation, ILLGeo, ILLExport, IAnalysis, IPasswords, ILLFormat, IDesignerImportService, ITemporaryRepos, TemporaryRepos, IFormulaData, ILLVariables, IFormulas, ITranslationObject, IApplicationState, ApplicationState, BetterArray, LLdictionary, LLChoices, LLTranslation, DesignerTranslation, LLGeo, LLExport, Analysis, Passwords, LLFormat, FormulaData, LLVariables, Formulas
Version: 1.1 (2026-02-16)
Factory helpers
create #
Create a new specification facade from a workbook
Signature:
Public Function Create(ByVal specsWorkbook As Workbook) As ILinelistSpecs
Construction and identity accessors. Validates the workbook structure upfront (checking for all required worksheets and named ranges), then constructs a new LinelistSpecs instance with caches initialised. Returns the ILinelistSpecs interface.
Parameters:
specsWorkbook: Workbook. The specifications workbook to wrap.
Returns: ILinelistSpecs. A fully initialised facade ready for use.
Throws:
- ProjectError.ObjectNotInitialized When specsWorkbook is Nothing.
- ProjectError.ElementNotFound When required worksheets are missing.
des-workbook #
Designer workbook backing all specification queries
Signature:
Public Property Get DesWorkbook() As Workbook
Returns the designer/specifications workbook reference. Raises an error if the workbook has not been assigned via the factory method.
Returns: Workbook. The designer workbook.
Throws:
- ProjectError.ObjectNotInitialized When the workbook is not set.
State management
reset-caches #
Reset every cached collaborator
Signature:
Public Sub ResetCaches()
Cache invalidation for collaborator objects, translations, and categories. Clears all cached collaborator objects, the translation scope cache, and the category cache. Call after importing new data so subsequent reads query the workbook again.
Category helpers
categories #
Resolve category values for a variable with caching
Signature:
Public Function Categories(ByVal varName As String, Optional ByVal useShortlabels As Boolean = False) As BetterArray
Category resolution and caching for choice-type variables. Returns the list of category values for a choice-type variable (choice_manual, choice_multiple, choice_custom, or choice_formula). Results are cached using parallel key/value BetterArrays for efficient repeated access. Always returns a cloned BetterArray to prevent callers from modifying the cached copy.
Parameters:
varName: String. The variable name whose categories to resolve.useShortlabels: Boolean. When True, returns short labels. Defaults to False.
Returns: BetterArray. Cloned list of category values.
Throws:
- ProjectError.InvalidArgument When varName is empty.
- ProjectError.ElementNotFound When the variable has no selectable categories.
Core accessors
dictionary #
Linelist dictionary
Signature:
Public Property Get Dictionary() As ILLdictionary
Public property accessors for each collaborator object, exposing the lazy-loaded instances through their respective interfaces. Returns the ILLdictionary instance providing column and row access to the Dictionary worksheet. Lazy-loaded on first access.
Returns: ILLdictionary. The dictionary collaborator.
choices #
Choices catalogue
Signature:
Public Property Get Choices() As ILLChoices
Returns the ILLChoices instance providing category lookups from the Choices worksheet. Lazy-loaded on first access.
Returns: ILLChoices. The choices collaborator.
design-format #
Visual formatting specifications
Signature:
Public Property Get DesignFormat() As ILLFormat
Returns the ILLFormat instance providing sheet and cell formatting methods based on the __formatter worksheet. Lazy-loaded on first access.
Returns: ILLFormat. The format collaborator.
analysis #
Analysis setup specifications
Signature:
Public Property Get Analysis() As IAnalysis
Returns the IAnalysis instance providing access to the Analysis worksheet configuration. Lazy-loaded on first access.
Returns: IAnalysis. The analysis collaborator.
export-object #
Export column specifications
Signature:
Public Property Get ExportObject() As ILLExport
Returns the ILLExport instance providing access to export column definitions from the Exports worksheet. Lazy-loaded on first access.
Returns: ILLExport. The export collaborator.
password #
Password manager
Signature:
Public Property Get Password() As IPasswords
Returns the IPasswords instance providing workbook and sheet protection utilities from the __pass worksheet. Lazy-loaded on first access.
Returns: IPasswords. The password collaborator.
geo-object #
Geographic data manager
Signature:
Public Property Get GeoObject() As ILLGeo
Returns the ILLGeo instance providing geographic hierarchy lookups from the Geo worksheet. Lazy-loaded on first access.
Returns: ILLGeo. The geo collaborator.
formula-data-object #
Formula data provider
Signature:
Public Property Get FormulaDataObject() As IFormulaData
Returns the IFormulaData instance providing formula parsing support from the __formula worksheet. Lazy-loaded on first access.
Returns: IFormulaData. The formula data collaborator.
has-template #
Whether the workbook uses a ribbon template
Signature:
Public Property Get HasTemplate() As Boolean
Reads the RNG_MainTemp named range on the Main worksheet and returns True when the value equals "has template".
Returns: Boolean. True when a template is configured.
translations #
Translation tables manager
Signature:
Public Property Get Translations() As ILLTranslation
Returns the ILLTranslation instance providing access to the linelist translation worksheet. Lazy-loaded on first access.
Returns: ILLTranslation. The translations collaborator.
designer-translations #
Designer translation accessor
Signature:
Public Property Get DesignerTranslations() As IDesignerTranslation
Returns the IDesignerTranslation instance providing designer UI translations from the DesignerTranslation worksheet. Lazy-loaded on first access.
Returns: IDesignerTranslation. The designer translation collaborator.
trans-object #
Scoped translation object
Signature:
Public Property Get TransObject(Optional ByVal translationScope As Byte = TranslationOfMessages) As ITranslationObject
Returns an ITranslationObject for the requested translation scope. Results are cached per scope using direct fields for each TranslationScope value (0-4), avoiding generic container overhead.
Parameters:
translationScope: Byte. The translation scope constant (e.g., TranslationOfMessages, TranslationOfDictionary). Defaults to TranslationOfMessages.
Returns: ITranslationObject. The scoped translation object.
Throws:
- ProjectError.ElementNotFound When the scope is not available.
temporary-sheet-name #
Temporary sheet name for a given scope
Signature:
Public Property Get TemporarySheetName(ByVal scope As Byte) As String
Returns the fixed worksheet name used for temporary internal sheets, mapped from the TempSheetScope enum (TempSheetAnalysis, TempSheetList, etc.) to its canonical name string.
Parameters:
scope: Byte. A TempSheetScope enum value.
Returns: String. The worksheet name string.
Throws:
- ProjectError.InvalidArgument When the scope is not recognised.
value #
Configuration value by tag name
Signature:
Public Property Get Value(ByVal tagName As String) As String
Returns a configuration value from the Main worksheet for the given tag name. The special tag "numberofexports" returns the export count from the Exports worksheet; all other tags resolve the named range directly on the Main worksheet.
Parameters:
tagName: String. The configuration key to look up.
Returns: String. The configuration value, or empty string if tagName is empty.
Workbook orchestration
prepare #
Prepare all specifications using an import service
Signature:
Public Sub Prepare(ByVal importService As IDesignerImportService)
Lifecycle methods for importing, preparing, exporting, and error-managing the specifications workbook. Orchestrates the full specification preparation workflow:
- Creates a temporary repository for working files.
- Creates a new output workbook (from template if configured).
- Exports designer components via the import service.
- Retrieves exported domain instances from the service.
- Prepares the dictionary with preserved sheet names and geo references.
- Adds the "list auto" column if not already present.
- Translates and sorts all collaborators using dictionary translations. Handles errors with cleanup and busy-state restoration.
Parameters:
importService: IDesignerImportService. The configured import service.
Throws:
- ProjectError.ObjectNotInitialized When importService is Nothing.
- ProjectError.ErrorUnexpectedState When an unexpected error occurs.
ll-workbook #
The output linelist workbook created during Prepare
Signature:
Public Property Get LLWorkbook() As Workbook
Returns the linelist workbook created by Prepare that received exported data from the import service. Returns Nothing before Prepare is called.
Returns: Workbook. The linelist workbook, or Nothing.
temporary-repos #
The temporary repository created during Prepare
Signature:
Public Property Get OutputTemporaryRepos() As ITemporaryRepos
Returns the ITemporaryRepos instance created by Prepare for working files. Returns Nothing before Prepare is called.
Returns: ITemporaryRepos. The temporary repository, or Nothing.
error-manage #
Display an error dialog for specification failures
Signature:
Public Sub ErrorManage(Optional ByVal textMessage As String = vbNullString)
Shows a message box describing the error and informing the user that the linelist creation process is being aborted.
Parameters:
textMessage: String. Error description. Defaults to vbNullString.
Internal members (not exported)
Factory helpers
self #
Interface-cast self reference
Signature:
Public Property Get Self() As ILinelistSpecs
Returns the current instance cast as ILinelistSpecs for fluent construction patterns within the factory method.
Returns: ILinelistSpecs. This instance as its interface type.
internal-workbook #
Setter for the backing workbook reference
Signature:
Public Property Set InternalWorkbook(ByVal specsWorkbook As Workbook)
Used during construction to assign the workbook before caches are initialised. Not part of the public interface.
State management
reset-object-caches #
Clear all collaborator object references
Signature:
Private Sub ResetObjectCaches()
reset-translation-cache #
Clear the translation scope cache
Signature:
Private Sub ResetTranslationCache()
reset-category-cache #
Clear the category list cache
Signature:
Private Sub ResetCategoryCache()
Guard helpers
ensure-workbook #
Verify that the backing workbook is assigned
Signature:
Private Sub EnsureWorkbook()
Lazy-initialisation guards for the workbook and category arrays.
Throws:
- ProjectError.ObjectNotInitialized When the workbook is Nothing.
ensure-category-arrays #
Create the parallel category arrays if they do not exist
Signature:
Private Sub EnsureCategoryArrays()
Worksheet resolution
resolve-sheet #
Resolve a worksheet by name with optional error surfacing
Signature:
Private Function ResolveSheet(ByVal sheetName As String, _
Optional ByVal allowMissing As Boolean = False) As Worksheet
Direct worksheet lookups by name within the specifications workbook. Looks up a worksheet in the specifications workbook by name. When the sheet is not found and allowMissing is False, raises a descriptive error.
Parameters:
sheetName: String. The worksheet name to find.allowMissing: Boolean. When True, returns Nothing instead of raising.
Returns: Worksheet. The resolved worksheet, or Nothing if allowMissing.
Throws:
- ProjectError.InvalidArgument When sheetName is empty and not allowMissing.
- ProjectError.ElementNotFound When the sheet is missing and not allowMissing.
External workbook helpers
enter-busy-state #
Transition the application into a busy state
Signature:
Private Sub EnterBusyState(ByRef busyScope As IApplicationState)
Utilities for opening, closing, and validating external workbooks during the Prepare workflow. Creates or refreshes an ApplicationState snapshot and applies the busy state (suppressing screen updates and calculation) if not already busy.
Parameters:
busyScope: IApplicationState (ByRef). The state object to manage.
import-geobase #
Import geobase data from the user-specified path
Signature:
Private Sub ImportGeobase(ByVal geoObj As ILLGeo)
Reads the geobase file path from the Main worksheet. If the path is not empty, opens the geobase workbook, sets the dictionary language on the exported geo worksheet via RNG_MetaLang, calls geoObj.Import to populate the output geo sheet, then closes the geobase workbook. Silently skips if the path is empty or the file cannot be opened.
Parameters:
geoObj: ILLGeo. The geo instance on the output workbook.dictLang: String. The dictionary language code for RNG_MetaLang.
exit-busy-state #
Restore the application from a busy state
Signature:
Private Sub ExitBusyState(ByRef busyScope As IApplicationState)
Parameters:
busyScope: IApplicationState (ByRef). The state object to restore and release.
build-preserved-sheet-names #
Build the list of sheet names to preserve during dictionary preparation
Signature:
Private Function BuildPreservedSheetNames(ByVal messageTranslations As ITranslationObject) As BetterArray
Collects all specification sheet names and temporary sheet names into a BetterArray, then appends translated linelist sheet names (Admin, Analysis, Spatial, etc.) when message translations are available.
Parameters:
messageTranslations: ITranslationObject. The message translations for resolving linelist sheet names, or Nothing to skip translated names.
Returns: BetterArray. The list of preserved sheet names.
safe-translated-value #
Look up a translation key, falling back to the key itself on failure
Signature:
Private Function SafeTranslatedValue(ByVal translations As ITranslationObject, ByVal key As String) As String
Parameters:
translations: ITranslationObject. The translation object to query.key: String. The translation key.
Returns: String. The translated value, or the key if translation fails.
reset-post-import-caches #
Clear caches that become stale after importing new data
Signature:
Private Sub ResetPostImportCaches()
Resets the variables object, category cache, and translation cache so they are rebuilt from the freshly imported data.
Workbook validation
validate-workbook-reference #
Validate a workbook reference and its structure
Signature:
Private Sub ValidateWorkbookReference(ByVal specsWorkbook As Workbook)
Structural validation of specifications workbooks.
Throws:
- ProjectError.ObjectNotInitialized When specsWorkbook is Nothing.
- ProjectError.ElementNotFound When required sheets are missing.
validate-workbook-structure #
Check that a workbook contains all required worksheets and named ranges
Signature:
Private Sub ValidateWorkbookStructure(ByVal specsWorkbook As Workbook)
Iterates the list of required sheet names and collects any that are missing. If the format sheet exists, also validates that the DESIGNTYPE named range is present.
Parameters:
specsWorkbook: Workbook. The workbook to validate.
Throws:
- ProjectError.ElementNotFound When required sheets or ranges are missing.
required-sheet-names #
Return the array of required specification worksheet names
Signature:
Private Function RequiredSheetNames() As Variant
Returns: Variant. Array of sheet name strings.
worksheet-exists-internal #
Test whether a worksheet exists in a workbook
Signature:
Private Function WorksheetExistsInternal(ByVal specsWorkbook As Workbook, _
ByVal sheetName As String) As Boolean
Parameters:
specsWorkbook: Workbook. The workbook to search.sheetName: String. The worksheet name to look for.
Returns: Boolean. True when the worksheet exists.
range-exists-internal #
Test whether a named range exists on a worksheet
Signature:
Private Function RangeExistsInternal(ByVal hostSheet As Worksheet, _
ByVal rangeName As String) As Boolean
Parameters:
hostSheet: Worksheet. The worksheet to search.rangeName: String. The named range to look for.
Returns: Boolean. True when the named range exists.
join-names #
Join a BetterArray of names into a comma-separated, quoted string
Signature:
Private Function JoinNames(ByVal values As BetterArray) As String
Parameters:
values: BetterArray. The names to join.
Returns: String. Formatted string like "'Sheet1', 'Sheet2'".
safe-workbook-name #
Safely retrieve a workbook's name, returning "
Signature:
Private Function SafeWorkbookName(ByVal specsWorkbook As Workbook) As String
Parameters:
specsWorkbook: Workbook. The workbook whose name to retrieve.
Returns: String. The workbook name or "
Collaborator ensures
ensure-exports #
Lazy-load the export collaborator
Signature:
Private Sub EnsureExports()
Lazy-initialisation guards for each collaborator object. Each EnsureXxx method creates the collaborator from its backing worksheet on first access, then caches it for subsequent calls.
ensure-dictionary #
Lazy-load the dictionary collaborator
Signature:
Private Sub EnsureDictionary()
Requires the export collaborator to be available first (for the number of exports parameter), then creates the dictionary from the Dictionary worksheet.
ensure-choices #
Lazy-load the choices collaborator
Signature:
Private Sub EnsureChoices()
ensure-translations #
Lazy-load the translations collaborator
Signature:
Private Sub EnsureTranslations()
Creates the LLTranslation instance from the linelist translation worksheet.
ensure-designer-translations #
Lazy-load the designer translations collaborator
Signature:
Private Sub EnsureDesignerTranslations()
ensure-geo #
Lazy-load the geo collaborator
Signature:
Private Sub EnsureGeo()
ensure-analysis #
Lazy-load the analysis collaborator
Signature:
Private Sub EnsureAnalysis()
ensure-passwords #
Lazy-load the passwords collaborator
Signature:
Private Sub EnsurePasswords()
ensure-formula-data #
Lazy-load the formula data collaborator
Signature:
Private Sub EnsureFormulaData()
ensure-variables #
Lazy-load the variables collaborator
Signature:
Private Sub EnsureVariables()
Requires the dictionary to be available first, then creates the LLVariables instance from it.
ensure-format #
Lazy-load the format collaborator
Signature:
Private Sub EnsureFormat()
Resolves the design name from the DESIGNTYPE named range on the format sheet, then creates the LLFormat instance.
resolve-design-name #
Extract the design name from the format worksheet's DESIGNTYPE range
Signature:
Private Function ResolveDesignName(ByVal formatSheet As Worksheet) As String
Parameters:
formatSheet: Worksheet. The format worksheet.
Returns: String. The trimmed design type name.
Throws:
- ProjectError.ElementNotFound When the DESIGNTYPE range is missing.
ensure-category-lookup #
Ensure choices, variables, and category arrays are ready
Signature:
Private Sub EnsureCategoryLookup()
number-of-exports #
Return the number of exports defined in the export specifications
Signature:
Private Function NumberOfExports() As Long
Returns: Long. The export count.
List auto helpers
add-list-auto #
Populate the "list auto" dictionary column for list_auto variables
Signature:
Private Sub AddListAuto()
Automatic list column generation for formula-based variables. Adds a "list auto" column to the dictionary, then finds all variables with control type "list_auto" and marks their control details with "list_auto_origin". For formula-type variables (formula, case_when, choice_formula), recursively traces referenced variables and marks them as well.
recursive-list-auto #
Recursively mark referenced variables in formula chains as list_auto
Signature:
Private Sub RecursiveListAuto(ByVal varName As String)
Parses the control details of a formula-type variable using the Formulas engine, extracts the list of referenced variables, marks each with "list_auto_origin", and recurses into any that are themselves formulas or case_when types.
Parameters:
varName: String. The formula variable whose references to trace.
Category helpers
find-category-index #
Search the category keys array for a matching key
Signature:
Private Function FindCategoryIndex(ByVal cacheKey As String) As Long
Parameters:
cacheKey: String. The key to search for.
Returns: Long. The 1-based index if found, or 0 if not found.
resolve-category-list #
Build a category list from the choices sheet for a given variable
Signature:
Private Function ResolveCategoryList(ByVal varName As String, _
ByVal useShortlabels As Boolean) As BetterArray
Determines the category name from the variable's control type and control details, then queries the choices collaborator.
Parameters:
varName: String. The variable name.useShortlabels: Boolean. Whether to use short labels.
Returns: BetterArray. The resolved category list.
Throws:
- ProjectError.InvalidArgument When varName is empty.
- ProjectError.ElementNotFound When the variable or category is not found.
normalise-control-type #
Strip parenthesised suffixes from a control type string
Signature:
Private Function NormaliseControlType(ByVal controlValue As String) As String
Parameters:
controlValue: String. The raw control type value.
Returns: String. The normalised, lower-cased control type.
extract-choice-formula #
Extract the choice name from a CHOICE_FORMULA(...) control details string
Signature:
Private Function ExtractChoiceFormula(ByVal controlDetails As String) As String
Parameters:
controlDetails: String. The raw control details value.
Returns: String. The extracted choice name.
Core accessors
resolve-translation-scope #
Query the translations collaborator for a given scope
Signature:
Private Function ResolveTranslationScope(ByVal translationScope As Byte) As ITranslationObject
Parameters:
translationScope: Byte. The translation scope to resolve.
Returns: ITranslationObject. The resolved translation object.
Throws:
- ProjectError.ElementNotFound When the scope returns Nothing.
Error handling
throw-error #
Raise a project error with the class name as source
Signature:
Private Sub ThrowError(ByVal errNumber As Long, ByVal messageText As String)
Internal error-raising utility.
Parameters:
errNumber: Long. The ProjectError constant.messageText: String. The error description.
Test support
test-assign-designer-translations #
Inject a mock IDesignerTranslation instance for testing
Signature:
Public Sub TestAssignDesignerTranslations(ByVal designerTrads As IDesignerTranslation)
Backdoor setters for injecting mock collaborators during testing.
Parameters:
designerTrads: IDesignerTranslation. The mock designer translations object.
test-assign-translations #
Inject a mock ILLTranslation instance for testing
Signature:
Public Sub TestAssignTranslations(ByVal translations As ILLTranslation)
Also resets the translation cache to ensure the mock object is used for subsequent TransObject lookups.
Parameters:
translations: ILLTranslation. The mock translations object.
Interface implementation
ILinelistSpecs_ResetCaches #
Signature:
Private Sub ILinelistSpecs_ResetCaches()
ILinelistSpecs delegation stubs. Each member forwards to its corresponding public member on the concrete class. No @label tags are needed on delegation stubs.
Used in (17 file(s))
- AnalysisOutput.cls
- CrossTable.cls
- GraphSpecs.cls
- ILinelist.cls
- ILinelistSpecs.cls
- Linelist.cls
- LinelistSpecs.cls
- ListBuilder.cls
- SectionBuilder.cls
- VarWriter.cls
- DesignerMain.bas
- EventsDesignerAdvanced.bas
- LinelistSpecsWorkbookStub.cls
- LinelistStub.cls
- LLVarContextSpecsStub.cls
- TableSpecsLinelistStub.cls
- TestLinelistSpecs.bas