/*************************************************** * * cismet GmbH, Saarbruecken, Germany * * ... and it just works. * ****************************************************/ package Sirius.navigator.ui.tree; import Sirius.navigator.connection.SessionManager; import Sirius.navigator.exception.ConnectionException; import Sirius.navigator.plugin.PluginRegistry; import Sirius.navigator.plugin.interfaces.PluginSupport; import Sirius.navigator.resource.PropertyManager; import Sirius.navigator.types.treenode.*; import Sirius.navigator.ui.ComponentRegistry; import Sirius.server.middleware.types.*; import org.apache.log4j.Logger; import java.awt.EventQueue; import java.awt.Toolkit; import java.beans.PropertyChangeListener; import java.util.*; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.concurrent.ExecutionException; import javax.swing.JFrame; import javax.swing.SwingWorker; import javax.swing.tree.DefaultTreeModel; import de.cismet.cids.navigator.utils.ClassCacheMultiple; import de.cismet.cids.navigator.utils.DirectedMetaObjectNodeComparator; import de.cismet.cids.navigator.utils.MetaTreeNodeVisualization; import de.cismet.cids.server.search.MetaObjectNodeServerSearch; import de.cismet.cids.utils.ClassloadingHelper; import de.cismet.cismap.commons.interaction.CismapBroker; import de.cismet.tools.CismetThreadPool; import de.cismet.tools.collections.HashArrayList; /** * Der SearchTree dient zum Anzeigen von Suchergebnissen. Neben der Funktionalit\u00E4t, die er von GenericMetaTree * erbt, bietet er zusaetzlich noch die Moeglichkeit, die Suchergebnisse schrittweise anzuzeigen. D.h. es wird immer nur * ein kleiner Ausschnitt fester Groesse aus der gesamten Ergebissmenge angezeigt. Um durch die Ergebnissmenge zu * navigieren stellt der SearchTree spezielle Methoden bereit. * * @version $Revision$, $Date$ */ public class SearchResultsTree extends MetaCatalogueTree { //~ Static fields/initializers --------------------------------------------- private static final transient Logger log = Logger.getLogger(SearchResultsTree.class); //~ Instance fields -------------------------------------------------------- protected HashArrayList<Node> resultNodes = new HashArrayList<Node>(); protected boolean muteResultNodeListeners = false; private boolean empty = true; private final RootTreeNode rootNode; private Thread runningNameLoader = null; private SwingWorker<ArrayList<DefaultMetaTreeNode>, Void> refreshWorker; private boolean syncWithMap = false; private boolean ascending = true; private final WaitTreeNode waitTreeNode = new WaitTreeNode(); private boolean syncWithRenderer; private MetaObjectNodeServerSearch underlyingSearch; private ArrayList<ResultNodeListener> resultNodeListeners = new ArrayList<ResultNodeListener>(); //~ Constructors ----------------------------------------------------------- /** * Erzeugt einen neuen, leeren, SearchTree. Es werden jeweils 50 Objekte angezeigt. * * @throws Exception DOCUMENT ME! */ public SearchResultsTree() throws Exception { this(true, 2); } /** * Creates a new SearchResultsTree object. * * @param useThread DOCUMENT ME! * @param maxThreadCount DOCUMENT ME! * * @throws Exception DOCUMENT ME! */ public SearchResultsTree(final boolean useThread, final int maxThreadCount) throws Exception { super(new RootTreeNode(), false, useThread, maxThreadCount); this.rootNode = (RootTreeNode)this.defaultTreeModel.getRoot(); defaultTreeModel.setAsksAllowsChildren(true); this.defaultTreeModel.setAsksAllowsChildren(true); } //~ Methods ---------------------------------------------------------------- /** * Setzt die ResultNodes fuer den Suchbaum, d.h. die Ergebnisse der Suche. * * @param nodes Ergebnisse, die im SearchTree angezeigt werden sollen. */ public void setResultNodes(final Node[] nodes) { if (log.isInfoEnabled()) { log.info("[SearchResultsTree] filling tree with '" + nodes.length + "' nodes"); // NOI18N } if ((nodes == null) || (nodes.length < 1)) { empty = true; resultNodes.clear(); fireResultNodesCleared(); } else { empty = false; resultNodes = new HashArrayList<Node>(Arrays.asList(filterNodesWithoutPermission(nodes))); fireResultNodesChanged(); } if (resultNodes.size() > 0) { refreshTree(true); } } /** * Removes all nodes, which references a cidsBean without read permissions. This is required to consider the * CustomBeanPermissionProvider. * * @param nodes the nodes to check for read permissions * * @return an array with all nodes with read permissions. */ private Node[] filterNodesWithoutPermission(final Node[] nodes) { final List<Node> nodeList = new ArrayList<Node>(); if (!PropertyManager.USE_CUSTOM_BEAN_PERMISSION_PROVIDER_FOR_SEARCH) { return nodes; } for (final Node nodeToCheck : nodes) { if (nodeToCheck instanceof MetaObjectNode) { final MetaObjectNode mon = (MetaObjectNode)nodeToCheck; final MetaClass mc = ClassCacheMultiple.getMetaClass(mon.getDomain(), mon.getClassId()); if (existsCustomBeanPermissonProviderForClass(mc)) { if (mon.getObject() == null) { try { final MetaObject MetaObject = SessionManager.getProxy() .getMetaObject(mon.getObjectId(), mon.getClassId(), mon.getDomain()); mon.setObject(MetaObject); } catch (ConnectionException e) { log.error("Cannot load meta object to check the read permissions", e); continue; } } if (!mon.getObject().getBean().hasObjectReadPermission(SessionManager.getSession().getUser())) { continue; } } } nodeList.add(nodeToCheck); } return nodeList.toArray(new Node[nodeList.size()]); } /** * Checks if a CustomBeanPermissionProvider for the given class exists. * * @param mc the class, it should be checked for * * @return true, iff a CistomBeanPermissionProvider for the given class exists */ private boolean existsCustomBeanPermissonProviderForClass(final MetaClass mc) { try { final Class cpp = ClassloadingHelper.getDynamicClass(mc, ClassloadingHelper.CLASS_TYPE.PERMISSION_PROVIDER); if (log.isDebugEnabled()) { log.debug("custom read permission provider retrieval result: " + cpp); // NOI18N } return cpp != null; } catch (Exception ex) { log.warn("error during creation of custom permission provider", ex); // NOI18N return true; } } /** * DOCUMENT ME! */ public void syncWithMap() { syncWithMap(isSyncWithMap()); } /** * DOCUMENT ME! * * @param rnl DOCUMENT ME! */ public void addResultNodeListener(final ResultNodeListener rnl) { resultNodeListeners.add(rnl); } /** * DOCUMENT ME! * * @param rnl DOCUMENT ME! */ public void removeResultNodeListener(final ResultNodeListener rnl) { resultNodeListeners.add(rnl); } /** * DOCUMENT ME! */ public void fireResultNodesChanged() { if (!muteResultNodeListeners) { for (final ResultNodeListener rnl : resultNodeListeners) { rnl.resultNodesChanged(); } } } /** * DOCUMENT ME! */ public void fireResultNodesFiltered() { if (!muteResultNodeListeners) { for (final ResultNodeListener rnl : resultNodeListeners) { rnl.resultNodesFiltered(); } } } /** * DOCUMENT ME! */ public void fireResultNodesCleared() { if (!muteResultNodeListeners) { for (final ResultNodeListener rnl : resultNodeListeners) { rnl.resultNodesCleared(); } } } /** * DOCUMENT ME! * * @param sync DOCUMENT ME! */ public void syncWithMap(final boolean sync) { if (sync) { if (log.isDebugEnabled()) { log.debug("syncWithMap"); // NOI18N } if (!isSyncWithRenderer()) { PluginRegistry.getRegistry() .getPluginDescriptor("cismap") .getUIDescriptor("cismap") .getView() .makeVisible(); } try { final PluginSupport map = PluginRegistry.getRegistry().getPlugin("cismap"); // NOI18N final List<DefaultMetaTreeNode> v = new ArrayList<DefaultMetaTreeNode>(); final DefaultTreeModel dtm = (DefaultTreeModel)getModel(); for (int i = 0; i < ((DefaultMetaTreeNode)dtm.getRoot()).getChildCount(); ++i) { if (resultNodes.get(i) instanceof MetaObjectNode) { final DefaultMetaTreeNode otn = (DefaultMetaTreeNode)((DefaultMetaTreeNode)dtm.getRoot()) .getChildAt(i); v.add(otn); } } MetaTreeNodeVisualization.getInstance().addVisualization(v); } catch (Throwable t) { log.warn("Fehler beim synchronisieren der Suchergebnisse mit der Karte", t); // NOI18N } } } /** * DOCUMENT ME! */ public void syncWithRenderer() { syncWithRenderer(isSyncWithRenderer()); } /** * DOCUMENT ME! * * @param sync DOCUMENT ME! */ public void syncWithRenderer(final boolean sync) { if (sync) { if (log.isDebugEnabled()) { log.debug("syncWithRenderer"); // NOI18N } if (!isSyncWithMap()) { ComponentRegistry.getRegistry().getGUIContainer().select(ComponentRegistry.DESCRIPTION_PANE); } setSelectionInterval(0, getRowCount()); } } /** * DOCUMENT ME! * * @param nodes DOCUMENT ME! * @param append DOCUMENT ME! * @param listener DOCUMENT ME! */ public void setResultNodes(final Node[] nodes, final boolean append, final PropertyChangeListener listener) { setResultNodes(nodes, append, listener, false); } /** * Setzt die ResultNodes fuer den Suchbaum, d.h. die Ergebnisse der Suche.<br> * Diese Ergebnisse koennen an eine bereits vorhandene Ergebnissmenge angehaengt werden * * @param nodes Ergebnisse, die im SearchTree angezeigt werden sollen. * @param append Ergebnisse anhaengen. * @param listener DOCUMENT ME! * @param simpleSort if true, sorts the search results alphabetically. Usually set to false, as a more specific * sorting order is wished. */ public void setResultNodes(final Node[] nodes, final boolean append, final PropertyChangeListener listener, final boolean simpleSort) { setResultNodes(nodes, append, listener, simpleSort, true); } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public MetaObjectNodeServerSearch getUnderlyingSearch() { return underlyingSearch; } /** * DOCUMENT ME! * * @param underlyingSearch DOCUMENT ME! */ public void setUnderlyingSearch(final MetaObjectNodeServerSearch underlyingSearch) { this.underlyingSearch = underlyingSearch; } /** * DOCUMENT ME! * * @param args DOCUMENT ME! */ public static void main(final String[] args) { final JFrame frame = new JFrame(); try { final SearchResultsTree tree = new SearchResultsTree(); frame.setSize(100, 100); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); } /** * Setzt die ResultNodes fuer den Suchbaum, d.h. die Ergebnisse der Suche.<br> * Diese Ergebnisse koennen an eine bereits vorhandene Ergebnissmenge angehaengt werden * * @param nodes Ergebnisse, die im SearchTree angezeigt werden sollen. * @param append Ergebnisse anhaengen. * @param listener DOCUMENT ME! * @param simpleSort if true, sorts the search results alphabetically. Usually set to false, as a more specific * sorting order is wished. * @param sortActive if false, no sort will be done (the value of simpleSort will be ignored, if sortActive is * false) */ public void setResultNodes(final Node[] nodes, final boolean append, final PropertyChangeListener listener, final boolean simpleSort, final boolean sortActive) { if (log.isInfoEnabled()) { log.info("[SearchResultsTree] " + (append ? "appending" : "setting") + " '" + nodes.length + "' nodes"); // NOI18N } if ((append == true) && ((nodes == null) || (nodes.length < 1))) { return; } else if ((append == false) && ((nodes == null) || (nodes.length < 1))) { this.clear(); return; } else if ((append == true) && (empty == false)) { resultNodes.addAll(Arrays.asList(filterNodesWithoutPermission(nodes))); } else { this.clear(); resultNodes = new HashArrayList<Node>(Arrays.asList(filterNodesWithoutPermission(nodes))); } empty = false; refreshTree(true, listener, simpleSort, sortActive); fireResultNodesChanged(); if (!getModel().getRoot().equals(rootNode)) { ((DefaultTreeModel)getModel()).setRoot(rootNode); ((DefaultTreeModel)getModel()).reload(); } } /** * DOCUMENT ME! * * @param initialFill sort DOCUMENT ME! */ protected void refreshTree(final boolean initialFill) { refreshTree(initialFill, null); } /** * DOCUMENT ME! * * @param initialFill DOCUMENT ME! * @param listener DOCUMENT ME! */ private void refreshTree(final boolean initialFill, final PropertyChangeListener listener) { refreshTree(initialFill, listener, false); } /** * DOCUMENT ME! * * @param initialFill DOCUMENT ME! * @param listener DOCUMENT ME! * @param simpleSort DOCUMENT ME! */ private void refreshTree(final boolean initialFill, final PropertyChangeListener listener, final boolean simpleSort) { refreshTree(initialFill, listener, simpleSort, true); } /** * DOCUMENT ME! * * @param initialFill sort DOCUMENT ME! * @param listener DOCUMENT ME! * @param simpleSort if true, sorts the search results alphabetically. Usually set to false, as a more specific * sorting order is wished. * @param sortActive simpleSort if false, no sort will be done (the value of simpleSort will be ignored, if * sortActive is false) */ private void refreshTree(final boolean initialFill, final PropertyChangeListener listener, final boolean simpleSort, final boolean sortActive) { if ((refreshWorker != null) && !refreshWorker.isDone()) { log.warn("Refreshing search result tree is triggered while another refresh process is still not done."); refreshWorker.cancel(true); } EventQueue.invokeLater(new Runnable() { @Override public void run() { rootNode.removeAllChildren(); if (resultNodes.size() > 0) { rootNode.add(waitTreeNode); } defaultTreeModel.nodeStructureChanged(rootNode); refreshWorker = new RefreshTreeWorker(initialFill, simpleSort, sortActive); refreshWorker.addPropertyChangeListener(listener); CismetThreadPool.execute(refreshWorker); } }); } /** * DOCUMENT ME! */ private void checkForDynamicNodes() { final DefaultTreeModel dtm = (DefaultTreeModel)getModel(); final DefaultMetaTreeNode node = (DefaultMetaTreeNode)dtm.getRoot(); if (runningNameLoader != null) { runningNameLoader.interrupt(); } final Thread t = new Thread("SearchResultsTree checkForDynamicNodes()") { @Override public void run() { runningNameLoader = this; for (int i = 0; i < dtm.getChildCount(node); ++i) { if (interrupted()) { break; } try { final DefaultMetaTreeNode n = (DefaultMetaTreeNode)dtm.getChild(node, i); if ((n != null) && (n.getNode().getName() == null) && n.isObjectNode()) { try { final ObjectTreeNode on = ((ObjectTreeNode)n); EventQueue.invokeLater(new Runnable() { @Override public void run() { n.getNode() .setName( org.openide.util.NbBundle.getMessage( SearchResultsTree.class, "SearchResultsTree.checkForDynamicNodes().loadName")); // NOI18N dtm.nodeChanged(on); } }); if (log.isDebugEnabled()) { log.debug("caching object node"); // NOI18N } final MetaObject MetaObject = SessionManager.getProxy() .getMetaObject(on.getMetaObjectNode().getObjectId(), on.getMetaObjectNode().getClassId(), on.getMetaObjectNode().getDomain()); on.getMetaObjectNode().setObject(MetaObject); EventQueue.invokeLater(new Runnable() { @Override public void run() { n.getNode().setName(MetaObject.toString()); dtm.nodeChanged(on); } }); } catch (final Exception t) { log.error("could not retrieve meta object of node '" + this + "'", t); // NOI18N } } else { if (log.isDebugEnabled()) { log.debug("n.getNode().getName()!=null: " + n.getNode().getName() + ":"); // NOI18N } } } catch (final Exception e) { log.error("Error while loading the name", e); // NOI18N } } runningNameLoader = null; } }; CismetThreadPool.execute(t); } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public List<Node> getResultNodes() { return resultNodes; } /** * DOCUMENT ME! * * @param n DOCUMENT ME! * * @return DOCUMENT ME! */ public boolean containsNode(final Node n) { return (n != null) && resultNodes.contains(n); } /** * Diese Funktion dient dazu, eine Selektion von Knoten aus dem SearchTree zu loeschen. * * @param selectedNodes Die Knoten, die geloescht werden sollen. * * @return true, wenn mindestens ein Knoten geloescht wurde. */ public boolean removeResultNodes(final DefaultMetaTreeNode[] selectedNodes) { if (log.isInfoEnabled()) { log.info("[SearchResultsTree] removing '" + selectedNodes + "' nodes"); // NOI18N } //J- boolean deleted = false; if ((selectedNodes == null) || (selectedNodes.length < 1)) { return deleted; } final List tmpNodeVector = new ArrayList(); tmpNodeVector.addAll(Arrays.asList(resultNodes)); for (int i = 0; i < tmpNodeVector.size(); i++) { for (int j = 0; j < selectedNodes.length; j++) { if ((i < tmpNodeVector.size()) && selectedNodes[j].equalsNode((Node)tmpNodeVector.get(i))) { tmpNodeVector.remove(i); deleted = true; j--; } } } //J+ if (deleted) { this.setResultNodes((Node[])tmpNodeVector.toArray(new Node[tmpNodeVector.size()]), false, null); } return deleted; } /** * DOCUMENT ME! */ public void removeSelectedResultNodes() { final Collection selectedNodes = this.getSelectedNodes(); if (selectedNodes != null) { this.removeResultNodes(selectedNodes); refreshTree(false); } } /** * DOCUMENT ME! * * @param selectedNodes DOCUMENT ME! * * @return DOCUMENT ME! */ public boolean removeResultNodes(final Collection selectedNodes) { if (log.isInfoEnabled()) { log.info("[SearchResultsTree] removing '" + selectedNodes + "' nodes"); // NOI18N } boolean deleted = false; try { if ((selectedNodes != null) && (selectedNodes.size() > 0)) { final ArrayList all = new ArrayList(Arrays.asList(resultNodes)); final ArrayList allWorkingCopy = new ArrayList(Arrays.asList(resultNodes)); final ArrayList selectionTreeNodes = new ArrayList(selectedNodes); final ArrayList selection = new ArrayList(); for (final Object selO : selectionTreeNodes) { if (selO instanceof DefaultMetaTreeNode) { final Node n = ((DefaultMetaTreeNode)selO).getNode(); selection.add(n); deleted = true; } } resultNodes.removeAll(selection); fireResultNodesChanged(); // if (resultNodes.size() == 0) { // clear(); // } else { // defaultTreeModel.nodeStructureChanged(rootNode); // } } // // for (final Object allO : all) { // for (final Object selO : selection) { // if ((allO instanceof MetaObjectNode) && (selO instanceof MetaObjectNode)) { // final MetaObjectNode allMON = (MetaObjectNode)allO; // final MetaObjectNode selMON = (MetaObjectNode)selO; // if ((allMON.getObjectId() == selMON.getObjectId()) // && (allMON.getClassId() == selMON.getClassId()) // && (allMON.getId() == selMON.getId()) // && allMON.getDomain().equals(selMON.getDomain()) // && allMON.toString().equals(selMON.toString())) { // allWorkingCopy.remove(allO); // deleted = true; // } // } else if ((allO instanceof MetaNode) && (selO instanceof MetaNode)) { // final MetaNode allMN = (MetaNode)allO; // final MetaNode selMN = (MetaNode)selO; // if ((allMN.getId() == selMN.getId()) // && allMN.getDomain().equals(selMN.getDomain()) // && allMN.toString().equals(selMN.toString())) { // allWorkingCopy.remove(allO); // deleted = true; // } // } // } // } // // this.setResultNodes((Node[])allWorkingCopy.toArray(new Node[allWorkingCopy.size()]), false, null); // } } catch (Exception e) { log.error("Fehler beim Entfernen eines Objektes aus den Suchergebnissen", e); } return deleted; } /** * Setzt den SearchTree komplett zurueck und entfernt alle Knoten. */ public void clear() { log.info("[SearchResultsTree] removing all nodes"); // NOI18N resultNodes.clear(); fireResultNodesCleared(); empty = true; rootNode.removeAllChildren(); firePropertyChange("browse", 0, 1); // NOI18N defaultTreeModel.nodeStructureChanged(rootNode); System.gc(); } /** * Returns a flag indicating whether the SearchResultsTree is empty or not. * * @return Flag indicating whether tree is empty or not. */ public boolean isEmpty() { return this.empty; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public boolean isSyncWithMap() { return syncWithMap; } /** * DOCUMENT ME! * * @param syncWithMap DOCUMENT ME! */ public void setSyncWithMap(final boolean syncWithMap) { this.syncWithMap = syncWithMap; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public boolean isSyncWithRenderer() { return syncWithRenderer; } /** * DOCUMENT ME! * * @param syncWithRenderer syncWithMap DOCUMENT ME! */ public void setSyncWithRenderer(final boolean syncWithRenderer) { this.syncWithRenderer = syncWithRenderer; } /** * Changes the sort order to ascending or descending according to the given parameter. * * @param ascending Whether to sort ascending ( <code>true</code>) or descending ( <code>false</code>). */ public void sort(final boolean ascending) { this.ascending = ascending; refreshTree(false); } /** * DOCUMENT ME! */ public void cancelNodeLoading() { if ((refreshWorker != null) && !refreshWorker.isDone()) { refreshWorker.cancel(true); rootNode.removeAllChildren(); defaultTreeModel.nodeStructureChanged(rootNode); } } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public SwingWorker getNodeLoadingWorker() { return refreshWorker; } /** * A SwingWorker which encapsulates sorting the results and refreshing the * tree. This worker is needed since it could be necessary to load every * object during the first sort process on a certain result set. * * @version $Revision$, $Date$ */ //J- private class RefreshTreeWorker extends SwingWorker<ArrayList<DefaultMetaTreeNode>, Void> { //~ Instance fields ---------------------------------------------------- private boolean initialFill = false; private DirectedMetaObjectNodeComparator comparator; private boolean simpleSort = false; private boolean sortActive = true; //~ Constructors ------------------------------------------------------- /** * Creates a new RefreshTreeWorker object. * * @param initialFill A flag indicating whether to sort the result set * or not. */ public RefreshTreeWorker(final boolean initialFill) { this.initialFill = initialFill; comparator = new DirectedMetaObjectNodeComparator(ascending); } /** * * @param initialFill * @param simpleSort if true, sorts the search results alphabetically. * Usually set to false, as a more specific sorting order is wished. */ public RefreshTreeWorker(final boolean initialFill, boolean simpleSort) { this(initialFill, simpleSort, true); } /** * * @param initialFill * @param simpleSort if true, sorts the search results alphabetically. * Usually set to false, as a more specific sorting order is wished. * @param sortActive if false, no sort will be done (the value of * simpleSort will be ignored, if sortActive is false) */ public RefreshTreeWorker(final boolean initialFill, boolean simpleSort, boolean sortActive) { this.initialFill = initialFill; comparator = new DirectedMetaObjectNodeComparator(ascending); this.simpleSort = simpleSort; this.sortActive = sortActive; } //~ Methods ------------------------------------------------------------ @Override protected ArrayList<DefaultMetaTreeNode> doInBackground() throws Exception { Thread.currentThread().setName("RefreshTreeWorker"); if (!isCancelled() && sortActive) { Collections.sort(resultNodes, comparator); } final ArrayList<DefaultMetaTreeNode> nodesToAdd = new ArrayList<DefaultMetaTreeNode>(resultNodes.size()); for (int i = 0; i < resultNodes.size(); i++) { if (resultNodes.get(i) instanceof MetaNode) { final PureTreeNode iPTN = new PureTreeNode((MetaNode) resultNodes.get(i)); nodesToAdd.add(iPTN); // if(LOG.isDebugEnabled())LOG.debug("[DefaultTreeNodeLoader] PureNode Children added"); } else if (resultNodes.get(i) instanceof MetaClassNode) { final ClassTreeNode iCTN = new ClassTreeNode((MetaClassNode) resultNodes.get(i)); nodesToAdd.add(iCTN); // if(LOG.isDebugEnabled())LOG.debug("[DefaultTreeNodeLoader] ClassNode Children added"); } else if (resultNodes.get(i) instanceof MetaObjectNode) { final ObjectTreeNode otn = new ObjectTreeNode((MetaObjectNode) resultNodes.get(i)); // toString aufrufen, damit das MetaObject nicht erst im CellRenderer des MetaCatalogueTree vom // Server geholt wird otn.toString(); nodesToAdd.add(otn); // if(LOG.isDebugEnabled())LOG.debug("[DefaultTreeNodeLoader] ObjectNode Children added"); } else { log.fatal("[DefaultTreeNodeLoader] Wrong Node Type: '" + resultNodes.get(i) + "'"); // NOI18N throw new Exception("[DDefaultTreeNodeLoader] Wrong Node Type: '" + resultNodes.get(i) + "'"); // NOI18N } } return nodesToAdd; } @Override protected void done() { if (isCancelled()) { comparator.cancel(); } rootNode.removeAllChildren(); try { if (!isCancelled()) { ArrayList<DefaultMetaTreeNode> result = get(); if (!isCancelled()) { for (DefaultMetaTreeNode dmtn : result) { rootNode.add(dmtn); } //MetaTreeNodeRenderer renderer = new MetaTreeNodeRenderer(); if(!result.isEmpty()) { setRowHeight(getCellRenderer().getTreeCellRendererComponent(SearchResultsTree.this, rootNode.getFirstChild(), false, false, false, 0, false).getHeight()); } setLargeModel(result.size() > 15); SearchResultsTree.this.firePropertyChange("browse", 0, 1); // NOI18N defaultTreeModel.nodeStructureChanged(rootNode); if (initialFill) { syncWithMap(); syncWithRenderer(); checkForDynamicNodes(); if (simpleSort && sortActive) { SearchResultsTree.this.sort(true); } } } } } catch (InterruptedException ex) { log.error("Error occured while refreshing search results tree", ex); } catch (ExecutionException ex) { log.error("Error occured while refreshing search results tree", ex); } } } //J+ }