cet.runtime

Timeout changes for CET updates

We've added better timeout handling for CET updates. Previously when the CET update timed out due to unexpected errors, CET would only show that the update timed out but would not stop until the user aborted the update. We have changed this so that the update process tries to detect if the update process has terminated due to unexpected error and report the failure to the user now.

putIgnoreDir() changes in cm.extension

The rescursive behavior of putIgnoreDir() has been corrected in 17.5. To minimize migration effort, the recursive parameter now defaults to false, preserving the previous behavior for existing code.

Previously, only the specified directory was added to the ignore list due to an implementation issue. In the recursive case, instead of adding each discovered subdirectory, the method repeatedly adds the original directory to the ignore list, producing duplicate entries and failing to add the subdirectories into the ignore list.

Existing code that calls putIgnoreDir() without specifying the recursive parameter should continue to behave as before. Code that explicitly specifies subdirectories individually is also unaffected.

The corrected recursive behavior makes it possible to ignore an entire directory tree by calling putIgnoreDir(dir, recursive=true), which now registers both the specified directory and all of its subdirectories into the ignore list.

cm.abstract.dataSymInterface

class MtrlApplication

The _uniqueKey field in MtrlApplication was added to speed up unique key generation for certain environment. However, this field was also mistakenly streamed into DB3 format, resulting in unintended data entry being saved to the file. From 17.5 onwards, this field will be excluded from DB3 saving. The saved DB3 in 17.5 should remain compatible when opened in both older and newer versions of CET.

External Reference Key (E-KEY) matching behavior changes

The changes to External Reference Key (E-KEY) matching behavior are made for two main reasons:

  • Introducing AND condition to align with the E-KEY behavior defined in the OFDA schema.
  • Ensure OR condition is still achievable to avoid breaking existing catalogue implementation

Old Behavior

Prior to 17.5, the E-KEY matching was evaluated independently for each selected option, using an OR condition across all keys. If any E-KEY on a selected option matched an E-KEY on the Product's External Reference, it was considered a match.

New Behavior

The optionExternals and optionExternalsFromExtKeys methods in the DsiPData class have been changed so that the matching logic is evaluated using the combined set of E-KEYs from all selected options. The new matching logic is descriped as follow:

  • AND across types: If an External Reference contains multiple E-KEY types, at least one E-KEY from each type must match.
  • OR within a type: If an External Reference contains multiple E-KEYs of the same type, matching any one of those E-KEYs satisfies that type.
  • Matching E-KEYs can come from different selected options. They are combined when evaluating whether the External Reference matches.

For example, given the following E-KEYs on an External Reference (E-KEY format: Type/Value):

E-KEYs in a Product's External Reference: X/A, X/B, Y/C

The matching condition is: (X/A OR X/B) AND Y/C

This means the selected options must contain either X/A or X/B, as well as Y/C, for the External Reference to match.

When is migration required?

Existing catalogues using multiple E-KEY types should be reviewed, as different E-KEY types are now evaluated using an AND condition. All E-KEY types defined on an External Reference must be satisfied by the selected options for it to match.

The migration work is mainly required on the catalogue side. For more details on how to migrate the catalogue, please refer to this page.

Remove uninstalled catalogs

We have updated the functionality for the "Keep catalogue files after uninstalling catalogue" option in the control panel under the "Catalogues" tab. Previously this functionality was intended to remove the files in the portfolio (cid) folder after all the catalogs in the portfolio were turned off (this state was known as the portfolio uninstalled state). However this did not work correctly.

We have fixed this functionality to work correctly now so that when the option is unchecked, all the catalogs under the portfolio have been turned off, the portfolio folder in the catalog directory will be removed now. Additionally when an extension is uninstalled when the option is unchecked, we remove all related portfolio folders that were registered by that extension. This removal is done silently and over time to minimize interruptions to the user experience.

cm.abstract.dataSymbol

Part Measurements and Generic Codes

Configura SIF rows generated for data-symbol parts now include VO (volume), WD (width), DP (depth), and HT (height). A value from Part.genericCode() is written as CG; TAG2 supplies CG only when the part has no generic code.

OFDA measurement values are now emitted through Part.xmlMeasurement(). The type, measurement system, and unit remain XML attributes, while numeric values are normalized through the shared conversion helper.

OFDA XML 04.02.00 Export Compatibility

DsPart.xmlOptions() now writes OmitOnOrder before the option price. This changes the order of elements in exported OFDA XML without changing their values. Extensions or integrations that compare or parse option elements positionally must update for the 04.02.00 ordering. See the cm.abstract.ofdaXml migration notes for the other OFDA XML output changes.

cm.abstract.draw

class DrawMeasure

The documentation for d has been corrected. It used to say that d was the shortest leg length among p0 and p1. Existing dimension values are not changed, but d should now be interpreted as the extension length from p0.

If your code needs the shortest leg length, call minLegLength() instead.

cm.abstract.engine.ofml

Apply OFML block mapping to its UV mapping

Updated OFML graphics so that it applies the block mapping and rotate parameter to its UV mapping.

cm.abstract.materialHandling

MhPrimPopulatorStepper now includes previous collision primitive when calculating next step

Previously in MhPrimPopulatorStepper.nextStep(MhPopulator populator, Object obj) the steps returned only contained the CollisionPrimitive of the passed in obj. It did not contain the CollisionPrimitive of the steps that came before it, meaning that when checking for collision with the previousStep, it does not check for collision with the primitives of the steps that came before it. We have updated this method to include primitives from the previous steps as well in each returned step.

public class MhPrimPopulatorStepper extends MhLimitPopulatorStepper {

Old:
    public MhPopulatorStep nextStep(MhPopulator populator, Object obj) {
                ...
                prim = mhInstanceCollisionPrim(prim, moveTransform(dp.v));
                if (!(endPrim and primConflicts(prim, endPrim))) {
                    return MhPopulatorStep(l, stepSize, prim);
                }
    }


New:
    public MhPopulatorStep nextStep(MhPopulator populator, Object obj) {
                ...
                MhCollisionPrimitiveSet set(null, null);
                set << mhInstanceCollisionPrim(prim, moveTransform(dp.v));
                if (lastStep) set << lastPrim;
                prim = set;

                if (!(endPrim and primConflicts(prim, endPrim))) {
                    return MhPopulatorStep(l, stepSize, prim);
                }
    }
}

