Showing results for 
Search instead for 
Did you mean: 
Showing results for 
Search instead for 
Did you mean: 

Community Tip - New to the community? Learn how to post a question and get help from PTC and industry experts! X

where used tab custom column


where used tab custom column


Need to add a couple of custom column (for custom attributes) in the where used tab.

Pl help,


Ravin Kayasth


You need to write some java code, and have some JCA skills :

If you add &jcaDebug=1 at the end of the URL, you'll see this.


What you need to do is to create a new class to extends WhereUsedTreeBuilder

and override    public ComponentConfig buildComponentConfig(ComponentParams componentParams) throws WTException

The existing code is

    public ComponentConfig buildComponentConfig(ComponentParams componentParams) throws WTException {
        if (log.isDebugEnabled()) {
            log.debug((Object)"WhereUsedTreeBuilder - Entering buildComponentConfig");
        if (log.isTraceEnabled()) {
            log.trace((Object)("WhereUsedTreeBuilder.buildComponentConfig input params " + (Object)componentParams));
        String string = "";
        NmHelperBean nmHelperBean = ((JcaComponentParams)componentParams).getHelperBean();
        NmCommandBean nmCommandBean = nmHelperBean.getNmCommandBean();
        NmSessionBean nmSessionBean = nmHelperBean.getNmSessionBean();
        ComponentConfigFactory componentConfigFactory = this.getComponentConfigFactory();
        JcaTreeConfig jcaTreeConfig = (JcaTreeConfig)componentConfigFactory.newTreeConfig();
        Object object = nmCommandBean.getPageOid().getRef();
        string = EnterpriseHelper.isProjectLink((Persistable)object) ? "whereUsed" : "whereUsed.view";
        if (nmCommandBean.getTextParameter("viewchange") != null) {
            nmSessionBean.removeAllNodes(nmCommandBean, "whereUsed.view");
        componentParams.setAttribute("whereUsedTableID", (Object)string);
        ColumnConfig columnConfig = componentConfigFactory.newColumnConfig("number", true);
        jcaTreeConfig.addComponent((ComponentConfig)componentConfigFactory.newColumnConfig("orgid", false));
        columnConfig = componentConfigFactory.newColumnConfig("groupedVersions", false);
        jcaTreeConfig.addComponent((ComponentConfig)componentConfigFactory.newColumnConfig("name", true));
        columnConfig = componentConfigFactory.newColumnConfig("containerName", true);
        columnConfig = componentConfigFactory.newColumnConfig("nmActions", false);
        ((JcaColumnConfig)columnConfig).setDescriptorProperty((Object)"actionModel", (Object)"EMPTY_ACTION_MODEL");
        if (log.isDebugEnabled()) {
            log.debug((Object)("Tree Id is   :-- " + jcaTreeConfig.getId()));
        return jcaTreeConfig;

So, you should end with something like this :

package ext.myProject.jca;

import com.ptc.jca.mvc.components.JcaTreeConfig;
import com.ptc.mvc.components.ComponentConfig;
import com.ptc.mvc.components.ComponentConfig;
import com.ptc.mvc.components.ComponentConfigFactory;
import com.ptc.mvc.components.ComponentParams;
import wt.util.WTException;

* $Rev::                                                                                                   $:  Version
* $Author::                                                                                                $:  Dernier modificateur
* $Date::                                                                                                  $:  Date du dernier commit
* Url de la version la plus recente
* $HeadURL$
public class MyCustomWhereUsedTreeBuilder extends WhereUsedTreeBuilder {

    public ComponentConfig buildComponentConfig(ComponentParams componentParams) throws WTException {
        JcaTreeConfig jcaTreeConfig = (JcaTreeConfig) super.buildComponentConfig(componentParams);

        ComponentConfigFactory componentConfigFactory = this.getComponentConfigFactory();
        jcaTreeConfig.addComponent((ComponentConfig)componentConfigFactory.newColumnConfig("myCustomAttribute", false));
        return jcaTreeConfig;                                                                                   

And to replace the existing table by yours, you need to declare it in Windchill/codebase/config/mvc/custom.xml

by adding

<bean class="ext.myProject.jca.MyCustomWhereUsedTreeBuilder"/>

This should be enough.

Data are queried in buildComponentData, and uses com.ptc.windchill.enterprise.object.WhereUsedTreeHandler.

Normally, you new attributes in jcaTreeConfig should be queried.

‌If you change or even create a new table view, you need to delete the views in the DB.

Check first if a view already exists:

select * from TABLEVIEWDESCRIPTOR where TABLEID = 'whereUsed.view';select * from ACTIVEVIEWLINK where TABLEID='whereUsed.view';

If so, do a backup of the table and delete them:

Delete from TABLEVIEWDESCRIPTOR where TABLEID='whereUsed.view';Delete from ACTIVEVIEWLINK where TABLEID='whereUsed.view';commit;

Then restart Windchill

Have fun

Hi fellow devs,


I had to modify the same tree/table and got on the same path described by oliverfresse, however there are some additional things you have to do to achieve the expected. After you have everything oliverfresse described, you have to extend the TableBuilder attached to this TreeBuilder and reference that new class.


    public ConfigurableTable buildConfigurableTable(String paramString) throws WTException {
        ConfigurableTable table = null;
        if (paramString.equals(TABLEID)) {
            table = newCustomWhereUsedTableView();
        } else {
            table = super.buildConfigurableTable(paramString);
        return table;

In this custom table view you have to define your columns per view. Something like this:



    public List<TableViewDescriptor> getOOTBTableViews(String paramString, Locale paramLocale) throws WTException {
        ArrayList<TableViewDescriptor> localArrayList = new ArrayList<TableViewDescriptor>(1);
        Vector<TableColumnDefinition> localVector1 = new Vector<TableColumnDefinition>(6);
        Vector<TableColumnDefinition> localVector2 = new Vector<TableColumnDefinition>(6);
        try {
            localVector1.add(TableColumnDefinition.newTableColumnDefinition("number", true));
            localVector1.add(TableColumnDefinition.newTableColumnDefinition("orgid", true));
            localVector1.add(TableColumnDefinition.newTableColumnDefinition("groupedVersions", false));
            localVector1.add(TableColumnDefinition.newTableColumnDefinition("myCustomAttribute", false));
            localVector1.add(TableColumnDefinition.newTableColumnDefinition("name", false));
            localVector1.add(TableColumnDefinition.newTableColumnDefinition("containerName", false));
            String str1 = getViewResourceEntryKey(RESOURCE, "3");
            String str2 = getViewResourceEntryKey(RESOURCE, "3");
            TableViewDescriptor localTableViewDescriptor = TableViewDescriptor.newTableViewDescriptor(str1, paramString,
                    true, true, localVector1, null, true, str2);

            localVector2.add(TableColumnDefinition.newTableColumnDefinition("number", true));
            localVector2.add(TableColumnDefinition.newTableColumnDefinition("orgid", true));
            localVector2.add(TableColumnDefinition.newTableColumnDefinition("groupedVersions", false));
            localVector2.add(TableColumnDefinition.newTableColumnDefinition("myCustomAttribute", false));
            localVector2.add(TableColumnDefinition.newTableColumnDefinition("name", false));
            localVector2.add(TableColumnDefinition.newTableColumnDefinition("containerName", false));
            str1 = getViewResourceEntryKey(RESOURCE, "2");
            str2 = getViewResourceEntryKey(RESOURCE, "2");
            localTableViewDescriptor = TableViewDescriptor.newTableViewDescriptor(str1, paramString, true, true,
                    localVector2, null, true, str2);
        } catch (WTPropertyVetoException localWTPropertyVetoException) {
            throw new WTRuntimeException(localWTPropertyVetoException);
        return localArrayList;

Note the myCustomAttribute added. After this you have to create a dataUtility in which you add your value. In the treeBuilder you have to set your column as column.setTargetObject(""); so that you will get the WhereUsedDataItem type (mixture of PartMaster and Part info encapsulated in it) in the dataUtility. Personally I have overridden the grouppedVersions dataUtility and left the super class to construct the data and just went through the nmActions (for the respective WTParts) and changed the display value (description) of the nmAction from version to the custom attribute.

Until this point you will have the new column, however the view selection is dependent on the real whereUsed table. In order that your view selector to work you have to override the TreeHandler also.


    public void buildNodeData(Object paramObject, ComponentResultProcessor paramComponentResultProcessor)
            throws Exception {
        Map<Object, List> localMap;
        if (paramObject == TreeNode.RootNode) {
            treeHandler = new CustomWhereUsedTreeHandler(paramComponentResultProcessor.getParams());
        } else {
            ArrayList<Object> localArrayList = new ArrayList<Object>();
            if (treeHandler == null) {
                treeHandler = new CustomWhereUsedTreeHandler(paramComponentResultProcessor.getParams());
            localMap = treeHandler.getNodes(localArrayList);
            Set<Object> localSet = localMap.keySet();
            for (Object localObject : localSet) {

And in this custom tree handler you have to change the name of the tableID that you set in the treeBuilder.


public CustomWhereUsedTreeHandler(ComponentParams paramComponentParams) throws WTException {
        currentView = TableViewUtils.getCurrentView(TABLEID);

 Also in the treeBuilder buildComponentConfig you have to set these properties of the tree:

treeConfig.setLabel("Custom Where Used");
compParams.setAttribute("whereUsedTableID", TABLEID);

If anyone is interested in any further details, you can send me a pm.






Hi TamasBiro,

I tried to deploy your solution in Windchill 11.0 and I did not succeed.

I encountered some difficulties, for example could not find the TableBuilder Class.


Can you share the source code?



sorry for replying this late, I did not check my account since a while. I don't think this is still relevant for you, however for future devs might come in handy. I had a mistake in my explanation. There is no tableBuilder, instead you have to extend only the mentioned treeBuilder to assign a different tableView to it. Consider where I say tableBuilder I'm still talking about the WhereUsedTreeBuilder which I extended and registered the TableView that I was describing afterwards. Note that everywhere I use the same TABLEID, which is set also for the treeConfig ( 

compParams.setAttribute("whereUsedTableID", TABLEID);


Tamas - Can you please give further details about this customization? we would like to apply it to our WNC 11.0 M030 CPS16/CPS17 Instance...





please explain where you are stuck, then I could give some more details, however if you follow the steps oliverfresse described and extend it with the code I posted above, you should be able to figure it out.





Hello TamasBiro.

Could you explane this point

You write
"you have to create a dataUtility in which you add your value. In the treeBuilder you have to set your column as column.setTargetObject("")"

I need to add colum whereUsedQuantity to this table.
Could you tell more about dataUtility for new colum.

import java.util.Locale;

import com.ptc.core.components.descriptor.ModelContext;
import com.ptc.core.components.rendering.GuiComponent;
import com.ptc.core.components.rendering.guicomponents.GUIComponentArray;
import com.ptc.core.components.rendering.guicomponents.NmActionGuiComponent;
import com.ptc.netmarkets.util.misc.NmAction;
import com.ptc.windchill.enterprise.object.dataUtilities.GroupedVersionsDataUtility;

import wt.lifecycle.LifeCycleManaged;
import wt.lifecycle._LifeCycleManaged;
import wt.util.WTException;
import wt.util.WTMessage;

 * @author tamas.biro
public class GroupedStatesDataUtility extends GroupedVersionsDataUtility {

    private static final String COLUMNID = "groupedStates";
    protected static final String RESOURCE = "ext.whereused.resource.CustomRB";

    protected String getColumnId() {
        return COLUMNID;

    public Object getDataValue(String paramString, Object paramObject, ModelContext paramModelContext)
            throws WTException {
        GUIComponentArray grouppedVersions = (GUIComponentArray) super.getDataValue(paramString, paramObject,
        GUIComponentArray grouppedStates = new GUIComponentArray();

        for (int i = 0; i < grouppedVersions.size(); i++) {
            GuiComponent comp = grouppedVersions.get(i);
            if (comp instanceof NmActionGuiComponent) {
                NmAction action = ((NmActionGuiComponent) comp).getAction();
                Object contextObject = action.getContextObject().getRefObject();
                if (contextObject instanceof LifeCycleManaged) {
                    action.setDesc(((_LifeCycleManaged) contextObject).getState().getState().getDisplay());

        return grouppedStates;


    public String getLabel(String paramString, ModelContext paramModelContext) throws WTException {
        String str = null;
        Locale localLocale = getLocale();
        str = WTMessage.getLocalizedMessage(RESOURCE, "GROUPPED_STATES", null, localLocale);
        if (str == null) {
            str = paramString;
        return str;
22-Sapphire I

Hi all.

You can check another solution described on a following thread How-to-Customize-where-used-panel


Top Tags