private void renderReport(DBRProgressMonitor monitor, CompareReport report) {
    try {
      File reportFile;
      switch (settings.getOutputType()) {
        case BROWSER:
          reportFile = File.createTempFile("compare-report", ".html");
          break;
        default:
          {
            StringBuilder fileName = new StringBuilder("compare"); // "compare-report.html";
            for (DBNDatabaseNode node : report.getNodes()) {
              fileName.append("-").append(CommonUtils.escapeIdentifier(node.getName()));
            }
            fileName.append("-report.html");
            reportFile = new File(settings.getOutputFolder(), fileName.toString());
            break;
          }
      }

      reportFile.deleteOnExit();
      OutputStream outputStream = new FileOutputStream(reportFile);
      try {
        monitor.beginTask("Render report", report.getReportLines().size());
        CompareReportRenderer reportRenderer = new CompareReportRenderer();
        reportRenderer.renderReport(monitor, report, getSettings(), outputStream);
        monitor.done();
      } finally {
        ContentUtils.close(outputStream);
      }
      UIUtils.launchProgram(reportFile.getAbsolutePath());
    } catch (IOException e) {
      showError(e.getMessage());
      log.error(e);
    }
  }
 boolean hasChildItem(DBSObject object) {
   if (childNodes != null) {
     for (DBNDatabaseNode child : childNodes) {
       if (child.getObject() == object) {
         return true;
       }
     }
   }
   return false;
 }
 public boolean hasChildren(DBRProgressMonitor monitor, DBXTreeNode childType) throws DBException {
   if (isDisposed()) {
     return false;
   }
   DBNDatabaseNode[] children = getChildren(monitor);
   if (!ArrayUtils.isEmpty(children)) {
     for (DBNDatabaseNode child : children) {
       if (child.getMeta() == childType) {
         return true;
       }
     }
   }
   return false;
 }
 void removeChildItem(DBSObject object) {
   DBNNode childNode = null;
   synchronized (this) {
     if (!ArrayUtils.isEmpty(childNodes)) {
       for (int i = 0; i < childNodes.length; i++) {
         final DBNDatabaseNode child = childNodes[i];
         if (child.getObject() == object) {
           childNode = child;
           childNodes = ArrayUtils.remove(DBNDatabaseNode.class, childNodes, i);
           break;
         }
       }
     }
   }
   if (childNode != null) {
     childNode.dispose(true);
   }
 }
  /**
   * Extract items using reflect api
   *
   * @param monitor progress monitor
   * @param meta items meta info
   * @param oldList previous child items
   * @param toList list ot add new items @return true on success
   * @return true on success
   * @throws DBException on any DB error
   */
  private boolean loadTreeItems(
      DBRProgressMonitor monitor,
      DBXTreeItem meta,
      final DBNDatabaseNode[] oldList,
      final List<DBNDatabaseNode> toList)
      throws DBException {
    if (this.isDisposed()) {
      // Property reading can take really long time so this node can be disposed at this moment -
      // check it
      return false;
    }
    // Read property using reflection
    Object valueObject = getValueObject();
    if (valueObject == null) {
      return false;
    }
    String propertyName = meta.getPropertyName();
    Object propertyValue = extractPropertyValue(monitor, valueObject, propertyName);
    if (propertyValue == null) {
      return false;
    }
    if (!(propertyValue instanceof Collection<?>)) {
      log.warn(
          "Bad property '"
              + propertyName
              + "' value: "
              + propertyValue.getClass().getName()); // $NON-NLS-1$ //$NON-NLS-2$
      return false;
    }

    DBSObjectFilter filter = getNodeFilter(meta, false);
    this.filtered = filter != null && !filter.isEmpty();

    Collection<?> itemList = (Collection<?>) propertyValue;
    if (itemList.isEmpty()) {
      return false;
    }
    if (this.isDisposed()) {
      // Property reading can take really long time so this node can be disposed at this moment -
      // check it
      return false;
    }

    DBPDataSourceContainer dataSourceContainer = getDataSourceContainer();
    boolean showSystem = dataSourceContainer == null || dataSourceContainer.isShowSystemObjects();
    for (Object childItem : itemList) {
      if (childItem == null) {
        continue;
      }
      if (!(childItem instanceof DBSObject)) {
        log.warn("Bad item type: " + childItem.getClass().getName()); // $NON-NLS-1$
        continue;
      }
      if (DBUtils.isHiddenObject(childItem)) {
        // Skip hidden objects
        continue;
      }
      if (!showSystem
          && childItem instanceof DBPSystemObject
          && ((DBPSystemObject) childItem).isSystem()) {
        // Skip system objects
        continue;
      }
      if (filter != null && !filter.matches(((DBSObject) childItem).getName())) {
        // Doesn't match filter
        continue;
      }
      DBSObject object = (DBSObject) childItem;
      boolean added = false;
      if (oldList != null) {
        // Check that new object is a replacement of old one
        for (DBNDatabaseNode oldChild : oldList) {
          if (oldChild.getMeta() == meta && equalObjects(oldChild.getObject(), object)) {
            oldChild.reloadObject(monitor, object);

            if (oldChild.allowsChildren() && !oldChild.needsInitialization()) {
              // Refresh children recursive
              oldChild.reloadChildren(monitor);
            }
            getModel().fireNodeUpdate(this, oldChild, DBNEvent.NodeChange.REFRESH);

            toList.add(oldChild);
            added = true;
            break;
          }
        }
      }
      if (!added) {
        // Simply add new item
        DBNDatabaseItem treeItem = new DBNDatabaseItem(this, meta, object, oldList != null);
        toList.add(treeItem);
      }
    }

    if (oldList != null) {
      // Now remove all non-existing items
      for (DBNDatabaseNode oldChild : oldList) {
        if (oldChild.getMeta() != meta) {
          // Wrong type
          continue;
        }
        boolean found = false;
        for (Object childItem : itemList) {
          if (childItem instanceof DBSObject
              && equalObjects(oldChild.getObject(), (DBSObject) childItem)) {
            found = true;
            break;
          }
        }
        if (!found) {
          // Remove old child object
          oldChild.dispose(true);
        }
      }
    }
    return true;
  }
  private void loadChildren(
      DBRProgressMonitor monitor,
      final DBXTreeNode meta,
      final DBNDatabaseNode[] oldList,
      final List<DBNDatabaseNode> toList)
      throws DBException {
    if (monitor.isCanceled()) {
      return;
    }
    this.filtered = false;

    List<DBXTreeNode> childMetas = meta.getChildren(this);
    if (CommonUtils.isEmpty(childMetas)) {
      return;
    }
    monitor.beginTask(ModelMessages.model_navigator_load_items_, childMetas.size());

    for (DBXTreeNode child : childMetas) {
      if (monitor.isCanceled()) {
        break;
      }
      monitor.subTask(
          ModelMessages.model_navigator_load_
              + " "
              + child.getChildrenType(getObject().getDataSource()));
      if (child instanceof DBXTreeItem) {
        final DBXTreeItem item = (DBXTreeItem) child;
        boolean isLoaded = loadTreeItems(monitor, item, oldList, toList);
        if (!isLoaded && item.isOptional() && item.getRecursiveLink() == null) {
          // This may occur only if no child nodes was read
          // Then we try to go on next DBX level
          loadChildren(monitor, item, oldList, toList);
        }
      } else if (child instanceof DBXTreeFolder) {
        if (oldList == null) {
          // Load new folders only if there are no old ones
          toList.add(new DBNDatabaseFolder(this, (DBXTreeFolder) child));
        } else {
          for (DBNDatabaseNode oldFolder : oldList) {
            if (oldFolder.getMeta() == child) {
              oldFolder.reloadChildren(monitor);
              toList.add(oldFolder);
              break;
            }
          }
        }
      } else if (child instanceof DBXTreeObject) {
        if (oldList == null) {
          // Load new objects only if there are no old ones
          toList.add(new DBNDatabaseObject(this, (DBXTreeObject) child));
        } else {
          for (DBNDatabaseNode oldObject : oldList) {
            if (oldObject.getMeta() == child) {
              oldObject.reloadChildren(monitor);
              toList.add(oldObject);
              break;
            }
          }
        }
      } else {
        log.warn("Unsupported meta node type: " + child); // $NON-NLS-1$
      }
      monitor.worked(1);
    }
    monitor.done();

    if (filtered) {
      getModel().fireNodeUpdate(this, this, DBNEvent.NodeChange.REFRESH);
    }
  }