unitLoad lookup fallbacks

As part of our efforts to support having no unit loads generated for levels, we've added some fallback lookups to minimize cases where unit loads are not generated when they actually should be, such as trying to insert a unit load from the toolbox when the configuration is currently set to no unit load.

MhStorageConfiguration.unitLoadKey() has been updated to also check unitLoad() if there is no value for the unitLoadKey property. unitLoad() has also been updated to work with compartment types.

public class MhStorageConfiguration extends MhSystemConfiguration {

Old:
    extend public Str unitLoadKey() {
        return getValue(cMhUnitLoadKeyPK).?Str;
    }


New:
    extend public Str unitLoadKey() {
        Str res = getValue(cMhUnitLoadKeyPK).?Str;
        if (res) return res;

        if (UnitLoad ul = unitLoad()) {
            return ul.gid.hex;
        }

        return null;
    }


Old:
    extend public UnitLoad unitLoad(Object env=null) {
        return getValue(cMhUnitLoadPK, env=env).?UnitLoad;
    }


New:
    extend public UnitLoad unitLoad(Object env=null) {
        UnitLoad res = getValue(cMhUnitLoadPK, env=env).?UnitLoad;
        if (res) return res;

        for (compType in orderedCompartmentTypes()) {
            if (UnitLoad ul = compType.compProps.unitLoad) {
                return ul;
            }
        }

        return null;
    }
}

MhUnitLoadSpawner.shapeCreationProps() has a small change to find first unitLoadKey from domain if configuration does not return a unitLoadKey.

public class MhUnitLoadSpawner extends MhStorageSpawner {

Old:
    public str->Object shapeCreationProps() {
            ...
            if (!ul) {
                SubSet ss = config.getDomain(cMhUnitLoadKeyPK);
                if (ss.any) ?key = ss.next(key);
            }

            return props { unitLoadKey=key };
        }
    }


New:
    public str->Object shapeCreationProps() {
            ...
            if (!ul) {
                SubSet ss = config.getDomain(cMhUnitLoadKeyPK);
                if (ss.any) {
                    if (!key.any) ?key = ss.first();
                    if (?str next = ss.next(key)) key = next;
                }
            }

            return props { unitLoadKey=key };
        }
    }
}

Behavior changes for spawners

MhRackFrameSpawner was mistakenly missing a behavior mhRowChildCopyPasteBehavior in its method override of MhBehavior[] customOtherBehaviors(). This has now been added so if you are also overriding customOtherBehaviors() to add this behavior in after super(), that can now be removed.

public class MhRackFrameSpawner extends MhFrameSpawner {

Updated:
    public MhBehavior[] customOtherBehaviors() {
        ...
        res << mhRowChildCopyPasteBehavior;
        return res;
    }
}

MhFrameSpawner now has an override for customDebugBehaviors() to use mhDebugLinksBehavior.

public class MhFrameSpawner extends MhStorageSpawner {

    public MhBehavior[] customDebugBehaviors() {
        return [MhBehavior: mhDebugLinksBehavior];
    }
}

MhSpacerSpawner has removed mhDebugLinksBehavior from customOtherBehaviors() and moved it to customDebugBehaviors().

public class MhSpacerSpawner extends MhStorageSpawner {

Old: public MhBehavior[] customOtherBehaviors() { ... res << mhDebugLinksBehavior; return res; }

New: public MhBehavior[] customOtherBehaviors() { ... return res; }

New: public MhBehavior[] customDebugBehaviors() { return [MhBehavior: mhDebugLinksBehavior]; } }

MhUnitLoadSpawner has removed mhDebugResolverPrimitivesBehavior from customOtherBehaviors() and moved it to customDebugBehaviors().

public class MhUnitLoadSpawner extends MhStorageSpawner {

Old:
    public MhBehavior[] customOtherBehaviors() {
        ...
        res << mhDebugResolverPrimitivesBehavior;
        return res;
    }

New:
    public MhBehavior[] customOtherBehaviors() {
        ...
        return res;
    }


New:
    public MhBehavior[] customDebugBehaviors() {
        return [MhBehavior: mhDebugResolverPrimitivesBehavior];
    }
}

MhSnapperInfo changes

When a MhSnapperInfo is appended to MhSnapperBehavior, we no longer suppress the removeChild and setParent snapper functions if it was a silent append. They will now be called with the silent flag passed into them, allowing the ChildSnapperNode family to be appropriately updated.

public class MhSnapperBehavior extends MhBehavior {

Old:
    extend public void append(MhSnapper snapper, bool silent) {
        init? infos();
        MhSnapperInfo info = createSnapperInfo(snapper);
        infos << info;
        
        if (!silent) {
            snapper.parent.?removeChild(snapper);
            snapper.setParent(null);
        }
    }


New:
    extend public void append(MhSnapper snapper, bool silent) {
        init? infos();
        MhSnapperInfo info = createSnapperInfo(snapper);
        infos << info;
        
        snapper.parent.?removeChild(snapper, silent=silent);
        snapper.setParent(null, silent=silent);
    }
}

Master link changes

The function MhMasterLinkFinalizeFunction has had it's multiChildrenLink functionality modified. In linkSiblingAndCousin(MhEngine engine, MhEngineEntry entry, Transform rootParentTransform), it now only links bays and frames. This change was made to avoid linking levels together with anything, as it was linking spanning levels with frames and bays.

public class MhMasterLinkFinalizeFunction extends MhSystemEngineFunction {

    extend public MhEngineEntry[] getAllowedMultiLinkChildren(MhEngineEntry[] children) {
        MhEngineEntry[] res(children.count);
        MhEngineEntryFilter filter = multiLinkChildrenFilter();
        for (child in children) {
            if (filter.accepts(child)) {
                res << child;
            }
        }

        return res;
    }


    extend public MhEngineEntryFilter multiLinkChildrenFilter() {
        return mhFrameOrBayEntryFilter;
    }
}

cm.abstract.mezzanine

Gates new property

AbsMezzGate has a new property openRatio that is visible by default in quick properties that is meant to represent the degree to which the gate graphics is open. If you wish to utilize this property, you'll have to update your get3D methods to offset the graphics by openRatio. Otherwise hiding this property is also an option.

cm.abstract.ofdaXml

Generic Codes and Base Part XML Export

