@Override
  protected Component createDatabaseDemoPanel() throws SQLException {
    if (_connection == null) {
      return new JPanel();
    }
    final TableModel tableModel = createTableModel();
    final SortableTable table = new SortableTable(tableModel);
    final JScrollPane scroller = new JScrollPane(table);
    scroller
        .getVerticalScrollBar()
        .addAdjustmentListener(
            new AdjustmentListener() {
              public void adjustmentValueChanged(AdjustmentEvent e) {
                table.setCellContentVisible(!e.getValueIsAdjusting());
              }
            });
    scroller.addComponentListener(
        new ComponentAdapter() {
          @Override
          public void componentResized(ComponentEvent e) {
            int rowCount = scroller.getViewport().getHeight() / table.getRowHeight();
            PageNavigationSupport pageNavigationSupport =
                (PageNavigationSupport)
                    TableModelWrapperUtils.getActualTableModel(
                        table.getModel(), PageNavigationSupport.class);
            if (pageNavigationSupport != null) {
              pageNavigationSupport.setPageSize(rowCount);
            }
          }
        });

    JPanel demoPanel = new JPanel(new BorderLayout(4, 4));
    demoPanel.add(scroller);
    customizeDemoPanel(table, tableModel, demoPanel);
    return demoPanel;
  }
  @Override
  public Component getOptionsPanel() {
    JPanel panel = new JPanel(new GridLayout(0, 1, 4, 4));
    final JCheckBox hideOriginalTableHeader = new JCheckBox("Hide the original table header");
    hideOriginalTableHeader.addItemListener(
        new ItemListener() {
          public void itemStateChanged(ItemEvent e) {
            JTableHeader header = _table.getTableHeader();
            if (header instanceof NestedTableHeader) {
              ((NestedTableHeader) header)
                  .setOriginalTableHeaderVisible(!hideOriginalTableHeader.isSelected());
            }
          }
        });
    panel.add(hideOriginalTableHeader);

    final JCheckBox autoStartCellEditing = new JCheckBox("Auto-start editing when TAB or ENTER");
    autoStartCellEditing.addItemListener(
        new ItemListener() {
          public void itemStateChanged(ItemEvent e) {
            _table.setAutoStartCellEditing(autoStartCellEditing.isSelected());
          }
        });
    autoStartCellEditing.setSelected(_table.isAutoStartCellEditing());
    panel.add(autoStartCellEditing);

    final JCheckBox autoSelectTextWhenStartsEditing =
        new JCheckBox("Auto-select the cell text when editing");
    autoSelectTextWhenStartsEditing.addItemListener(
        new ItemListener() {
          public void itemStateChanged(ItemEvent e) {
            _table.setAutoSelectTextWhenStartsEditing(autoSelectTextWhenStartsEditing.isSelected());
          }
        });
    autoSelectTextWhenStartsEditing.setSelected(_table.isAutoSelectTextWhenStartsEditing());
    panel.add(autoSelectTextWhenStartsEditing);

    final JCheckBox enable = new JCheckBox("Enable Table");
    enable.addItemListener(
        new ItemListener() {
          public void itemStateChanged(ItemEvent e) {
            _table.setEnabled(enable.isSelected());
          }
        });
    enable.setSelected(_table.isEnabled());
    panel.add(enable);

    JCheckBox columnAutoResizable = new JCheckBox("Column Auto Resizable");
    columnAutoResizable.addItemListener(
        new ItemListener() {
          public void itemStateChanged(ItemEvent e) {
            boolean selected = e.getStateChange() == ItemEvent.SELECTED;
            _table.setColumnAutoResizable(selected);
            _table.setAutoResizeMode(
                selected ? JTable.AUTO_RESIZE_OFF : JTable.AUTO_RESIZE_ALL_COLUMNS);
          }
        });
    columnAutoResizable.setSelected(_table.isColumnAutoResizable());
    panel.add(columnAutoResizable);

    JComboBox autoCompletionModeComboBox =
        new JComboBox(
            new Object[] {
              "Disabled", "Cells in the same column", "Cells in the same row", "All cells"
            });
    autoCompletionModeComboBox.setSelectedIndex(_table.getEditorAutoCompletionMode());
    autoCompletionModeComboBox.addItemListener(
        new ItemListener() {
          public void itemStateChanged(ItemEvent e) {
            if (e.getStateChange() == ItemEvent.SELECTED) {
              _table.setEditorAutoCompletionMode(((JComboBox) e.getSource()).getSelectedIndex());
            }
          }
        });
    panel.add(
        JideSwingUtilities.createLabeledComponent(
            new JLabel("AutoCompletion Mode: "),
            autoCompletionModeComboBox,
            BorderLayout.BEFORE_LINE_BEGINS));

    return panel;
  }
  protected void customizeDemoPanel(
      final JTable table, final TableModel tableModel, final JPanel demoPanel) {
    final QuickTableFilterField field =
        new QuickTableFilterField(tableModel) {
          @Override
          public Filter getFilter() {
            String s = getSearchingText();
            if (s != null && s.length() > 0) {
              if (isWildcardEnabled()) {
                s = s.replace("*", "%");
                s = s.replace(".", "_");
              }
              StringBuffer pattern = new StringBuffer();
              if (isFromStart()) {
                pattern.append(s).append("%");
              } else {
                pattern.append("%").append(s).append("%");
              }
              LikeFilter likeFilter = new LikeFilter(pattern.toString());
              likeFilter.setCaseSensitive(isCaseSensitive());
              return likeFilter;
            } else {
              return null;
            }
          }

          @Override
          protected IFilterableTableModel createFilterableTableModel(TableModel tableModel) {
            if (tableModel instanceof IFilterableTableModel) {
              return (IFilterableTableModel) tableModel;
            } else {
              return super.createFilterableTableModel(tableModel);
            }
          }
        };

    final FilterableTableModel filterableTableModel =
        new FilterableTableModel(field.getDisplayTableModel());
    int floatColumnIndex = -1;
    for (int i = 0; i < filterableTableModel.getColumnCount(); i++) {
      if (filterableTableModel.getColumnClass(i) == Float.class) {
        floatColumnIndex = i;
        break;
      }
    }
    final int filterColumnIndex = floatColumnIndex == -1 ? 3 : floatColumnIndex;
    JCheckBox addFilterCheckBox1 = new JCheckBox("Using local filtering");
    final JLabel filterMessage1 = new JLabel();
    addFilterCheckBox1.addItemListener(
        new ItemListener() {
          public void itemStateChanged(ItemEvent e) {
            if (e.getStateChange() == ItemEvent.SELECTED) {
              //                        filterableTableModel.addFilter(1, new LikeFilter("%Meat%"));
              //                        filterableTableModel.addFilter(filterColumnIndex, new
              // GreaterThanFilter(1000f));
              //                        filterableTableModel.addFilter(filterColumnIndex, new
              // BetweenFilter(20f, 60f));
              filterableTableModel.addFilter(
                  filterColumnIndex, new InFilter(new Object[] {45f, 46f, 77f}));
            } else {
              filterableTableModel.clearFilters();
            }
            long start = System.nanoTime();
            filterableTableModel.setFiltersApplied(true);
            long end = System.nanoTime();
            filterMessage1.setText("Taking " + (end - start) / 1000000 + " ms");
          }
        });
    JCheckBox addFilterCheckBox2 = new JCheckBox("Using the database filtering feature");
    final JLabel filterMessage2 = new JLabel();
    addFilterCheckBox2.addItemListener(
        new ItemListener() {
          public void itemStateChanged(ItemEvent e) {
            if (tableModel instanceof IFilterableTableModel) {
              if (e.getStateChange() == ItemEvent.SELECTED) {
                //                        tableModel.addFilter(1, new LikeFilter("Meat"));
                //                        tableModel.addFilter(filterColumnIndex, new
                // GreaterThanFilter(1000f));
                //                        tableModel.addFilter(filterColumnIndex, new
                // BetweenFilter(20f, 60f));
                ((IFilterableTableModel) tableModel)
                    .addFilter(filterColumnIndex, new InFilter(new Object[] {45f, 46f, 77f}));
              } else {
                ((IFilterableTableModel) tableModel).clearFilters();
              }
              long start = System.nanoTime();
              ((IFilterableTableModel) tableModel).setFiltersApplied(true);
              long end = System.nanoTime();
              filterMessage2.setText("Taking " + (end - start) / 1000000 + " ms");
            }
          }
        });

    JPanel checkBoxPanel = new JPanel(new GridLayout(2, 2, 0, 0));
    checkBoxPanel.add(addFilterCheckBox1);
    checkBoxPanel.add(addFilterCheckBox2);
    checkBoxPanel.add(filterMessage1);
    checkBoxPanel.add(filterMessage2);

    demoPanel.add(checkBoxPanel, BorderLayout.BEFORE_FIRST_LINE);

    table.setModel(filterableTableModel);
    demoPanel.add(
        JideSwingUtilities.createLabeledComponent(
            new JLabel("QuickTableFilterField (use SQL LIKE):"),
            field,
            BorderLayout.BEFORE_LINE_BEGINS),
        BorderLayout.AFTER_LAST_LINE);
    demoPanel.setBorder(
        BorderFactory.createCompoundBorder(
            BorderFactory.createTitledBorder("Demo for DatabaseTableModel"),
            BorderFactory.createEmptyBorder(5, 10, 5, 10)));
  }
  public Component getDemoPanel() {
    JPanel panel = new JPanel(new BorderLayout(6, 6));
    DefaultTableModel model = new CustomizedTableModel(8, 8);
    model.setValueAt("no editing", 2, 2);
    model.setValueAt("no stop", 2, 3);
    model.setValueAt("valid", 2, 4);
    _table = new JideTable(model);
    _table.setNestedTableHeader(true);
    _table.setAlwaysRequestFocusForEditor(true);
    _table.setClickCountToStart(2);
    _table.setEditorAutoCompletionMode(JideTable.EDITOR_AUTO_COMPLETION_MODE_TABLE);

    TableColumnGroup all = new TableColumnGroup("AH");
    TableColumnGroup first = new TableColumnGroup("AB");
    first.add(_table.getColumnModel().getColumn(0));
    first.add(_table.getColumnModel().getColumn(1));
    TableColumnGroup second = new TableColumnGroup("CD");
    second.add(_table.getColumnModel().getColumn(2));
    second.add(_table.getColumnModel().getColumn(3));
    TableColumnGroup third = new TableColumnGroup("EF");
    third.add(_table.getColumnModel().getColumn(4));
    third.add(_table.getColumnModel().getColumn(5));
    TableColumnGroup fourth = new TableColumnGroup("GH");
    fourth.add(_table.getColumnModel().getColumn(6));
    fourth.add(_table.getColumnModel().getColumn(7));
    all.add(first);
    all.add(second);
    all.add(third);
    all.add(fourth);

    if (_table.getTableHeader() instanceof NestedTableHeader) {
      NestedTableHeader header = (NestedTableHeader) _table.getTableHeader();
      header.addColumnGroup(all);
    }

    panel.add(new JScrollPane(_table), BorderLayout.CENTER);
    _message = new JLabel();
    panel.add(_message, BorderLayout.AFTER_LAST_LINE);
    _table.addCellEditorListener(
        new JideCellEditorListener() {
          public boolean editingStarting(ChangeEvent e) {
            int row = ((CellChangeEvent) e).getRow();
            int column = ((CellChangeEvent) e).getColumn();
            if ("no editing".equals(_table.getValueAt(row, column))) {
              _message.setText("Editing is not started because editingStarting() returns false.");
              return false;
            } else {
              return true;
            }
          }

          public void editingStarted(ChangeEvent e) {}

          public boolean editingStopping(ChangeEvent e) {
            if (e.getSource() instanceof CellEditor) {
              if ("no stop".equals(((CellEditor) e.getSource()).getCellEditorValue())) {
                _message.setText("Editing is not stopped because editingStopping() returns false.");
                return false;
              }
            }
            return true;
          }

          public void editingCanceled(ChangeEvent e) {}

          public void editingStopped(ChangeEvent e) {}
        });

    _table.addValidator(
        new Validator() {
          public ValidationResult validating(ValidationObject e) {
            if ("invalid".equals(e.getNewValue())) {
              ValidationResult validationResult =
                  new ValidationResult(0, false, "The value is \"invalid\"");
              _message.setText(validationResult.getMessage());
              return validationResult;
            } else {
              return ValidationResult.OK;
            }
          }
        });
    _message.setForeground(Color.RED);
    _message.setText("");
    return panel;
  }