{"id":552,"date":"2012-10-26T15:56:26","date_gmt":"2012-10-26T10:26:26","guid":{"rendered":"http:\/\/ramkulkarni.com\/blog\/?p=552"},"modified":"2012-10-26T15:56:26","modified_gmt":"2012-10-26T10:26:26","slug":"maintaining-expandcollapse-state-in-eclipse-treeviewer","status":"publish","type":"post","link":"http:\/\/ramkulkarni.com\/blog\/maintaining-expandcollapse-state-in-eclipse-treeviewer\/","title":{"rendered":"Maintaining expanded\/collapsed state in Eclipse TreeViewer"},"content":{"rendered":"<p>JFace TreeViewer is a very useful UI control for displaying hierarchical data. It is used extensively in Eclipse, for example in Project\/Package\/Navigator view, Outline view, Debug Variables view etc. Eclipse .org hosts a nice article on TreeViewer &#8211; <a href=\"http:\/\/www.eclipse.org\/articles\/Article-TreeViewer\/TreeViewerArticle.htm\" target=\"_blank\">How to use the JFace Tree Viewer<\/a>.<\/p>\n<p>To specify data and its hierarchy in the TreeViewer, you implement <a href=\"http:\/\/help.eclipse.org\/indigo\/topic\/org.eclipse.platform.doc.isv\/reference\/api\/org\/eclipse\/jface\/viewers\/ITreeContentProvider.html\" target=\"_blank\">ITreeContentProvider<\/a> interface. This interface has methods like getElements, getChildren which you need to override to provide content and structure to the TreeViewer. You would typically return array of your model objects from getElements or getChildren methods. And since it is a tree view, you can expand or collapse the nodes. The model classes for an example in the above article could be Category (book, game etc.), Book and Game. Category can have Books or Games. You might load this information from a database and pass it to the content provider object. To refresh information in the TreeViewer, you would call one of the variants of refresh() function.<\/p>\n<p><!--more--><\/p>\n<p>If you are not recreating model objects on every refresh, then the tree maintains state (collapsed\/expanded) of each node. However if you are constructing model objects again, then the TreeViewer does not maintain state of nodes. It would collapse all the nodes. This would happen even if data is not changed. For example consider Category class as follows &#8211;<\/p>\n<pre style=\"color: #000000; background: #ffffff;\"><span style=\"color: #7f0055; font-weight: bold;\">public<\/span> <span style=\"color: #7f0055; font-weight: bold;\">class<\/span> Category\n{\n    <span style=\"color: #7f0055; font-weight: bold;\">private<\/span> <span style=\"color: #7f0055; font-weight: bold;\">String<\/span> name;\n    <span style=\"color: #7f0055; font-weight: bold;\">private<\/span> <span style=\"color: #7f0055; font-weight: bold;\">Object<\/span>[] children; <span style=\"color: #3f7f59;\">\/\/books or games<\/span>\n\n    <span style=\"color: #3f7f59;\">\/\/...<\/span>\n}<\/pre>\n<p>and you have a category in the TreeView with name=&#8221;Books&#8221; and a few child nodes. If you refresh the tree by creating new category object with the same information, then the node for this category would be collapsed in the tree, even if the previous state of the node was expanded.<\/p>\n<p>This is because the updateChildren method of AbstractTreeViewClass first check the state of each node in the tree and stores model objects (data) of all expanded nodes in a Map. Then it iterates through new model objects and checks if new object exists in the map. Eclipse\/JFace uses CustomHashTable for this purpose. If it finds the object in the expanded map, then it expands the new node. It checks if given (model) object exists in the map by checking two things &#8211; 1. hash code 2. calling equals method. So even if data in two model objects are same, they would not be same for the CustomHashTable because their hash code may be different and equals method would return false (default implementation of equals compares reference\/address of objects).<\/p>\n<p>Therefore if you want to maintain state of nodes in the TreeViewer, your model object should override hashCode() and equals() method. The hashCode method should return the same value for same data and equals should return true. In the above example, we could modify Category class as follows to maintain its state in the TreeViewer &#8211;<\/p>\n<pre style=\"color: #000000; background: #ffffff;\"><span style=\"color: #7f0055; font-weight: bold;\">public<\/span> <span style=\"color: #7f0055; font-weight: bold;\">class<\/span> Category\n{\n    <span style=\"color: #7f0055; font-weight: bold;\">private<\/span> <span style=\"color: #7f0055; font-weight: bold;\">String<\/span> name;\n    <span style=\"color: #7f0055; font-weight: bold;\">private<\/span> <span style=\"color: #7f0055; font-weight: bold;\">Object<\/span>[] children; <span style=\"color: #3f7f59;\">\/\/books or games<\/span>\n\n    <span style=\"color: #7f0055; font-weight: bold;\">public<\/span> <span style=\"color: #7f0055; font-weight: bold;\">int<\/span> hashCode()\n    {\n        <span style=\"color: #7f0055; font-weight: bold;\">return<\/span> name.hashCode();\n    }\n\n    <span style=\"color: #7f0055; font-weight: bold;\">public<\/span> <span style=\"color: #7f0055; font-weight: bold;\">boolean<\/span> equals (<span style=\"color: #7f0055; font-weight: bold;\">Object<\/span> obj)\n    {\n        <span style=\"color: #7f0055; font-weight: bold;\">if<\/span> (obj <span style=\"color: #7f0055; font-weight: bold;\">instanceof<\/span> Category == <span style=\"color: #7f0055; font-weight: bold;\">false<\/span>)\n            <span style=\"color: #7f0055; font-weight: bold;\">return<\/span> <span style=\"color: #7f0055; font-weight: bold;\">false<\/span>;\n\n        <span style=\"color: #7f0055; font-weight: bold;\">return<\/span> name.equals(((Category)obj).name);\n    }\n\n    <span style=\"color: #3f7f59;\">\/\/...<\/span>\n}<\/pre>\n<p>-Ram Kulkarni<\/p>\n","protected":false},"excerpt":{"rendered":"<p>JFace TreeViewer is a very useful UI control for displaying hierarchical data. It is used extensively in Eclipse, for example in Project\/Package\/Navigator view, Outline view, Debug Variables view etc. Eclipse .org hosts a nice article on TreeViewer &#8211; How to use the JFace Tree Viewer. To specify data and its hierarchy in the TreeViewer, you &hellip; <\/p>\n<p class=\"link-more\"><a href=\"http:\/\/ramkulkarni.com\/blog\/maintaining-expandcollapse-state-in-eclipse-treeviewer\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Maintaining expanded\/collapsed state in Eclipse TreeViewer&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[38,1],"tags":[25,56],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p2g9O8-8U","jetpack-related-posts":[],"_links":{"self":[{"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/posts\/552"}],"collection":[{"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/comments?post=552"}],"version-history":[{"count":0,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/posts\/552\/revisions"}],"wp:attachment":[{"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/media?parent=552"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/categories?post=552"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/tags?post=552"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}