OfdaXMLOrderLineProxy.xmlSpecItemDataFromPart() now calls Part.xmlMeasurements() and Part.xmlUserDefined() by default. OfdaXMLOrderLineProdProxy writes product options and then delegates to this base behavior. Custom proxies that override xmlSpecItemDataFromPart() without calling super() will not receive the new common measurement and generic-code output.

DiscountCategory is populated from Part.genericCode(). The UserDefined generic-code value uses the same interface and falls back to the TAG2 label when no generic code is available. Integrations should account for these newly populated elements.

OFDA XML 04.02.00 Export Compatibility

OfdaXMLOrderLineProxy.xmlGeneratePartAttributes() now writes one Comment per part attribute. The previous combined value:

<Comment>
  <Type>LineNote</Type>
  <Value>Note : Description</Value>
</Comment>

is replaced by separate note and description values:

<Comment>
  <Type>OtherType</Type>
  <OtherType>Note</OtherType>
  <Description>Description</Description>
</Comment>

Code that consumes, validates, compares, or transforms exported OFDA XML must account for the new attribute structure. In particular, consumers should no longer expect the note and description to be combined in a Value element.

Element ordering has also changed:

  • Line-item pricing is written before comments and part attributes.
  • Part attributes are written before individual tags and specification-item data.
  • Product options are written before measurements.
  • OmitOnOrder is written before option pricing.

XML consumers and snapshot/reference files that depend on element order must be updated.

getOfdaXMLProxy(Part part) now searches the part's complete class hierarchy for the first registered package proxy. The previous search stopped after 15 inheritance levels. Deeply inherited part classes may therefore resolve a proxy where they previously returned null; extensions should verify that the nearest registered package proxy is appropriate for those classes.

cm.abstract.office

Extensible Type Elevation Merging

Calling mergeAll() on a non-panel TypeElevation now collects split TypeElevation objects and removes them before inserting the merged elevation. This replaces the previous panel-only search.

The base implementation can collect split elevations belonging to other TypeElevation subclasses in the same space. Extensions whose elevation objects must only merge with the same product, system, or subclass should override collectMergers() and append only compatible objects to the supplied set. PanelTypeElevation already does this to retain panel-only merging.

cm.abstract.part

Part Dimensions and Special Creation

ProdPartCreator now copies the supplied option sequence. Later changes to the caller's original sequence no longer change the creator's options.

ProdPart.internal_generateConfiguraSifRows() now includes weight, volume, width, depth, height, source/package code, and generic code. A stored or adjusted generic code is emitted as CG; TAG2 is used for CG only when no generic code is available.

ProdPartAddition and ProdPartOverride now select their behavior through ProdPartCreator.optionHandling. Existing streamed instances that lack this field are migrated to addition or override respectively when loaded.

cm.abstract.part.query

Multiline Query and Article View Text

OptionMakeSpecialDialog now creates optDescTF as a FormattedTextArea with line breaking. The control is 100 pixels high and enables automatic scrolling after its size has been established.

Old: optDescTF = FormattedTextField(this,
                                    font=smallSystemFont,
                                    frameStyle=flatFrame);

New: optDescTF = FormattedTextArea(this,
                                   font=smallSystemFont,
                                   frameStyle=flatFrame,
                                   lineBreak=true);
New: optDescTF.h = 100;
New: optDescTF.autoScroll = true;

Custom layouts or UI automation that depend on the previous single-line control or dialog dimensions should be updated for the taller description area.

cm.application

Separate menu entries for horizontal and vertical split views

The single split-view menu item has been replaced with separate menu items for horizontal and vertical split layouts:

cm.application.menuStdViews

// Menu item keys
Old: views#twoViews
New: views#horizontalSplitViews
New: views#verticalSplitViews

cm.core

cm.core

Handling quarantine of root parents when child snappers crash

Crash isolation has been improved for parent-child snapper hierarchies.

Previously, when a child snapper crashed, only that child was converted into an ExceptionProxySnapper. During restoration, the child snapper could be restored independently and attempt to enter the space without its parent, causing CET to crash because child snappers cannot exist directly in a space.snappers.

To prevent this, the runtime now quarantines the root parent whenever any snapper in the hierarchy crashes. This ensures the entire parent-child hierarchy is isolated and later restored together.

As a result:

  • The root parent and all of its descendants become ExceptionProxySnapper.
  • The entire hierarchy is restored as a single unit (could be seen from the drawing).
  • Parent-child relationships are preserved throughout isolation and restoration.
  • Child snappers are never restored directly into a space without their parent.

Implementation

Before calling isolateCrashingSnapper(..), the runtime now resolves the crashing snapper's root parent, ensuring parent-child hierarchies are quarantined first before restoring them as one ExceptionProxySnapper.

Files affected

  • cm/core/ExceptionProxySnapper.cm
  • cm/core/stream/load.cm
  • cm/core/space.cm
  • cm/core/view2D.cm
  • cm/core/view3D.cm
  • cm/core/snapAlternative.cm

For more implementation details, refer to this merge request !44030.

Split-view Resource Label

The single split-view resource label has been replaced with separate labels for horizontal and vertical split layouts:

Old: $twoViewsMenuLabel
New: $horizontalViewsMenuLabel
New: $verticalViewsMenuLabel

Split-View Orientation and Divider Interface Changes

The meanings of the remaining split multiViewState values are now orientation-based:

  • multiViewState.horizontal displays the 2D view above the 3D view.
  • multiViewState.vertical displays the 2D view to the left of the 3D view.

Review conditionals that use these values even if they still compile. Also review any code that persists or exchanges their integer representations: horizontal is now 3, while vertical remains 2 but represents the left/right layout.

Preserving Part Adjustments When Resetting Item Tags

TaggableSnapper.resetItemTags() now calls resetPartItemTagInfos() before removing displayed item tags. The reset is canceled if that hook returns false.

For adjusted parts with user-modified Ind. Tags, the default implementation asks the user whether to preserve adjustments. Choosing Yes migrates each adjustment to the key produced by the default tag; choosing No resets the tags without migrating adjustments; closing the prompt cancels the entire reset. User tag information unrelated to the snapper's raw parts is no longer cleared as a side effect.

PsLayoutEditLabelDialog is now fixed size

Changed PsLayoutEditLabelDialog to be a fixed size now.

