Google Tag Manager

2008/03/26

JTable pagination using RowFilter

Code

private static int LR_PAGE_SIZE = 5;

private final String[] columnNames = {"Year", "String", "Comment"};
private final DefaultTableModel model = new DefaultTableModel(null, columnNames) {
  @Override public Class<?> getColumnClass(int column) {
    return (column == 0) ? Integer.class : Object.class;
  }
};
private TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model);
private Box box = Box.createHorizontalBox();

private void initLinkBox(final int itemsPerPage, final int currentPageIndex) {
  // assert currentPageIndex > 0;
  sorter.setRowFilter(new RowFilter<TableModel, Integer>() {
    @Override
    public boolean include(Entry<? extends TableModel, ? extends Integer> entry) {
      int ti = currentPageIndex - 1;
      int ei = entry.getIdentifier();
      return ti * itemsPerPage <= ei && ei < ti * itemsPerPage + itemsPerPage;
    }
  });

  int startPageIndex = currentPageIndex - LR_PAGE_SIZE;
  if (startPageIndex <= 0) {
    startPageIndex = 1;
  }

// #if 0 //BUG
  // int maxPageIndex = (model.getRowCount() / itemsPerPage) + 1;
// #else
  /* "maxPageIndex" gives one blank page if the module of the division is not zero.
   *   pointed out by erServi
   * e.g. rowCount=100, maxPageIndex=100
   */
  int rowCount = model.getRowCount();
  int v = rowCount % itemsPerPage == 0 ? 0 : 1;
  int maxPageIndex = rowCount / itemsPerPage + v;
// #endif
  int endPageIndex = currentPageIndex + LR_PAGE_SIZE - 1;
  if (endPageIndex > maxPageIndex) {
    endPageIndex = maxPageIndex;
  }

  box.removeAll();
  if (startPageIndex >= endPageIndex) {
    // if I only have one page, Y don't want to see pagination buttons
    // suggested by erServi
    return;
  }

  ButtonGroup bg = new ButtonGroup();
  JRadioButton f = makePrevNextRadioButton(
      itemsPerPage, 1, "|<", currentPageIndex > 1);
  box.add(f);
  bg.add(f);
  JRadioButton p = makePrevNextRadioButton(
      itemsPerPage, currentPageIndex - 1, "<", currentPageIndex > 1);
  box.add(p);
  bg.add(p);
  box.add(Box.createHorizontalGlue());
  for (int i = startPageIndex; i <= endPageIndex; i++) {
    JRadioButton c = makeRadioButton(itemsPerPage, currentPageIndex, i);
    box.add(c);
    bg.add(c);
  }
  box.add(Box.createHorizontalGlue());
  JRadioButton n = makePrevNextRadioButton(
      itemsPerPage, currentPageIndex + 1, ">", currentPageIndex < maxPageIndex);
  box.add(n);
  bg.add(n);
  JRadioButton l = makePrevNextRadioButton(
      itemsPerPage, maxPageIndex, ">|", currentPageIndex < maxPageIndex);
  box.add(l);
  bg.add(l);
  box.revalidate();
  box.repaint();
}

References

2008/03/21

Horizontally fill tabs of a JTabbedPane

Code

// horizontal filling, same width tabs
class ClippedTitleTabbedPane extends JTabbedPane {
  public ClippedTitleTabbedPane() {
    super();
  }

  public ClippedTitleTabbedPane(int tabPlacement) {
    super(tabPlacement);
  }

  private Insets getTabInsets() {
    Insets i = UIManager.getInsets("TabbedPane.tabInsets");
    if (i != null) {
      return i;
    } else {
      SynthStyle style = SynthLookAndFeel.getStyle(this, Region.TABBED_PANE_TAB);
      SynthContext context = new SynthContext(
        this, Region.TABBED_PANE_TAB, style, SynthConstants.ENABLED);
      return style.getInsets(context, null);
    }
  }

  private Insets getTabAreaInsets() {
    Insets i = UIManager.getInsets("TabbedPane.tabAreaInsets");
    if (i != null) {
      return i;
    } else {
      SynthStyle style = SynthLookAndFeel.getStyle(this, Region.TABBED_PANE_TAB_AREA);
      SynthContext context = new SynthContext(
        this, Region.TABBED_PANE_TAB_AREA, style, SynthConstants.ENABLED);
      return style.getInsets(context, null);
    }
  }

