docs: function(options) {
          var r, parentID, depth, leafRow, row, ID;
  
          // successful join requires that options object be given and that all columns exist
          if (!options) {
              this.joined = false;
          } else {
              this.idColumn = options.idColumn;
              this.parentIdColumn = options.parentIdColumn;
              this.treeColumn = options.treeColumn;
              this.groupColumn = options.groupColumn;
              this.joined = !!(this.idColumn && this.parentIdColumn && this.treeColumn && this.groupColumn);
          }
  
          this.buildIndex(); // make all rows visible to getRow()
  
          r = this.getRowCount();
          if (this.joined) {
              // mutate data row with __DEPTH (all rows) and __EXPANDED (all "parent" rows)
              var idColumnName = this.idColumn.name,
                  parentIdColumnName = this.parentIdColumn.name;
  
              this.maxDepth = 0;
  
              while (r--) {
                  depth = 0;
                  leafRow = this.getRow(r);
                  row = leafRow;
                  ID = row[idColumnName];
  
                  while ((parentID = row[parentIdColumnName]) != null) {
                      row = this.findRow(idColumnName, parentID);
                      ++depth;
                  }
  
                  if (this.maxDepth < depth) {
                      this.maxDepth = depth;
                  }
  
                  leafRow.__DEPTH = depth;
  
                  if (!this.findRow(parentIdColumnName, ID)) {
                      delete leafRow.__EXPANDED; // no longer expandable
                  } else if (leafRow.__EXPANDED === undefined) { // retain previous setting for old rows
                      leafRow.__EXPANDED = false; // default for new row is unexpanded
                  }
              }
          } else {
              // flatten the tree so group sorter sees it as a single group
              while (r--) {
                  this.getRow(r).__DEPTH = 0;
              }
          }
  
          // look for DataSourceTreeviewFilter
  
          return this.joined;
      }