Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    createRecordComponent for TreegGrid missing ImgButton

    Hi,
    The TreeGrid examples found in http://www.smartclient.com/smartgwt/showcase/#main contain employee data. We have these combined and extended with image buttons for our purposes.

    Our components have been created in the overridden function createRecordComponent().
    These components may contain two or three image buttons based on icons for folders and nodes respectively, depending on the tree item.

    There is a problem using it. By some tree manipulations as open/close folder, drag and drop there are either false mapped or missing button components. We have tested the pooling modes DATA and RECYCLE too with overridden updateRecordComponent().
    We guess this is a refreshing/viewing problem. How can we solve this problem, and please clear whether our program logic is false or is it a GWT4 bug?

    Remarks: We would like to use it with our own data source connecting to arbitrary kind of DB, e.g. Oracle, asynchronously by Virgo web server. This DB management works correct.

    Browser: FireFox 24.0 + Google Web Toolkit Developer Plugin for Firefox Version 1.24
    SmartGWT Version: Version4.1d BuildDate: Mon Sep 23 09:59:00 GMT+200 2013

    Regards
    Béla

    Code:
    import com.google.gwt.i18n.client.NumberFormat;
    import com.smartgwt.client.types.Alignment;
    import com.smartgwt.client.types.RecordComponentPoolingMode;
    import com.smartgwt.client.types.TreeModelType;
    import com.smartgwt.client.widgets.Canvas;
    import com.smartgwt.client.widgets.ImgButton;
    import com.smartgwt.client.widgets.events.DropEvent;
    import com.smartgwt.client.widgets.events.DropHandler;
    import com.smartgwt.client.widgets.grid.CellFormatter;
    import com.smartgwt.client.widgets.grid.ListGridRecord;
    import com.smartgwt.client.widgets.layout.HLayout;
    import com.smartgwt.client.widgets.tree.Tree;
    import com.smartgwt.client.widgets.tree.TreeGrid;
    import com.smartgwt.client.widgets.tree.TreeGridField;
    import com.smartgwt.client.widgets.tree.TreeNode;
    import com.smartgwt.client.widgets.tree.events.FolderClosedEvent;
    import com.smartgwt.client.widgets.tree.events.FolderClosedHandler;
    import com.smartgwt.client.widgets.tree.events.FolderOpenedEvent;
    import com.smartgwt.client.widgets.tree.events.FolderOpenedHandler;
    
    public class SimpleTestGrid extends TreeGrid {
    	private static int buttonId = 1;
    	private static String iconPath = "16/icons/";
    
    	public static final TreeNode[] employeeData = new TreeNode[] {
    			new EN("400", "100", "Cha Mad", "MgrChief", 20000, true),
    			new EN("189", "400", "Gen Por", "Mgr Tech", 19000, true),
    			new EN("265", "189", "Oli Dou", "Asset Sp", 18000, false),
    			new EN("264", "189", "Che Pea", "Dsl Sys ", 17000, false),
    			new EN("263", "189", "Pri Sam", "Line Wrk", 16000, false),
    			new EN("188", "400", "Rog Leg", "Mgr Syst", 15000, true),
    			new EN("262", "188", "Jac Des", "Line Wrk", 14000, false),
    			new EN("261", "188", "Kay Mon", "Stn Opr ", 13000, false),
    			new EN("260", "188", "Fra Dug", "Fire Sec", 12000, false),
    			new EN("259", "188", "Jac Leb", "Purch Cl", 11000, false),
    			new EN("258", "188", "Ren Xia", "Mobile E", 10000, false),
    			new EN("257", "188", "Oli Heb", "Met Read", 10900, false),
    			new EN("182", "400", "Tam Kan", "Mgr Site", 10800, true),
    			new EN("195", "182", "Kai Kon", "Stores W", 10700, false),
    			new EN("194", "182", "Fel Pip", "Dsl Sys ", 10600, false),
    			new EN("193", "182", "Dar Fee", "Inventor", 10500, false) };
    
    	public SimpleTestGrid() {
    		Tree employeeTree = new Tree();
    		employeeTree.setModelType(TreeModelType.PARENT);
    		employeeTree.setRootValue(1);
    		employeeTree.setNameProperty("Name");
    		employeeTree.setIdField("EmployeeId");
    		employeeTree.setParentIdField("ReportsTo");
    		employeeTree.setOpenProperty("isOpen");
    		employeeTree.setData(employeeData);
    
    		TreeGridField formattedField = new TreeGridField("Name");
    		formattedField.setCellFormatter(new CellFormatter() {
    			@Override
    			public String format(Object value, ListGridRecord record,
    					int rowNum, int colNum) {
    				return record.getAttributeAsString("Job") + ": " + value + " ("
    						+ (rowNum + colNum) + ")";
    			}
    		});
    
    		setCanEdit(true);
    		setLoadDataOnDemand(false);
    		setWidth("500");
    		setNodeIcon(iconPath + "node.png");
    		setFolderIcon(iconPath + "folder.png");
    		setShowOpenIcons(false);
    		setShowDropIcons(false);
    		setCanReorderRecords(true);
    		setCanAcceptDroppedRecords(true);
    		setShowOpenIcons(false);
    		setDropIconSuffix("into");
    		setClosedIconSuffix("");
    		setData(employeeTree);
    		setAutoFetchData(true);
    		setShowRecordComponents(true);
    		setShowRecordComponentsByCell(true);
    		RecordComponentPoolingMode pool = RecordComponentPoolingMode.VIEWPORT; //.DATA //.RECYCLE -> updateRecordComponent(); 
    		setRecordComponentPoolingMode(pool);
    
    		TreeGridField salaryField = new TreeGridField("Salary");
    		salaryField.setCellFormatter(new CellFormatter() {
    			@SuppressWarnings("unused")
    			@Override
    			public String format(Object value, ListGridRecord record,
    					int rowNum, int colNum) {
    				if (value != null) {
    					NumberFormat nf = NumberFormat.getFormat("#,##0");
    					try {
    						return "$" + nf.format(((Number) value).longValue());
    					} catch (Exception e) {
    						return value.toString();
    					}
    				}
    				return null;
    			}
    		});
    
    		TreeGridField work = new TreeGridField("Work");
    		work.setWidth(70);
    		work.setCanFilter(false);
    		work.setCanSort(false);
    
    		setFields(formattedField, salaryField, work);
    
    		addFolderOpenedHandler(new FolderOpenedHandler() {
    			@Override
    			public void onFolderOpened(FolderOpenedEvent event) {
    			}
    		});
    		addFolderClosedHandler(new FolderClosedHandler() {
    			@Override
    			public void onFolderClosed(FolderClosedEvent event) {
    				invalidateRecordComponents();
    			}
    		});
    		addDropHandler(new DropHandler() {
    			@Override
    			public void onDrop(DropEvent event) {
    				invalidateRecordComponents();
    			}
    		});
    	}
    
    	public static class EN extends com.smartgwt.client.widgets.tree.TreeNode {
    		public EN(String employeeId, String reportsTo, String name, String job,
    				int salary, boolean isOpen) {
    			setAttribute("EmployeeId", employeeId);
    			setAttribute("ReportsTo", reportsTo);
    			setAttribute("Name", name);
    			setAttribute("Job", job);
    			setAttribute("Salary", salary);
    			setAttribute("isOpen", isOpen);
    		}
    	}
    
    	@Override
    	public Canvas updateRecordComponent(ListGridRecord record, Integer colNum,
    			Canvas component, boolean recordChanged) {
    		if (colNum != getFieldNum("Work")) {
    			return super.updateRecordComponent(record, colNum, component,
    					recordChanged);
    		}
    		return createRecordComponent(record, colNum);
    	}
    
    	@Override
    	protected Canvas createRecordComponent(final ListGridRecord record,
    			Integer colNum) {
    		if (colNum != getFieldNum("Work")) {
    			return super.createRecordComponent(record, colNum);
    		}
    
    		HLayout canvas = new HLayout(3);
    		canvas.setSnapTo("CC");
    		canvas.setWidth(118);
    		canvas.setHeight(22);
    
    		if ("Mgr".equals(record.getAttributeAsString("Job").substring(0, 3))) {
    			createFolder(canvas);
    		} else {
    			createNode(canvas);
    		}
    
    		return canvas;
    	}
    
    	private void createNode(HLayout canvas) {
    		ImgButton run = getButton("delete");
    		ImgButton edit = getButton("edit");
    		ImgButton delete = getButton("run");
    
    		canvas.addMember(edit);
    		canvas.addMember(delete);
    		canvas.addMember(run);
    	}
    
    	private void createFolder(HLayout canvas) {
    		ImgButton deleteFolder = getButton("delete");
    		ImgButton editFolder = getButton("edit");
    
    		canvas.addMember(editFolder);
    		canvas.addMember(deleteFolder);
    	}
    
    	public static ImgButton getButton(String name) {
    		ImgButton button = new ImgButton();
    		button.setID("_img_" + buttonId++);
    		button.setShowDown(false);
    		button.setShowRollOver(false);
    		button.setLayoutAlign(Alignment.CENTER);
    		button.setSrc(iconPath + name + ".png");
    		button.setPrompt(name);
    		button.setHeight(16);
    		button.setWidth(16);
    		return button;
    	}
    }
    Attached Files

    #2
    Please try the latest patched build, there were fixes in this area recently. Let us know if the problem still persists and we can take a look.

    Comment


      #3
      Retest failed
      SmartGWT Version: 4.1d BuildDate: Mon Oct 14 09:59:00 CEST 2013
      Attached Files

      Comment


        #4
        Ok, we'll take a look and update this thread when we have more information.

        Comment


          #5
          Firstly, testing against latest 4.1d code, we don't see any issues if we add your SimpleTestGrid class, create an instance of it, run the project and then open/close/reposition nodes.

          Can you confirm that the code you posted shows the behavior in your screenshot?

          If so, can you be more specific about what steps can be taken using this code to cause the bad behavior?

          It seems like having a dataSource and loadOnDemand might be more likely to cause issues like the ones you describe, especially if you see them in "data" pooling mode - but this sample doesn't use a dataSource and preloads all the data.

          Please clarify.

          Secondly, this code is a little confused...

          1) Its not clear why you're invalidating the record components on close and drop (which in this sample doesn't work) - was there some particular reason for this?

          2) updateRecordComponent() is calling createRecordComponent() directly, which defeats the concept of pooling - updateRecordComponent() receives a component as a parameter - the purpose of this method is to update that component and return it in a state that suits the new record. So, in this case, you might have createRecordComponent() *always* create a layout with three buttons, but only show the third one for Managers. Then, when updateRecordComponent() is called, just check the "Job" and show or hide the third button on the passed component before returning it.

          Note also that 2) above is not applicable to "data" pooling mode and shouldn't be implemented in that mode.

          Comment


            #6
            Thank you for the detailed answer.

            I have retested the previously attached code with the download version smartgwtpro-4.1d.zip from
            /builds/SmartGWT/4.1d/Pro/2013-10-16 (SmartGWT Version: 4.1d BuildDate: Wed Oct 16 12:52:00 CEST 2013)

            Test A) I can confirm that the screenshot was reproduced that way:
            A1) Start. OK
            A2) Resizing columns. OK
            A3) Drag "Mgr Site: Tam Kan" and drop before "Dsl Sys : Che Pea" FAILED: Missing Icons
            A4) Collapse root. OK
            A5) Expand root. FAILED: Missing Icons
            A6) Drag "Mgr Syst: Rog Leg" and drop before "Dsl Sys : Fel Pip" FAILED: Missing and wrong positioned Icons

            We have used the viewport pooling mode without extra settings. Log.txt shows all in right created.

            Special thanks for clearing the main concept and details in the second part, mainly for 2)
            The extended code contains my research to get the expected result.
            1) I tried to force refreshing the grid. That was the only reason.
            2) The goal is to show 3 icons for employee nodes and only 2 icons for manager folders. Calling updateRecordComponent() was (false) tested for pooling mode recycle.

            Test B) The same steps show the result for the retested pooling mode data. After expansion the icons are correct created. Additional steps B4, B5, B7 and B8 show collapsed and expanded tree correct.
            Code:
            RecordComponentPoolingMode pool = RecordComponentPoolingMode.DATA;
            Which pooling mode should we use when we can have large data sets?
            Attached Files

            Comment


              #7
              The code (extended with "Mgr." +) for the log:
              Code:
              @Override
              protected Canvas createRecordComponent(final ListGridRecord record,
              		Integer colNum) {
              	if (colNum != getFieldNum("Work")) {
              		return super.createRecordComponent(record, colNum);
              	}
              
              	HLayout canvas = new HLayout(3);
              	canvas.setSnapTo("CC");
              	canvas.setWidth(118);
              	canvas.setHeight(22);
              
              	if ("Mgr".equals(record.getAttributeAsString("Job").substring(0, 3))) {
              		createFolder(canvas);
              		System.out.println("Mgr." + record.getAttributeAsString("Name")
              				+ " created " + canvas.getMembers().length);
              	} else {
              		createNode(canvas);
              		System.out.println(record.getAttributeAsString("Name")
              				+ " created " + canvas.getMembers().length);
              	}
              
              	return canvas;
              }
              The code for the version:
              Code:
              import com.smartgwt.client.util.SC;
              SC.say("SmartGWT Version: "
              		+ com.smartgwt.client.Version.getVersion()
              		+ " BuildDate: "
              		+ com.smartgwt.client.Version.getBuildDate());
              We have only the following files replaced in our file system with the fresh ones from the downloaded zip: smartgwt.jar, smartgwtpro.jar, smartgwt-skins.jar. Should we do some other steps to update the right version?
              Attached Files

              Comment


                #8
                Ok, we've fixed what looks like the underlying cause of this issue - in fact, it was that dataChanged() was firing too often, and remapping the embedded components numerous times. As of builds dated October 19, tomorrow, and later, you should find that everything works as expected (in all pooling modes).

                You should also find it to be quite a lot quicker!

                A few points:

                1) There's no need to call invalidateRecordComponents() - get rid of the two handlers that call it in your SimpleTestGrid.

                2) Below is some code that more correctly uses the recordComponent subsystem in your use case (for "recycle" mode, the most efficient) - creates components the way you want them, with 2 or 3 icons, and then updates them as necessary when dataChanged fires.

                Code:
                @Override
                public Canvas updateRecordComponent(ListGridRecord record, Integer colNum, Canvas component, boolean recordChanged) {
                	if (colNum != getFieldNum("Work")) {
                		return null;
                	}
                
                	if (component != null) {
                		if ("Mgr".equals(record.getAttributeAsString("Job").substring(0, 3))) {
                			((HLayout)component).getMember(1).hide();
                			System.out.println("UPDATED MANAGER buttons: " + record.getAttributeAsString("Name") + " (2 buttons)");
                		} else {
                			((HLayout)component).getMember(1).show();
                			System.out.println("UPDATED NORMAL buttons: " + record.getAttributeAsString("Name") + " (3 buttons)");
                		}
                		return component;
                	}
                	return createRecordComponent(record, colNum);
                }
                
                @Override
                protected Canvas createRecordComponent(final ListGridRecord record, Integer colNum) {
                	if (colNum != getFieldNum("Work")) {
                		return null;
                	}
                
                	HLayout canvas = new HLayout(3);
                	canvas.setSnapTo("CC");
                	canvas.setWidth(118);
                	canvas.setHeight(22);
                
                	if ("Mgr".equals(record.getAttributeAsString("Job").substring(0, 3))) {
                		createNode(canvas, true);
                		System.out.println("CREATED MANAGER buttons: " + record.getAttributeAsString("Name") + " (2 buttons)");
                	} else {
                		createNode(canvas, false);
                		System.out.println("CREATED NORMAL buttons: " + record.getAttributeAsString("Name") + " (3 buttons)");
                	}
                
                	return canvas;
                }
                
                private void createNode(HLayout canvas, boolean isManager) {
                	ImgButton run = getButton("delete");
                	ImgButton edit = getButton("edit");
                	ImgButton delete = getButton("run");
                
                	canvas.addMember(edit);
                	canvas.addMember(delete);
                	canvas.addMember(run);
                	if (isManager) canvas.getMember(1).hide();
                }
                Last edited by Isomorphic; 18 Oct 2013, 03:53.

                Comment


                  #9
                  Thank you for the answer. After my holiday the next week I’ll post a feedback.

                  Comment


                    #10
                    Thank you for the details. The code was tested. Test failed in all pooling mode. Some operations work OK. After 8-10 mixed operations (collapse, expand, drag and drop branches) there were missing icons and broken rows too. Screenshots show the example configurations.

                    SmartGWT Version: 4.1d BuildDate: Sun Oct 20 09:59:00 CEST 2013
                    My log extension: it contains date + time, as in code part for updateRecordComponent()
                    Code:
                    if ("Mgr"
                    		.equals(record.getAttributeAsString("Job").substring(0, 3))) {
                    	((HLayout) component).getMember(1).hide();
                    	System.out.println(new Date() + " UPDATED MANAGER buttons: "
                    			+ record.getAttributeAsString("Name") + " (2 buttons)");
                    } else {
                    	((HLayout) component).getMember(1).show();
                    	System.out.println(new Date() + " UPDATED NORMAL buttons: "
                    			+ record.getAttributeAsString("Name") + " (3 buttons)");
                    }
                    return component;
                    Attached Files

                    Comment


                      #11
                      We're not sure what you mean by "the code was tested" - please post whatever code you are testing, and make sure it contains the fixes we pointed out in post #8.

                      Also, as previously requested, we need exact steps that lead to bad behavior. Saying that "8-10 mixed operations" are required is not good enough, as we have already attempted to reproduce by trying a random mix of operations - we need a specific set of steps that always works to create an issue.

                      Comment


                        #12
                        OK, I give the test details.
                        I’m testing your suggested code from post #8, plus little extension "new Date() + " for log.
                        RecordComponentPoolingMode pool = RecordComponentPoolingMode.RECYCLE;

                        Test steps:
                        T0) Start. OK
                        T1) Bigger panel. OK
                        T2) Resizing columns. OK
                        T3) Drag "Mgr Site: Tam Kan" and drop before "Dsl Sys : Che Pea" OK
                        T4) Collapse root. OK
                        T5) Expand root. OK
                        T6) Drag "Mgr Syst: Rog Leg" and drop before "Dsl Sys : Fel Pip" FAILED: Missing and wrong positioned Icons

                        SmartGWT Version: 4.1d BuildDate: Sun Oct 20 09:59:00 CEST 2013
                        Attached Files

                        Comment


                          #13
                          This code has not been adjusted according to our recommendations (still has calls to invalidateRecordComponents()).

                          Comment


                            #14
                            OK, sorry, thank you. I cleared it and I retested it in all pooling mode, data and recycle work OK. There is yet some problem with viewport, could you please check the attached code.

                            Test steps:
                            T0) Start. OK
                            T1) Bigger panel. OK
                            T2) Resizing columns. OK
                            T3) Drag "Mgr Site: Tam Kan" and drop before "Dsl Sys : Che Pea" OK
                            T4) Collapse root. OK
                            T5) Expand root. FAILED

                            I am testing now our more sophisticated code providing further editing and data source operations…
                            Attached Files

                            Comment


                              #15
                              Instead of createRecordComponent our alternative solution with getAttribute/setAttribute works fine in
                              SmartGWT 4.1p pro.

                              Comment

                              Working...
                              X