/**
   * Creates a concrete loader.
   *
   * @see DataBrowserModel#createDataLoader(boolean, Collection)
   */
  protected List<DataBrowserLoader> createDataLoader(boolean refresh, Collection ids) {
    if (!withThumbnails) return null;
    List<ImageDisplay> l = getNodes();
    Iterator<ImageDisplay> i = l.iterator();
    ImageSet node;
    List<DataObject> images = new ArrayList<DataObject>();
    ImageNode selected;
    WellSampleData data;
    Thumbnail thumb;
    while (i.hasNext()) {
      node = (ImageSet) i.next();
      if (node instanceof WellImageSet) {
        selected = ((WellImageSet) node).getSelectedWellSample();
        data = (WellSampleData) selected.getHierarchyObject();
        if (data.getId() < 0) {
          thumb = selected.getThumbnail();
          thumb.setValid(false);
          thumb.setFullScaleThumb(
              Factory.createDefaultImageThumbnail(wellDimension.width, wellDimension.height));
        } else images.add(data.getImage());
      }
    }

    if (images.size() == 0) return null;
    return createThumbnailsLoader(sorter.sort(images));
  }
  /**
   * Creates a new instance.
   *
   * @param ctx The security context.
   * @param parent The parent of the wells.
   * @param wells The collection to wells the model is for.
   * @param withThumbnails Pass <code>true</code> to load the thumbnails, <code>false</code>
   *     otherwise.
   */
  WellsModel(SecurityContext ctx, Object parent, Set<WellData> wells, boolean withThumbnails) {
    super(ctx);
    if (wells == null) throw new IllegalArgumentException("No wells.");
    this.withThumbnails = withThumbnails;
    selectedNodes = new ArrayList<WellImageSet>();
    wellDimension = null;
    this.parent = parent;
    wellNodes = sortByRow(DataBrowserTranslator.transformHierarchy(wells));

    PlateData plate = (PlateData) parent;
    columnSequenceIndex = plate.getColumnSequenceIndex();
    rowSequenceIndex = plate.getRowSequenceIndex();
    selectedField = plate.getDefaultSample();
    if (selectedField < 0) selectedField = 0;
    Set<ImageDisplay> samples = new HashSet<ImageDisplay>();
    cells = new HashSet<CellDisplay>();
    rows = -1;
    columns = -1;
    int row, column;
    Iterator<ImageDisplay> j = wellNodes.iterator();
    WellImageSet node;
    ImageNode selected;
    int f;
    String columnSequence;
    String rowSequence;
    Map<Integer, ColourObject> cMap = new HashMap<Integer, ColourObject>();
    Map<Integer, ColourObject> rMap = new HashMap<Integer, ColourObject>();
    WellData data;
    String type;
    ColourObject co;
    Color color;
    boolean b;
    validWells = new ArrayList<WellGridElement>();
    int minRow = -1;
    int minColumn = -1;
    while (j.hasNext()) {
      node = (WellImageSet) j.next();
      row = node.getRow();
      column = node.getColumn();
      data = (WellData) node.getHierarchyObject();
      type = data.getWellType();
      if (cMap.containsKey(column)) {
        co = cMap.get(column);
        color = createColor(data);
        if (!UIUtilities.isSameColors(co.getColor(), color, true)
            || !isSameDescription(co.getDescription(), type)) {
          co.setColor(null);
          co.setDescription(null);
          cMap.put(column, co);
        }
      } else {
        cMap.put(column, new ColourObject(createColor(data), type));
      }

      if (rMap.containsKey(row)) {
        co = rMap.get(row);
        color = createColor(data);
        if (!UIUtilities.isSameColors(co.getColor(), color, true)
            || !isSameDescription(co.getDescription(), type)) {
          co.setColor(null);
          co.setDescription(null);
          rMap.put(row, co);
        }
      } else {
        rMap.put(row, new ColourObject(createColor(data), type));
      }
      if (row > rows) rows = row;
      if (column > columns) columns = column;

      if (minRow < 0 || minRow > row) {
        minRow = row;
      }

      if (minColumn < 0 || minColumn > column) {
        minColumn = column;
      }
      columnSequence = "";
      if (columnSequenceIndex == PlateData.ASCENDING_LETTER)
        columnSequence = UIUtilities.LETTERS.get(column + 1);
      else if (columnSequenceIndex == PlateData.ASCENDING_NUMBER)
        columnSequence = "" + (column + 1);
      rowSequence = "";
      if (rowSequenceIndex == PlateData.ASCENDING_LETTER)
        rowSequence = UIUtilities.LETTERS.get(row + 1);
      else if (rowSequenceIndex == PlateData.ASCENDING_NUMBER) rowSequence = "" + (row + 1);
      node.setCellDisplay(columnSequence, rowSequence);
      f = node.getNumberOfSamples();
      if (fieldsNumber < f) fieldsNumber = f;
      node.setSelectedWellSample(selectedField);
      selected = node.getSelectedWellSample();
      // set the title to Row/Column
      node.formatWellSampleTitle();
      samples.add(selected);
      b = false;
      if (node.isSampleValid()) {
        wellDimension = selected.getThumbnail().getOriginalSize();
        b = true;
      }
      validWells.add(new WellGridElement(row, column, b));
    }
    //
    if (minRow >= 0 || minColumn >= 0) {
      j = wellNodes.iterator();
      while (j.hasNext()) {
        node = (WellImageSet) j.next();
        if (minRow > 0) node.setIndentRow(minRow);
        if (minColumn > 0) node.setIndentColumn(minColumn);
        if (node.getRow() == minRow || node.getColumn() == minColumn) node.formatWellSampleTitle();
      }
    }

    columns++;
    rows++;
    CellDisplay cell;
    for (int k = 1; k <= columns; k++) {
      columnSequence = "";
      if (columnSequenceIndex == PlateData.ASCENDING_LETTER)
        columnSequence = UIUtilities.LETTERS.get(k + 1);
      else if (columnSequenceIndex == PlateData.ASCENDING_NUMBER) columnSequence = "" + k;
      cell = new CellDisplay(k - 1, columnSequence);
      co = cMap.get(k - 1);
      if (co != null) {
        cell.setHighlight(co.getColor());
        cell.setDescription(co.getDescription());
      }
      // if (!isMac)
      // samples.add(cell);
      // cells.add(cell);
    }
    for (int k = 1; k <= rows; k++) {
      rowSequence = "";
      if (rowSequenceIndex == PlateData.ASCENDING_LETTER) rowSequence = UIUtilities.LETTERS.get(k);
      else if (rowSequenceIndex == PlateData.ASCENDING_NUMBER) rowSequence = "" + k;

      cell = new CellDisplay(k - 1, rowSequence, CellDisplay.TYPE_VERTICAL);
      co = rMap.get(k - 1);
      if (co != null) {
        cell.setHighlight(co.getColor());
        cell.setDescription(co.getDescription());
      }
      // if (!isMac)
      // samples.add(cell);
      // cells.add(cell);
    }
    browser = BrowserFactory.createBrowser(samples);
    browser.accept(new DecoratorVisitor(getCurrentUser().getId()));

    layoutBrowser(LayoutFactory.PLATE_LAYOUT);
    if (wellDimension == null)
      wellDimension =
          new Dimension(ThumbnailProvider.THUMB_MAX_WIDTH, ThumbnailProvider.THUMB_MAX_HEIGHT);
  }