4
4
*--------------------------------------------------------------------------------------------*/
5
5
6
6
import { BeEvent } from "@itwin/core-bentley" ;
7
- import { IModelApp , IModelConnection } from "@itwin/core-frontend" ;
7
+ import type { IModelConnection } from "@itwin/core-frontend" ;
8
+ import { IModelApp } from "@itwin/core-frontend" ;
8
9
import type { FormatDefinition , FormatsChangedArgs , FormatsProvider , MutableFormatsProvider } from "@itwin/core-quantity" ;
9
10
import type { FormatSet } from "@itwin/ecschema-metadata" ;
10
11
import { SchemaFormatsProvider , SchemaItemType , SchemaKey , SchemaMatchType } from "@itwin/ecschema-metadata" ;
@@ -14,10 +15,14 @@ export class FormatManager {
14
15
private _formatSets : FormatSet [ ] = [ ] ;
15
16
private _fallbackFormatProvider ?: FormatsProvider ;
16
17
private _activeFormatSet ?: FormatSet ;
18
+ private _activeFormatSetFormatsProvider ?: FormatSetFormatsProvider ;
17
19
private _iModelOpened : boolean = false ;
18
20
private _removeListeners : ( ( ) => void ) [ ] = [ ] ;
19
21
20
- public static get instance ( ) : FormatManager {
22
+ /** Event raised when the active format set changes */
23
+ public readonly onActiveFormatSetChanged = new BeEvent < ( formatSet : FormatSet | undefined ) => void > ( ) ;
24
+
25
+ public static get instance ( ) : FormatManager | undefined {
21
26
return this . _instance ;
22
27
}
23
28
@@ -33,22 +38,15 @@ export class FormatManager {
33
38
return this . _activeFormatSet ;
34
39
}
35
40
41
+ public get activeFormatSetFormatsProvider ( ) : FormatSetFormatsProvider | undefined {
42
+ return this . _activeFormatSetFormatsProvider ;
43
+ }
44
+
36
45
/** Initialize with a set of format sets to use */
37
46
public static async initialize ( formatSets : FormatSet [ ] , fallbackProvider ?: FormatsProvider ) : Promise < void > {
38
- if ( this . _instance )
39
- throw new Error ( "FormatManager is already initialized." ) ;
47
+ if ( this . _instance ) throw new Error ( "FormatManager is already initialized." ) ;
40
48
41
49
this . _instance = new FormatManager ( formatSets , fallbackProvider ) ;
42
-
43
- this . _instance . _removeListeners . push ( IModelConnection . onOpen . addListener ( async ( iModel : IModelConnection ) => {
44
- // Initialize the formats provider for the opened iModel
45
- this . _instance . _iModelOpened = true ;
46
- await this . _instance . onIModelOpen ( iModel ) ;
47
- } ) ) ;
48
-
49
- this . _instance . _removeListeners . push ( IModelConnection . onClose . addListener ( async ( ) => {
50
- this . _instance . _iModelOpened = false ;
51
- } ) ) ;
52
50
}
53
51
54
52
public constructor ( formatSets : FormatSet [ ] , fallbackProvider ?: FormatsProvider ) {
@@ -66,10 +64,13 @@ export class FormatManager {
66
64
public setActiveFormatSet ( formatSet : FormatSet ) : void {
67
65
const formatSetFormatsProvider = new FormatSetFormatsProvider ( formatSet , this . _fallbackFormatProvider ) ;
68
66
this . _activeFormatSet = formatSet ;
67
+ this . _activeFormatSetFormatsProvider = formatSetFormatsProvider ;
69
68
70
69
if ( this . _iModelOpened ) {
71
70
IModelApp . formatsProvider = formatSetFormatsProvider ;
72
71
}
72
+
73
+ this . onActiveFormatSetChanged . raiseEvent ( formatSet ) ;
73
74
}
74
75
75
76
// Typically, enables a SchemaFormatsProvider to be the fallback during runtime.
@@ -78,6 +79,7 @@ export class FormatManager {
78
79
if ( this . _activeFormatSet ) {
79
80
// If we have an active format set, we need to update the formats provider to include the new fallback.
80
81
const newFormatSetFormatsProvider = new FormatSetFormatsProvider ( this . _activeFormatSet , this . _fallbackFormatProvider ) ;
82
+ this . _activeFormatSetFormatsProvider = newFormatSetFormatsProvider ;
81
83
IModelApp . formatsProvider = newFormatSetFormatsProvider ;
82
84
}
83
85
}
@@ -86,37 +88,46 @@ export class FormatManager {
86
88
return this . _fallbackFormatProvider ;
87
89
}
88
90
91
+ public async onIModelClose ( ) {
92
+ // Clean up listeners
93
+ this . _removeListeners . forEach ( ( removeListener ) => removeListener ( ) ) ;
94
+ this . _fallbackFormatProvider = undefined ;
95
+ if ( this . _activeFormatSetFormatsProvider ) {
96
+ this . _activeFormatSetFormatsProvider . clearFallbackProvider ( ) ; // Works here because the fallback provider is the SchemaFormatsProvider used onIModelOpen.
97
+ }
98
+ this . _iModelOpened = false ;
99
+ }
100
+
101
+ /**
102
+ * If FormatSetFormatsProvider was successfully set, renders the usage of IModelApp.quantityFormatter.activeUnitSystem pointless when formatting.
103
+ */
89
104
public async onIModelOpen ( iModel : IModelConnection ) : Promise < void > {
90
105
// Set up schema-based units and formats providers
91
-
92
106
const schemaFormatsProvider = new SchemaFormatsProvider ( iModel . schemaContext , IModelApp . quantityFormatter . activeUnitSystem ) ;
93
107
this . fallbackFormatsProvider = schemaFormatsProvider ;
94
-
108
+ this . _removeListeners . push (
109
+ IModelApp . quantityFormatter . onActiveFormattingUnitSystemChanged . addListener ( ( args ) => {
110
+ schemaFormatsProvider . unitSystem = args . system ;
111
+ } ) ,
112
+ ) ;
95
113
// Query schemas for KindOfQuantity items
96
114
try {
97
115
const schemaFormatSet : FormatSet = {
98
116
name : "SchemaFormats" ,
99
117
label : "Example Format Set" ,
100
- formats : { }
118
+ formats : { } ,
101
119
} ;
102
- const reader = iModel . createQueryReader ( "SELECT\n ks.Name || '.' || k.Name AS kindOfQuantityFullName,\n COUNT(*) AS propertyCount,\n json_group_array(p.Name) AS propertyNames\nFROM\n ECDbMeta.ECPropertyDef p\n JOIN ECDbMeta.KindOfQuantityDef k ON k.ECInstanceId = p.KindOfQuantity.Id\n JOIN ECDbMeta.ECSchemaDef ks ON ks.ECInstanceId = k.Schema.Id\nGROUP BY\n ks.Name,\n k.Name\nORDER BY\n propertyCount DESC;" ) ;
103
- while ( await reader . step ( ) ) {
104
- console . log ( reader . current [ 0 ] ) ;
105
- const formatName = reader . current [ 0 ] . kindOfQuantityFullName ;
106
- const format = await schemaFormatsProvider . getFormat ( formatName ) ;
107
- if ( format ) {
108
- schemaFormatSet . formats [ formatName ] = format ;
109
- }
110
- }
120
+
121
+
111
122
// Try to get known schemas that typically contain KindOfQuantity items, and get all the formats from kind of quantities
112
123
const schemaNames = [ "AecUnits" ] ;
113
124
114
125
for ( const schemaName of schemaNames ) {
115
126
try {
116
127
const schema = await iModel . schemaContext . getSchema ( new SchemaKey ( schemaName , SchemaMatchType . Latest ) ) ;
117
- if ( schema ) {
128
+ if ( schema ) {
118
129
for ( const schemaItem of schema . getItems ( ) ) {
119
- console . log ( schemaItem )
130
+ console . log ( schemaItem ) ;
120
131
if ( schemaItem . schemaItemType === SchemaItemType . KindOfQuantity ) {
121
132
const format = await schemaFormatsProvider . getFormat ( schemaItem . fullName ) ;
122
133
if ( format ) {
@@ -130,14 +141,29 @@ export class FormatManager {
130
141
}
131
142
}
132
143
144
+ // Get all used KindOfQuantities from the iModel, and populate the formatSet.
145
+ const reader = iModel . createQueryReader (
146
+ "SELECT\n ks.Name || '.' || k.Name AS kindOfQuantityFullName,\n COUNT(*) AS propertyCount,\n json_group_array(p.Name) AS propertyNames\nFROM\n ECDbMeta.ECPropertyDef p\n JOIN ECDbMeta.KindOfQuantityDef k ON k.ECInstanceId = p.KindOfQuantity.Id\n JOIN ECDbMeta.ECSchemaDef ks ON ks.ECInstanceId = k.Schema.Id\nGROUP BY\n ks.Name,\n k.Name\nORDER BY\n propertyCount DESC;" ,
147
+ ) ;
148
+ const allRows = await reader . toArray ( ) ;
149
+ for ( const row of allRows ) {
150
+ const formatName = row [ 0 ] ;
151
+ const format = await schemaFormatsProvider . getFormat ( formatName ) ;
152
+ if ( format ) {
153
+ schemaFormatSet . formats [ formatName ] = format ;
154
+ }
155
+ }
156
+
157
+
133
158
// Set this as the active format set if we found any formats
134
159
if ( Object . keys ( schemaFormatSet . formats ) . length > 0 ) {
160
+ this . _iModelOpened = true ;
135
161
this . setActiveFormatSet ( schemaFormatSet ) ;
162
+
136
163
console . log ( `Created schema-based format set with ${ Object . keys ( schemaFormatSet . formats ) . length } formats` ) ;
137
164
} else {
138
165
console . log ( "No KindOfQuantity items found in known schemas" ) ;
139
166
}
140
-
141
167
} catch ( error ) {
142
168
console . error ( "Failed to query schema items:" , error ) ;
143
169
}
@@ -160,6 +186,10 @@ export class FormatSetFormatsProvider implements MutableFormatsProvider {
160
186
this . onFormatsChanged . raiseEvent ( { formatsChanged : [ name ] } ) ;
161
187
}
162
188
189
+ public clearFallbackProvider ( ) : void {
190
+ this . _fallbackProvider = undefined ;
191
+ }
192
+
163
193
public async getFormat ( name : string ) : Promise < FormatDefinition | undefined > {
164
194
const format = this . _formatSet . formats [ name ] ;
165
195
if ( format )
0 commit comments