  @Override public void doLayout() {
    int tabCount  = getTabCount();
    if (tabCount == 0) return;
    Insets tabInsets   = getTabInsets();
    Insets tabAreaInsets = getTabAreaInsets();
    Insets insets = getInsets();
    int areaWidth = getWidth() - tabAreaInsets.left - tabAreaInsets.right
                    - insets.left        - insets.right;
    int tabWidth  = 0; // = tabInsets.left + tabInsets.right + 3;
    int gap     = 0;

    switch (getTabPlacement()) {
    case LEFT:
    case RIGHT:
      tabWidth = areaWidth / 4;
      gap = 0;
      break;
    case BOTTOM:
    case TOP:
    default:
      tabWidth = areaWidth / tabCount;
      gap = areaWidth - (tabWidth * tabCount);
    }
    // "3" is magic number @see BasicTabbedPaneUI#calculateTabWidth
    tabWidth = tabWidth - tabInsets.left - tabInsets.right - 3;
    for (int i = 0; i < tabCount; i++) {
      JComponent l = (JComponent) getTabComponentAt(i);
      if (l == null) break;
      l.setPreferredSize(new Dimension(tabWidth + (i < gap ? 1 : 0), l.getPreferredSize().height));
    }
    super.doLayout();
  }

  @Override public void insertTab(
      String title, Icon icon, Component component, String tip, int index) {
    super.insertTab(title, icon, component, tip == null ? title : tip, index);
    JLabel label = new JLabel(title, SwingConstants.CENTER);
    Dimension dim = label.getPreferredSize();
    Insets tabInsets = getTabInsets();
    label.setPreferredSize(new Dimension(0, dim.height + tabInsets.top + tabInsets.bottom));
    setTabComponentAt(index, label);
  }
}

References

2008/03/18

JProgressBar in JTable Cell

Code

class ProgressRenderer extends DefaultTableCellRenderer {
  private final JProgressBar b = new JProgressBar(0, 100);
  public ProgressRenderer() {
    super();
    setOpaque(true);
    b.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
  }
  public Component getTableCellRendererComponent(JTable table, Object value,
        boolean isSelected, boolean hasFocus, int row, int column) {
    Integer i = (Integer) value;
    String text = "Done";
    if (i < 0) {
      text = "Canceled";
    } else if (i < 100) {
      b.setValue(i);
      return b;
    }
    super.getTableCellRendererComponent(table, text, isSelected, hasFocus, row, column);
    return this;
  }
}
final Executor executor = Executors.newCachedThreadPool();
final int rowNumber = model.getRowCount();
SwingWorker<Integer, Integer> worker = new SwingWorker<Integer, Integer>() {
  private int sleepDummy = new Random().nextInt(100) + 1;
  private int lengthOfTask = 120;
  @Override
  protected Integer doInBackground() {
    int current = 0;
    while (current < lengthOfTask && !isCancelled()) {
      if (!table.isDisplayable()) {
        return -1;
      }
      current++;
      try {
        Thread.sleep(sleepDummy);
      } catch (InterruptedException ie) {
        publish(-1);
        break;
      }
      publish(100 * current / lengthOfTask);
    }
    return sleepDummy * lengthOfTask;
  }
  @Override
  protected void process(List<Integer> chunks) {
    for (Integer value : chunks) {
      model.setValueAt(value, rowNumber, 2);
    }
    // model.fireTableCellUpdated(rowNumber, 2);
  }
  @Override
  protected void done() {
    String text;
    int i = -1;
    if (isCancelled()) {
      text = "Canceled";
    } else {
      try {
        i = get();
        text = (i>=0)?"Done":"Disposed";
      } catch (Exception ignore) {
        ignore.printStackTrace();
        text = ignore.getMessage();
      }
    }
    System.out.println(rowNumber +":"+text+"("+i+"ms)");
  }
};
model.addTest(new Test("example", 0), worker);
executor.execute(worker); // JDK 1.6.0_18
// worker.execute();

References