<> <> <> <> DIRECTORY CD, CDBasics, CDCallSpecific, CDDirectory, CDDirectoryOps, CDEnvironment, CDEvents, CDGenerate, CDRemote, CDImports, CDImportsExtras, CDInstances, CDIO, CDOps, CDOrient, CDProperties, CDValue, Rope, SymTab, TerminalIO, TokenIO, UserProfile; CDImportsImpl: CEDAR PROGRAM IMPORTS CD, CDBasics, CDDirectory, CDDirectoryOps, CDEnvironment, CDEvents, CDGenerate, CDRemote, CDInstances, CDIO, CDOps, CDOrient, CDProperties, CDValue, Rope, SymTab, TerminalIO, TokenIO, UserProfile EXPORTS CDImports, CDImportsExtras SHARES CDDirectory, CDRemote = BEGIN ROPE: TYPE = Rope.ROPE; BoolOrInteractive: TYPE = CDImports.BoolOrInteractive; ImportPtr: TYPE = CDImports.ImportPtr; ImportRep: TYPE = CDImports.ImportRep; ImportList: TYPE = CDImports.ImportList; ImportDesign: TYPE = CDImports.ImportDesign; ImpList: TYPE = LIST OF REF ImportDesign; importListKey: ATOM = $ImportList; -- for CDValue importsClass: PUBLIC CD.ObjectClass = CD.RegisterObjectClass[$Import, [ drawMe: DrawForImport, quickDrawMe: QuickDrawReference, showMeSelected: DrawSelectionForImport, internalRead: ReadImportOb, internalWrite: WriteImportOb, describe: DescribeImport, interestRect: InterestRect ]]; ImpOfDesign: TYPE = REF ImpOfDesignRec; ImpOfDesignRec: TYPE = RECORD [ d: CD.Design_NIL, obTab: SymTab.Ref_ ]; EachImpOb: PROC [priv: ImpOfDesign, proc: PROC [ob: CD.Object]] = { EachPair: PROC [key: REF, val: REF] RETURNS [quit: BOOL_FALSE] = {proc[NARROW[val]]}; [] _ SymTab.Pairs[priv.obTab, EachPair] }; NewPerImpDesign: PROC RETURNS [handle: ImpOfDesign] = { handle _ NEW[ImpOfDesignRec_[obTab: SymTab.Create[17]]] }; EnumerateItsObjects: PROC [me: CD.Object, p: CDDirectory.EnumerateObjectsProc, x: REF] = { <> <> }; ReplaceDirectChild: CDDirectory.ReplaceDChildsProc = { <<-- PROC[me: CD.Object, design: CD.Design, replace: LIST OF REF ReplaceRec] -->> <> <> }; InternalCreateImport: PROC [into: CD.Design, size: CD.Position_[1, 1], ir: CD.Rect _ [0, 0, -1, -1], objectName, importeeName: ROPE, autoLoad: BOOL _ FALSE, --loads file if neccessary; if loaded, import design is made autoImport: BOOL _ FALSE, --import design even if not loaded successfully autoCreateOb: BOOL _ FALSE, --creates ob if not found or design not loaded (but not if import not made) allowConflicts: BoolOrInteractive_false, --allow size conflicts on the object include: BOOL _ TRUE] RETURNS [ob: CD.Object _ NIL] = { referedOb: CD.Object _ NIL; iR: CD.Rect; import: REF ImportDesign; impPriv: ImpOfDesign; probablySize: CD.Position _ CDBasics.MaxPoint[size, [1, 1]]; <<--make an import of the importee design >> import _ GetImportEntry[into, importeeName, false]; IF (import=NIL OR ~import.loaded) AND autoLoad THEN { loaded: BOOL _ Load[into: into, importeeName: importeeName, overload: false, allowConflicts: false]; IF loaded AND import=NIL THEN import _ GetImportEntry[into, importeeName, false]; }; IF import=NIL AND autoImport THEN import _ GetImportEntry[into, importeeName, true]; IF import=NIL THEN RETURN [NIL]; <<--search for an already existing import object >> IF CDBasics.NonEmpty[ir] THEN iR _ ir ELSE iR _ CDBasics.RectAt[[0, 0], probablySize]; impPriv _ NARROW[import.reservedForCDImports]; WITH SymTab.Fetch[impPriv.obTab, objectName].val SELECT FROM ob: CD.Object => { IF ob.size=size AND (CD.InterestRect[ob]=iR OR ~CDBasics.NonEmpty[ir]) THEN RETURN [ob]; IF allowConflicts=true THEN RETURN [ob]; IF allowConflicts=interactive AND TerminalIO.Confirm[choice: "ignore", label: "size conflicts"] THEN RETURN [ob]; RETURN [NIL] }; ENDCASE => NULL; <<--already existing imported object not found; make new object>> <<--if not load, trust for the size... it is checked at binding time>> IF import.loaded THEN referedOb _ CDDirectory.Fetch[impPriv.d, objectName].object; IF referedOb=NIL AND ~autoCreateOb THEN RETURN [NIL]; IF allowConflicts=true AND referedOb#NIL THEN { probablySize _ referedOb.size; iR _ CD.InterestRect[referedOb]; }; ob _ NEW[CD.ObjectRep_[ size: probablySize, class: importsClass, layer: CD.undefLayer, specificRef: NEW[ImportRep _ [ objectName: objectName, ir: iR, designName: importeeName ]] ]]; [] _ SymTab.Store[impPriv.obTab, objectName, ob]; IF include THEN [] _ CDDirectory.Include[design: into, object: ob, alternateName: Rope.Cat[importeeName, ".", objectName]]; IF import.loaded THEN [] _ BindObject[into, ob, impPriv.d, allowConflicts]; }; CreateImport: PUBLIC PROC [into: CD.Design, objectName, importeeName: ROPE] RETURNS [ob: CD.Object] = { ob _ InternalCreateImport[into: into, objectName: objectName, importeeName: importeeName, autoCreateOb: FALSE, autoImport: FALSE, autoLoad: TRUE, allowConflicts: true, include: TRUE]; }; ShortName: PROC [me: CD.Object, iPtr: ImportPtr] RETURNS [n: ROPE] = INLINE { n _ CDDirectory.Name[me]; IF Rope.IsEmpty[n] THEN n _ iPtr.objectName; }; DescribeImport: PROC[me: CD.Object] RETURNS [ROPE] = { iPtr: ImportPtr = NARROW[me.specificRef]; RETURN [Rope.Cat["reference to ", iPtr.designName, ".", iPtr.objectName]]; }; MapIR: PROC [ob: CD.Object, pos: CD.Position, orient: CD.Orientation] RETURNS [CD.Rect] = INLINE { RETURN [CDOrient.MapRect[ itemInCell: CD.InterestRect[ob], cellSize: ob.size, cellInstOrient: orient, cellInstPos: pos ]] }; DrawForImport: PROC [inst: CD.Instance, pos: CD.Position, orient: CD.Orientation, pr: CD.DrawRef] = { iPtr: ImportPtr = NARROW[inst.ob.specificRef]; IF iPtr.boundInstance#NIL THEN pr.drawChild[iPtr.boundInstance, pos, orient, pr] ELSE { r: CD.Rect = MapIR[inst.ob, pos, orient]; pr.drawRect[r, CD.shadeLayer, pr]; pr.drawComment[r, ShortName[inst.ob, iPtr], pr]; } }; QuickDrawReference: PROC [inst: CD.Instance, pos: CD.Position, orient: CD.Orientation, pr: CD.DrawRef] = { iPtr: ImportPtr = NARROW[inst.ob.specificRef]; IF iPtr.boundInstance#NIL THEN iPtr.boundInstance.ob.class.quickDrawMe[iPtr.boundInstance, pos, orient, pr] ELSE { r: CD.Rect = MapIR[inst.ob, pos, orient]; pr.drawRect[r, CD.shadeLayer, pr]; pr.drawComment[r, ShortName[inst.ob, iPtr], pr]; } }; DrawSelectionForImport: PROC [inst: CD.Instance, pos: CD.Position, orient: CD.Orientation, pr: CD.DrawRef] = { iPtr: ImportPtr = NARROW[inst.ob.specificRef]; IF iPtr.boundInstance#NIL THEN iPtr.boundInstance.ob.class.showMeSelected[iPtr.boundInstance, pos, orient, pr] ELSE pr.drawOutLine[MapIR[inst.ob, pos, orient], CD.selectionLayer, pr] }; InterestRect: PROC [ob: CD.Object] RETURNS [CD.Rect] = { RETURN [NARROW[ob.specificRef, ImportPtr].ir] }; WriteImportOb: CD.InternalWriteProc -- PROC [me: Object] -- = { iPtr: ImportPtr = NARROW[me.specificRef]; CDIO.WritePos[me.size]; CDIO.WriteRect[iPtr.ir]; TokenIO.WriteRope[iPtr.objectName]; TokenIO.WriteRope[iPtr.designName]; }; ReadImportOb: CD.InternalReadProc --PROC [] RETURNS [Object]-- = { sz: CD.Position = CDIO.ReadPos[]; ir: CD.Rect; objectName: ROPE; importeeName: ROPE; ob: CD.Object; IF CDIO.VersionKey[] >= 8 THEN ir _ CDIO.ReadRect[] ELSE ir _ CDBasics.RectAt[[0, 0], sz]; objectName _ TokenIO.ReadRope[]; importeeName _ TokenIO.ReadRope[]; ob _ InternalCreateImport[ into: CDIO.DesignInReadOperation[], ir: ir, size: sz, objectName: objectName, importeeName: importeeName, autoCreateOb: TRUE, autoImport: TRUE, autoLoad: FALSE, allowConflicts: interactive, include: FALSE ]; RETURN [ob] }; GetImportList: PUBLIC PROC [design: CD.Design] RETURNS [imp: REF ImportList] = { WITH CDValue.Fetch[design, importListKey, design] SELECT FROM imp: REF ImportList => RETURN[imp]; ENDCASE => { imp _ NEW[ImportList _ [list: NIL]]; [] _ CDValue.StoreConditional[boundTo: design, key: importListKey, value: imp]; RETURN [GetImportList[design]] }; }; GetImportEntry: PUBLIC PROC [into: CD.Design, importeeName: ROPE_NIL, createIfNotFound: BoolOrInteractive _ true] RETURNS [REF ImportDesign_NIL] = { <<--get the entry in design into telling about importing importeeName >> ToBool: PROC[b: BoolOrInteractive, r, r2: ROPE_NIL] RETURNS [BOOL] = { SELECT b FROM true => RETURN [TRUE]; false => RETURN [FALSE]; ENDCASE => { TerminalIO.WriteRopes[r, r2]; RETURN [TerminalIO.Confirm[r]] } }; mdata: REF ImportDesign _ NIL; impl: REF ImportList = GetImportList[into]; IF Rope.IsEmpty[importeeName] THEN ERROR CD.Error[ec: other, explanation: "design has empty name, but shouldn't"]; IF impl#NIL THEN FOR l: ImpList _ impl.list, l.rest WHILE l#NIL DO IF l.first#NIL AND Rope.Equal[l.first.importeeName, importeeName] THEN RETURN [l.first] ENDLOOP; IF ToBool[createIfNotFound, "create an import", importeeName] THEN { pData: ImpOfDesign _ NewPerImpDesign[]; mdata _ NEW[ImportDesign _ [importeeName: importeeName, loaded: FALSE, reservedForCDImports: pData]]; IF Rope.Equal[into.name, importeeName] THEN ERROR CD.Error[ec: other, explanation: "circular import"]; impl.list _ CONS[mdata, impl.list]; --should be atomic-- }; RETURN [mdata] }; BindImportee: PROC [importer, importee: CD.Design, allowSizeConflicts, overload: BoolOrInteractive _ true] = { done1: BOOL _ TRUE; BindOneOb: PROC [ob: CD.Object] = { IF ~BindObject[importer, ob, importee, allowSizeConflicts].ok THEN done1 _ FALSE }; impPriv: ImpOfDesign; mdata: REF ImportDesign; IF importer=importee OR Rope.Equal[importer.name, importee.name] THEN ERROR; mdata _ GetImportEntry[importer, importee.name, true]; IF mdata=NIL THEN ERROR; impPriv _ NARROW[mdata.reservedForCDImports]; IF mdata.loaded THEN { IF overload=false THEN RETURN ELSE IF overload=interactive THEN IF NOT TerminalIO.Confirm[label: "design already loaded", choice: "overload"] THEN { TerminalIO.WriteRope["dont overload; not done\n"]; RETURN } }; impPriv.d _ importee; mdata.loaded _ TRUE; EachImpOb[impPriv, BindOneOb]; IF NOT done1 THEN TerminalIO.WriteRope["some import not bound\n"]; CDOps.DelayedRedraw[importer]; }; BindObject: PROC [design: CD.Design, ob: CD.Object, importee: CD.Design, allowSizeConflicts: BoolOrInteractive _ true] RETURNS [ok: BOOL_FALSE] = { iPtr: ImportPtr = NARROW[ob.specificRef, ImportPtr]; oldRect, newRect: CD.Rect; referedOb: CD.Object _ CDDirectory.Fetch[importee, iPtr.objectName].object; IF referedOb=NIL THEN { TerminalIO.WriteF["object %g in %g not found\n", [rope[iPtr.objectName]], [rope[importee.name]]]; RETURN }; oldRect _ InterestRect[ob]; newRect _ CD.InterestRect[referedOb]; IF newRect#oldRect THEN { TerminalIO.WriteRopes["size miss match for object ", iPtr.objectName]; IF allowSizeConflicts=false THEN { TerminalIO.WriteRope["not resolved\n"]; RETURN }; IF allowSizeConflicts=interactive THEN { IF ~TerminalIO.Confirm[choice: "import anyway", label: "size conflict"] THEN { TerminalIO.WriteRope["no\n"]; RETURN }; TerminalIO.WriteRope["yes\n"]; }; }; iPtr.boundInstance _ CDInstances.NewInst[ob: referedOb]; BEGIN oldSize: CD.Position = ob.size; oldBase: CD.Position = CDBasics.BaseOfRect[oldRect]; newSize: CD.Position = referedOb.size; newBase: CD.Position = CDBasics.BaseOfRect[newRect]; IF oldSize#newSize OR oldRect#newRect THEN { ob.size _ newSize; iPtr.ir _ newRect; CDDirectory.RepositionObject[design: design, ob: ob, oldSize: oldSize, baseOff: CDBasics.SubPoints[oldBase, newBase]]; }; END; CDDirectory.PropagateChange[ob, design]; ok _ TRUE; }; RemSpaces: PROC [r: ROPE] RETURNS [ROPE_NIL] = { leng: INT _ Rope.Length[r]; start: INT _ 0; WHILE startstart THEN RETURN [Rope.Substr[r, start, leng-start]]; }; GetHintList: PROC [for: CD.Design] RETURNS [LIST OF ROPE_NIL] = { IF for#NIL THEN WITH CDProperties.GetDesignProp[for, $ImportHints] SELECT FROM rL: LIST OF ROPE => RETURN [rL]; ENDCASE => NULL; }; UseFile: PROC [into: CD.Design, importeeName: ROPE] RETURNS [f: ROPE_NIL] = { rl: LIST OF ROPE _ GetHintList[into]; key, rest: ROPE _ NIL; FOR list: LIST OF ROPE _ rl, list.rest WHILE list#NIL DO [key, rest] _ CDEnvironment.SplitLine[list.first]; IF Rope.Equal[importeeName, key] THEN RETURN [RemSpaces[rest]]; ENDLOOP; f _ UserProfile.Token[Rope.Cat["ChipNDale.ImportFor.", importeeName], NIL]; }; GetOrLoadImportee: PROC [into: CD.Design, importeeName: ROPE] RETURNS [d: CD.Design_NIL] = { ENABLE CDRemote.ioFailed => GOTO thatsit; d _ CDRemote.FetchDesign[into, importeeName]; IF d=NIL THEN { [] _ CDRemote.GetTableUsingFile[for: into, remoteDesign: importeeName, remoteFile: UseFile[into, importeeName]]; d _ CDRemote.FetchDesign[into, importeeName]; } EXITS thatsit => NULL; }; Load: PUBLIC PROC [into: CD.Design, importeeName: ROPE, overload, allowConflicts: BoolOrInteractive_true] RETURNS [done: BOOL_FALSE] = { indirectImport: REF ImportList; importee: CD.Design _ GetOrLoadImportee[into, importeeName]; IF importee=NIL THEN { TerminalIO.WriteRope["load not done\n"]; RETURN }; indirectImport _ GetImportList[importee]; IF indirectImport^.list#NIL THEN TerminalIO.WriteRope["There are indirect imports\n"]; <<-- check for forbidden circular import>> FOR list: ImpList _ indirectImport^, list.rest WHILE list#NIL DO IF Rope.Equal[list.first.importeeName, into.name] THEN { TerminalIO.WriteRope["**creates circular imports\n"]; RETURN } ENDLOOP; <<-- now we certainly have no circular import>> <<-->> <<-- do the actual import>> BindImportee[importer: into, importee: importee, allowSizeConflicts: allowConflicts, overload: overload]; <<--check all already imported designs for importing the new design>> FOR list: ImpList _ GetImportList[into]^, list.rest WHILE list#NIL DO ip: ImpOfDesign = NARROW[list.first.reservedForCDImports]; IF ip.d#NIL AND ip.d#importee THEN BindImportee[importer: ip.d, importee: importee, allowSizeConflicts: false, overload: true]; ENDLOOP; <<--check the new design for importing of already imported and loaded designs>> FOR list: ImpList _ indirectImport^, list.rest WHILE list#NIL DO ip: ImpOfDesign = NARROW[list.first.reservedForCDImports]; IF ip.d=NIL THEN {--new design did not load.. imp: REF ImportDesign _ GetImportEntry[into, list.first.importeeName, false]; IF imp#NIL THEN { oldip: ImpOfDesign = NARROW[imp.reservedForCDImports]; IF oldip.d#NIL AND oldip.d#importee THEN BindImportee[importer: importee, importee: oldip.d, allowSizeConflicts: false, overload: true]; }; } ENDLOOP; done _ TRUE; }; DesignHasBeenRenamed: CDEvents.EventProc = { <<-- prevent renaming if it would cause circularity>> imp: REF ImportDesign = GetImportEntry[into: design, importeeName: design.name, createIfNotFound: false]; IF imp#NIL THEN { dont _ TRUE; TerminalIO.WriteRope["rename causes circularities; not done\n"] }; }; OneLevelIncludedCopy: PUBLIC PROC [impObject: CD.Object, design: CD.Design] RETURNS [CD.Object] = { <<--imp is an imported and bound object which will be made local to design>> ReplaceChildrenByImports: PROC[me: CD.Object, design: CD.Design, importeeName: ROPE] = { replaceList: CDDirectory.ReplaceList_NIL; PerChild: CDDirectory.EnumerateObjectsProc = { --PROC [me: CD.Object, x: REF] IF me.class.inDirectory THEN { impChild: CD.Object; FOR list: CDDirectory.ReplaceList _ replaceList, list.rest WHILE list#NIL DO IF list.first.old=me THEN RETURN -- eliminate duplicates ENDLOOP; impChild _ InternalCreateImport[ into: design, objectName: CDDirectory.Name[me], importeeName: importeeName, size: me.size, autoImport: TRUE, autoLoad: FALSE, autoCreateOb: TRUE, allowConflicts: true, include: TRUE ]; replaceList _ CONS[ NEW[CDDirectory.ReplaceRec_[ old: me, oldSize: me.size, new: impChild, newSize: impChild.size, off: [0, 0] ]], replaceList ]; } }; <<>> <<--build list of direct children>> CDDirectory.EnumerateChildObjects[me: me, p: PerChild, x: NIL]; <<--replace each direct child by an import>> IF replaceList#NIL THEN [] _ CDDirectory.ReplaceDirectChild[me: me, design: design, replace: replaceList]; }; --ReplaceChildrenByImports <<>> <<--OneLevelIncludedCopy>> WITH impObject.specificRef SELECT FROM impPtr: ImportPtr => { newOb: CD.Object; tm, cm: CDDirectory.DMode; import: REF ImportDesign = GetImportEntry[design, impPtr.designName, false]; ip: ImpOfDesign; IF impPtr.boundInstance=NIL OR import=NIL OR ~import.loaded THEN ERROR CD.Error[callingError, "OneLevelIncludedCopy impObject not bound "]; ip _ NARROW[import.reservedForCDImports]; [newOb, tm, cm] _ CDDirectory.Another[me: impPtr.boundInstance.ob, fromOrNil: ip.d, into: design]; IF newOb=NIL OR tm=immutable THEN ERROR; IF tm=ready THEN [] _ CDDirectory.Include[design, newOb]; IF cm=immutable THEN ReplaceChildrenByImports[me: newOb, design: design, importeeName: import.importeeName]; RETURN [newOb] }; ENDCASE => ERROR CD.Error[callingError, "bad object class"] }; Another: PROC [me: CD.Object, fromOrNil: CD.Design, into: CD.Design, friendly: BOOL] RETURNS [new: CD.Object, topMode: CDDirectory.InclOrReady _ included, childMode: CDDirectory.ImmOrIncl _ included] = { impPtr: ImportPtr = NARROW[me.specificRef]; own: REF; IF into=NIL THEN ERROR; new _ InternalCreateImport[into: into, objectName: impPtr.objectName, importeeName: impPtr.designName, autoCreateOb: TRUE, autoImport: TRUE, allowConflicts: true, include: TRUE, size: me.size, autoLoad: FALSE]; IF new#me THEN { IF new=NIL THEN ERROR; own _ CDProperties.GetObjectProp[new, $OwnerDesign]; CDProperties.AppendProps[looser: me.properties, winner: new.properties, putOnto: new]; CDProperties.PutObjectProp[new, $OwnerDesign, own]; }; }; Expand: PROC [me: CD.Object, fromOrNil: CD.Design, into: CD.Design, friendly: BOOL] RETURNS [new: CD.Object, topMode: CDDirectory.DMode _ immutable, childMode: CDDirectory.ImmOrIncl _ immutable] = { impPtr: ImportPtr = NARROW[me.specificRef]; IF impPtr.boundInstance=NIL THEN RETURN [NIL]; --can not expand unloaded object IF into#NIL --AND friendly-- THEN { tm, cm: CDDirectory.DMode; [me, tm, cm] _ CDDirectory.Another[me: me, fromOrNil: fromOrNil, into: into]; IF me#NIL AND tm=included THEN { new _ OneLevelIncludedCopy[impObject: me, design: into]; IF new#NIL THEN RETURN [new, included, included]; } }; RETURN [impPtr.boundInstance.ob, immutable, immutable]; }; MergeInImports: PUBLIC PROC [into: CD.Design, importeeName: ROPE] = { <<--Includes all the imported and bound objects from importeeName (including >> <<--their transitive closure; but not indirect imports) into design.>> imp: REF ImportDesign _ GetImportEntry[into, importeeName, false]; IF imp=NIL THEN { TerminalIO.WriteRopes["MergeInImports not done; ", importeeName, " is not imported\n"]; RETURN }; IF ~imp.loaded THEN { TerminalIO.WriteRopes["MerginImport not done; ", importeeName, " is not loaded\n"]; RETURN }; BEGIN EachOb: PROC [ob: CD.Object] = { pr: ImportPtr = NARROW[ob.specificRef]; IF pr.boundInstance#NIL THEN { newOb: CD.Object _ CDGenerate.FetchNCall[table: generatorTable, design: into, key: pr.objectName, cache: TRUE]; IF newOb#NIL THEN { remList _ CONS[pr.objectName, remList]; CDDirectory.ReplaceObject[design: into, old: ob, new: newOb]; IF CDDirectoryOps.RemoveIfUnused[design: into, ob: ob].done THEN { [] _ CDDirectory.Rename[into, newOb, pr.objectName]; }; } } }; remList: LIST OF ROPE _ NIL; impPrivate: ImpOfDesign = NARROW[imp.reservedForCDImports]; generatorTable: CDGenerate.Table; importee: CD.Design _ impPrivate.d; CDRemote.CacheDesign[for: into, remote: importee]; generatorTable _ CDRemote.GetTable[imp.importeeName]; EachImpOb[impPrivate, EachOb]; FOR l: LIST OF ROPE _ remList, l.rest WHILE l#NIL DO [] _ SymTab.Delete[impPrivate.obTab, l.first]; ENDLOOP END }; HasUnloadedImports: PUBLIC PROC [design: CD.Design] RETURNS [yes: BOOL_FALSE] = { CheckObjectLoaded: PROC [ob: CD.Object] = { ip: ImportPtr = NARROW[ob.specificRef]; IF ip.boundInstance=NIL THEN ERROR unLoaded; }; unLoaded: ERROR = CODE; impList: REF CDImports.ImportList = GetImportList[design]; IF impList#NIL THEN FOR list: LIST OF REF CDImports.ImportDesign _ impList^, list.rest WHILE list#NIL DO IF ~list.first.loaded THEN { <<--a directly imported design is not loaded>> RETURN [yes _ TRUE] } ELSE { p: ImpOfDesign _ NARROW[list.first.reservedForCDImports]; <<--check all objects of this design>> EachImpOb[p, CheckObjectLoaded ! unLoaded => GOTO HasUnLoaded]; <<--check for indirect objects; there are no loops>> yes _ p.d#NIL AND HasUnloadedImports[p.d]; } ENDLOOP; EXITS HasUnLoaded => RETURN [TRUE] }; dirProcs: REF CDDirectory.DirectoryProcs ~ CDDirectory.InstallDirectoryProcs[importsClass, [ enumerateChildObjects: EnumerateItsObjects, replaceDirectChilds: ReplaceDirectChild, another: Another, expand: Expand ]]; CDValue.RegisterKey[importListKey]; CDEvents.RegisterEventProc[$RenameDesign, DesignHasBeenRenamed]; END.