CM Language

Definining a literal Range in reverse order as part of the for syntax will now cause the loop to be skipped entirely. Rewrite the Range literal to correct order. The regular expression for.*\(.*[.][.].*reverse can be used to quickly find all places in your code where you are using the reverse keyword with a literal Range.

cet.runtime

Method signature changes in MCClient.

Old:
final public bool onlineLogin()
new:
final public bool onlineLogin(bool useCachedPassword=true)

The license client tester has been removed.

Removed:
public void testConfiguraLicenseClient()

Removed login from the license client.

cm.abstract.dataSymInterface

The constructors of DsiConstraintSelPath have been changed.

Old:
public constructor auto(path, feature, option);
public constructor auto(path, feature, option, checkedV);
public constructor auto(path, feature, option, numV);
New:
public constructor(str path, SFeature feature, Option option, DsiPDataOption dataOption, DsiPDataOption parentDataOption)

Component Tab and Component Tab Creator End of Life

The following interfaces will be removed as part of the Component Tab and Component Tab Creator EOL effort:

cm.abstract.dataSymInterface.catalog

class ProductCatalog

Removed: extend public void appendToolbox(str url)

cm.abstract.dataSymbol

Component Tab and Component Tab Creator End of Life

The following interfaces will be removed as part of the Component Tab and Component Tab Creator EOL effort:

cm.abstract.dataSymbol

// Functions:
Removed: public bool dsCloneToolboxes(DataCatalog catalog, ProductCatalog productCatalog, DsToolboxCreatorToolboxCards toolboxCards)
Removed: public str dsToolboxFileStr(DataCatalog catalog, DsToolboxCreatorToolboxCards cards, DsToolboxCreatorToolboxCard card)

cm.abstract.dataSymbol.ui.toolboxCreator

Note: cm.abstract.dataSymbol.ui.toolboxCreator package is completely removed. If your extension has dependency to this package, please remove it.

// Constants
Removed: public const str dsToolboxCreatorFileType = ".cmtbxc";

// Functions
Removed: public Image DsToolboxCreatorLoadToolboxImage(Url file)
Removed: public DsToolboxCreatorExtensionToolboxCard dsToolboxCreatorCreateExtensionToolboxCard(Window parent, symbol pkg, DsToolboxCreatorToolboxCard card, str sortKey, str groupId, str libraryFunctionName=null, Image image=null, str label=null)
Removed: public str tbCatCardStatsEntityKey(DsCatalogToolboxData cData)
Removed: public void dsToolboxCreatorToolboxCardSetSectionLabelAnimationEnv(Window window, DsDragAnimationEnv env)
Removed: public void dsToolboxCreatorToolboxCardSetSectionAnimationEnv(Window window, DsDragAnimationEnv env)
Removed: public void dsToolboxCreatorToolboxCardSetThumbnailViewAnimationEnv(Window window, DsDragAnimationEnv env)
Removed: public void dsToolboxCreatorToolboxCardSetToolboxSectionWindowAnimationEnv(Window window, DsDragAnimationEnv env)
Removed: public void dsToolboxCreatorToolboxCardSetHeaderAnimationEnv(Window window, DsDragAnimationEnv env)
Removed: public void dsToolboxCreatorToolboxCardSetImageSectionAnimationEnv(Window window, DsDragAnimationEnv env)
Removed: public void dsToolboxCreatorToolboxCardSetSchemeButtonAnimationEnv(Window window, DsDragAnimationEnv env)
Removed: public Library dsToolboxCreatorLibraryFromCard(Card card, symbol pkg)
Removed: public void faceliftPreprocess(Library library)
Removed: public str->str dsDefaultSchemeDescriptionMap(str{} languages)

// Classes
Removed: public class DsToolboxCreatorCardPropertyWindow extends SubWindow
Removed: public class DsToolboxCreatorCardWindow extends CardWindow
Removed: public class DsToolboxCreatorControlWindow extends SubWindow
Removed: public class DsToolboxCreatorDataCatalogHeader extends DsDataCatalogHeader
Removed: public class DsToolboxCreatorDataCatalogSectionedLabel extends DsDataCatalogSectionedLabel
Removed: public class DsToolboxCreatorDataCatalogSectionedScrollableSubWindow extends DsDataCatalogSectionedScrollableSubWindow
Removed: public class DsToolboxCreatorDesignWindow extends SubWindow
Removed: public class DsToolboxCreatorDialog extends DialogWindow
Removed: public class DsToolboxCreatorDeletionSubWindow extends SubWindow
Removed: public class DsToolboxCreatorDragAnimation extends DsDragAnimation
Removed: public class DsToolboxCreatorDropDownTreeView extends DropDownTreeView
Removed: public class DsToolboxCreatorDynamicCard extends DsDynamicCard
Removed: public class DsToolboxCreatorExtensionToolboxCard extends ExtensionToolboxCard
Removed: public class DsToolboxCreatorFillerInsertDragAnimation extends DsToolboxCreatorThumbnailViewMoveDragAnimation
Removed: public class DsToolboxCreatorFillerMoveDragAnimation extends DsToolboxCreatorThumbnailViewMoveDragAnimation
Removed: public class DsToolboxCreatorFillerThumbnail extends DsThumbnail
Removed: public class DsToolboxCreatorFocusLines
Removed: public class DsToolboxCreatorFocusRect
Removed: public class DsToolboxCreatorGroupInsertDragAnimation extends DsToolboxCreatorDragAnimation
Removed: public class DsToolboxCreatorGroupMoveDragAnimation extends DsToolboxCreatorGroupInsertDragAnimation
Removed: public class DsToolboxCreatorHeaderInsertDragAnimation extends DsToolboxCreatorGroupInsertDragAnimation
Removed: public class DsToolboxCreatorHeaderLimb extends DsDynamicHeaderLimb
Removed: public class DsToolboxCreatorHeaderMoveDragAnimation extends DsToolboxCreatorGroupMoveDragAnimation
Removed: public class DsToolboxCreatorHeaderPropertyWindow extends SubWindow
Removed: public class DsToolboxCreatorImageSectionInsertDragAnimation extends DsToolboxCreatorDragAnimation
Removed: public class DsToolboxCreatorImageSectionMoveDragAnimation extends DsToolboxCreatorImageSectionInsertDragAnimation
Removed: public class DsToolboxCreatorImageSectionPropertyWindow extends ShrinkWindow
Removed: public class DsToolboxCreatorLibraryLimb extends DsDynamicLibraryLimb
Removed: public class DsToolboxCreatorProductCatalogLimbBuilder extends DsProductCatalogLimbBuilder
Removed: public class DsToolboxCreatorProductLevelPropertySubWindow extends ShrinkWindow
Removed: public class DsToolboxCreatorProductViewInsertDragAnimation extends DsDragAnimation
Removed: public class DsToolboxCreatorPropertyWindow extends SubWindow
Removed: public class DsToolboxCreatorSchemeButton extends DsDataCatalogSchemeButton
Removed: public class DsToolboxCreatorSchemeButtonInsertDragAnimation extends DsToolboxCreatorDragAnimation
Removed: public class DsToolboxCreatorSchemeButtonMoveDragAnimation extends DsToolboxCreatorSchemeButtonInsertDragAnimation
Removed: public class DsToolboxCreatorSchemeButtonPropertyWindow extends ShrinkWindow
Removed: public class DsToolboxCreatorSectionLabelPropertyWindow extends SubWindow
Removed: public class DsToolboxCreatorSideBarPropertiesPropertyWindow extends DsInWindowSideBarProperties
Removed: public class DsToolboxCreatorThumbnailsLimb extends DsThumbnailsLimb
Removed: public class DsToolboxCreatorThumbnailPropertyWindow extends SubWindow
Removed: public class DsToolboxCreatorThumbnailViewMoveDragAnimation extends DsThumbnailViewMoveDragAnimation
Removed: public class DsToolboxCreatorToolboxCard
Removed: public class DsToolboxCreatorToolboxCards
Removed: public class DsToolboxCreatorToolboxSectionedScrollableSubWindow extends ToolboxSectionedScrollableSubWindow
Removed: public class DsToolboxCreatorToolboxThumbnail extends DsToolboxThumbnail
Removed: public class DsToolboxCreatorToolboxThumbnailView extends DsToolboxThumbnailView
Removed: public class DsToolboxCreatorTooltip
Removed: public class DsToolboxCreatorTreeViewItem extends TreeViewItem
Removed: public class DsToolboxCreatorHeaderTreeViewItem extends DsToolboxCreatorTreeViewItem
Removed: public class DsToolboxCreatorGroupTreeViewItem extends DsToolboxCreatorTreeViewItem
Removed: public class DsToolboxCreatorProductViewTreeViewItem extends DsToolboxCreatorTreeViewItem
Removed: public class DsToolboxCreatorFillerTreeViewItem extends DsToolboxCreatorTreeViewItem
Removed: public class DsToolboxCreatorImageSectionTreeViewItem extends DsToolboxCreatorTreeViewItem
Removed: public class DsToolboxCreatorSchemeButtonTreeViewItem extends DsToolboxCreatorTreeViewItem
Removed: public class DsToolboxCreatorUIBuilder extends DsNewUIBuilder
Removed: public class DsToolboxCreatorUIGroupBuilder extends DsUIGroupBuilder

Ind. Tag identity and user-tag storage

class DsPart

If your data symbol part subclass previously used itemTagKey() or partSourceId to control Ind. Tag identity, move that logic to sourceId().

Old: public constructor(Snapper snapper, DsPData data, double basePrice, Double optionPriceSum, double qty=1, str partSourceId=null)
New: public constructor(Snapper snapper, DsPData data, double basePrice, Double optionPriceSum, double qty=1, str sourceId=null)

Old: public constructor(Snapper snapper, DsPData data, str articleCode, str description, double basePrice, Double optionPriceSum, double quantity=1, double inPrice=0, bool flattenable=true, bool group=false, partStyle style=psNone, str flattenableKey=null, bool allowOtherParent=true, str partSourceId=null)
New: public constructor(Snapper snapper, DsPData data, str articleCode, str description, double basePrice, Double optionPriceSum, double quantity=1, double inPrice=0, bool flattenable=true, bool group=false, partStyle style=psNone, str flattenableKey=null, bool allowOtherParent=true, str sourceId=null)

Old override point: public str itemTagKey()
New override point: public str sourceId()

class DataSymbol

Old: public void setItemTagInfo(Part part, str key, ItemTagInfo info, bool userMod=false)
New: public void setItemTagInfo(Part part, str key, ItemTagInfo info)

class DsPicklist

The following picklist-local user-tag storage fields have been removed. If your code accessed them directly, migrate to the shared helper APIs in cm.core.part.userTagInfoHolder.cm.

Removed: public str->ItemTagInfo tagInfos();
Removed: public str->str tagInfoKeys();

class DsPicklistQuantityGridCell

The freeform picklist quantity cell now uses a custom numeric field instead of relying only on the older default text parsing path.

Old: public class DsPicklistQuantityGridCell extends PicklistInputGridCell
New: public class DsPicklistQuantityGridCell extends DsPicklistInputGridCell

Old: extend public FormattedTextField getCustomField(Control popup)
New: extend public FormattedTextField getCustomField(GridWindow gw, Control popup)

Old: public FormattedTextField getCustomField(Control popup)
New: public FormattedTextField getCustomField(GridWindow gw, Control popup)

This is the class-level migration surface behind the quantity-input behavior change in Catalogue Explorer freeform picklists.

class DsPart

DsPart now exposes additional public hooks for the 17.0 option-identity and added-option workflows.

Removed: public str optSpecialKey(PartOptionItem opt)

Old: public str getCompanyCode()
New: public str companyCode()

Old: extend public str catalogCode()
New: public str catalogCode()

Old: extend public double pkgCount()
New: public double pkgCount()

Added: extend public void xmlAdditionalOptions(DsiPDataOption dataOpt|, int index, str prefix, XmlStreamBuf buf, bool recurse=true)
Added: extend public void xmlAdditionalOptions(SpecOption anchorOpt|, int index, str prefix, XmlStreamBuf buf, bool recurse=true)
Added: extend public void xmlAdditionalOptions(str key|, int index, str prefix, XmlStreamBuf buf, bool recurse=true)
Added: extend public void generateCustomOptionXmlTag(CustomSpecOption customOpt, int index, str prefix, XmlStreamBuf buf)
Added: extend public void generateAdditionalOptions(DsiPDataOption dataOpt|, ItemData itemData, bool recurse=true)
Added: extend public void generateAdditionalOptions(SpecOption anchorOpt|, ItemData itemData, bool recurse=true)
Added: extend public void generateAdditionalOptions(str key|, ItemData itemData, bool recurse=true)

class DsPart pricing behavior

DsPart now participates more directly in the shared 17.0 currency-translation pricing flow.

Changed behavior/important usage: public double basePrice(bool includeChildren=false, Space space=null, bool translatePrice=true)
Changed behavior/important usage: public Double generateOptionPriceSum()

For data-symbol parts, this means base price and option-price calculations now flow through the shared CET-currency translation behavior more consistently.

Removed data-symbol package-count column APIs

The older data-symbol-specific package-count column interfaces have been removed. If your package references them directly, update that code to use the shared core package-count column instead.

Removed: public const DsPackageCountColumn dsPkgCountColumn()
Removed: public class DsPackageCountColumn extends BasicPartColumn

Replacement: use cm.core.init.packageCountColumn() / PackageCountColumn.

class DsPData

DsPData also gained new hooks for the 17.0 option-export flows.

Added: extend public void generateOptionRows(PartOptionItem opt, DsPart part, SifEnv env, Space space, str featureCode=null, str featureDesc=null)
Added: extend public void generateAdditionalOptionRows(DsiPDataOption dataOpt|, DsPart part, SifEnv env, Space space, bool recurse=true)
Added: extend public void generateAdditionalOptionRows(SpecOption anchorOpt|, DsPart part, SifEnv env, Space space, bool recurse=true)
Added: extend public void generateAdditionalOptionRows(str key|, DsPart part, SifEnv env, Space space, bool recurse=true)

These methods are the entry points for packages that need to participate in SIF export of added options.

class DsSpecOption

DsSpecOption should also be considered part of the 17.0 migration surface for data-symbol packages because its key generation feeds directly into option-special identity and migration.

Added/important usage: public class DsSpecOption extends SpecOption
Added/important usage: public DsPDataOption option
Added/important usage: public str generateKey()
Added/important usage: public str adjustmentKey()

For data-symbol options, generateKey() and adjustmentKey() now depend on DsPDataOption.optionToRootPath() when available. generateKey() also includes groupCode when present. That is why data-symbol option-special migration and added-option ordering need their own DsPartSpecialMigrator handling instead of assuming base SpecOption keys are sufficient.

class DsPartSpecialMigrator

DsPartSpecialMigrator is the public data-symbol-specific migration helper for 17.0 option-special migration. It extends ProdPartSpecialMigrator and adjusts the legacy-key logic for DsSpecOption and feature-option combinations.

Added: public class DsPartSpecialMigrator extends ProdPartSpecialMigrator
Added: public str oldOptSpecialsKey(Part part, PartOptionItem opt)
Added: public str oldOptSpecialsKey(PartOptionItem opt)

If your catalogue package historically used custom DsPart option keys, subclass DsPartSpecialMigrator and override those methods. The Fika example does exactly this by returning FikaDsPartSpecialMigrator from the snapper prop and overriding oldPartSpecialsKey(Part part) for its older key histories.

Opt-in migration hook for snappers

The migrator types are opt-in. If your snapper package needs to preserve old part or option specials, expose a PartSpecialMigrator "partSpecialMigrator" prop on the snapper and return the right migrator instance for that snapper family.

A downstream example from custom.fika looks like this:

PartSpecialMigrator "partSpecialMigrator" {
    Object default(..) {
        return FikaDsPartSpecialMigrator();
    }
}

The searchable base types involved are:

New/important: class PartSpecialMigrator
New/important: class ProdPartSpecialMigrator
New/important: class DsPartSpecialMigrator

cm.abstract.draw

class DrawLine

Changed the length setter function from final to extend.

Old: final public double length=(double v) {
New: extend public double length=(double v) {
Removed: extend public void lengthChanged() {

class DrawMeasure

Renamed two methods to more clearly convey what they do.

Old: extend public void setP0(point p, Angle forcedAngle=null, bool updateD=true) {
New: extend public void setSpaceP0(point p, Angle forcedAngle=null, bool updateD=true) {
Old: extend public void setP1(point p, Angle forcedAngle=null) {
New: extend public void setSpaceP1(point p, Angle forcedAngle=null) {

class DrawText

Removed the following functions:

Removed: final public void drawHelpFrameIfSelected(GInstance gs) {
Removed: extend public void drawMarginHelpFrameIfSelected(GInstance gs, rect mr) {
Removed: final public void drawHelpFrameIfSelectedOrZoomedOut(GInstance gs, GTextBox gText) {

Instead, use one of these:

Added: final public void drawHelpFrame(GInstance gs) {
Added: final public void drawMarginHelpFrame(GInstance gs) {

class LinearReplicateAction

Old: extend public void addSuperStretchVessel(point p) {
New: extend public void addSuperStretchVessel(point p, angle a) {

cm.abstract.extrusions

class AbsExtrCollection

Changed the constructor to optionally support custom labels for collections.

Old: public constructor(str collectionName, str dbPath, str namespace, str uom, symbol[] tags, int version, Material m) {
New: public constructor(str collectionName, str dbPath, str namespace, str uom, symbol[] tags, int version, Material m, str collectionLabel=null) {

Steal was removed and made inaccessible, not meant to be used from the outside.

Old: extend public void steal(AbsExtrCollection f) {
New: extend package void registryCopyContent(AbsExtrCollection f) {

Minor name changes:

Old: final public AbsExtrProfile get(str name) {
New: final public AbsExtrProfile get(str id) {

class AbsExtrProfile

Made member not intended to be changed from the outside private but public readable.

Old: public str id;
New: private str id : public readable;

class AbsExtrProfileDef

Added a optional construction argument to decide whether the profile shape should be closed or not.

Old: public constructor(str coll, str name, AbsExtrShapeDefItem[] shapeDef) {
New: public constructor(str coll, str name, AbsExtrShapeDefItem[] shapeDef, bool closeProfile=true) {

cm.abstract.k2.data

K2PriceListManager

Unused methods in K2PriceListManager removed:

Removed: extend public void updateChannelsFromOfflineData()
Removed: extend public void updateChannelsFromOnlineData(str->str response)

This is now handled by K2ChannelManager, see cm/abstract/k2/k2ChannelManager.cm.

cm.abstract.kitchen.whitegoods

WgApplianceEnv

Removed old constructor:

Removed: public constructor(str article,
         str brand=null,
		 str model3DStr=null,
		 str productCode=null,
		 str eanCode=null,
		 str extProductSheetLink=null,
		 str cetType=null,
		 size snapperSize = (0, 0, 0),
		 size nicheSize = (0, 0, 0),
		 double depthOffset=0,
		 double heightOffset=0,
		 fanCm3DType fanType=fanCm3DType.undefined,
		 whitegoodsFrontType front=whitegoodsFrontType.undefined,
		 str accessoriesList=null,
		 str imageStr=null,
		 symbol creatorPkg=#:package : caller eval,
		 bool hidden=false)

Instead use:

public constructor(str article,
		           str brand=null,
		           str model3DStr=null,
		           str productCode=null,
		           str eanCode=null,
		           str extProductSheetLink=null,
		           str cetType=null,
		           size snapperSize = (0, 0, 0),
		           size nicheSize = (0, 0, 0),
		           double depthOffset=0,
		           double heightOffset=0,
		           fanCm3DType fanType=fanCm3DType.undefined,
		           whitegoodsFrontType front=whitegoodsFrontType.undefined,
		           str accessoriesList=null,
		           str imageStr=null,
		           symbol creatorPkg=#:package : caller eval,
		           bool hidden=false,
		           str rsKey=null)

cm.abstract.material

AbsMaterial thumbnailType

AbsMaterial now includes thumbnailType method, subclasses will need to remove extend keyword if they had previously defined this method.

AbsMaterial
public class AbsMaterial extends CachedMaterial {
    extend public gmThumbnailType thumbnailType() {..}
}
public class FOMaterial extends OfficeMaterial {
    Old: extend public gmThumbnailType thumbnailType() {..}
    New: public gmThumbnailType thumbnailType() {..}
}

cm.abstract.materialHandling

System configuration changes

The abstract class MhSystemConfiguration, and the child classes MhStorageConfiguration and MhStorageEditorConfiguration have had similar methods declared in them.

MhStorageConfiguration.configUserPropertyChanged(str key, Object value, Object oldValue, Object propOwner, MhStorageConfigurationItem item) and MhStorageEditorConfiguration.userPropertyChange(MhStorageEditorItem item, CoreProperty property, Object oldValue) were both doing similar logic and so we have now created a new method in the parent class MhSystemConfiguration that calls this similar functionality. If you had previously overridden either of these two methods, you should now override configUserPropertyChanged(MhSystemConfigurationItem item, CoreProperty property, Object oldValue) instead.

public class MhSystemConfiguration extends CoreObject {

    Added:
    /**
     * Config user property changed.
     */
    extend public void configUserPropertyChanged(MhSystemConfigurationItem item, CoreProperty property, Object oldValue) {
        if (property.owner != item) {
            item.?additionalPropChanged(property.key, property.value, oldValue, property.owner);
        }

        configUserPropertyChanged(property.key, property.value, oldValue, property.owner, item);
    }
}


public class MhStorageConfiguration extends MhSystemConfiguration {

    Removed:
    /**
     * configUserPropertyChanged - user changed property. Adjust configuration accordingly.
     */
    extend public void configUserPropertyChanged(str key, Object value, Object oldValue, Object propOwner, MhStorageConfigurationItem item) {
        for (it in items) {
            it.configUserPropertyChanged(..);
        }
    }
}


public class MhStorageEditorConfiguration extends MhSystemConfiguration {

    Removed:
    /**
     * User property changed.
     */
    extend public void userPropertyChange(MhStorageEditorItem item, CoreProperty property, Object oldValue) {
        if (property.owner != item) {
            item.additionalPropChanged(property.key, property.value, oldValue, property.owner);
        }
        
        if (space and !skipPushToPreview(..-)) {
            beforePushPropToPreview(..);
            pushPropToPreview(space, ..-);
            afterPushPropToPreview(..);
        }
    }
}

Aisle function changes

The function Snapper getNextSingleAisle(MhSnapper snapper, bool top=true) has been removed and a function Snapper getNextAisle(MhSnapper snapper, bool top=true) has been added.

Removed:
public Snapper getNextSingleAisle(MhSnapper snapper, bool top=true) {
    for (r in getAllRows(snapper, top=top, reverse=false)) {
        if (r == snapper) continue;
        if (r.isSingle and r.isAisle) return r;
    }

    return null;
}


Added:
public Snapper getNextAisle(MhSnapper snapper, bool top=true) {
    for (r in getAllRows(snapper, top=top, reverse=false)) {
        if (r == snapper) continue;
        if ((r.isDouble and r.isAisle and !r.isFlueGap) or
            (r.isSingle and r.isAisle)) return r;
    }

    return null;
}

Engine entry additional shape arguments

Previously MhEngineEntry has a map field str->Object additionalShapeArgs that allows storing key-value data. This has now been changed to a private field str->Object _additionalShapeArgs and new public methods have been introduced with the same name. This is so that the source of this map can be overridden.

For example, MhEngineConstructionEntry overrides the additionalShapeArgs methods to put/retrieve data from the owned constructionInfo() object instead. The class MhEngineConstructionEntryInfo now has a new field str->Object _additionalShapeArgs and method str->Object additionalShapeArgs(). This allows the map of the info class to be set independently and for the data to later be assigned to a MhEngineConstructionEntry at a later time.

// cm/abstract/materialHandling/engine/mhEngineEntry.cm
public class MhEngineEntry extends MhEngineEntryBase {
    Old: public str->Object additionalShapeArgs;
    New: private str->Object _additionalShapeArgs;
    New: extend public str->Object additionalShapeArgs() { }
    New: extend public str->Object additionalShapeArgs=(str->Object args) { }
    New: extend public Object getAdditionalShapeArg(str key) { }
    New: extend public void putAdditionalShapeArg(str key, Object val) { }
}

// cm/abstract/materialHandling/engine/mhEngineConstructionEntry.cm
public class MhEngineConstructionEntryInfo {
    New: private str->Object _additionalShapeArgs;
    New: extend public str->Object additionalShapeArgs() { }
}

// cm/abstract/materialHandling/mhSnapperSpawner.cm
public class MhSnapperSpawner extends SnapperSpawner {
    Old: extend public MhEngineConstructionEntry engineConstructionEntry() { }
    New: extend public MhEngineConstructionEntry engineConstructionEntry(MhEngineConstructionEntryInfo info=null) { }
}

The additionalShapeArgs are primarily used to push property values to spawned snappers on constructions. They can also be used to hold distinct entry values to be used during engine functions.

These additionalShapeArgs are applied in three areas during construction, one during instantiation of an MhEngineConstructionEntry, one during spawning of a snapper, and one more time after export of entry.

1. Instantiation of `MhEngineConstructionEntry`
public class MhSnapperSpawner extends SnapperSpawner {

    /**
     * Engine construction entry (used by entry layout only).
     */
    extend public MhEngineConstructionEntry engineConstructionEntry(MhEngineConstructionEntryInfo info=null) {
        MhSnapperShape shape = createShape();
        for (key, val in info.?additionalShapeArgs) shape.?changeShape(key, val);
        ...
    }
}

2. Spawning of a snapper
public class MhEngineConstructionEntry extends MhEngineSnapperEntry {

    /**
     * Spawn snapper.
     */
    extend public MhSnapper spawnSnapper(MhEngine engine, MhSystemSpawnerSelector spawnerSelector=null) {
        ...
        if (MhSnapper s = spawnerSelector.?spawnSnapper(classification, shapeArgs=shapeArgs+additionalShapeArgs, env=this)) {
            return s;
        }
        ...
    }
}

3. After export of entry.
public class MhSnapperShape extends CorePropObj {

    /**
     * Entry exported.
     */
    extend public void entryExported(MhSnapper snapper, MhEngineEntry entry) {
        ...

        // Apply additional shape args on exported as they are not included in entry cache key so export function might have spawned snapper without using correct shape args from mhSystemEngineCache.
        if (entry as MhEngineConstructionEntry) {
            for (key, val in entry.additionalShapeArgs()) {
                changeShape(key, val);
            }
        }
    }
}

Level clearance changes

Several changes have been made for handling level clearances in the abstract. First of all, the class MhClearanceSpecLevelClearanceBehavior and the field levelClearanceZ field in MhClearanceSpec have been removed.

How this would be used is the MhClearanceSpecLevelClearanceBehavior class would call spec.?collisionPrimitives(shape, env) which by default would call MhClearanceSpec.levelClearanceCollision(MhSnapperShape shape, MhCollisionFetchEnv env) that returns a CollisionPrimitive built based on spec.levelClearanceZ. This would result in a CollisionPrimitive always being built for the level.

Removed: public mhLazyGlobal MhBehavior mhClearanceSpecLevelClearanceBehavior = MhClearanceSpecLevelClearanceBehavior();
Removed: public class MhClearanceSpecLevelClearanceBehavior extends MhClearanceSpecBehavior 

public class MhClearanceSpec extends CorePropObj {
    Removed: public Double levelClearanceZ;
    Removed: Prop cMhLevelClearanceZPK : attributes={#allowPush, #allowPushNull};
}

Instead of always building a CollisionPrimitive for the level to represent the level clearance, we now only append this primitive during the construction of entries.

public class MhLevelShape extends MhBoxSnapperShape {

    Old:
    extend public void appendLevelClearancePrimitives(CollisionPrimitive{} prims,
                                                      MhCollisionFetchEnv env) {
        if (?MhClearanceBehavior b = owner.?behavior("levelClearance")) {
            if (!env) env = MhCollisionFetchEnv();
            Transform t = env.transform;

            double elevation;
            if (t) elevation = t.pos.z;
            else elevation = owner.toSpaceTransform().pos.z;
            MhClearanceCollisionFetchEnv clearanceEnv(env, elevation,
                                                      owner.rootParent.MhSnapper.?classification);
            b.appendCollisionPrimitives(this, clearanceEnv, prims);
        }
    }


    New:
    extend public void appendLevelClearancePrimitives(CollisionPrimitive{} prims,
                                                      MhCollisionFetchEnv env) {
    }
}


public class MhLevelSpawner extends MhStorageSpawner {

    New:
    /**
     * Return construction entry collision primitive.
     */
    public CollisionPrimitive engineConstructionCollision(MhSnapperShape shape,
                                                          MhEngineConstructionEntry entry) {
        CollisionPrimitive res = super(..);
        appendLevelClearancePrimitive(res, shape, entry);
        return res;
    }


    New:
    /**
     * Append level clearance primitive.
     * Simple implementation of level clearance when using MhCompartmentType with no unit loads. For custom logic, override either this or MhClearanceSpec.levelClearanceCollision().
     */
    extend public void appendLevelClearancePrimitive(CollisionPrimitive prim,
                                                     MhSnapperShape shape,
                                                     MhEngineConstructionEntry entry) {
        if (prim as CollisionPrimitiveSet) {
            if (?MhClearanceBehavior b = statelessBehavior("Clearance")) {
                MhCollisionFetchEnv env(reason=#construction, entry=entry);
                b.appendCollisionPrimitives(shape, env, prim.subPrims);
            }
        }
    }
}

Due to the above change in behavior, the ownership of a level clearance value has been changed from the clearance spec to the engine entry, more specifically it is stored in the additionalShapeArgs() of MhEngineEntry.

public class MhClearanceSpec extends CorePropObj {

    Old:
    /**
     * Collision primitives based on `levelClearanceZ`.
     */
    extend public CollisionPrimitive[] levelClearanceCollision(MhSnapperShape shape,
                                                               MhCollisionFetchEnv env) {
        CollisionPrimitive[] res(4);
        if (levelClearanceZ and shape) {
            box b = shape.localBound();
            b.h = levelClearanceZ.v;
            static Layer layer = Layer(layerSet(sClearance, sLevelClearanceZ), layerSet(sLevel, sLevelFrame));
            res << mhGetBoxCollisionPrimitive(b, layer, env.transform);
        }
        return res.any ? res : null;
    }


    New:
    /**
     * Collision primitives for level clearance.
     */
    extend public CollisionPrimitive[] levelClearanceCollision(MhSnapperShape shape,
                                                               MhCollisionFetchEnv env) {
        CollisionPrimitive[] res(4);

        // Append level clearance collision from MhCompartmentType during construction.
        if (env.?reason == #construction) {
            MhEngineEntry entry = env.entry;
            if (?Double levelClearance = entry.?getAdditionalShapeArg("levelClearance")) {
                box b = shape.?localBound([sLevelFrame]);
                b.h += levelClearance.v;
                static Layer layer = Layer(layerSet(sClearance, sLevelClearanceZ),
                                           layerSet(sLevel, sLevelFrame));
                res << mhGetBoxCollisionPrimitive(b, layer);
            }
        }

        return res.any ? res : null;
    }
}


public class MhCollisionFetchEnv {
    New: public MhEngineEntry entry;

    Old: public constructor(symbol reason=#none, Transform transform=null, bool includeChildren=false, Object arg=null)
    New: public constructor(symbol reason=#none, Transform transform=null, bool includeChildren=false, MhEngineEntry entry=null, Object arg=null)
}

Unit load clearance changes

Changes have been made to support different level entries having different unit load clearances. MhUnitLoadSpawner can pass in different clearance specs for each level entry instead of always using the same clearance spec from the configuration.

public class MhEntryLayoutEnv {
    New: public MhEngineEntry entry;
}

public class MhUnitLoadSpawner extends MhStorageSpawner {

    Old:
    extend public void appendAdditionalConstructionCollision(MhEngineConstructionEntry entry, str unitLoadKey, LayerSet rootParentClassification, MhEntryLayoutEnv env) {
        ...
        for (MhClearanceSpecBehavior behavior in collection.behaviors) {
            MhStorageClearanceCollisionFetchEnv clearanceEnv(..., clearanceSpec=config.?clearanceSpec);
            behavior.appendCollisionPrimitives(loadShape, clearanceEnv, set.subPrims);
        }
    }


    New:
    extend public void appendAdditionalConstructionCollision(MhEngineConstructionEntry entry, str unitLoadKey, LayerSet rootParentClassification, MhEntryLayoutEnv env) {
        ...
        MhClearanceSpec spec;
        if (?MhEngineConstructionEntry parent = env.entry) {
            if (?MhClearanceSpec cSpec = parent.getAdditionalShapeArg(cMhClearanceSpecPK)) {
                spec = cSpec;
            }
        }
        if (!spec) spec = config.?clearanceSpec;
        for (MhClearanceSpecBehavior behavior in collection.behaviors) {
            MhStorageClearanceCollisionFetchEnv clearanceEnv(..., clearanceSpec=spec);
            behavior.appendCollisionPrimitives(loadShape, clearanceEnv, set.subPrims);
        }
    }
}

Unit load construction changes

We have added further control over the number of unit loads populated during construction.

MhUnitLoadConstructionalPopulateFunction class (unitLoadConstructionalPopulate) had the argument loadCount, which was passed to MhConstructionUnitLoadArrangement to populate unit loads perpendicular to the populate vector. It has been renamed to repeatCount. Additionally, a new argument ulCount has been added to represent the number of unit loads to populate in the direction of population. If left as null, the previous behavior will be used which is to populate as many loads as possible. Similarly the MhConstructionUnitLoadArrangement class now holds fields repeatCount and ulCount in place of the previous field count.

Effectively, previous specification of loadCount will now need to specify repeatCount instead. Make sure to search for loadCount in your extension as engine function execute arguments do not throw compile errors for incorrect arguments.

// cm/abstract/materialHandling/storage/engine/mhUnitLoadConstructionalPopulateFunction.cm
public class MhUnitLoadConstructionalPopulateFunction extends MhSystemEngineFunction {
    Old: public Int loadCount;
    New: public Int repeatCount; //replaces loadCount
    New: public int ulCount;
}

// cm/abstract/materialHandling/storage/mhUnitLoadArrangement.cm
public class MhConstructionUnitLoadArrangement extends MhUnitLoadArrangement {
    Old: public int count;
    New: public int repeatCount; //replaces count
    New: public int ulCount;

    Old: public constructor(MhPopulator populator, MhEngineEntry defaultLoadEntry, int count=1, vector direction=(0, 1, 0), bool spreadEvenly=true) { }
    New: public constructor(MhPopulator populator, MhEngineEntry defaultLoadEntry, int ulCount=0, int repeatCount=1, vector direction=(0, 1, 0), bool spreadEvenly=true) { }
}

The repeatCount and ulCount fields for MhUnitLoadConstructionalPopulateFunction are typically passed in from MhLevelConstructionalPopulateFunction.levelChildConstruction(MhEngineConstructionEntry entry) where it passes the values from entry.constructionInfo. Additionally in MhEngineLevelConstructionEntryInfo, the field noOfUnitLoads was renamed to noOfUnitLoadsX and both noOfUnitLoadsX and noOfUnitLoadsY fields are now boxed Int types instead of primitive int.

// cm/abstract/materialHandling/storage/engine/mhLevelConstructionalPopulateFunction.cm
public class MhLevelConstructionalPopulateFunction extends MhSystemEngineFunction {

    /**
     * levelChildContruction
     */
    extend public void levelChildConstruction(MhEngineConstructionEntry entry) {
        ...
            ?MhEngineLevelConstructionEntryInfo info = entry.constructionInfo;
            Int ulXCount = info.?noOfUnitLoadsX;
            Int ulYCount = info.?noOfUnitLoadsY;
            if (!ulYCount) ulYCount = configuration.unitLoadCountY();

            engine.exec("unitLoadConstruction", ...,
                        ulCount=ulXCount, repeatCount=ulYCount,
                        ...);
        ...
    }
}

public class MhEngineLevelConstructionEntryInfo extends MhEngineConstructionEntryInfo {
    Old: public int noOfUnitLoads;
    New: public Int noOfUnitLoadsX;
    Old: public int noOfUnitLoadsY;
    New: public Int noOfUnitLoadsY;
}

Changes to Unit Load Ensure Clearance Function

Some method and argument names in MhUnitLoadEnsureClearanceFunction2 were updated to more accurately represent that the function operates on populated child entries rather than the imported entries.

// cm/abstract/materialHandling/storage/engine/mhUnitLoadEnsureClearanceFunction.cm
public class MhUnitLoadEnsureClearanceFunction2 extends MhSystemEngineFunction {
    Old: extend public MhUnitLoadArrangement unitLoadArrangement(MhEngineEntry[] imported, MhPopulator populator)
    New: extend public MhUnitLoadArrangement unitLoadArrangement(MhEngineEntry[] children, MhPopulator populator)

    Old: extend public MhEngineEntry loadEntryToKeep(MhEngineEntry[] imported)
    New: extend public MhEngineEntry loadEntryToKeep(MhEngineEntry[] children)

    Old: extend public bool spreadUnitLoad(MhEngineEntry[] imported)
    New: extend public bool spreadUnitLoad(MhEngineEntry[] children)

    Old: extend public MhEngineEntry[] importedChildren(MhEngineEntry level)
    New: extend public MhEngineEntry[] childEntries(MhEngineEntry level) 
}

Changes to Level Arrange Function

From the MhLevelArrangeFunction2, the field arrangedByOtherBay was removed as it was not used.

// cm/abstract/materialHandling/storage/engine/mhLevelArrangeFunction.cm
public class MhLevelArrangeFunction2 extends MhSystemEngineFunction {
    Removed: public Bool arrangedByOtherBay;
}

Config behavior changes

For doing config comparisons between two snappers, a new strict argument was introduced where it allows a new comparison logic when strict=false. When strict=false, classifications are compared by doing a LayerSet.eval() where one symbol match is required instead of a total match between layers.

// cm/abstract/materialHandling/storage/behavior/mhConfigBehaviors.cm
Old: public bool basicConfigEq(MhSnapper a, MhSnapper b, SnapperFilter childFilter=null)
New: public bool basicConfigEq(MhSnapper a, MhSnapper b, bool strict=true, SnapperFilter childFilter=null)

Old: public bool basicConfigNoChildrenEq(MhSnapper a, MhSnapper b)
New: public bool basicConfigNoChildrenEq(MhSnapper a, MhSnapper b, bool strict)

Old: public bool basicConfigNoChildrenNoShapeEq(MhSnapper a, MhSnapper b)
New: public bool basicConfigNoChildrenNoShapeEq(MhSnapper a, MhSnapper b, bool strict=true)

MhStorageEditorConfigPropModifyUndoOp changes

Undo operation class MhStorageEditorConfigPropModifyUndoOp now stores the Guid to the config instead of the config object itself.

public class MhStorageEditorConfigPropModifyUndoOp extends MhStorageEditorUndoOp {
    Removed: public MhStorageEditorConfiguration config : copy=reference;
    New: public Guid configGid;
    New: public constructor(MhStorageEditorDialog dialog, Guid configGid, str propKey, Object propVal) {
}

Storage editor visibility toggle changes

Removed classes MhStorageEditorDimensionToolbarModelItem and MhBayEditorElevArrowToolbarModelItem. Both functionalities are now implemented in MhStorageEditorConfiguration. Instead of separate toolbar items, they have been combined into one visibility toolbar item.

Removed: public class MhStorageEditorDimensionToolbarModelItem extends ToolbarModelItem {
Removed: public class MhBayEditorElevArrowToolbarModelItem extends ToolbarModelItem {
Removed: public const str cMhArrowVisibilityStateKey = "arrowVisibilityState";


public class MhStorageEditorConfiguration extends MhSystemConfiguration {

    New:
    /**
     * Allow dimension visibility toggle?
     */
    extend public bool allowDimensionVisibilityToggle(View view) {
        return false;
    }


    New:
    /**
     * Allow arrow visibility toggle?
     */
    extend public bool allowArrowVisibilityToggle(View view) {
        return false;
    }


    New:
    /**
     * Dimension visibility toggle changed.
     */
    extend public void dimensionVisibilityToggleChanged(bool state, View view) {
        if (Space space = view.?space) {
            mhStorageEditorDimensionTogglePutCached(space, value=state);
            for (s in space.snappers) mhUpdateEditorDimensionVisibility(s);
        }
    }


    New:
    /**
     * Arrow visibility toggle changed.
     */
    extend public void arrowVisibilityToggleChanged(bool state, View view) {
        if (Space space = view.?space) {
            mhStorageEditorArrowTogglePutCached(space, value=state);
            insertArrowVessel(space);
        }
    }


    New:
    /**
     * Update snappers visibility.
     */
    extend public void updateSnappersVisibility() {
        for (s in space.snappers) mhUpdateEditorDimensionVisibility(s);
        insertArrowVessel(space);
    }
}

The dimensions toggle is visible by default for bay editor. The arrow toggle is visible by default for frame editor, and bay editor's 3D view.

Editor visibility toggles

Removal of MhConfigNameDialog

MhConfigNameDialog was a dialog specifically used to rename configurations. It was used together with the function str mhConfigMakeNameDialog(Window parent, str label, sizeI size=sizeI(400, 150), str initName=null, str headerName=null, pointI pos=(-1, -1)). Both the class and function have been removed.

Removed: public class MhConfigNameDialog extends NameDialog {
Removed: public str mhConfigMakeNameDialog(Window parent, str label, sizeI size=sizeI(400, 150), str initName=null, str headerName=null, pointI pos=(-1, -1)) {

This functionality has been replaced with the class MhValidNameDialog which shares most of the functionality, but instead takes in a sequence of str that is considered invalid. Replace calls of the function with the following code instead:

Old:
str name = mhConfigMakeNameDialog(this, "Name", initName=config.label);

New:
var cont = mhSystemConfigurationManager.getContainer(config);
str[] invalidNames();
for (otherConfig in cont.configs) {
    if (otherConfig == config) continue;
    invalidNames << otherConfig.label;
}
str name = mhMakeValidNameDialog(this, $name, initName=config.label, invalidNames=invalidNames);

MhSnapperApplyAnimation changes

This class had two methods void switchChildren(Snapper oldSnapper, Snapper newSnapper, bool forceSwitch) and void switchChildren(Snapper oldSnapper, Snapper newSnapper) which have been removed and replaced with void switchChildren(Snapper oldSnapper, Snapper newSnapper, bool forceSwitch=false).

This change is to combine the two methods into one. You can view the 16.5 Major migration guide section "Changes to spread tools switchChildren logic" for more comprehensive information regarding the usage of switchChildren.

public class MhSnapperApplyAnimation extends MhSnapperSpreadToolAnimation {
    Removed: extend public void switchChildren(Snapper oldSnapper, Snapper newSnapper, bool forceSwitch) {
    Removed: extend public void switchChildren(Snapper oldSnapper, Snapper newSnapper) {
    Added: extend public void switchChildren(Snapper oldSnapper, Snapper newSnapper, bool forceSwitch=false) {

Preconfigurator dialog changes

We have undertaken a series of enhancements to the Preconfigurator UI builder and preview system to improve overall performance, increase consistency during navigation, and introduce new features that support additional preview snappers as well as orthographic camera.

    // cm/abstract/materialHandling/storage/mhStorageConfiguratorUIBuilder.cm
    Old: extend public Window propertiesWindow(Window w, MhSystemConfiguration config)
    New: extend public Window buildPropertiesWindow(Window w, MhSystemConfiguration config)

Additional methods has been introduce for each configurator item to allow preview to be display for each MhCompartmentType.

    // Snappers preview for each item.
    public class MhStorageConfigurationItem extends MhSystemConfigurationItem 
        /**
         * Snappers preview.
         */
        extend public Snapper{} previewSnappers() {
                return null;
        }
    }

The MhConfigSnapperPreviewWindow class has been replaced with MhConfigViewContainer to better support model‑contextual elements and streamline the overall design.

Additionally, with the introduction of the new orthographic camera in the Preconfigurator, some methods have been deprecated as they are no longer relevant.

A feature from pre-configura has been removed from 17.0. Previously, the previewWindow functionality was intended to support custom 2D graphics—such as supplementary diagrams or detailed visual overlays—but this approach is now superseded by the enhanced capabilities of the orthographic camera system

    // cm/abstract/materialHandling/storage/mhConfiguratorPreview3D.cm
    Old: public class MhConfigSnapperPreviewWindow extends SubWindow
    New: public class MhConfigViewContainer extends MultiViewContainer

    // cm/abstract/materialHandling/storage/mhStorageConfigurator.cm
    Removed: public CardWindow cardWindow;
    Removed: public MhConfigSnapperPreviewWindow snapperPreviewContainer;
    Removed: extend public bool changeSnapperPreviewParent(CardWindow cw, SubWindow sub, bool requiresRebuild=false)
    Removed: extend public bool changeSnapperPreviewParent(MhStorageConfigurationItemUIBuilder itemBuilder, SubWindow sub)

    // cm/abstract/materialHandling/storage/mhStorageConfiguratorUIBuilder.cm
    Removed: public MhConfigurationContentSubWindow main;
    Removed: extend public void zoomToMainComponent(MhStorageConfiguratorDialog dialog)
    Removed: extend public MhConfigurationContentSubWindow createContentSubWindow(Window w)
    Removed: extend public Window previewWindow(Window w, MhSystemConfiguration config) 
    Removed: extend public Image previewButtonIcon(str key)

Orthographic preview

GFX behavior changes

This class MhRowAnimationEngineGfxBehavior is now made abstract and can no longer be instantiated. The logics in this class has been moved out to MhRowAnimationEngineGfxBehaviorG1 which is the replacement of the original class. This was introduce as part of the new MhRowAnimationEngineGfxBehaviorG2 which mean to unified 2D and 3D generation.

    Old: public class MhRowAnimationEngineGfxBehavior extends MhGenericEngineGfxBehavior
    New: public class MhRowAnimationEngineGfxBehavior extends MhGenericEngineGfxBehavior : abstract

    /**
     * Row Animation Graphics.
     * 
     * It ultimately draws what is in the 'groupedEntries', little to no interpretation.
     * 
     * G1:
     *   creates the rects/boxes for graphics individually for 2D/3D methods.
     *   supports cmSym 
     *   collision forces red coloring
     */
    public class MhRowAnimationEngineGfxBehaviorG1 extends MhRowAnimationEngineGfxBehavior


    /**
     * Row Animation Graphics.
     * 
     * It ultimately draws what is in the 'groupedEntries', little to no interpretation.
     * 
     * Key differences from G1:
     *  unified box creation for 2D and 3D
     *  check for collision passed into the color method for more flexibility
     * 
     * NOTE: no CmSym Support.
     */
    public class MhRowAnimationEngineGfxBehaviorG2 extends MhGenericEngineGfxBehavior

Additional implementation has been added into the MhTunnelShape class that support fill cross and material for the tunnel graphic.

    // cm/abstract/materialHandling/storage/racking/behavior/mhTunnelGfxBehavior.cm
    Old: extend public APath2D crossShape(box b)
    New: extend public AShape2D crossShape(MhSnapper owner, box b)

    Old: extend public APath2D tunnelSymPath(box b)
    New: extend public APath2D tunnelPath(MhSnapper owner, box b)

    Old: extend public GMaterial3D material3D()
    New: extend public Material3D material3D(MhSnapper owner)

Unit load snapping

The bool shouldReplace now is passed into the class contructor.

public class MhUnderUnitLoadCollisionAlternative extends MhFixedPointCollisionAlternative {
    Old:
    /**
     * Constructor
     */
    public constructor(Snapper snapper, box unitLoadbound, point ip,
                       orientation ir=(0deg, 0deg, 0deg),
                       bool middle=true, double depth=0d,
                       double dualPlacementOffset=0d,
                       Double distanceToSnapper=null) {
            super(snapper, ip, ir, shouldReplace=shouldReplace, distanceToSnapper=distanceToSnapper);
            set*(this: middle, depth, dualPlacementOffset);
            this.unitLoadbound = unitLoadbound;
    }

    New: 
    /**
     * Constructor
     */
    public constructor(Snapper snapper, box unitLoadbound, point ip,
                       orientation ir=(0deg, 0deg, 0deg),
                       bool shouldReplace=false,
                       bool middle=true, double depth=0d,
                       double dualPlacementOffset=0d,
                       Double distanceToSnapper=null) {
            super(snapper, ip, ir, shouldReplace=shouldReplace, distanceToSnapper=distanceToSnapper);
            set*(this: middle, depth, dualPlacementOffset);
            this.unitLoadbound = unitLoadbound;
    }
}

MhRowShape changes

We have removed fields and methods related to the collection of left and right strechers. These stretchers were only used in multibay/multiframe setups. They have been moved into MhMultiRowShape instead in the cm.abstract.materialHandling.storage.multi abstract extension dedicated to multibay/multiframe setups.

public class MhRowShape extends MhSnapperShape {
    Removed: public Connector[] leftStretchers : stream=null, copy=null;
    Removed: public Connector[] rightStretchers : stream=null, copy=null;


    Removed:
    /**
     * Init stretchers.
     */
    extend public void initStretcherConnectors() {


    Removed:
    /**
     * Init left stretcher connectors.
     */
    extend public void initLeftStretcherConnectors() {


    Removed:
    /**
     * Init right stretcher connectors.
     */
    extend public void initRightStretcherConnectors() {


    Removed:
    /**
     * Clear stretcher connectors.
     */
    extend public void clearStretcherConnectors() {


    Removed:
    /**
     * Update stretcher connectors.
     */
    extend public void updateStretcherConnectors() {
}

Row engine behavior changes

The following classes MhAisleRowEngineBehavior, MhFlueGapRowEngineBehavior, and MhBayRowEngineBehavior have had the same interfaces changed for the method shouldRunMultiChildrenLink().

public class MhAisleRowEngineBehavior extends MhEngineBehavior {
    Old: extend public bool shouldRunMultiChildrenLink() {
    New: extend public bool shouldRunMultiChildrenLink(MhSnapper snapper) {
}


public class MhFlueGapRowEngineBehavior extends MhEngineBehavior {
    Old: extend public bool shouldRunMultiChildrenLink() {
    New: extend public bool shouldRunMultiChildrenLink(MhSnapper snapper) {
}


public class MhBayRowEngineBehavior extends MhEngineBehavior {
    Old: extend public bool shouldRunMultiChildrenLink() {
    New: extend public bool shouldRunMultiChildrenLink(MhSnapper snapper) {
}

Constant moved package

The global constant sFrameAccessory has been moved from package cm.abstract.materialHandling.storage.racking to cm.abstract.materialHandling.storage.

cm.abstract.mezzanine

AbsMezzLevelRectInsertAnimation changes

Removed field str volumeId and replaced with a private field private symbol volumeId. Replaced methods str volId=(str id) with symbol volId=(symbol id) and str volId() with symbol volId(). Also renamed method AbsMezzDecking holeCandidate(AnimationMouseInfo mi) to `AbsMezzDecking getHoleCandidate(AnimationMouseInfo mi).

public class AbsMezzLevelRectInsertAnimation extends DrawShapeRectAnimation {

    Old: public str volumeId;
    New: private symbol volumeId;

    Old: extend public str volId=(str id) {
    New: extend public symbol volId=(symbol id) {

    Old: extend public str volId() {
    New: extend public symbol volId() {

    Old: extend public AbsMezzDecking holeCandidate(AnimationMouseInfo mi) {
    New: extend public AbsMezzDecking getHoleCandidate(AnimationMouseInfo mi) {
}

Mezzanine function changes

Removed function void mezzInsertRails(APolyline2D poly, AbsMezzDecking{} deckings, Space space). Call function void mezzInsertRailGroup(APolyline2D poly, APolyline2D[] holes, AbsMezzDecking{} deckings, Space space) instead.

Updated function signature:

Old:
public (AShape2D->AbsMezzDecking{}) mezzCombinedShapes(AbsMezzDecking{} deckings, bool ignoreTh=false) {

New:
public (AShape2D->AbsMezzDecking{}) mezzCombinedShapes(AbsMezzDecking{} deckings, bool ignoreTh=false, bool forStructure=false) {

AbsMezzRail changes

The method Graph get2D() has been removed and replaced with post2D(AbsMezzGraphNode node). It was previously used to create a circle graph to represent a post, but we no longer draw the posts in abstract by default.

public class AbsMezzRail extends Model3DSnapper {
    Old: extend public Graph get2D() {
    New: extend public Graph post2D(AbsMezzGraphNode node) {
}

The method Primitive3D rail3D(point2D from, point2D to) has been removed and replaced with Primitive3D rail3D(AbsMezzGraphNode n0, AbsMezzGraphNode n1). The method Primitive3D post3D() has been removed and replaced with post3D(AbsMezzGraphNode node)`.

public class AbsMezzRail extends Model3DSnapper {
    Old: extend public Primitive3D rail3D(point2D from, point2D to) {
    New: extend public Primitive3D rail3D(AbsMezzGraphNode n0, AbsMezzGraphNode n1) {

    Old: extend public Primitive3D post3D() {
    New: extend public Primitive3D post3D(AbsMezzGraphNode node) {
}

Graphics visitors changes

The following has been removed:

Removed: public const bool dbg_absMezzRailGfx;

public class AbsMezzGraphNodeRail3DVisitor extends AbsMezzGraphNodeVisitor {
    Removed: public AbsMezzGraphNode->(AbsMezzGraphNode-><double, point2D, point2D>[]) processed();
}


public class AbsMezzGraphNodeRail2DVisitor extends AbsMezzGraphNodeVisitor {
    Removed: public AbsMezzGraphNode->(AbsMezzGraphNode-><double, point2D, point2D>[]) processed();
}


public class AbsMezzGraphNodeVisitor extends Visitor {
    Removed: extend public Primitive3D dbgArrow3D(AbsMezzGraphNode from, AbsMezzGraphNode to, double height) {
    Removed: extend public Graph dbgArrow2D(AbsMezzGraphNode from, AbsMezzGraphNode to) {
}

AbsMezzEdge changes

AbsMezzEdge has been made unstreamable as these are meant to be temporary objects representing two AbsMezzGraphNode objects.

AbsMezzDecking changes

Removed field SnapperRef{} rackingRefs in AbsMezzDecking. Use methods SnapperRef{} refs() and SnapperRef{} refs=(SnapperRef{} r) instead.

public class AbsMezzDecking extends DrawShapeSnapper {
    Removed: public SnapperRef{} rackingRefs;
}

Structures reworked

The structures snapper has been reworked. Instead of each structures snapper representing a group of lines, we now have a structure snapper for every line.

Removed the following classes:

Removed: public class AbsMezzPurlins extends AbsMezzStructures {
Removed: public class AbsMezzColumns extends AbsMezzStructures {
Removed: public class AbsMezzBeams extends AbsMezzStructures {

Renamed class AbsMezzStructures to AbsMezzStructure. Field line[] lines is now line ln.

Old:
public class AbsMezzStructures extends ModelSnapper {
    public line[] lines;
    public constructor(line[] lines) { }
}


New:
public class AbsMezzStructure extends ModelSnapper {
    public line ln;
    public constructor(line ln) { }
}

Removed and replaced the below methods in AbsMezzDecking.

public class AbsMezzDecking extends DrawShapeSnapper {

    Old: extend public AbsMezzBeams createBeams() {
    New: extend public AbsMezzStructure createBeam() {

    Old: extend public AbsMezzPurlins createPurlins() {
    New: extend public AbsMezzStructure createSecondary() {

    Old: extend public AbsMezzColumns createColumns() {
    New: extend public AbsMezzStructure createColumn() {
}

AbsMezzStructureLinesEnv changes

Renamed the following fields:

public class AbsMezzStructureLinesEnv extends PropObj {
    Old: public line[] purlinLines;
    New: public line[] secondaryLines;

    Old: public double purlinMaxDist = 200mm;
    New: public double secondaryMaxDist = 200mm;

    Old: public size2D purlinSize = (64mm, 120mm);
    New: public size2D secondarySize = (64mm, 120mm);
}

AbsMezzStructureLinesGenerator changes

Updated method signature

public class AbsMezzStructureLinesGenerator {

    Old:
    extend public void processGeneratedLinesToBeam(line[] beamLines, line[] purlinLines, line[] columnLines, size2D beamSize, double deckingThickness=0) {

    New:
    extend public void processGeneratedLinesToBeam(line[] beamLines, line[] secondaryLines, line[] columnLines, size2D beamSize, double deckingThickness=0) {

}

cm.abstract.office

Removed file electrical.cm

The old public office electrical framework was removed from cm.abstract.office. If your package depends on these interfaces today, the expected migration path is to copy the removed interfaces and any needed implementation from the old office electrical system into your own package, then update your package code to reference those local types instead of the deleted cm.abstract.office ones.

Removed: public class AbstractPointEOPosition extends EOPosition
Removed: public class PointEOPosition extends AbstractPointEOPosition
Removed: public class LineEOPosition extends EOPosition
Removed: public class EORange extends EOPosition
Removed: public class PanelFrameElectricals extends CorePropObj
Removed: public class InsertElectricalObject extends ToolAnimation
Removed: public class ElLinkSnap extends LinkSnap
Removed: public class ElectricalConnection extends CorePropObj

class PanelFrame

The old panel-frame electrical extension points are gone from cm.abstract.office. Packages can no longer plug electrical behavior into PanelFrame through the removed ElectricalObject / EOPosition flow unless they recreate that API in their own package.

Removed: extend public PanelFrameElectricals electricalData()
Removed: extend public EOPosition[] electricalPositions(ElectricalObject z)
Removed: extend public bool apply(ElectricalObject z, EOPosition pos, ElectricalAction action)
Removed: extend public bool remove(EOPosition pos, ElectricalAction action)
Removed: extend public electricalAction allow(ElectricalObject z, EOPosition pos, bool replace, bool toogle)

class PanelJunctionSnapper

The old junction routing hooks were also removed from the shared office package. Packages that still use the old electrical model should move these hooks into their own junction classes.

Removed: extend public PanelJunctionElectricalConnect[] electricalConnects(bool visual=false)
Removed: extend public EORange[] routingPositions(ElectricalConnection z)

package dependencies

cm.abstract.office now imports cm.abstract.pathing, and the corresponding abstract extension adds cm.abstract.pathing as a package dependency. This matters if you choose to adopt the new routed electrical model used by custom.fika, but it is not required just to preserve an older package-owned copy of the removed electrical interfaces.

Added/important usage: use cm.abstract.pathing;

cm.abstract.part

class ProdPart

ProdPart now distinguishes between base part options and all part options, where allPartOptions() includes custom inserted options. The old spec-option invalidation flow has been broadened accordingly.

Added: extend public PartOption[] allPartOptions()
Added: extend public void setPartOptions(PartOption[] options, bool invalidatePartOptions=true)
Added: extend public PartOption[] rebuildPartOptions()
Added: extend public PartOption[] insertCustomOptions(PartOption[] options)

Old: extend public void invalidateSpecOptions(bool invalidateOptionPriceSum=true)
New: extend public void invalidatePartOptions(bool invalidateOptionPriceSum=true)

If you extend ProdPart and cache or mutate options, update your code to invalidate part options through invalidatePartOptions(...) and to choose between options() and allPartOptions() appropriately.

class ProdPart custom option ordering interfaces

ProdPart now exposes explicit interfaces for tracking custom inserted options by anchor key. These interfaces are important if you build, reorder, export, or inspect additional options.

Added: public str->CustomSpecOption anchorKeyToCustom
Added: extend public CustomSpecOption[] customSpecOptions(PropObj s=null)
Added: extend public str->CustomOptionSpecial getCustomOptionSpecials(PropObj s=null)
Added: extend public void putFollowingCustom(str anchorKey, CustomSpecOption custom)
Added: extend public CustomSpecOption getFollowingCustom(str anchorKey)
Added: extend public CustomSpecOption getFollowingCustom(PartOptionItem anchor)

class PartOption

PartOption is part of the 17.0 migration surface because inserted custom options now need a public insertion hook at the option-branch level.

Added: extend public void insertPartOptionItem(int index, PartOptionItem newOption)

If you implement a custom PartOption, add support for insertPartOptionItem(...) so ProdPart.insertCustomOptions(...) and related added-option flows can splice inserted options into the correct branch.

class ProdPartOption

ProdPartOption is the standard product-part implementation of the new PartOption insertion interface.

Added: public void insertPartOptionItem(int index, PartOptionItem newOption)

The default 17.0 product-part option flow now relies on ProdPartOption.insertPartOptionItem(...) when rebuilding allPartOptions() with inserted custom options.

class PartOptionItem

PartOptionItem is now an important part of the public migration surface because 17.0 uses option identity more broadly across query import, option-special lookup, and additional-option ordering.

Added/important usage: extend public str key()
Added/important usage: extend public void setKey(str value)
Added/important usage: extend public str generateKey()
Added/important usage: extend public double upcharge(Part owner=null, Space space=null, bool translatePrice=false)
Added/important usage: extend public int sequence()
Added/important usage: extend public str getUserDefined(str type)
Added/important usage: extend public void setUserDefined(str type, str contents)

Implementers should treat key() as the stable option identifier used by query rows, option-special storage, and imported/additional-option workflows.

class SpecOption

SpecOption is now more directly part of the migration story because 17.0 relies on its stable key for option identity.

Added/important usage: public str uniqueKey
Added/important usage: public str key()
Added/important usage: public void setKey(str value)
Added/important usage: public str groupCode
Added/important usage: public str groupCode()
Added/important usage: extend public str adjustmentKey()
Added/important usage: public str specialsKey()

Old: public constructor(str code, str description, str groupDescription=null,
                        int level=1, bool exportable=true)
New: public constructor(str code, str description, str groupCode=null, str groupDescription=null,
                        int level=1, bool exportable=true)

Old: public constructor(str code, str description, str groupDescription=null,
                        int level=1, double price=0.0, bool exportable=true)
New: public constructor(str code, str description, str groupCode=null, str groupDescription=null,
                        int level=1, double price=0.0, bool exportable=true)

The practical effect is that option-special and query-row identity now follows SpecOption.key() rather than being built from the owning part special key. adjustmentKey() remains the adjustment-facing identity, while specialsKey() now follows the stable option key. groupCode is now first-class option data and is carried through option creation and import flows, rather than existing only as loosely attached metadata.

For custom option rows, this also replaces the older CustomSpecOption key-storage model. The old dedicated _specialsKey field on CustomSpecOption is no longer the source of truth; instead, the special's specialsKey() now maps to the generated option item's PartOptionItem.key() / SpecOption.uniqueKey.

class OptionSpecial

OptionSpecial now exposes setter interfaces for feature metadata used by the new option export and added-option flows.

Removed: public Part originalPart
Removed: public str originalOptStr
Removed: extend public Part originalPart=(Part value)

Added/important usage: extend public str featureCode=(str value)
Added/important usage: extend public str featureDescription=(str value)

class CustomOptionSpecial

CustomOptionSpecial now exposes explicit anchor and feature-metadata interfaces for 17.0 added-option ordering and export.

Added/important usage: public str anchorOptKey
Added/important usage: extend public str anchorOptKey=(str value)
Added/important usage: public str featureCode=(str value)
Added/important usage: public str featureDescription=(str value)

anchorOptKey identifies which normal option or added option a custom option follows. The feature setters are used when custom options are exported back out as XML, OFDA, PMX, or SIF option data.

class OptionSpecialHolder

Option specials are no longer expected to live in PartSpecialHolder.specials() for 17.0-created data. OptionSpecialHolder is the new public holder type for per-part option-special state.

Added: public class OptionSpecialHolder
Added: extend public bool any()
Added: extend public bool empty()
Added: extend public void clear()
Added: extend public void put(str key, OptionSpecial special)
Added: extend public OptionSpecial get(str key)
Added: extend public void remove(str key)
Added: extend public void removeOptionSpecials()
Added: extend public bool anySpecials()
Added: extend public bool emptySpecials()
Added: extend public void putAddition(CustomOptionSpecial custom)
Added: extend public CustomOptionSpecial getAddition(str key)
Added: extend public void removeAddition(str key)
Added: extend public void removeAdditions()
Added: extend public bool anyAdditions()
Added: extend public bool emptyAdditions()
Added: extend public CustomSpecOption[] getAdditionalOptions()

Option-special holder functions

The holder is managed through a new shared function surface in cm.abstract.part.optionSpecialHolderFunctions.cm. These names are useful search targets if your code still assumes all specials live under cSpecialHolderKey.

Added: public const str cOptionSpecialHolder = "optionSpecialHolder";
Added: public str optionSpecialHolderPropKey(Part part)
Added: public OptionSpecialHolder initOptionSpecialHolder(PropObj s, Part part)
Added: public OptionSpecialHolder getOptionSpecialHolder(PropObj s, Part part)
Added: public void removeOptionSpecialHolder(PropObj s, Part part, bool invalidateWorldPrice)
Added: public void putOptionSpecial(PropObj s, Part part, str key, OptionSpecial special, bool invalidateWorldPrice)
Added: public OptionSpecial getOptionSpecial(PropObj s, Part part, str key)
Added: public void removeOptionSpecial(PropObj s, Part part, str key, bool invalidateWorldPrice)
Added: public void removeAllOptionSpecials(PropObj s, Part part, bool invalidateWorldPrice)
Added: public void putAdditionalOption(PropObj s, Part part, CustomOptionSpecial special, bool invalidateWorldPrice)
Added: public CustomOptionSpecial getAdditionalOptionSpecial(PropObj s, Part part, str key)
Added: public CustomOptionSpecial getAdditionalOptionSpecial(PropObj s, Part part, PartOptionItem opt)
Added: public void removeAdditionalOption(PropObj s, Part part, str key, bool invalidateWorldPrice)
Added: public void removeAdditionalOption(PropObj s, Part part, PartOptionItem opt, bool invalidateWorldPrice)
Added: public void removeAdditionalOptions(PropObj s, Part part, bool invalidateWorldPrice)

class ProdPart option-special and addition APIs

ProdPart now has a larger public API for option specials, additional options, and option customization state. These APIs are used by the new product-part query import workflow.

Added: extend public OptionSpecialHolder initOptionSpecialHolder()
Added: extend public OptionSpecialHolder optionSpecialHolder(PropObj s=null)

Added: extend public OptionSpecial getOptSpecial(str key, PropObj s=null)

Old: extend public void putOptSpecial(str key, OptionSpecial special, PropObj s=null, bool invalidateWorldPrice=true)
New: extend public void putOptSpecial(str key, OptionSpecial special, bool invalidateWorldPrice, PropObj s=null)

Old: extend public void putOptSpecial(PartOptionItem opt, OptionSpecial special, PropObj s=null, bool invalidateWorldPrice=true)
New: extend public void putOptSpecial(PartOptionItem opt, OptionSpecial special, bool invalidateWorldPrice, PropObj s=null)

Old: extend public void removeOptSpecial(str optSpecialKey, PropObj s=null, bool invalidateWorldPrice=true)
New: extend public void removeOptSpecial(str optSpecialKey, bool invalidateWorldPrice, PropObj s=null)

Old: extend public void removeOptSpecial(PartOptionItem opt, PropObj s=null, bool invalidateWorldPrice=true)
New: extend public void removeOptSpecial(PartOptionItem opt, bool invalidateWorldPrice, PropObj s=null)

Old: extend public void removeOptSpecials(PropObj s=null, bool invalidateWorldPrice=true)
New: extend public void removeOptSpecials(bool invalidateWorldPrice, PropObj s=null)

Added: extend public bool isAdditionalOption(PartOptionItem opt, PropObj s=null)
Added: extend public void putAdditionalOption(CustomOptionSpecial special, bool invalidateWorldPrice, PropObj s=null)
Added: extend public CustomOptionSpecial getAdditionalOptionSpecial(str key, PropObj s=null)
Added: extend public CustomOptionSpecial getAdditionalOptionSpecial(PartOptionItem opt, PropObj s=null)
Added: extend public void removeAdditionalOption(str key, bool invalidateWorldPrice, PropObj s=null)
Added: extend public void removeAdditionalOption(PartOptionItem opt, bool invalidateWorldPrice, PropObj s=null)
Added: extend public void removeAdditionalOptions(bool invalidateWorldPrice, PropObj s=null)
Added: extend public customizationType customizationStatus(PartOptionItem option, PropObj s=null)
Added: extend public symbol{} customizationStates(PartOptionItem option, PropObj s=null)

class ProdPartSpecialMigrator

ProdPartSpecialMigrator is the new public migration helper for moving pre-17.0 product-part option specials out of PartSpecialHolder and into the new per-part holder structure.

Added: public class ProdPartSpecialMigrator extends PartSpecialMigrator
Added: public void attemptMigrateSpecials(Part part, PropObj s)
Added: extend public void attemptMigrateOptionSpecials(Part part, PropObj s)
Added: extend public void attemptMigrateCustomOptionsSpecials(Part part, PropObj s)
Added: extend public str oldOptSpecialsKey(Part part, PartOptionItem opt)
Added: extend public str oldOptSpecialsKey(PartOptionItem opt)

Override oldOptSpecialsKey(...) if your package previously saved option specials with package-specific keys.

class ProdPartCreator

ProdPartCreator is the product-part-specific creator base used for 17.0 additions and overrides. It extends PartCreator, generates a ProdPart, replays options through processOptions(...), and includes option codes in the generated flattenable key.

Added: public class ProdPartCreator extends PartCreator
Added: public PartOption[] options
Added: public constructor(PartData data, PartOption[] options=null)
Added: public Part generatePart(PropObj owner=null)
Added: public str generateFlattenableKey(Part part)
Added: extend public void processOptions(ProdPart part)

class ProdPartAddition

ProdPartAddition is the new creator type for additional product parts. Instead of applying its PartOption[] directly to the generated part, it converts them into CustomOptionSpecials and stores them as additional options in OptionSpecialHolder.

Added: public class ProdPartAddition extends ProdPartCreator
Added: public void processOptions(ProdPart part)
Added: extend public CustomOptionSpecial createCustomOptionSpecial(Part part, PartOptionItem opt)

class ProdPartOverride

ProdPartOverride is the new creator type for product-part overrides. It generates a ProdPart and applies the stored PartOption[] directly with setPartOptions(...).

Added: public class ProdPartOverride extends ProdPartCreator
Added: public void processOptions(ProdPart part)

These types participate in the core Snapper.fetchParts() customization flow through the owner-level PartCreator APIs documented in cm.core.part.

class ProdPart changed signatures and moved flows

Several existing ProdPart interfaces changed shape in 17.0.

Old: public Double upcharge()
New: public Double upcharge(bool includeChildren=false, Space space=null, bool translatePrice=true, bool invalidate=false)

Old: extend public CustomSpecOption[] customSpecOptions()
New: extend public CustomSpecOption[] customSpecOptions(PropObj s=null)

Old: public bool containsAnySpecials(PropObj s=null)
New: public bool containsAnySpecials(bool ignoreStandardSpecial=false, PropObj s=null)

Old: public Double upcharge()
New: public Double upcharge(bool includeChildren=false, Space space=null, bool translatePrice=true, bool invalidate=false)

Old: extend public CustomSpecOption[] customSpecOptions()
New: extend public CustomSpecOption[] customSpecOptions(PropObj s=null)

Old: extend public void initializePartFromItemData(ItemData item, ProjectInformation projectInfo)
New: public void initializePartFromItemData(ItemData item, ProjectInformation projectInfo)

The important runtime consequence is that product-part option upcharge is now expected to translate to the current CET currency by default through the shared translatePrice=true flow. If your manufacturer package overrides option pricing, verify that option rows and option-derived totals are still correct and are not translated twice.

The following shared import/export hooks are also now part of the effective ProdPart surface because 17.0 routes more behavior through common Part logic:

Added/changed usage: public void importOFDASpecItemTag(XmlTag tag, OFDAHeaderContent header=null)
Added: extend public void importOptionTag(XmlTag tag, OFDAHeaderContent header=null)

class ProdPart option identity

Option special keys now use the option's own stable key instead of composing a key from the part special key.

Old: extend public str optSpecialKey(PartOptionItem opt) {
         return specialsKey() # opt.specialsKey();
     }
New: extend public str optSpecialKey(PartOptionItem opt) {
         return opt.?key();
     }

If you persisted or compared option special keys manually, update that logic to use the option key directly.

Other ProdPart public changes

Added: public loadFailedResult loadFailed(ObjectFormatter formatter, LoadFailure failure)
Added: public PartInfoTree[] infoTrees()

Old: public void removeAllSpecials(PropObj s=null, bool invalidateWorldPrice=true)
New: public void removeAllSpecials(bool invalidateWorldPrice, PropObj s=null)

Added: public void removeOverrideCreator(bool invalidateWorldPrice, PropObj s=null)
Added: public void removeAdditionCreator(bool invalidateWorldPrice, PropObj s=null)
Added: public loadFailedResult loadFailed(ObjectFormatter formatter, LoadFailure failure)
Added: public PartInfoTree[] infoTrees()
Added: public void removeAllSpecials(PropObj s=null, bool invalidateWorldPrice=true)
Added: public void removeOverrideCreator(PropObj s=null, bool invalidateWorldPrice=true)
Added: public void removeAdditionCreator(PropObj s=null, bool invalidateWorldPrice=true)

cm.abstract.part.import

class ProdPartSIFImporterEnv

ProdPartSIFImporterEnv is the new SIF environment for importing ProdPart objects and their options.

Added: public class ProdPartSIFImporterEnv extends PartSIFImporterEnv
Added: public PartOptionItem currentOpt
Added: public PartOptionItem[] currentPartOpts
Added: public void beginImport(Url file, Part[] part)
Added: public void importKeyValue(str key, str value, Part[] part)
Added: public Part createPart(Object data)
Added: extend public PartOptionItem createOption(Object data, Part[] part)
Added: extend public str headerOptionKey()
Added: public void flushPart(Part[] part)
Added: extend public void flushOption(Part[] part)

The default SIF option mapping uses ON, OD, O1/OL, OP, and OG to build SpecOption objects before appending them to the imported ProdPart. In that mapping, OP now imports into SpecOption.groupCode and OG imports into SpecOption.groupDescription.

class ProdPartPMXImporterEnv

ProdPartPMXImporterEnv is the new PMX environment for creating ProdPart instances during PMX import.

Added: public class ProdPartPMXImporterEnv extends PartPMXImporterEnv
Added: public Part createPart(Object data)

This environment mainly switches the created part type to ProdPart. The PMX population hook itself remains initializePartFromItemData(...), which was already part of the older PMX path.

class ProdPartOFDAImporterEnv

ProdPartOFDAImporterEnv is the new OFDA XML environment for creating ProdPart instances.

Added: public class ProdPartOFDAImporterEnv extends PartOFDAImporterEnv
Added: public Part createPart(Object data)

class ProdPart OFDA option import hooks

These ProdPart interfaces are now part of the 17.0 import surface for OFDA XML product-part import.

Added/changed usage: public void importOFDASpecItemTag(XmlTag tag, OFDAHeaderContent header=null)
Added: extend public void importOptionTag(XmlTag tag, OFDAHeaderContent header=null)

importOptionTag(...) is the new shared hook for reading <Option> and <CustomOption> tags into SpecOption objects, including nested option tags.

cm.abstract.part.query

OptionMakeSpecialDialog

Option special generation now uses the owning Part to convert the amount from calculation currency before saving the special. This relies on the updated PartMakeSpecialDialog constructor from cm.core.part.query, so custom call sites should pass the owning part when constructing option special dialogs.

ProdPartQueryDialogBehavior

ProdPartQueryDialogBehavior now exposes import and option-drag extension points.

New: public SubWindow initImportWindow(QueryDialog dialog, Url url=null)
New: public PartImporterEnv getImporterEnv(str suffix)
New: public void beginGridDragAnimation(QueryDialog dialog, pointI dragPoint, Object dragValue)
New: public range[] getValidDragRanges(QueryDialog dialog, Object dragValue)

The option-special dialog creation path was also updated to pass the owning part into OptionMakeSpecialDialog.

ProdPartQueryDialogDataEnv

ProdPartQueryDialogDataEnv now includes public APIs for option filtering, option import, option overrides, and additional option specials. Key additions include:

New: extend public bool acceptPartOpt(Part part, SpecOption opt)
New: extend public PartOptionItem getOption(int row)
New: extend public Part getOptionParentPart(int row)
New: extend public void putOptionSpecial(int row, OptionSpecial special)
New: public void putOverride(int row, Object data)
New: extend public OptionSpecial createOptionSpecial(Part part, PartOptionItem option, bool priceReplace=true)
New: public void putAddition(int row, Object data)
New: extend public void putAdditionalOption(int row, PartOptionItem newOption)
New: extend public void putAdditionalOptionSpecial(int row, CustomOptionSpecial special)
New: extend public CustomOptionSpecial getAdditionalOptionSpecial(int row)
New: public void removeAddition(int row)
New: extend public void removeAdditionalOption(int row)
New: extend public CustomOptionSpecial createCustomOptionSpecial(Part part, PartOptionItem option)

createOptionRowData also changed its row identifier source:

Old: str optRowID = part.optSpecialKey(option)
New: str optRowID = option.key()

If you extend the product-part query data environment, review any assumptions about option row identifiers and option insertion/removal behavior.

Import-related classes

The following new public classes were added for product-part option import support:

New: public class ProdPartQueryImportWindow extends QueryImportWindow
New: public class QueryImportOptionTVI extends QueryImportTVI

These are used to display option items in the import tree and support dragging imported options into the query grid.

Other public additions

New: public customizationType customizationStatus()   // on QueryOptionRowData
New: extend public void putAddition(CustomOptionSpecial special)   // on QueryOptionRowData
New: extend public CustomOptionSpecial getAddition()   // on QueryOptionRowData
New: extend public void removeAddition()   // on QueryOptionRowData
New: extend public void putAddition(CustomOptionSpecial special)   // on QueryProdPartRowData
New: public int initialColumnWidth(str columnLabel)   // on QueryProdPartGridBuilderEnv
New: extend public Brush getStateBrush(customizationType status)   // on QueryProdPartGridBuilderEnv

These query-side APIs rely on the option identity, option customization, and additional-option APIs added in cm.abstract.part.ProdPart.

cm.abstract.pmx

cm.abstract.pmx now depends on cm.core.pmx

The abstract PMX package now imports the shared PMX core package and expects PMX model/database types to come from there.

Old: use cm.abstract.pmx;
New: use cm.abstract.pmx;
New: use cm.core.pmx;

In practice, packages that only need the order exporter can usually keep use cm.abstract.pmx;. Packages that instantiate PMX records or database objects directly should also import cm.core.pmx.

Moved PMX model and database interfaces

The following public PMX classes were removed from cm.abstract.pmx and recreated in cm.core.pmx. Update imports and fully-qualified references accordingly.

Old: cm.abstract.pmx.AttributeData
New: cm.core.pmx.AttributeData

Old: cm.abstract.pmx.Database
New: cm.core.pmx.Database

Old: cm.abstract.pmx.ItemData
New: cm.core.pmx.ItemData

Old: cm.abstract.pmx.OptionData
New: cm.core.pmx.OptionData

Old: cm.abstract.pmx.PartDetails
New: cm.core.pmx.PartDetails

Old: cm.abstract.pmx.PictureData
New: cm.core.pmx.PictureData

Old: cm.abstract.pmx.ProjectInformation
New: cm.core.pmx.ProjectInformation

The internal bridge/base helpers also moved with the same package rewrite:

Old: cm.abstract.pmx.DataDefinition
New: cm.core.pmx.DataDefinition

Old: cm.abstract.pmx.PMXNetObj
New: cm.core.pmx.PMXNetObj

PMX import helpers were rerouted to cm.core.part.import

A few interfaces were removed from cm.abstract.pmx, but they were not moved to cm.core.pmx. They now belong to the part-import layer.

Old: cm.abstract.pmx.ItemDataConverter
New: cm.core.part.import.ItemDataConverter

Old: cm.abstract.pmx.registerItemDataConverter(...)
New: cm.core.part.import.registerItemDataConverter(...)

Old: cm.abstract.pmx.getConverter(...)
New: cm.core.part.import.getConverter(...)

Old: cm.abstract.pmx.PMXFilePartSource
New: cm.core.part.import.PMXFilePartSource

Use cm.core.part.import when your package creates parts from PMX files or registers PMX ItemData converters.

PMXExporter writes the new PMX project metadata records

PMXExporter now creates and inserts additional PMX records before item export. If you extend PMXExporter, override its insert flow, or substitute your own PMX Database, account for the extra records and database calls.

Added effective usage in PMXExporter: ShipToInformation shipToInfo
Added effective usage in PMXExporter: SoldToInformation soldToInfo
Added effective usage in PMXExporter: NotesTable notesInfo
Added effective usage in PMXExporter: OrderInformation[] orderInfos

Added effective database calls:
Database.insertNotesInfo(...)
Database.insertShipToInformation(...)
Database.insertSoldToInformation(...)
Database.insertOrderInformation(...)

ItemData.optionsSeq was removed in favor of options

This is a broader API migration than the single exporter line change. In 16.5, cm.abstract.pmx.ItemData stored PMX options in optionsSeq, ItemData.operator<<(OptionData) appended into optionsSeq, and exporter code iterated item.optionsSeq. In 17.0, the shared cm.core.pmx.ItemData removes optionsSeq and keeps one option sequence named options.

Update any custom code that builds, mutates, exports, or imports PMX ItemData objects accordingly.

Old field: public OptionData[] optionsSeq
New field: public OptionData[] options

Old exporter usage: insertOptionData(itemID, item.optionsSeq)
New exporter usage: insertOptionData(itemID, item.options)

This also affects code on both sides of PMX conversion:

Export generation in 17.0 writes option rows into itemData.options
Import initialization in 17.0 reads option rows from item.options

If your package previously touched optionsSeq directly, switch all such reads and writes to options. If you overrode PMX item-generation or PMX part-initialization flows, verify that they no longer assume two different option collections exist.

cm.abstract.projectInfo

class ProjectInformationDialog

ProjectInformationDialog now treats drop-down values as key-and-label pairs instead of only returning a single string value.

Changed behavior/important usage: drop-down field values can now be returned as `<str, str>` key/label pairs
Changed behavior/important usage: drop-down field restoration now looks up the saved label first, then falls back to the saved key

If you extend the dialog or depend on the stored value format for project-information drop-downs, review any code that assumes those controls round-trip only a single string.

cm.abstract.tools.elevationG2

class ElevArrowG2

createElevationSpace() now requires setting setNewGuid explicitly.

Old: extend public ElevSpaceG2 createElevationSpace() {
New: extend public ElevSpaceG2 createElevationSpace(bool setNewGuid) {

cm.application

releaseDebugActionCard.cm

Removed: public bool dbg_verboseProfilerDump = false;
Removed: public void repairBlocks() {

cm.core

cm.core

class Snapper

cm.core.Snapper now exposes the public load and fetch hooks that drive 17.0 part-special migration.

Added/important usage: public void loaded1(ObjectFormatter formatter, LoadFailInfo failInfo)
Added/important usage: extend public void initPartSpecialMigrator(ObjectFormatter formatter)
Added/important usage: extend public PartSpecialMigrator getPartSpecialMigrator(bool init=false)
Added/important usage: extend public void migratePartSpecials(Part[] parts)

These names are useful search targets if you are debugging why a package-specific PartSpecialMigrator is or is not being discovered during drawing load.

featureFilter.cm

Removed enum that is not used anywhere in the base repository.

Removed: public enum featureDetail : field access {

ContextualViewDropDownItem

The visibility of dropDownImage field has been altered, you will need to use setDropDownImage to change the image.

Old: public Image dropDownImage : copy=reference;
New: private Image dropDownImage : copy=reference, public readable;
New: final public void setDropDownImage(Image i)

InfoTipToggle

This class has been removed. You can replace it with FaceliftToggle

Old: public class InfoTipToggle extends CheckBox {
New: public class FaceliftToggle extends CheckBox {

selectLasso2DAnimation.cm

The following interfaces in SelectLasso2DAnimation have been changed:

Old: extend public bool isTarget(Snapper s, APolyline2D pline=null, bool quickElim=true) {
New: extend public bool isTarget(Snapper s, APolyline2D pline) {

The following interfaces in SelectLasso2DAnimation have been removed:

Removed: final public void appendTargets(line2D l) {
Removed: extend public bool contained(Snapper s, APolyline2D pline=null) {
Removed: extend public bool ridiculous(rect sb, APolyline2D pline) {
Removed: extend public bool plausible(rect sb, APolyline2D pline) {
Removed: extend public GeometricFinder[] getFinders(APolyline2D pline) {
Removed: extend public int snapperBoundInPolyline(Snapper s, APolyline2D pline) {
Removed: extend public int graphInPolyline(GraphPrimitive gp, APolyline2D pline, line2D e, bool oneUncontained, bool seen) {

Query language

Deprecated functions have been removed.

Old: public void removeOldCetQLParamsFromSnapper(Snapper z) : deprecated {
New: public void removeCetQLParamsFromSnapper(Snapper z) {

class TaggableSnapper

User-modified state is no longer passed through the setItemTagInfo(..) signature. Update any overrides to use the new three-parameter form.

Old: extend public void setItemTagInfo(Part part, str key, ItemTagInfo info, bool userMod=false)
New: extend public void setItemTagInfo(Part part, str key, ItemTagInfo info)

class DVariable

DVariable now accepts stored drop-down values as key-and-label pairs in addition to plain strings.

Added/important usage: `value` can now be a `?<str, str>` pair, where the stored DVariable value becomes the first item

This supports the 17.0 project-information drop-down fix, where UI code can preserve the display label for output while still storing the underlying key.

class PackageCountColumn

Package count is now exposed as a shared core part column instead of only through the older data-symbol-specific column package.

Added: public const PackageCountColumn packageCountColumn()
Added: public class PackageCountColumn extends BasicPartColumn

PackageCountColumn reads Part.pkgCount() and is now part of the core part-column registration path.

cm.core.calc

class GlobalPartAdjustmentSum

The compatibility interfaces added for 16.5 were removed in 17.0.

Old: extend public str displayName()
New: extend public str displayName(bool showSummationLabel=true)

Old: extend public void setCells(GridWindow gw, int row, int last, Space space)
New: extend public void setCells(GridWindow gw, int row, int last, Space space, bool showSummationLabel=true)

If you override or extend these methods on custom GlobalPartAdjustmentSum classes, update your signatures to include the new showSummationLabel argument and use it when rendering the sum line label.

Summary line helpers

The following overloads for getSummaryLines were changed in 17.0 (cm/core/calc/globalPartAdjustment.cm).

Most call sites can continue to omit the new argument because it has a default value. If your code depended on the removed two-argument overloads as distinct interfaces, update it to call the three-argument version instead.

Old: public SummaryLine[] getSummaryLines(Space space, SummaryPriceInfo pInfo)
New: public SummaryLine[] getSummaryLines(Space space, SummaryPriceInfo pInfo, bool showSummationLabels=true)

Old: public SummaryLine[] getSummaryLines(AdditionalGlobalPartAdjustment[] items, SummaryPriceInfo pInfo)
New: public SummaryLine[] getSummaryLines(AdditionalGlobalPartAdjustment[] items, SummaryPriceInfo pInfo, bool showSummationLabels=true)

cm.core.collabG3

class CollFileType

isLoadable() now passes the CollFile as an argument. Useful to check if the file is loadable using CollFile's data.

Old: extend public bool isLoadable() {
New: extend public bool isLoadable(CollFileG3 file) {

cm.core.nwd

Function names have been retained, no changes beyond the following are needed.

Old: use cm.core.nwd;
New: use cm.core.sceneExport.nwd;
Old: use cm.core.nwd.export;
New: use cm.core.sceneExport.nwd.export;

cm.core.part

class Part

If your custom Part subclass overrides Ind. Tag identity or ItemTagInfo key generation, move that logic to the new override points below.

Old: extend public str itemTagKey()
New: final public str itemTagKey()
New override point: extend public str sourceId()

Old: extend public str itemTagInfoKey()
New: final public str itemTagInfoKey()
New override point: extend public str defaultItemTagInfoKey()

Old: extend public ItemTagInfo setItemTagInfo(str text)
New: extend public ItemTagInfo setUserItemTagInfo(str text)

class PartProxy

PartProxy now has a matching hook for the final flattenable-key phase.

Added: extend public void finalizeFlattenbleKey(Part part)

This gives proxy-based part implementations a dedicated extension point for adjusting the part after the flattenable key has been finalized.

Constructor terminology for stable part identity

The constructor argument previously named partSourceId is now sourceId in core Part and in downstream part subclasses that forward into it.

Old: public constructor(PartData data, str partSourceId=null)
New: public constructor(PartData data, str sourceId=null)

Old: public constructor(Snapper snapper, str articleCode, str description, double basePrice, Double optionPriceSum, ..., str partSourceId=null)
New: public constructor(Snapper snapper, str articleCode, str description, double basePrice, Double optionPriceSum, ..., str sourceId=null)

Old: public constructor(Snapper snapper, str articleCode, str description, double listPrice, ..., str partSourceId=null)
New: public constructor(Snapper snapper, str articleCode, str description, double listPrice, ..., str sourceId=null)

Added: extend public void setSourceId(str id)
Added: extend public str sourceId()
Added: extend public str{} sourceIds()

class Part customization APIs

Part now exposes public APIs for additions, overrides, and overall customization state. These are used by the new query import workflow.

Added: extend public bool isOverride(PropObj s=null)
Added: extend public void putOverrideCreator(PartCreator overrideSpecial, bool invalidateWorldPrice, PropObj s=null)
Added: extend public PartCreator getOverrideCreator(PropObj s=null)
Added: extend public void removeOverrideCreator(bool invalidateWorldPrice, PropObj s=null)

Added: extend public bool isAddition(PropObj s=null)
Added: extend public void putAdditionCreator(PartCreator additionSpecial, bool invalidateWorldPrice, PropObj s=null)
Added: extend public PartCreator getAdditionCreator(PropObj s=null)
Added: extend public void removeAdditionCreator(bool invalidateWorldPrice, PropObj s=null)

Added: extend public customizationType customizationStatus(PropObj s=null)
Added: extend public symbol{} customizationStates(PropObj s=null)

class Part special and standard-special APIs

Part now separates user-visible specials from internal standard specials, and several special-management signatures now require the invalidateWorldPrice argument before PropObj s.

Old: extend public bool containsSpecial(PropObj s=null)
New: extend public bool containsSpecial(bool ignoreStandardSpecial=false, PropObj s=null)

Old: extend public bool containsAnySpecials(PropObj s=null)
New: extend public bool containsAnySpecials(bool ignoreStandardSpecial=false, PropObj s=null)

Old: extend public PartSpecial getSpecial(PropObj s=null)
New: extend public PartSpecial getSpecial(bool ignoreStandardSpecial=false, PropObj s=null)

Old: extend public PartSpecial getSpecial(str id, PropObj s=null)
New: extend public PartSpecial getSpecial(str id, bool ignoreStandardSpecial=false, PropObj s=null)

Old: extend public void putSpecial(PartSpecial special, PropObj s=null, bool invalidateWorldPrice=true)
New: extend public void putSpecial(PartSpecial special, bool invalidateWorldPrice, PropObj s=null)

Old: extend public void putSpecial(str id, PartSpecial special, PropObj s=null, bool invalidateWorldPrice=true)
New: extend public void putSpecial(str id, PartSpecial special, bool invalidateWorldPrice, PropObj s=null)

Old: extend public void removeSpecial(str id, PropObj s=null, bool invalidateWorldPrice=true)
New: extend public void removeSpecial(str id, bool invalidateWorldPrice, PropObj s=null)

Old: extend public void removeSpecial(PropObj s=null, bool invalidateWorldPrice=true)
New: extend public void removeSpecial(bool invalidateWorldPrice, PropObj s=null)

Old: extend public void removeAllSpecials(PropObj s=null, bool invalidateWorldPrice=true)
New: extend public void removeAllSpecials(bool invalidateWorldPrice, PropObj s=null)

Added: extend public PartSpecial getStandardSpecial(PropObj s=null)
Added: extend public PartSpecial getStandardSpecial(str id, PropObj s=null)
Added: extend public void putStandardSpecial(PartSpecial special, bool invalidateWorldPrice, PropObj s=null)
Added: extend public void putStandardSpecial(str id, PartSpecial special, bool invalidateWorldPrice, PropObj s=null)
Added: extend public void removeStandardSpecial(str id, bool invalidateWorldPrice, PropObj s=null)
Added: extend public void removeStandardSpecial(bool invalidateWorldPrice, PropObj s=null)

Standard specials are a new lower-priority internal-special system. getSpecial(...) now falls back to getStandardSpecial(...) unless ignoreStandardSpecial=true is passed. Implementers should also expect standard specials to be treated differently from user specials in user-facing state such as highlighting and customization-status checks.

class PartSpecial

The PartSpecial constructor is now more permissive and can be called without explicitly passing all fields.

Old: public constructor(str partNum, str descr, bool priceReplace, double amount)
New: public constructor(str partNum=null, str descr=null, bool priceReplace=true, double amount=0)

class PartSpecialHolder

PartSpecialHolder remains part of the public cm.core.part surface, but in 17.0 it is more clearly the holder for part-level customization data. If your code previously assumed option specials also lived here forever, that assumption is no longer valid.

Changed meaning: public class PartSpecialHolder
Added: public str->PartSpecial standardSpecials()
Added: public str->PartCreator overrides()
Added: private PartCreator[] additions()
Added: private str->int additionKeyToIdx()

Added: extend public PartSpecial getStandardSpecial(str key)
Added: extend public void putStandardSpecial(str key, PartSpecial special)
Added: extend public void removeStandardSpecial(str key)

Added: extend public PartCreator getOverrideCreator(str key)
Added: extend public void putOverrideCreator(str key, PartCreator special)
Added: extend public void removeOverrideCreator(str key)
Added: extend public void removeAllOverrides()
Added: extend public void putAdditionCreator(PartCreator custom)
Added: extend public PartCreator getAdditionCreator(int index)
Added: extend public PartCreator getAdditionCreator(str key)
Added: extend public void removeAdditionCreator(int index)
Added: extend public void removeAdditionCreator(str additionKey)
Added: extend public void removeAllAdditions()
Added: extend public Part[] getAdditionalParts(PropObj s)
Added: extend public void appendAdditionKeyToIdx(str key)
Added: extend public void rebuildAdditionKeyToIdx()

Part-special helper functions

The shared helper functions in cm.core.part.partSpecialHolderFunctions.cm also changed shape in 17.0. These names are useful search targets if your code manages owner-level part specials directly.

Old: public void removeSpecialHolder(PropObj s, bool invalidateWorldPrice=true)
New: public void removeSpecialHolder(PropObj s, bool invalidateWorldPrice)

Old: public void putSpecial(PropObj s, str key, PartSpecial special, bool invalidateWorldPrice=true)
New: public void putSpecial(PropObj s, str key, PartSpecial special, bool invalidateWorldPrice)

Old: public void removeSpecial(PropObj s, str key, bool invalidateWorldPrice=true)
New: public void removeSpecial(PropObj s, str key, bool invalidateWorldPrice)

Old: public void removeAllSpecials(PropObj s, bool invalidateWorldPrice=true)
New: public void removeAllSpecials(PropObj s, bool invalidateWorldPrice)

Added: public bool containsStandardSpecial(PropObj s)
Added: public PartSpecial getStandardSpecial(PropObj s, str key)
Added: public void putStandardSpecial(PropObj s, str key, PartSpecial special, bool invalidateWorldPrice)
Added: public void removeStandardSpecial(PropObj s, str key, bool invalidateWorldPrice)
Added: public void removeAllStandardSpecials(PropObj s, bool invalidateWorldPrice)

Added: public void putOverrideCreator(PropObj s, str key, PartCreator creator, bool invalidateWorldPrice)
Added: public void removeOverrideCreator(PropObj s, str key, bool invalidateWorldPrice)
Added: public void removeAllOverrides(PropObj s, bool invalidateWorldPrice)
Added: public void putAdditionCreator(PropObj s, PartCreator custom, bool invalidateWorldPrice)
Added: public void removeAdditionCreator(PropObj s, int index, bool invalidateWorldPrice)
Added: public void removeAdditionCreator(PropObj s, str key, bool invalidateWorldPrice)
Added: public void removeAllAdditions(PropObj s, bool invalidateWorldPrice)

class PartSpecialMigrator

PartSpecialMigrator is the new base migration helper for packages that need to remap old special keys to 17.0 sourceId()-based keys.

Added: public class PartSpecialMigrator
Added: public bool pendingMigration
Added: public str{} migrated
Added: public Version version
Added: extend public void migrateSpecials(Part[] parts, PropObj s)
Added: extend public void beforeMigration(Part[] parts, PropObj s)
Added: extend public void attemptMigrateSpecials(Part part, PropObj s)
Added: extend public str oldPartSpecialsKey(Part part)
Added: extend public void afterMigration(Part[] parts, PropObj s)

If your package used a non-default pre-17.0 part-special key, override oldPartSpecialsKey(...) in a subclass.

How PartSpecialMigrator is discovered during load

The migrator lookup happens from cm.core.Snapper, which is important if you are trying to wire a package-specific migrator into drawing load.

Important load APIs on Snapper:
extend public void initPartSpecialMigrator(ObjectFormatter formatter)
extend public PartSpecialMigrator getPartSpecialMigrator(bool init=false)
extend public void migratePartSpecials(Part[] parts)

At a high level, Snapper.loaded1() calls initPartSpecialMigrator(formatter). If the snapper already has a non-empty PartSpecialHolder and the loaded package version is older than the current runtime, CET resolves this."partSpecialMigrator" through getPartSpecialMigrator(init=true), initializes it from the prop default if needed, and marks pendingMigration = true with the loaded package version. Later, migratePartSpecials(parts) checks that flag and calls migrateSpecials(parts, this).

That means a migrator is not found by package scanning or global registration. It is found by the snapper exposing a partSpecialMigrator prop/default that returns the right PartSpecialMigrator instance.

class PartCreator

PartCreator is the new base customization object used for part additions and overrides. It stores PartData, generates a stable creator key, lazily creates a Part, and can replay extended adjustments onto the generated part.

Added: public class PartCreator
Added: public constructor(PartData data)
Added: extend public str key()
Added: extend public str generateKey()
Added: extend public Part part(PropObj owner=null)
Added: extend public void invalidate()
Added: extend public Part generatePart(PropObj owner=null)
Added: extend public str generateFlattenableKey(Part part)
Added: extend public void setPartDataValues(Part part, PropObj owner=null)
Added: extend public void applyExtendedAdjustments(Part part, Space space)

If your extension needs custom addition or override generation, subclass PartCreator instead of treating additions and overrides as raw Part instances.

class Part metadata APIs

Company and catalog access are now part of the core Part API instead of only being available through higher-level part types.

Added: extend public str companyCode()
Added: extend public str catalog()
Added: extend public str catalogCode()
Added: extend public double pkgCount()
Added: extend public void generatePartDetails(PartDetails partDetails)

If you previously depended on AbsPart-specific metadata accessors, prefer the new core Part interfaces where possible. pkgCount() is now part of the shared core part surface and feeds both column/UI output and exported part details.

class Part pricing APIs

The shared core pricing APIs now consistently honor CET currency translation in more places.

Changed behavior/important usage: extend public double basePrice(bool includeChildren=false, Space space=null, bool translatePrice=true)
Changed behavior/important usage: extend public double optionPriceSum(bool includeChildren=false, Space space=null, bool translatePrice=true, bool invalidate=false)
Changed behavior/important usage: extend public Double upcharge(bool includeChildren=false, Space space=null, bool translatePrice=true, bool invalidate=false)
Changed behavior/important usage: final public double listPrice(bool includeChildren=false, Space space=null, bool translatePrice=true)
Changed behavior/important usage: final public double validListPrice(bool includeChildren=false, Space space=null, bool translatePrice=true)
Changed behavior/important usage: extend public double totalBasePrice(bool includeChildren=false, Space space=null, bool translatePrice=true)
Changed behavior/important usage: extend public double totalOptionPriceSum(bool includeChildren=false, Space space=null, bool translatePrice=true, bool invalidate=false)
Changed behavior/important usage: extend public double totalListPrice(bool includeChildren=false, Space space=null, bool translatePrice=true)
Changed behavior/important usage: extend public double totalValidListPrice(bool includeChildren=false, Space space=null, bool translatePrice=true)

The signatures are mostly unchanged, but 17.0 changes the shared runtime behavior so these methods now translate prices to the current CET currency more consistently. If your package overrides pricing logic, verify that your override neither skips the new translation path nor translates prices twice.

class PartData

Part data objects now expose package count as part of the shared core data contract.

Added: extend public double pkgCount()
Added: extend public double setPkgCount(double value)

class BasicPartData

BasicPartData now stores package count directly.

Added: public double _pkgCount = 1
Added: public double pkgCount()
Added: public double setPkgCount(double value)

class PartDetails

PMX/export part details now include package count.

Added: final public int packageCount()
Added: final public int packageCount=(int value)

cm.core.part.import

class PartImporter

PartImporter is the new abstract base class for file-based part importers.

Added: public class PartImporter : abstract
Added: public PartImporterEnv env
Added: public constructor()
Added: public constructor auto()
Added: extend public Part[] import(Url file, PartImporterEnv env=null)
Added: extend public str{} supportedFileSuffixes()
Added: extend public bool validFile(Url file)

class PartImporterEnv

PartImporterEnv is the new abstract environment type paired with PartImporter. Override it to control record import, part creation, and import lifecycle hooks.

Added: public class PartImporterEnv : abstract
Added: public bool silent
Added: public constructor auto()
Added: public constructor()
Added: extend public void beginImport(Url file, Part[] parts)
Added: extend public void import(Object data, Part[] parts)
Added: extend public Part createPart(Object data)
Added: extend public void endImport(Url file, Part[] parts)

classes PartSIFImporter, PartPMXImporter, and PartOFDAImporter

These are the new concrete importers for the built-in file formats.

Added: public class PartSIFImporter extends PartImporter
Added: public constructor(bool silent=false)
Added: public constructor(PartSIFImporterEnv env)
Added: public str{} supportedFileSuffixes()
Added: public Part[] import(Url file, PartImporterEnv env=null)

Added: public class PartPMXImporter extends PartImporter
Added: public constructor(bool silent=false)
Added: public constructor(PartPMXImporterEnv env)
Added: public str{} supportedFileSuffixes()
Added: public Part[] import(Url file, PartImporterEnv env=null)

Added: public class PartOFDAImporter extends PartImporter
Added: public OFDAHeaderContent header
Added: public constructor(bool silent=false)
Added: public constructor(PartOFDAImporterEnv env)
Added: public str{} supportedFileSuffixes()
Added: public Part[] import(Url file, PartImporterEnv env=null)
Added: extend public void importHeader(XmlTag root)
Added: extend public void importOrderLineItems(XmlTag root, Part[] data, PartImporterEnv env)
Added: extend public XmlTag[] getOrderLineItemTags(XmlTag current)

classes PartSIFImporterEnv, PartPMXImporterEnv, and PartOFDAImporterEnv

These new environments implement the default import behavior for each file type.

Added: public class PartSIFImporterEnv extends PartImporterEnv
Added: public Part currentPart
Added: public void beginImport(Url file, Part[] parts)
Added: public void import(Object data, Part[] parts)
Added: extend public void importKeyValue(str key, str value, Part[] parts)
Added: extend public void importPartTag(str key, str value)
Added: public Part createPart(Object data)
Added: public void endImport(Url file, Part[] parts)
Added: extend public str headerPartKey()
Added: extend public void flushPart(Part[] parts)

Added: public class PartPMXImporterEnv extends PartImporterEnv
Added: public Part currentPart
Added: public void beginImport(Url file, Part[] parts)
Added: public void import(Object data, Part[] parts)
Added: public Part createPart(Object data)
Added: public void endImport(Url file, Part[] parts)
Added: extend public void flushPart(Part[] parts)

Added: public class PartOFDAImporterEnv extends PartImporterEnv
Added: public Part currentPart
Added: public void beginImport(Url file, Part[] parts)
Added: public void import(Object data, Part[] parts)
Added: extend public void importOrderLineItemTag(XmlTag tag, Part[] parts, OFDAHeaderContent header=null)
Added: public void endImport(Url file, Part[] part)
Added: public Part createPart(Object data)
Added: extend public void flushPart(Part[] parts)

class Part OFDA import hooks

These are the new import-facing Part interfaces added in 17.0. They are the main Part APIs that packages need to override for the new OFDA XML importer.

Added: extend public void importOFDAOrderLineItemTag(XmlTag tag, OFDAHeaderContent header=null)
Added: extend public void importOFDAOrderLineItemChildTag(XmlTag child, XmlTag oliTag, OFDAHeaderContent header=null)
Added: extend public void importOFDATag(XmlTag tag, OFDAHeaderContent header=null)
Added: extend public void importOFDAPriceTag(XmlTag tag, OFDAHeaderContent header=null)
Added: extend public void importOFDASpecItemTag(XmlTag tag, OFDAHeaderContent header=null)
Added: extend public void importOFDACatalogTag(XmlTag tag, OFDAHeaderContent header=null)

The PMX hook initializePartFromItemData(ItemData item, ProjectInformation projectInfo) is still used by the new importer package, but that interface was already part of the older PMX import path and is not new for 17.0.

cm.core.part.query

QueryDialog

QueryDialog now extends ResizableDialogWindow instead of DialogWindow. The dialog also exposes a new right-side subwindow and resize-related API.

Old: public class QueryDialog extends DialogWindow
New: public class QueryDialog extends ResizableDialogWindow

New: public SubWindow rightWindow
New: public event clientBoundChangedEvent
New: public event resizeEndEvent
New: public event resizingEvent
New: extend public SubWindow rightWindow()
New: public sizeI minimalSize()
New: public sizeI maximalSize()

If you subclass QueryDialog or depend on its window lifecycle or layout behavior, verify that your code still works with a resizable frame and with the additional rightWindow region.

PartMakeSpecialDialog

The constructor now requires the owning Part in addition to the original PartSpecial.

Old: public constructor(Window parent, PartSpecial original, str label=$specialsDialog)
New: public constructor(Window parent, Part part, PartSpecial original, str label=$specialsDialog)

Update custom call sites to pass the owning part when opening the special dialog.

QueryControlWindow

QueryControlWindow has a broader public interface for import support, state-driven button updates, and help UI.

Old: public QueryButton specialsButton
New: public Button specialsButton

Old: public QueryButton removeSpecialsButton
New: public Button removeSpecialsButton

Old: public QueryButton exportButton
New: public Button exportButton

New: public SelectButton importButton
New: public event specialsBtnClicked
New: public event removeSpecialsBtnClicked
New: public event exportBtnClicked
New: public event importBtnClicked
New: public event helpBtnClicked
New: public str getHelpText()
New: extend public void setSpecialControlEnablement(bool enable=true, bool refresh=true)
New: extend public void update(customizationType state)

If you customized the top control window, update any code that assumed the controls were QueryButtons and consider hooking the new events instead of direct button callbacks.

QuerySubWindow

QuerySubWindow now inherits constructors from SubWindow and adds generic control and help-dialog hooks.

Old: public class QuerySubWindow extends SubWindow
New: public class QuerySubWindow extends SubWindow : inherit constructors

New: public Button helpButton
New: public void querySubWindowControlEventCB(Control c)
New: extend public void showHelpDialog()
New: extend public str getHelpText()
New: extend public void queryControlEventCB(Control c)

Use queryControlEventCB when building subwindows that route child control callbacks through the shared querySubWindowControlEventCB function. Override getHelpText() if your subwindow exposes the new help button.

Import and drag/drop types

The following new public classes were added for query import support:

New: public class QueryImportWindow extends QuerySubWindow
New: public class QueryImportTreeView extends AxTreeView
New: public class QueryImportTVI extends AxColumnsTVI
New: public class QueryImportPartTVI extends QueryImportTVI
New: public class QueryDragEventArgs
New: public class QueryGridOptionDragAnimation extends QueryGridDragAnimation

New on QueryImportWindow: public str getHelpText()

These provide extension points for file import UI, imported-part tree views, popup menu handling, help dialogs, and drag/drop behavior into the query grid.

QueryDialogBehavior

QueryDialogBehavior now includes public extension points for import-window lifecycle and import/drag handling. Key additions include:

New: extend public SubWindow initImportWindow(QueryDialog dialog, Url url=null)
New: extend public void initImportWindowEvents(SubWindow importWindow)
New: extend public SubWindow rightWindow(QueryDialog dialog)
New: extend public void openImportWindow(QueryDialog dialog, bool showFilePrompt=true, Url file=null)
New: extend public void closeImportWindow(QueryDialog dialog, bool dispose=false)
New: extend public str[] importFileFilters()
New: extend public <str, str>[] getImportFileLabelsAndSuffixes()
New: extend public PartImporter getImporter(str suffix)
New: extend public PartImporterEnv getImporterEnv(str suffix)
New: extend public void updateGridDragAnimation(QueryDialog dialog, pointI dragPoint, Object dragValue)
New: extend public void beginGridDragAnimation(QueryDialog dialog, pointI dragPoint, Object dragValue)
New: extend public range[] getValidDragRanges(QueryDialog dialog, Object dragValue)
New: extend public bool validateImportedData(Object data, QueryDialog dialog)
New: extend public bool validateImportedPart(Part part, QueryDialog dialog)
New: extend public bool validatePricing(Part part, QueryDialog dialog)
New: extend public void cleanImportedData(Object data)

If you provide a custom QueryDialogBehavior, review these new hooks and add overrides where needed to support import sources, validation rules, or custom drag/drop behavior.

Row customization APIs

QueryRowData and QueryPartRowData now expose customization-state and creator-management helpers.

New: extend public customizationType customizationStatus()

New on QueryPartRowData:
extend public void putAddition(PartCreator creator)
extend public PartCreator getAddition()
extend public void removeAddition()
extend public void putOverride(PartCreator creator)
extend public PartCreator getOverride()
extend public void removeOverride()

These APIs are used by the new import workflow and are backed by the stable identity and customization APIs added in cm.core.part.Part.

Other public additions

New: public void closeAllQueryDialogs()
New: extend public Brush getStateBrush(customizationType status)
New: public int initialColumnWidth(str columnLabel)
New: public str toolTipText()   // on EditGridCell
New: public const color ultraLightGreenColor = color(160, 190, 160)

cm.core.pmx

New package cm.core.pmx

The PMX core/runtime interfaces now live in a new package. Import it anywhere you construct PMX record objects, talk to the PMX database wrapper, or need PMX constants.

Added: package cm.core.pmx : 17.0.100;
Added: use cm.core.pmx;

Public PMX types moved from cm.abstract.pmx

These public types keep the same names but now come from cm.core.pmx.

Old: cm.abstract.pmx.AttributeData
New: cm.core.pmx.AttributeData

Old: cm.abstract.pmx.Database
New: cm.core.pmx.Database

Old: cm.abstract.pmx.ItemData
New: cm.core.pmx.ItemData

Old: cm.abstract.pmx.itemDataStatus
New: cm.core.pmx.itemDataStatus

Old: cm.abstract.pmx.OptionData
New: cm.core.pmx.OptionData

Old: cm.abstract.pmx.PartDetails
New: cm.core.pmx.PartDetails

Old: cm.abstract.pmx.PictureData
New: cm.core.pmx.PictureData

Old: cm.abstract.pmx.ProjectInformation
New: cm.core.pmx.ProjectInformation

The following previously-abstract support types also moved into the new package:

Old: cm.abstract.pmx.DataDefinition
New: cm.core.pmx.DataDefinition

Old: cm.abstract.pmx.PMXNetObj
New: cm.core.pmx.PMXNetObj

New public PMX project metadata types

cm.core.pmx exposes additional PMX record objects that can now be created and inserted explicitly.

Added: public class NotesTable
Added: public class OrderInformation
Added: public class ShipToInformation
Added: public class SoldToInformation

These are the types now used by cm.abstract.pmx.PMXExporter when exporting project-level PMX metadata.

Database has new schema-update and metadata insertion APIs

If you subclass, wrap, or call Database directly, update your code for the broader 17.0 surface.

Added: extend public void makeDatabaseStructureUpdates()
Added: final public bool checkIfColumnExists(str tableName, str columnName)
Added: final public void alterProjectInformationTableAddNewColumns(str oldTblName)

Added: final public int64 insertNotesInfo(NotesTable in_notesInfo)
Added: final public int insertOrderInformation(OrderInformation in_orderInfo)
Added: final public int insertShipToInformation(ShipToInformation in_shipToInfo)
Added: final public int insertSoldToInformation(SoldToInformation in_soldToInfo)

The constructor now also performs structure updates when opening an existing PMX database file.

ProjectInformation constructor now accepts ProjectInfo

ProjectInformation still takes the PMX target path, but it now also accepts the source ProjectInfo object so it can populate the expanded project metadata.

Old: public constructor(Url pmxTargetPath)
New: public constructor(Url pmxTargetPath, ProjectInfo projInfo=null)

PartDetails has a new package-count property

PartDetails now carries package-count data.

Added: final public int packageCount()
Added: final public int packageCount=(int value)

Shared PMX constants now come from cm.core.pmx

cReconfigCategory was moved out of cm.abstract.pmx and is now public in cm.core.pmx. The shared PMX file filter is also now exposed from cm.core.pmx for importer/exporter code.

Old: cm.abstract.pmx.cReconfigCategory
New: cm.core.pmx.cReconfigCategory

Added shared constant in cm.core.pmx: public str[] pmxFileFilter

Any package that only needs PMX constants or the PMX file-extension filter should depend on cm.core.pmx instead of cm.abstract.pmx.

cm.core.propsScheme

class PropsScheme

PropsSchemeSpecificQPInfo now takes in a World to be compatible with multiple drawings. So initObjFromScheme also takes in World as an optional argument.

Old: extend public void initObjFromScheme(PropObj obj) {
New: extend public void initObjFromScheme(PropObj obj, World world=null) {

cm.core.selection

selectionVisualizer.cm

Removed: public class FunkySelectionVisualizer extends SelectionVisualizer {

cm.core.ui

libHelpText.cm

Made showLibHelpText return the constructed window.

Old: public void showLibHelpText(Window parent, str text="No help available in BETA version.", str title=null, str key=null, int width=300, PointI pos=null, symbol pkg=null) {
New: public DialogWindow showLibHelpText(Window parent, str text="No help available in BETA version.", str title=null, str key=null, int width=300, PointI pos=null, symbol pkg=null) {
Removed: public DialogWindow showLibHelpText2(str pkg="cm.std.tools", Window parent=null, str text="No help available in BETA version.", str key=null, PointI p=null) {

cm.core.user

class userDimensionStyle

Added a bool suppressZeroFraction argument to the constructor.

Old: public constructor(symbol pkg, str key, str name, alignment textAlignment, distanceUnit unit, int precision1, distanceUnit unit2, int precision2, bool suppressZeroFraction, double arrowHSize, Class arrowHType, Class arrowHType2, double gap, double extLineExt, bool onlyPaperView=false, bool stackDims=false, Bool showDistanceUnit=null) {
New: public constructor(symbol pkg, str key, str name, alignment textAlignment, distanceUnit unit, int precision1, distanceUnit unit2, int precision2, bool suppressZeroFraction, double arrowHSize, Class arrowHType, Class arrowHType2, double gap, double extLineExt, bool suppressZeroFeet=false, bool onlyPaperView=false, bool stackDims=false, Bool showDistanceUnit=null) {

cm.draw

class LineType

Combined all 5 constructors into 1. The default argument values are the same as before in all cases except for the constructor with the bool real argument. There shouldn't have been any reason to use that constructor since "real" width lines have never been supported. But if you want to ensure the same behavior as before, specify widthStyle=lineWidthStyle.variable for any instance that previously set the bool real argument to any value.

In the majority of cases though, all that needs to be done is to add the argument hint for the width (e.g. LineType(.., .., w=5)).

Old: public constructor() {
Old: public constructor(color lineColor) {
Old: public constructor(color lineColor, lineStyle style, int width=0) {
Old: public constructor(color lineColor, double width, bool real=false) {
Old: public constructor(color lineColor, lineStyle style, lineWidthStyle widthStyle, double w) {
New: public constructor(color lineColor=black, lineStyle style=lineStyle.solid, lineWidthStyle widthStyle=lineWidthStyle.unit, int w=0) {

Also consider if you should be using the LineType constructor at all. As long as the LineType instance does not need to be modified, it is recommended to get it using the lineType(..)-function instead, which returns a cached copy for improved performance.

lineType.cm

Change the width argument from a double to an integer, which is what the value has always been converted to internally. If you have previously passed it a fractional value and is unsure what to replace it with, you can just cast it to an integer (e.g. myVar.int) to maintain the same behaviour as before.

Old: public str lineCacheKey(color c, lineStyle style, lineWidthStyle widthStyle, double width) : inline {
New: public str lineCacheKey(color c, lineStyle style, lineWidthStyle widthStyle, int width) : inline {
Old: public LineType lineType(color c, lineStyle style=lineStyle.solid, lineWidthStyle widthStyle=lineWidthStyle.unit, double width=0) {
New: public LineType lineType(color c, lineStyle style=lineStyle.solid, lineWidthStyle widthStyle=lineWidthStyle.unit, int width=0) {

cm.extension

class ExtensionManager

The interfaces to getStateContaining and getInfoContaining have been changed to allow bypassing the pkgStateCache:

Old: final public ExtensionState getStateContaining(symbol pkg)
New: final public ExtensionState getStateContaining(symbol pkg, bool skipCache=false)

Old: final public ExtensionInfo getInfoContaining(symbol pkg)
New: final public ExtensionInfo getInfoContaining(symbol pkg, bool skipCache=false)

cm.geometry

class PickLineInfo

The constructor now requires you to specify the start point and the end point of the line, in world coordinates.

Removed: public constructor(pointF ipWC, int lineIndex) {
Added: public constructor(pointF ipWC, pointF p0WC, pointF p1WC, int lineIndex) {

cm.geometry2D

angle.cm

Renamed the atan functions that take 2 arguments to be correctly called atan2.

Old: public angle atan(double y, double x) : nonfglue = ang_atan2;
New: public angle atan2(double y, double x) : nonfglue = ang_atan2;
Old: public double atand(double y, double x) : nonfglue = ang_atan2d;
New: public double atan2Rad(double y, double x) : nonfglue = ang_atan2d;
Old: public double atanquick(double y, double x) : nonfglue = ang_qatan2d;
New: public double quickAtan2Rad(double y, double x) : nonfglue = ang_qatan2d;

angleF.cm

Renamed the atan functions that take 2 arguments to be correctly called atan2.

Old: public angle atan(float y, float x) : nonfglue = angF_atan2;
New: public angle atan2(float y, float x) : nonfglue = angF_atan2;
Old: public float atand(float y, float x) : nonfglue = angF_atan2f;
New: public float atan2Rad(float y, float x) : nonfglue = angF_atan2f;
Old: public float atanquick(float y, float x) : nonfglue = angF_qatan2f;
New: public float quickAtan2Rad(float y, float x) : nonfglue = angF_qatan2f;

cm.recovery

RecoveryWizard

createLogFile() will now be package to prevent others from rotating log files accidentally. Use cmWritable("log.cmtxt") instead to fetch the current log file.

Old: public Url createLogFile(CallStack stack=null, str msg="") {
New: package Url createLogFile(CallStack stack=null, str msg="") {

cm.statistics.reporter.test

Moved AEV dialog to cm.statistics.reporter to make it available for QA Tools

Moved classes AEVEventReciever,AEVButton and AEVDialog from cm.statistics.reporter.test to cm.statistics.reporter. This also moves the methods public void startAnalyticsEventViewer() and public void stopAnalyticsEventViewer().

cm.std.architectural

library.cm

Removed the classic library. Update references to the facelifted library or remove them.

Removed: public Library stdArchitecturalLibrary() {

cm.std.print

class QuotationListChapterCreator

A new public field was added to control whether printed summary sum lines include summation type labels.

New: public bool showSummationLabels = true

If you construct or configure QuotationListChapterCreator instances in code, you can now set showSummationLabels explicitly to control whether labels such as Sell, Buy, List, or Profit are shown on sum lines.

cm.std.tools

library.cm

Removed the classic library. Update references to the facelifted library or remove them.

Removed: public Library stdWallLibrary() {

paperLibrary.cm

Removed the classic library. Update references to the facelifted library or remove them.

Removed: public Library stdPaperToolsLibrary() {
Removed: public class ViewportSnapperLimbVisibility extends LibraryLimbVisibility {
Removed: public class XCLipLimbVisibility extends LibraryLimbVisibility {

cm.std.wall

library.cm

Removed the classic library. Update references to the facelifted library or remove them.

Removed: public Library stdWallLibrary() {

class Pillar

Replaced the thickness field with a width and depth component.

Old: public double thickness;
New: public double width;
New: public double depth;
Removed: public const DistanceRange pillarThicknessDomain(1cm, 100m);

class SpecialWallFeatureSearch

Removed: extend public void drawGraphsLocal(Snapper snapper, LayerBuffer lb) {

cm.test.cmunit

testcase.cm

Added caller eval to the testPackage(..) package-argument, which causes the package argument to be set from the call location rather than the function definition location. This means that if the function is called for example from the package "cm.core.dwg.test", it will now run all tests in that same package even if you don't pass any arguments to the function.

Old: public void testPackage(symbol pkg=#:package, bool verbose=false, bool hideErrors=false) {
New: public void testPackage(symbol pkg=#:package : caller eval, bool verbose=false, bool hideErrors=false) {
Removed: public void testPackage(symbol pkg=#:package : caller eval) {

For example, if you previously called the function like so:

testPackage(#:package, verbose=true);

You can now call it like this and it will still behave the same:

testPackage(verbose=true);

cm.test.cmunit.testInstructions

class GetWindowInstruction

Some classes in getWindowInstruction.cm has been moved to their own files: See getParentWindowInstruction.cm and getChildInstruction.cm.

Two deprecated constructors have been removed:

Removed: public constructor(str windowKey, str outputKey, SrcRef src=#:src) {
Removed: public constructor(Class windowClass, str outputKey, SrcRef src=#:src) {

Instead, use one of these constructors:

public constructor(str windowKey, str outputKey, bool ensureFound=true, bool ensureUnique=true, bool ensureValid=true, bool ensureVisible=true, SrcRef src=#:src) {
public constructor(Class windowClass, str outputKey, bool ensureFound=true, bool ensureUnique=true, bool ensureValid=true, bool ensureVisible=true, SrcRef src=#:src) {

class GetChildWindowInstruction

Two deprecated constructors have been removed:

Removed: public constructor(str windowKey, str parentKey, str outputKey, SrcRef src=#:src) {
Removed: public constructor(Class windowClass, str parentKey, str outputKey, SrcRef src=#:src) {

Instead, use one of these constructors:

public constructor(str windowKey, str parentKey|, str outputKey, bool ensureFound=true, bool ensureUnique=true, bool ensureValid=true, bool ensureVisible=true, SrcRef src=#:src) {
public constructor(Class windowClass, str parentKey|, str outputKey, bool ensureFound=true, bool ensureUnique=true, bool ensureValid=true, bool ensureVisible=true, SrcRef src=#:src) {

cm.win

Icons

Changes that have been done:

  1. We now return a DibImage instead of MemoryImage. For more details, check the run-time/behavior changes section.
  2. The argument bool newSvgRenderer now defaults to true for icon loading functions.
Old: public Image icon(str name, symbol key=#default, bool debug=false)
Old: public Image icon(str name, symbol key=#default, bool newSvgRenderer=false, bool debug=false)
New: public Image icon(str name, symbol key=#default, bool newSvgRenderer=true, bool debug=false)

Old: public Image icon(str name, bool enabled, symbol key=#default)
New: public Image icon(str name, bool enabled, symbol key=#default, bool newSvgRenderer=true)

Old: public Image disabledIcon(str name, symbol key=#default)
New: public Image disabledIcon(str name, symbol key=#default, bool newSvgRenderer=true)

Old: public Image dibIcon(str name, symbol key=#default, bool debug=false)
Old: public Image dibIcon(str name, symbol key=#default, bool newSvgRenderer=false, bool debug=false)
New: public Image dibIcon(str name, symbol key=#default, bool newSvgRenderer=true, bool debug=false)

Old: public Image disabledDibIcon(str name, symbol key=#default)
New: public Image disabledDibIcon(str name, symbol key=#default, bool newSvgRenderer=true)

IconFinder

The following fields and methods have been removed:

public str->DibImage dibIconLookup();
final public Image getDib(str name, bool debug=false)
final public Image getDib(str name, bool newSvgRenderer=false, bool debug=false)
final public Image getDisabledDib(str name, bool debug=false)

The following methods have been updated:

Old: final public Image get(str name, bool debug=false)
Old: final public Image get(str name, bool newSvgRenderer=false, bool debug=false)
New: final public Image get(str name, bool newSvgRenderer=true, bool debug=false)

IconDB

The following methods have been updated to remove bool dib=false:

Old: final public Image get(str name, symbol key, bool dib=false, bool debug=false)
Old: final public Image get(str name, symbol key, bool dib=false, bool newSvgRenderer=false, bool debug=false)
New: final public Image get(str name, symbol key, bool newSvgRenderer=true, bool debug=false)

Old: final public Image getDisabled(str name, symbol key, bool dib=false)
New: final public Image getDisabled(str name, symbol key)

SvgImage

Old: public constructor(Url imageFile, sizeI size=(-1, -1), SrcRef src=#:src)
Old: public constructor(Url imageFile, bool newSvgRenderer, sizeI size=(-1, -1)
New: public constructor(Url imageFile, bool newSvgRenderer=true, sizeI size=(-1, -1)

Old: public SvgImage vectorImage(Url url, bool use=false, SrcRef src=#:src)
Old: public SvgImage vectorImage(Url url, bool newSvgRenderer, bool use=false, SrcRef src=#:src)
New: public SvgImage vectorImage(Url url, bool newSvgRenderer=true, bool use=false, SrcRef src=#:src)

LinkButton

New argument str key in constructor.

Old: public constructor(Window parent, Font font=underlineSystemFont, Brush brush=null, FrameStyle frameStyle=noFrame, str label="", color labelColor=color(0, 0, 240), alignment textSide=undefinedAlignment, Image image=null, Image disabledImage=null, color color=nocolor, sizeI size=(-1, -1), pointI margins=(0, 0), alignment align=middle, str link=null, bool showUnderline=false, function(Control button) callback=null, SrcRef src=#:src) {
New: public constructor(Window parent, Font font=underlineSystemFont, Brush brush=null, FrameStyle frameStyle=noFrame, str label="", color labelColor=color(0, 0, 240), alignment textSide=undefinedAlignment, Image image=null, Image disabledImage=null, color color=nocolor, sizeI size=(-1, -1), pointI margins=(0, 0), alignment align=middle, str key=null, str link=null, bool showUnderline=false, function(Control button) callback=null, SrcRef src=#:src) {

Foreign windows

The function showForeignWindow no longer restores the window when setting its visibility. Use restoreForeignWindow if you want the old behavior of restoring the window.

Old: public void showForeignWindow2(mwnd hwnd) = win_showForeignWindow;
New: public void showForeignWindow(mwnd hwnd) = win_showForeignWindow;

Old: public void showForeignWindow(mwnd hwnd) = win_restoreForeignWindow;
New: public void restoreForeignWindow(mwnd hwnd) = win_restoreForeignWindow;

Removed deprecated functionality

The following functions have been removed.

public bool faceliftDeveloper() : deprecated { return staffan or prismDeveloper; }
public bool isAlphaLegacy(char c) { return spellChecker.isAlpha(c); }

Drop down functionality

AppWindow

Old: final public pointI dropDownShow(pointI p, bool autoSize=true)
New: final public pointI dropDownShow(pointI p, bool autoSize=true, bool enforceMinWidth=true)

Window

Old: extend public pointI showDropDownMenu(pointI p, bool pInScreenCoords=false, bool autoSize=true)
New: extend public pointI showDropDownMenu(pointI p, bool pInScreenCoords=false,
                                           bool autoSize=true, bool enforceMinWidth=true)

WebViewConfig

We have added a new argument bool establishSocketConnection=false into the constructor.

Old: public constructor(str key,
		       str url,
		       int port=-1,
		       bool launch=false,
		       str label="CET",
		       bool showPageTitle=false,
		       bool showNavigation=true,
		       bool alwaysOnTop=false,
		       bool hideUrl=false,
		       pointI initPos=(-1, -1),
		       sizeI initSize=(-1, -1),
		       bool resizable=false,
		       sizeI minSize=(-1, -1),
		       sizeI maxSize=(-1, -1),
		       bool devMode=false,
		       webViewCB msgCallback=null) 
New: public constructor(str key,
		       str url,
		       int port=-1,
		       bool launch=false,
		       str label="CET",
		       bool showPageTitle=false,
		       bool showNavigation=true,
		       bool alwaysOnTop=false,
		       bool hideUrl=false,
		       pointI initPos=(-1, -1),
		       sizeI initSize=(-1, -1),
		       bool resizable=false,
		       sizeI minSize=(-1, -1),
		       sizeI maxSize=(-1, -1),
		       bool devMode=false,
		       webViewCB msgCallback=null,
		       bool establishSocketConnection=false)

MessageWindow

The sizeI size argument has been changed to int width.

Old: public constructor(Window parent,
                        str message,
                        Image image,
                        str key=null,
                        sizeI size=(0, 0),
                        int internalMargin=7,
                        Brush brush=ultraLightGrayBrush,
                        FrameStyle frameStyle=lightGrayPenFrame,
                        color textColor=black,
                        color linkColor=primary600,
                        color linkHoverColor=primary600,
                        int textSize=12,
                        str fontFace=null,
                        function(Control button, str key):bool linkCallback=null,
                        SrcRef src=#:src) {
New: public constructor(Window parent,
                        str message,
                        Image image,
                        str key=null,
                        int width=0,
                        int internalMargin=7,
                        Brush brush=ultraLightGrayBrush,
                        FrameStyle frameStyle=lightGrayPenFrame,
                        color textColor=black,
                        color linkColor=primary600,
                        color linkHoverColor=primary600,
                        int textSize=12,
                        str fontFace=null,
                        function(Control button, str key):bool linkCallback=null,
                        SrcRef src=#:src) {

This MessageWindow constructor now takes in argument int width.

Old: public constructor(Window parent,
                        str message,
                        messageType msgType=messageType.undefined,
                        str key=null,
                        int internalMargin=7,
                        function(Control button, str key):bool linkCallback=null,
                        SrcRef src=#:src) {
New: public constructor(Window parent,
                        str message,
                        messageType msgType=messageType.undefined,
                        str key=null,
                        int width=0,
                        int internalMargin=7,
                        function(Control button, str key):bool linkCallback=null,
                        SrcRef src=#:src) {

eventLogG3.cm

statsMainExtensionPackage now accepts argument bool allowGuess to try guessing the main extension package via the provided package.

Old: public symbol statsMainExtensionPackage(symbol pkg)
New: public symbol statsMainExtensionPackage(symbol pkg, bool allowGuess=false)

getMainExtensionPackage now accepts argument bool skipCache to allow bypassing cached results

Old: public symbol getMainExtensionPackage(symbol pkg)
New: public symbol getMainExtensionPackage(symbol pkg, bool skipCache=false)

cm.win.advanced

FilmStripView

The following classes have been removed as film strip view functionality has been removed.

Removed: public class FilmStripView extends ThumbNailView {
Removed: public class PreviewWindow extends SubWindow {

The following fields and methods have been removed in ExploreDialog

Removed: public PreviewWindow previewWin;
Removed: extend public PreviewWindow buildPreviewWin() {
Removed: extend public void refreshPreviewWin() {
Removed: extend public void setPreviewContent(Image image=null, str label=null) {
Removed: extend public void updatePreviewButtons(bool disablePrev, bool disableNext) {
Removed: extend public sizeI previewImageSize() {
Removed: extend public bool filmStripMode() {

custom.accessories.genericElectrical

library.cm

Removed the classic library. Update references to the facelifted library or remove them.

Removed: public Library genericElectricalLibrary() {
Old: public Library faceliftElectricalLibrary() {
New: private Library faceliftElectricalLibrary() {

custom.accessories.lights

library.cm

Removed the classic library. Update references to the facelifted library or remove them.

Removed: public Library classicStdLightsLibrary() {
Old: public Library faceliftStdLightsLibrary() {
New: private Library faceliftStdLightsLibrary() {

custom.accessories.medical

library.cm

Removed the classic library. Update references to the facelifted library or remove them.

Removed: public Library medicalLibrary() {
Old: public Library faceliftMedicalLibrary() {
New: private Library faceliftMedicalLibrary() {

custom.accessories.plants

catalogues/library.cm

Removed the classic library. Update references to the facelifted library or remove them.

Removed: public Library stdPlantsLibrary() {
Old: public Library faceliftPlantsLibrary() {
New: private Library faceliftPlantsLibrary() {

custom.dataCatalog

Component Tab and Component Tab Creator End of Life

The following interfaces will be removed as part of the Component Tab and Component Tab Creator EOL effort:

custom.dataCatalog

// Functions
Removed: public void dcShowToolboxCreatorVendorChangeWarning(DataCatalog catalog)

custom.dataCatalog.builder

// Functions
Removed: public DcToolboxCreatorDialog dcToolboxCreatorDialog()
Removed: public DcToolboxCreatorDialog dcShowToolboxCreatorDialog()
Removed: public DcToolboxCreatorDialog dcShowToolboxCreatorDialog(bool setFocus)
Removed: public void dcCloseToolboxCreatorDialog()

// Classes
Removed: public class DcToolboxCreatorDialog extends DsToolboxCreatorDialog
Removed: public class DcAnimationTreeViewAnimationEnv extends DsDragAnimationEnv
Removed: public class DcDataCatalogLimbEnv extends DsDataCatalogLimbEnv
Removed: public class DcToolboxCreatorToolboxCards extends DsToolboxCreatorToolboxCards

custom.dataCatalog.builder.productCatalog

// Classes
Removed: public class DcProductCatalogToolboxProductReferencesEnv extends DcProductCatalogReferencesValidationEnv {
Removed: public class DcProductCatalogToolboxReferencesEnv extends DcValidationEnv
Removed: public class DcProductCatalogToolboxProductOptionsEnv extends DcValidationEnv

class DcProductLevelEditSubWindow

Removed: extend public void updateActivation()

class DcTableOfContentsSubWindow

// Field
public NoteWindow noteWindow;

// Methods
Removed: extend public void openToolboxCreator()
Removed: extend public void buildNoteWindow()
Removed: extend public void updateNote()

class DcTableOfContentToolboxSubWindow

Removed: public DsButton toolboxCreatorBtn;
Removed: extend public void updateActivation()

class DcTableOfContentsTreeView

Removed: public bool keyCode(Window originator, KeyCode keyCode)
Removed: public bool acceptTVI(TreeViewItem item)

custom.dataCatalog.builder.undo

// Classes:
Removed: public class DcTbOptionsValidationUndoOp extends DcUndoOp
Removed: public class DcProductCatalogAddToolboxesUndoOp extends DcUndoOp
Removed: public class DcProductCatalogRemoveToolboxesUndoOp extends DcProductCatalogAddToolboxesUndoOp

custom.dataCatalog.builder.scheme

// Classes
Removed: public class DcPsLayoutReferencesValidationEnv extends DcValidationEnv

custom.dataCatalog.builder.validation

// Classes
Removed: public class DcCompTabValidationResult extends DcValidationResult

Functions:
Removed: public void dcNavigateToToolboxCreator()
Removed: public void dcNavigateToToolboxCreatorCard(str code)

custom.dataCatalog.builder

class DcSIFExportEnv

The duplicate public constructor shape has been removed. The remaining constructor places catalogCodeOverride last, after fileRule3D and fileRule2D.

Removed: public constructor(str baseFileName, str[] priceLists, Url outputDir,
                            DataCatalog catalog, str preferredLanguage=null,
                            bool allowAlternateLanguage=true, str productCatalogKey=null,
                            str catalogCodeOverride=null,
                            bool filterProductsByCatalog=true,
                            bool exportMaterials=false,
                            bool renderGMaterials=false,
                            bool exportMaterialResolutions=false,
                            bool exportModels=false,
                            bool ignoreUndefined=true,
                            bool includeOFDAParams=false,
                            bool useInFile=false,
                            bool generateSifSafeFeatures=false,
                            bool fixProductRootMultiGraphics=false,
                            <str, bool, str, bool> fileRule3D=null,
                            <str, bool, str, bool> fileRule2D=null)

Supported constructor:
public constructor(str baseFileName, str[] priceLists, Url outputDir,
                   DataCatalog catalog, str preferredLanguage=null,
                   bool allowAlternateLanguage=true, str productCatalogKey=null,
                   bool filterProductsByCatalog=true,
                   bool exportMaterials=false,
                   bool renderGMaterials=false,
                   bool exportMaterialResolutions=false,
                   bool exportModels=false,
                   bool ignoreUndefined=true,
                   bool includeOFDAParams=false,
                   bool useInFile=false,
                   bool generateSifSafeFeatures=false,
                   bool fixProductRootMultiGraphics=false,
                   <str, bool, str, bool> fileRule3D=null,
                   <str, bool, str, bool> fileRule2D=null,
                   str catalogCodeOverride=null)

If your subclass constructor previously passed a positional null only to disambiguate catalogCodeOverride, you can remove that workaround and call the remaining constructor shape directly.

custom.dataCatalog.builder.geometry

class DcProductListSubWindow

Added 2 new parameters to updateProductDD to flag that first/last product is selected.

Old: extend public void updateProductDD(bool updateCard=true)
New: extend public void updateProductDD(bool updateCard=true, bool selFirstProd=false, bool selLastProd=false)

Added 2 new parameters to updateSelProd to flag that first/last product is selected.

Old: extend public void updateSelProd(int start) 
New: extend public void updateSelProd(int start, bool selFirstProd=false, bool selLastProd=false)

custom.dataCatalog.builder.ui.catalogTreeView

class DcAddProductTreeViewItem

Added 1 new parameter to 'dcBuildAddProductTreeViewItem' to keep track of the additional product's parent product.

Old: public DcAddProductTreeViewItem dcBuildAddProductTreeViewItem(DsiAddProductRefType prod, CatalogTreeViewEnv env)
New: public DcAddProductTreeViewItem dcBuildAddProductTreeViewItem(DsiAddProductRefType prod, CatalogTreeViewEnv env, DsProductType parentProd)

custom.fika

class FikaDsPartSpecialMigrator

FikaDsPartSpecialMigrator is the package-specific migrator used by Fika snappers.

Added: public class FikaDsPartSpecialMigrator extends DsPartSpecialMigrator
Added: public str oldPartSpecialsKey(Part part)

oldPartSpecialsKey(Part part) handles multiple historical key formats:

  • before 16.5 it falls back to the article code
  • before 17.0 it uses article code plus creatorKey()
  • otherwise it delegates to super(..)

Snapper prop partSpecialMigrator

Fika snappers now opt in to migration by exposing a PartSpecialMigrator "partSpecialMigrator" prop/default.

Added/important usage: PartSpecialMigrator "partSpecialMigrator" {
    Object default(..) {
        return FikaDsPartSpecialMigrator();
    }
}

If your package has older custom key history, this is the pattern to copy: provide the prop on the snapper family and return the right subclass for that package.