cm.core.calc

Multiline Query and Article View Text

When ArticleViewSnapper has Use newline enabled, information-row text returned by PartInfoColumn or BasicPartInfoTreeColumn is now passed through ArticleViewSnapperGText.breakLinesViaFormatter(). Long values can therefore wrap onto multiple lines and increase the row height in article-view previews and output.

New: gText = gText(indent # output, c.alignment);
New: if (useNewline) gText.breakLinesViaFormatter();

Custom information columns, visual comparisons, or layouts that assume one line per information row should account for the wrapped output.

cm.core.part

Query Dialog Sidebar and Model Import

Only one Query sidebar tab is expanded at a time. A tab's window is cached while the Query dialog remains open, so switching tabs preserves its contents; closing the dialog discards that state.

Applying an imported model creates or updates the queried snapper's graphical special after the user confirms the alignment options. Revert removes that graphical special and restores the owner's current graphics in the preview.

QuerySubWindow now initializes with stdLightFrame/frameStateDown defaults and invokes initEvents() automatically. Subclasses that require an unframed window must pass frameStyle=noFrame, and subclasses that previously wired events outside construction should avoid registering the same observers twice.

Generic Part Codes and Export Data

Generic-code lookup now prefers an adjusted value, then allows PartProxy.genericCode() to provide a value, and otherwise uses the value stored on PartData. Flattening a part preserves the stored generic code. Importing part data now stores item.genericCode directly instead of converting it into an adjusted value.

The Generic Code calculation column uses Part.genericCode() first and retains TAG2 as a fallback. Extensions that previously treated TAG2 as the only generic-code source should use the new interface.

Part Special Handling Helpers

containsSpecial(PropObj) now returns true only when the object's PartSpecialHolder contains data, rather than merely when a holder exists. Code that used an empty holder as a presence flag must use a different check.

applyCustomParts() now returns immediately for a null part sequence, applies additions, and then applies overrides through the two new helper functions.

Query Dialog API Follow-up

QueryButton.press() now invokes the inherited Button.press() before its onClick event. A constructor callback and an onClick observer can therefore both run for one press; verify that handlers do not perform the same action twice.

QueryTabWindow.setVisible(true) no longer calls alignControls() automatically. Custom tab windows that depend on realignment when shown must do so from their visibility handler or another appropriate lifecycle method.

The model-import preview now restores its initial camera location and recenters the extents whenever the preview is refreshed.

Part Owner Identification

Part

PartSourceInfo will be set during construction of a Part. The itemTagKey field on PartSourceInfo for a given Part after first setting the sourceId and when sourceId changes.

setUserItemTagInfo(str text) has been updated to use loop over PartSourceInfos instead of Snapper owners.

WorldPart

Added loaded0 call to initialize empty partSourcInfo.

Preserving Part Adjustments When Resetting Item Tags

Part.resetItemTagInfo() now restores the default ItemTagInfo across every owner, clears the cached final key, and returns the default info. Code that relied on the returned object representing the former user-modified info must be updated.

When an adjustment key changes, migrateAdjusmentKeys() now copies the adjustment to the new key instead of changing the existing adjustment in place. With markOldPending=true, the old adjustment remains available while it is active on another part and is silently removed after it becomes inactive rather than appearing as an orphan adjustment.

Refreshing a SinglePartAdjustment no longer replaces a previously stored adjustment currency with null. A non-null currency from the current part still takes precedence.

cm.core.part.query

Multiline Query and Article View Text

PartMakeSpecialDialog now initializes its part-number and description controls from the owning Part, rather than from the existing PartSpecial:

Old: partNumTF.setText(original.partNum);
Old: descrTF.setText(original.descr);

New: partNumTF.setText(part.articleCode());
New: descrTF.setText(part.description());

When an existing special is edited, the controls therefore start with the owning part's current article code and description. The description control is now 100 pixels high, supports line breaking, and enables automatic scrolling after layout. Update custom layouts, UI automation, or workflows that rely on the previous single-line control or on the special's stored values being prefilled.

EditGridCell now stores tooltip text through setToolTipText(), inserting a newline after every 100 characters. This applies both to the default outS() tooltip and to text explicitly supplied by extensions. Code that compares or reuses toolTipText() should account for the inserted newline characters.

New: public void setToolTipText(str text) {
         text = insertNewLines(text);
         super(..);
     }

cm.core.propsScheme.layout

PsLayoutPropsScheme groupName fixes

The groupName has been adjusted to remove "www." prefix and remove trailing ".com". This affects visual display of schemes in Schemes Explorer and the title bar.

cm.core3D

Improvements to 3D text spacing

3D text created through Text3D or meshFromText(...) may get a different final width and character layout than before.

This also affects existing content when older drawings are opened in 17.5.

If code depends on previous text extents, alignment, or placement based on the old spacing behavior, those cases may need to be reviewed.

cm.extension

putIgnoreDir() changes in cm.extension

The recursive behavior of putIgnoreDir() has been corrected in 17.5. To minimize migration effort, the recursive parameter now defaults to false, preserving the previous behavior for existing code.

Previously, only the specified directory was added to the ignore list due to an implementation issue. In the recursive case, instead of adding each discovered subdirectory, the method repeatedly adds the original directory to the ignore list, producing duplicate entries and failing to add the subdirectories into the ignore list.

Existing code that calls putIgnoreDir() without specifying the recursive parameter should continue to behave as before. Code that explicitly specifies subdirectories individually is also unaffected.

The corrected recursive behavior makes it possible to ignore an entire directory tree by calling putIgnoreDir(dir, recursive=true), which now registers both the specified directory and all of its subdirectories into the ignore list.

Use int64 instead for tracking file sizes related to extension archives and check for sufficient hard disk space during updates

Previously there was a bug related to the filesize of the ExtensionInfo file whereby it used a 32-bit integer to keep track of the extension's size. This caused it to overflow when the extension archive became larger than 2GB. To fix this we added int64 versions of the various filesizes we use to keep track of the extension sizes in 17.5 onwards. We stil maintain the 32-bit version for backwards compatibility. However please note this value might be inaccurate.

Also we added a hard disk space check for CET updates as sometimes there were issues where CET updates would fail when the user ran out of hard disk space during CET updates. We now do a minimum size check during CET updates where we check if the user has enough hard disk space to install an extension.

As sometimes other processes like downloader and Windows updates might end up filling up the hard disk while the CET updates are running, we still allow the user to proceed with the CET updates anyway. They will now receive a notification where they can choose to continue with the update or cancel it when CET detects there might not be sufficient hard disk space. However if the disk space ever drops below 1GB, we mark the update as having failed.

cm.recovery

More specific error reports

We have made some updates to the error reporting dialog to have better categorization and more information for crash reports. The following interface now sends reports as bug reports.

cm.recovery.errorDialog.cm

public void addReportErrorButton(FlexDialog d, ErrorDialogArgs errorDialogArgs) {

To send reports as feedback or crash, use the following interfaces instead.

Feedback: public void addReportFeedbackButton(FlexDialog d, ErrorDialogArgs errorDialogArgs) {
Crash: public void addReportCrashButton(FlexDialog d, ErrorDialogArgs errorDialogArgs) {

Also crash reports require a stack trace string or call stack now so that crash locations are now traceable and will trigger a devassert if the stack traces are empty (sendBitsCrashReport or addReportCrashButton).

cm.std.draw3D

class StaticDraw3DMeasure

StaticDraw3DMeasure now supports 3D and can be inserted in 3D through DimensionInsertAnimation.

This is intended to replace the old 3D dimension class, Draw3DMeasureDimension.

StaticDraw3DMeasure now has the viewVis property with values only2D, only3D, and both. Rendering, hit testing, connector visibility, and association graphics invalidation are filtered using this value. Custom overrides of contains, isVisibleIn2D, isVisibleIn3D, build2D, or get3D should respect the selected view.

DimensionInsertAnimation initializes a new dimension as only2D when inserted in a 2D view and only3D when inserted in a 3D view.

Dimensions loaded from drawings saved before this change are initialized as visible in 2D-only by the loadFailed handling code. Extensions that expect legacy dimensions to remain visible in 3D should explicitly migrate or initialize viewVis to both or only3D.

A new enableRender property controls whether 3D dimensions are shown in renderings or not. It is only available when the dimension is visible in 3D.

class ChainDraw3DMeasure

ChainDraw3DMeasure now explicitly denies 3D graphics, since the base class now has 3D graphics and chain dimensions do not support that behavior.

If your extension overrides get3D on ChainDraw3DMeasure to show custom 3D graphics, also override deny3D to return false.

For example:

public bool deny3D() {
    return false;
}

cm.test.cmunit.testInstructions

class PutAnimationPropInstruction

PutAnimationPropInstruction now works better with CoreAnimations, and should behave closer to editing the same property in the animation input window.

If PutAnimationPropInstruction cannot find a supported animation property to update, it now reports an error instead of continuing with a less clear failure.

class ClickConnectorInstruction

ClickConnectorInstruction now verifies that the connector's parent snapper is alive and not suspended before trying to click it. This makes tests fail closer to the real user-visible problem when a connector can be found internally but cannot actually be clicked.

Pass ensureConnectorSnapperAlive=false to the constructor for tests that intentionally click connectors whose parent snapper is not in a normal alive state.

cm.win

UrlField button background brush

UrlField.drawUrlButton() now obtains the button fill from buttonBgBrush() instead of reading skin.control directly. The default implementation returns skin.control, so unmodified fields retain their previous appearance.

Existing UrlField subclasses that already implement buttonBgBrush() will now have that method called whenever the browse button is drawn. Verify that the returned brush is appropriate for every enabled button state. Subclasses that override drawUrlButton() without calling super() are unaffected by this new hook.

win_drawGlyphOutline improvements

win_drawGlyphOutline now advances text using glyph advance (gmCellIncX) instead of advancing from the maximum x extent of each emitted glyph outline. This improves 3D text spacing, especially for whitespace characters, but may change the final width and appearance of text generated from outline data.

Changes to callerLoc

Separator for `callerLoc()`` has been changed from '.' to '::' to make it easier to extract the package name.

Manufacturer prefix for dialogs

Starting in 17.5 Major, subclasses of DialogWindow in an extension will show the manufacturer prefix in the title bar. This is to aid users to identify the source of a dialog.

The same behavior of showing manufacturer prefix also applies to the following classes:

  • FlexDialogWindow
  • ModalDialog
  • NonModalMessageBox
  • NonModalWarningDialog
  • ProgressDialog

res.images

Several icons have been moved to the icon library (res/iconLibrary/) and are now available through the cetIconLib() function.

Note: You can find icons by running the CET Facelift Test Tools extension and searching the CET Icon Library toolbox.

  • icon("res/images/architectural/carpetCircle2.png") should be replaced with cetIconLib("Tools/Circle-tool-blue_Color_24")
  • icon("res/images/architectural/carpetCustomShape2.png") should be replaced with cetIconLib("Tools/3D-custom-shape-blue_Color_24")
  • icon("res/images/architectural/carpetRect2.png") should be replaced with cetIconLib("Tools/3D-rectangle-blue_Color_24")
  • icon("res/images/architectural/levelAddPoint.png") should be replaced with cetIconLib("Tools/Add-point_Color_24")
  • icon("res/images/architectural/levelCircle.png") should be replaced with cetIconLib("Tools/Circle-tool_Color_24")
  • icon("res/images/architectural/levelCurve.png") should be replaced with cetIconLib("Tools/Switch-straight-curved_Color_24")
  • icon("res/images/architectural/levelCustomShape.png") should be replaced with cetIconLib("Tools/3D-custom-shape_Color_24")
  • icon("res/images/architectural/levelInsertWall.png") should be replaced with cetIconLib("Tools/Insert-wall-edge_Color_24")
  • icon("res/images/architectural/levelRect.png") should be replaced with cetIconLib("Tools/3D-rectangle_Color_24")
  • icon("res/images/architectural/levelRemovePoint.png") should be replaced with cetIconLib("Tools/Remove-point_Color_24")
  • icon("res/images/architectural/levelSlice.png") should be replaced with cetIconLib("Tools/Slice-shape_Color_24")
  • icon("res/images/architectural/levelStretch.png") should be replaced with cetIconLib("Tools/Stretch-level_Color_24")
  • icon("res/images/draw3D/doublerFacelift.png") should be replaced with cetIconLib("Tools/Show-double-line_Color_24")
  • icon("res/images/draw3D/helpLineFacelift.png") should be replaced with cetIconLib("Tools/Help-line_Color_24")
  • icon("res/images/draw3D/meeterFacelift.png") should be replaced with cetIconLib("Tools/Measure_Color_24")
  • icon("res/images/draw3D/mirrorHorizontalFacelift.svg") should be replaced with cetIconLib("Tools/Flip-horizontally_Color_24")
  • icon("res/images/draw3D/mirrorLineFacelift.svg") should be replaced with cetIconLib("Tools/Mirror-across-line_Color_24")
  • icon("res/images/draw3D/mirrorVerticalFacelift.svg") should be replaced with cetIconLib("Tools/Flip-vertically_Color_24")
  • icon("res/images/draw3D/referencePointFacelift.png") should be replaced with cetIconLib("Tools/Help-point_Color_24")
  • icon("res/images/draw3D/trimmerFacelift.png") should be replaced with cetIconLib("Tools/Trim-line_Color_24")
  • icon("res/images/facelift2023/tbDrawingPaper.png") should be replaced with cetIconLib("Tools/Drawing-paper_Color_24")
  • icon("res/images/facelift2023/tbDrawingPaper.svg") should be replaced with cetIconLib("Tools/Drawing-paper_Color_24")
  • icon("res/images/icons/removerFacelift.png") should be replaced with cetIconLib("Tools/Remove-snapper_Color_24")
  • icon("res/images/tools/addPoint.png") should be replaced with cetIconLib("Tools/Add-point_Color_24")
  • icon("res/images/tools/angleDimension.png") should be replaced with cetIconLib("Tools/Angle-dimension_Line_24")
  • icon("res/images/tools/arc3Points.png") should be replaced with cetIconLib("Tools/Arc-three-point_Color_24")
  • icon("res/images/tools/arcInside2Tangents.png") should be replaced with cetIconLib("Tools/Arc-two-tagnent_Color_24")
  • icon("res/images/tools/arcRadiusAngle.png") should be replaced with cetIconLib("Tools/Arc-radius-angle_Color_24")
  • icon("res/images/tools/arcTangentAngle.png") should be replaced with cetIconLib("Tools/Arc-tangent-angle_Color_24")
  • icon("res/images/tools/arrow2Lines.png") should be replaced with cetIconLib("Tools/Arrow-two-line_Color_24")
  • icon("res/images/tools/arrowNormal.png") should be replaced with cetIconLib("Tools/Arrow-default_Color_24")
  • icon("res/images/tools/baseline.png") should be replaced with cetIconLib("Tools/Baseline_Color_24")
  • icon("res/images/tools/baselineDimension.png") should be replaced with cetIconLib("Tools/Baseline-dimension_Color_24")
  • icon("res/images/tools/cadZeroPoint.png") should be replaced with cetIconLib("Tools/CAD-zero-point_Color_24")
  • icon("res/images/tools/calcAreaAddPoint.png") should be replaced with cetIconLib("Tools/Add-point_Color_24")
  • icon("res/images/tools/calcAreaCurve.png") should be replaced with cetIconLib("Tools/Switch-straight-curved_Color_24")
  • icon("res/images/tools/calcAreaCustomShape.png") should be replaced with cetIconLib("Tools/3D-custom-shape_Color_24")
  • icon("res/images/tools/calcAreaMoveLine.png") should be replaced with cetIconLib("Tools/Move-line_Color_24")
  • icon("res/images/tools/chainDimension.png") should be replaced with cetIconLib("Tools/Chain-dimension_Line_24")
  • icon("res/images/tools/circle.png") should be replaced with cetIconLib("Tools/Circle-tool_Color_24")
  • icon("res/images/tools/circleDiameter.png") should be replaced with cetIconLib("Tools/Circle-diameter-tool_Color_24")
  • icon("res/images/tools/circleEllipse.png") should be replaced with cetIconLib("Tools/Ellipse-tool_Color_24")
  • icon("res/images/tools/circleRadius.png") should be replaced with cetIconLib("Tools/Circle-tool_Color_24")
  • icon("res/images/tools/columnBalloon.png") should be replaced with cetIconLib("Tools/Column-balloon_Color_24")
  • icon("res/images/tools/curve.png") should be replaced with cetIconLib("Tools/Switch-straight-curved_Color_24")
  • icon("res/images/tools/customShape.png") should be replaced with cetIconLib("Tools/3D-custom-shape_Color_24")
  • icon("res/images/tools/dataField.png") should be replaced with cetIconLib("Tools/Data-field_Color_24")
  • icon("res/images/tools/doubleArc3Points.png") should be replaced with cetIconLib("Tools/Arc-three-point-double_Color_24")
  • icon("res/images/tools/doubleArcInside2Tangents.png") should be replaced with cetIconLib("Tools/Arc-two-tagnent-double_Color_24")
  • icon("res/images/tools/doubleArcTangentAngle.png") should be replaced with cetIconLib("Tools/Arc-tangent-angle-double_Color_24")
  • icon("res/images/tools/doubleLine.png") should be replaced with cetIconLib("Tools/Double-line_Color_24")
  • icon("res/images/tools/doubleRectangle2Sided.png") should be replaced with cetIconLib("Tools/3D-rectangle-two-sided_Color_24")
  • icon("res/images/tools/doubleRectangle3Sided.png") should be replaced with cetIconLib("Tools/3D-rectangle-three-sided_Color_24")
  • icon("res/images/tools/doubleRectangleDefault.png") should be replaced with cetIconLib("Tools/3D-rectangle_Color_24")
  • icon("res/images/tools/doubleRectangleEdgeDiagonal.png") should be replaced with cetIconLib("Tools/3D-rectangle-diagonal_Color_24")
  • icon("res/images/tools/faceliftPrintableArticleView.png") should be replaced with cetIconLib("Systemwide/Print_Line_16")
  • icon("res/images/tools/faceliftViewClip2D.png") should be replaced with cetIconLib("Systemwide/View-clip-2D_Color_16")
  • icon("res/images/tools/faceliftViewClipEmpty.png") should be replaced with cetIconLib("Systemwide/View-clip-empty_Color_16")
  • icon("res/images/tools/faceliftViewport3D.png") should be replaced with cetIconLib("Systemwide/View-clip-3D_Color_16")
  • icon("res/images/tools/helpLine.png") should be replaced with cetIconLib("Tools/Help-line_Color_24")
  • icon("res/images/tools/helpPoint.png") should be replaced with cetIconLib("Tools/Help-point_Color_24")
  • icon("res/images/tools/hideEntities.png") should be replaced with cetIconLib("Tools/Hide-entities_Color_24")
  • icon("res/images/tools/hideLayers.png") should be replaced with cetIconLib("Tools/Hide-layers_Color_24")
  • icon("res/images/tools/incrementer.png") should be replaced with cetIconLib("Tools/Incrementer_Color_24")
  • icon("res/images/tools/insertWall.png") should be replaced with cetIconLib("Tools/Insert-wall-edge_Color_24")
  • icon("res/images/tools/label.png") should be replaced with cetIconLib("Tools/Label_Color_24")
  • icon("res/images/tools/leader.png") should be replaced with cetIconLib("Tools/Leader_Color_24")
  • icon("res/images/tools/line.png") should be replaced with cetIconLib("Tools/Line_Color_24")
  • icon("res/images/tools/lineDimension.png") should be replaced with cetIconLib("Tools/Dimension_Line_24")
  • icon("res/images/tools/lineDimensionPaper.png") should be replaced with cetIconLib("Tools/Dimension_Line_24")
  • icon("res/images/tools/loadImage.png") should be replaced with cetIconLib("Tools/Import-image_Color_24")
  • icon("res/images/tools/measureAndScale.png") should be replaced with cetIconLib("Tools/Measure-and-scale_Color_24")
  • icon("res/images/tools/meetAtAngle.png") should be replaced with cetIconLib("Tools/Meet-at-angle_Color_24")
  • icon("res/images/tools/northArrow.png") should be replaced with cetIconLib("Tools/North-arrow_Color_24")
  • icon("res/images/tools/offsetLine.png") should be replaced with cetIconLib("Tools/Offset-line_Color_24")
  • icon("res/images/tools/pen.png") should be replaced with cetIconLib("Tools/Pen_Color_24")
  • icon("res/images/tools/photolabImage.png") should be replaced with cetIconLib("Tools/Image_Color_24")
  • icon("res/images/tools/polygonHelpLine.png") should be replaced with cetIconLib("Tools/Help-line_Color_24")
  • icon("res/images/tools/polygonHelpPoint.png") should be replaced with cetIconLib("Tools/Help-point_Color_24")
  • icon("res/images/tools/polygonLine.png") should be replaced with cetIconLib("Tools/Grouped-single-line_Color_24")
  • icon("res/images/tools/polygonLineArrow.png") should be replaced with cetIconLib("Tools/Arrow-multiple-line_Color_24")
  • icon("res/images/tools/polygonLineArrowConnected.png") should be replaced with cetIconLib("Tools/Arrow-group-line_Color_24")
  • icon("res/images/tools/polygonLineConnected.png") should be replaced with cetIconLib("Tools/Grouped-group-line_Color_24")
  • icon("res/images/tools/quickChainDimension.png") should be replaced with cetIconLib("Tools/Chain-dimension_Line_24")
  • icon("res/images/tools/radialDimension.png") should be replaced with cetIconLib("Tools/Radius-dimension_Line_24")
  • icon("res/images/tools/rectangle2Sided.png") should be replaced with cetIconLib("Tools/3D-rectangle-two-sided_Color_24")
  • icon("res/images/tools/rectangle3Sided.png") should be replaced with cetIconLib("Tools/3D-rectangle-three-sided_Color_24")
  • icon("res/images/tools/rectangleDefault.png") should be replaced with cetIconLib("Tools/3D-rectangle_Color_24")
  • icon("res/images/tools/rectangleEdgeDiagonal.png") should be replaced with cetIconLib("Tools/3D-rectangle-diagonal_Color_24")
  • icon("res/images/tools/removePoint.png") should be replaced with cetIconLib("Tools/Remove-point_Color_24")
  • icon("res/images/tools/replicateCircular.png") should be replaced with cetIconLib("Tools/Replicate-circular_Color_24")
  • icon("res/images/tools/replicateLinear.png") should be replaced with cetIconLib("Tools/Replicate-linear_Color_24")
  • icon("res/images/tools/replicateRectangular.png") should be replaced with cetIconLib("Tools/Replicate-rectangular_Color_24")
  • icon("res/images/tools/revisionCloudCircular.png") should be replaced with cetIconLib("Tools/Revision-cloud-circle_Color_24")
  • icon("res/images/tools/revisionCloudCustom.png") should be replaced with cetIconLib("Tools/Revision-cloud-custom_Color_24")
  • icon("res/images/tools/revisionCloudLasso.png") should be replaced with cetIconLib("Tools/Revision-cloud-lasso_Color_24")
  • icon("res/images/tools/revisionCloudRectangular.png") should be replaced with cetIconLib("Tools/Revision-cloud-rectangular_Color_24")
  • icon("res/images/tools/show.png") should be replaced with cetIconLib("Systemwide/Show_Line_24")
  • icon("res/images/tools/slice.png") should be replaced with cetIconLib("Tools/Slice-shape_Color_24")
  • icon("res/images/tools/spreadsheet.png") should be replaced with cetIconLib("Tools/Spreadsheet_Color_24")
  • icon("res/images/tools/square.png") should be replaced with cetIconLib("Tools/3D-rectangle_Color_24")
  • icon("res/images/tools/text.png") should be replaced with cetIconLib("Tools/Text_Color_24")
  • icon("res/images/tools/trimLine.png") should be replaced with cetIconLib("Tools/Trim-line_Color_24")
  • icon("res/images/tools/twoClickDimensionLarge.png") should be replaced with cetIconLib("Tools/Dimension_Line_24")
  • icon("res/images/wall/3DTextOnWallsFacelift.png") should be replaced with cetIconLib("Extension-specific/3D-text-on-walls_Color_24")
  • icon("res/images/wall/arcWallByRadiusAndAngleFacelift.png") should be replaced with cetIconLib("Extension-specific/Arc-wall-radius-angle_Color_24")
  • icon("res/images/wall/arcWallInsideTwoTangentLinesFacelift.png") should be replaced with cetIconLib("Extension-specific/Arc-wall-two-tangent-lines_Color_24")
  • icon("res/images/wall/arcWallThroughTangentAndAngleFacelift.png") should be replaced with cetIconLib("Extension-specific/Arc-wall-tangent-angle_Color_24")
  • icon("res/images/wall/ceilingDividedCenterFacelift.png") should be replaced with cetIconLib("Extension-specific/Ceiling-divided-center_Color_24")
  • icon("res/images/wall/ceilingDividedLeftFacelift.png") should be replaced with cetIconLib("Extension-specific/Ceiling-divided-left_Color_24")
  • icon("res/images/wall/ceilingDividedRightFacelift.png") should be replaced with cetIconLib("Extension-specific/Ceiling-divided-right_Color_24")
  • icon("res/images/wall/columnFacelift.png") should be replaced with cetIconLib("Extension-specific/Column_Color_24")
  • icon("res/images/wall/continuousWallFacelift.png") should be replaced with cetIconLib("Extension-specific/Continuous-wall_Color_24")
  • icon("res/images/wall/curtainsFacelift.png") should be replaced with cetIconLib("Extension-specific/Curtains_Color_24")
  • icon("res/images/wall/drainFacelift.png") should be replaced with cetIconLib("Extension-specific/Drain_Color_24")
  • icon("res/images/wall/explodeToThinStraightWallsFacelift.png") should be replaced with cetIconLib("Extension-specific/Explode-to-thin-walls_Color_24")
  • icon("res/images/wall/glassPartition.png") should be replaced with cetIconLib("Extension-specific/Glass-partition_Color_24")
  • icon("res/images/wall/glassPartitionDoor.png") should be replaced with cetIconLib("Extension-specific/Glass-partition-door_Color_24")
  • icon("res/images/wall/imageOnWallFacelift.png") should be replaced with cetIconLib("Extension-specific/Image-on-wall_Color_24")
  • icon("res/images/wall/panelCurtainFacelift.png") should be replaced with cetIconLib("Extension-specific/Panel-curtain_Color_24")
  • icon("res/images/wall/panelCurtainRodFacelift.png") should be replaced with cetIconLib("Extension-specific/Panel-curtain-rod_Color_24")
  • icon("res/images/wall/pilasterFacelift.png") should be replaced with cetIconLib("Extension-specific/Pilaster_Color_24")
  • icon("res/images/wall/plainCeilingFacelift.png") should be replaced with cetIconLib("Extension-specific/Plain-ceiling_Color_24")
  • icon("res/images/wall/radiatorFacelift.png") should be replaced with cetIconLib("Extension-specific/Radiator_Color_24")
  • icon("res/images/wall/rollerDoorFacelift.png") should be replaced with cetIconLib("Extension-specific/Roller-door_Color_24")
  • icon("res/images/wall/sectionalDoorFacelift.png") should be replaced with cetIconLib("Extension-specific/Sectional-door_Color_24")
  • icon("res/images/wall/slidingDoorFacelift.png") should be replaced with cetIconLib("Extension-specific/Sliding-door_Color_24")
  • icon("res/images/wall/straightMediumWallFacelift.png") should be replaced with cetIconLib("Extension-specific/Straight-medium-wall_Color_24")
  • icon("res/images/wall/straightThickWallFacelift.png") should be replaced with cetIconLib("Extension-specific/Straight-thick-wall_Color_24")
  • icon("res/images/wall/straightThinWallFacelift.png") should be replaced with cetIconLib("Extension-specific/Straight-thin-wall_Color_24")
  • icon("res/images/wall/surfaceTilesFacelift.png") should be replaced with cetIconLib("Extension-specific/Surface-tiles_Color_24")
  • icon("res/images/wall/triPilasterFacelift.png") should be replaced with cetIconLib("Extension-specific/Tri-pilaster_Color_24")
  • icon("res/images/wall/valveFacelift.png") should be replaced with cetIconLib("Extension-specific/Valve_Color_24")
  • icon("res/images/wall/venetianBlindsFacelift.png") should be replaced with cetIconLib("Extension-specific/Venetian-blinds_Color_24")
  • icon("res/images/wall/verticalBlindsFacelift.png") should be replaced with cetIconLib("Extension-specific/Vertical-blinds_Color_24")
  • icon("res/images/wall/wallDoorFacelift.png") should be replaced with cetIconLib("Extension-specific/Wall-door_Color_24")
  • icon("res/images/wall/wallDoubleDoorFacelift.png") should be replaced with cetIconLib("Extension-specific/Wall-double-door_Color_24")
  • icon("res/images/wall/wallModificationHoleFacelift.png") should be replaced with cetIconLib("Extension-specific/Wall-modification-hole_Color_24")
  • icon("res/images/wall/windowFacelift.png") should be replaced with cetIconLib("Extension-specific/Window_Color_24")
  • icon("res/images/wall/windowSillFacelift.png") should be replaced with cetIconLib("Extension-specific/Window-sill_Color_24")
  • icon("res/images/xclip/faceliftAlwaysReadableCompanion.png") should be replaced with cetIconLib("Tools/Rotate-always-readable-text_Line_24")
  • icon("res/images/xclip/faceliftApplyTemplate.png") should be replaced with cetIconLib("Tools/Apply-template_Color_24")
  • icon("res/images/xclip/faceliftBlackWhiteCompanion.png") should be replaced with cetIconLib("Tools/Show-only-black-and-white_Line_24")
  • icon("res/images/xclip/faceliftCollomBallonCompanion.png") should be replaced with cetIconLib("Tools/Column-balloon_Color_24")
  • icon("res/images/xclip/faceliftDebugCompanion.png") should be replaced with cetIconLib("Tools/Debug-information_Line_24")
  • icon("res/images/xclip/faceliftEllipses.png") should be replaced with cetIconLib("Tools/Ellipse-tool_Color_24")
  • icon("res/images/xclip/faceliftFrameCompanion.png") should be replaced with cetIconLib("Tools/Add-a-frame_Color_24")
  • icon("res/images/xclip/faceliftPartTagPlotStyleCompanion.png") should be replaced with cetIconLib("Drawing/Tag_Color_24")
  • icon("res/images/xclip/faceliftScalableTextCompanion.png") should be replaced with cetIconLib("Tools/Custom-scale-for-text-in-view-clip_Line_24")
  • icon("res/images/xclip/faceliftScaleCompanion.png") should be replaced with cetIconLib("Tools/Show-scale_Color_24")