Beispiel #1
0
 public SearchItemComponent(final SearchListComponent list) {
   super();
   this.list = list;
   this.setOpaque(false);
   // Initialisation de l'interface graphique
   this.searchMode =
       new JComboBox(
           new String[] {
             TM.tr("contains"),
             TM.tr("contains.exactly"),
             TM.tr("isLessThan"),
             TM.tr("isEqualTo"),
             TM.tr("isExactlyEqualTo"),
             TM.tr("isGreaterThan"),
             TM.tr("isEmpty")
           });
   final ListComboBoxModel comboModel = new ListComboBoxModel(Arrays.asList(TOUT));
   comboModel.setSelectOnAdd(false);
   // allow getColIndex() and thus getSearchItem() to work from now on
   assert comboModel.getSelectedItem() != null;
   this.comboColonnePourRecherche = new JComboBox(comboModel);
   uiInit();
 }
Beispiel #2
0
public class SearchItemComponent extends JPanel {
  private static final Column TOUT = new Column(TM.tr("all"), null, -1);
  private static final Mode[] MODES = {
    Mode.CONTAINS,
    Mode.CONTAINS_STRICT,
    Mode.LESS_THAN,
    Mode.EQUALS,
    Mode.EQUALS_STRICT,
    Mode.GREATER_THAN
  };

  @Immutable
  protected static final class Column {
    private final String label, id;
    private final int index;

    protected Column(String label, String id, int index) {
      super();
      this.label = label;
      this.id = id;
      this.index = index;
    }

    // the current label of the column
    // (not always the same for a column, it depends on names of the other columns)
    public final String getLabel() {
      return this.label;
    }

    // an identifier for the column, should never change
    public final String getID() {
      return this.id;
    }

    // the index of the column in the table model
    public final int getIndex() {
      return this.index;
    }
  }

  private JTextField textFieldRecherche = new JTextField(10);
  private final JComboBox comboColonnePourRecherche;
  private final JComboBox searchMode;
  private JCheckBox invertSearch = new JCheckBox(TM.tr("toReverse"));
  private JButton buttonAdd = new JButton("+");
  private JButton buttonRemove = new JButton();
  final SearchListComponent list;
  private String text = "";

  public SearchItemComponent(final SearchListComponent list) {
    super();
    this.list = list;
    this.setOpaque(false);
    // Initialisation de l'interface graphique
    this.searchMode =
        new JComboBox(
            new String[] {
              TM.tr("contains"),
              TM.tr("contains.exactly"),
              TM.tr("isLessThan"),
              TM.tr("isEqualTo"),
              TM.tr("isExactlyEqualTo"),
              TM.tr("isGreaterThan"),
              TM.tr("isEmpty")
            });
    final ListComboBoxModel comboModel = new ListComboBoxModel(Arrays.asList(TOUT));
    comboModel.setSelectOnAdd(false);
    // allow getColIndex() and thus getSearchItem() to work from now on
    assert comboModel.getSelectedItem() != null;
    this.comboColonnePourRecherche = new JComboBox(comboModel);
    uiInit();
  }

  private void uiInit() {
    this.setLayout(new GridBagLayout());
    final GridBagConstraints c = new GridBagConstraints();
    c.gridx = 0;
    c.gridy = 0;
    c.insets = new Insets(0, 2, 0, 2);
    c.fill = GridBagConstraints.HORIZONTAL;

    // designation
    // don't just use DefaultListCellRenderer, it fails on some l&f
    final ListCellRenderer old = this.comboColonnePourRecherche.getRenderer();
    this.comboColonnePourRecherche.setRenderer(
        new ListCellRenderer() {
          @Override
          public Component getListCellRendererComponent(
              JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            return old.getListCellRendererComponent(
                list, ((Column) value).getLabel(), index, isSelected, cellHasFocus);
          }
        });
    // hand tuned for a IListPanel width of 1024px
    this.comboColonnePourRecherche.setMinimumSize(new Dimension(150, 20));
    this.comboColonnePourRecherche.setOpaque(false);
    add(this.comboColonnePourRecherche, c);
    c.gridx++;
    // contient
    this.searchMode.setMinimumSize(new Dimension(40, 20));
    this.searchMode.setOpaque(false);
    add(this.searchMode, c);
    c.gridx++;
    // Texte de recherche
    c.weightx = 1;
    // about 10 characters
    this.textFieldRecherche.setMinimumSize(new Dimension(50, 20));
    add(this.textFieldRecherche, c);
    c.weightx = 0;
    c.gridx++;
    // inversion de la recherche
    this.invertSearch.setOpaque(false);
    if (!Boolean.getBoolean("org.openconcerto.ui.removeSwapSearchCheckBox")) {
      add(this.invertSearch, c);
    }
    // ajout d'un element de recherche
    c.gridx++;
    this.buttonAdd.setOpaque(false);
    add(this.buttonAdd, c);
    // supprime un element de recherche
    c.gridx++;
    this.buttonRemove.setIcon(new ImageIcon(BaseSQLComponent.class.getResource("delete.png")));
    this.buttonRemove.setBorder(BorderFactory.createEmptyBorder());
    this.buttonRemove.setOpaque(false);
    this.buttonRemove.setBorderPainted(false);
    this.buttonRemove.setFocusPainted(false);
    this.buttonRemove.setContentAreaFilled(false);
    add(this.buttonRemove, c);

    initCombo();
    initSearchText();
    initInvertSearch();

    this.buttonAdd.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            SearchItemComponent.this.list.addNewSearchItem();
          }
        });
    this.buttonRemove.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            SearchItemComponent.this.list.removeSearchItem(SearchItemComponent.this);
          }
        });
  }

  private void initInvertSearch() {
    this.invertSearch.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            updateSearchList();
          }
        });
  }

  private void initSearchText() {
    this.textFieldRecherche
        .getDocument()
        .addDocumentListener(
            new SimpleDocumentListener() {
              public void update(DocumentEvent e) {
                try {
                  // One ne peut pas appeler chercher() car le texte n'est pas encore a jour
                  SearchItemComponent.this.text =
                      e.getDocument().getText(0, e.getDocument().getLength()).trim();
                  updateSearchList();
                } catch (BadLocationException exn) {
                  // impossible
                  exn.printStackTrace();
                }
              }
            });
  }

  private void initCombo() {
    final ItemListener listener =
        new ItemListener() {
          public void itemStateChanged(ItemEvent e) {
            updateSearchList();
          }
        };
    this.searchMode.addItemListener(listener);

    final TableModelListener tableModelL =
        new TableModelListener() {
          @Override
          public void tableChanged(TableModelEvent e) {
            if (e.getColumn() == TableModelEvent.ALL_COLUMNS
                && e.getFirstRow() == TableModelEvent.HEADER_ROW) {
              columnsChanged(listener);
            }
          }
        };
    // allow the TableModel to die
    this.addHierarchyListener(
        new HierarchyListener() {
          public void hierarchyChanged(HierarchyEvent e) {
            if ((e.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0) {
              if (e.getChanged().isDisplayable()) {
                columnsChanged(listener);
                SearchItemComponent.this.list.getTableModel().addTableModelListener(tableModelL);
              } else {
                SearchItemComponent.this.list.getTableModel().removeTableModelListener(tableModelL);
              }
            }
          }
        });
    // that way the TableModelListener will get added automatically
    assert !this.isDisplayable();
  }

  private void selectAllColumnsItem() {
    this.comboColonnePourRecherche.setSelectedIndex(0);
  }

  private void fillColumnCombo(ItemListener listener) {
    // sort column names alphabetically
    final int columnCount = this.list.getTableModel().getColumnCount();
    final String[][] names = new String[columnCount][];
    final int[] indexes = new int[columnCount];
    for (int i = 0; i < columnCount; i++) {
      names[i] = this.list.getColumnNames(i);
      indexes[i] = 0;
    }
    // use column index as columns names are not unique
    final SortedMap<String, Integer> map = solve(names, indexes);
    final List<Column> cols = new ArrayList<Column>(columnCount);
    cols.add(TOUT);
    for (final Entry<String, Integer> e : map.entrySet()) {
      final int colIndex = e.getValue().intValue();
      final String[] colNames = names[colIndex];
      cols.add(new Column(e.getKey(), colNames[colNames.length - 1], colIndex));
    }

    // don't fire when filling, we will fire when selecting
    this.comboColonnePourRecherche.removeItemListener(listener);
    final ListComboBoxModel comboModel =
        (ListComboBoxModel) this.comboColonnePourRecherche.getModel();
    assert !comboModel.isSelectOnAdd() : "Otherwise our following select might not fire";
    comboModel.removeAllElements();
    comboModel.addAll(cols);
    this.comboColonnePourRecherche.addItemListener(listener);
  }

  private void columnsChanged(final ItemListener listener) {
    final String currentID = ((Column) this.comboColonnePourRecherche.getSelectedItem()).getID();
    fillColumnCombo(listener);
    final ListComboBoxModel comboModel =
        (ListComboBoxModel) this.comboColonnePourRecherche.getModel();
    // no selection since the model was just emptied
    assert this.comboColonnePourRecherche.getSelectedIndex() == -1
        && this.comboColonnePourRecherche.getSelectedItem() == null;
    // try to reselect the same column if it's still there
    for (final Object o : comboModel.getList()) {
      final Column col = (Column) o;
      if (CompareUtils.equals(col.getID(), currentID))
        this.comboColonnePourRecherche.setSelectedItem(o);
    }
    if (comboModel.getSelectedItem() == null) selectAllColumnsItem();
  }

  /**
   * Return a sorted map of column index by name.
   *
   * @param names all possible names for each column.
   * @param indexes index of the current name for each column.
   * @return a sorted map.
   */
  private SortedMap<String, Integer> solve(final String[][] names, final int[] indexes) {
    final int columnCount = names.length;
    // columns' index by name
    final CollectionMap<String, Integer> collisions =
        new CollectionMap<String, Integer>(columnCount);
    for (int i = 0; i < columnCount; i++) {
      final int index = indexes[i];
      if (index >= names[i].length)
        throw new IllegalStateException(
            "Ran out of names for " + i + " : " + Arrays.asList(names[i]));
      final String columnName = names[i][index];
      collisions.put(columnName, i);
    }
    final SortedMap<String, Integer> res = new TreeMap<String, Integer>();
    for (Entry<String, Collection<Integer>> e : collisions.entrySet()) {
      final Collection<Integer> indexesWithCollision = e.getValue();
      if (indexesWithCollision.size() > 1) {
        // increment only the minimum indexes to try to solve the conflict with the lowest
        // possible indexes
        int minIndex = Integer.MAX_VALUE;
        for (final Integer i : indexesWithCollision) {
          if (indexes[i] < minIndex) minIndex = indexes[i];
        }
        // now increment all indexes equal to minimum
        for (final Integer i : indexesWithCollision) {
          if (indexes[i] == minIndex) indexes[i]++;
        }
      } else {
        res.put(e.getKey(), indexesWithCollision.iterator().next());
      }
    }
    if (res.size() == columnCount) return res;
    else return solve(names, indexes);
  }

  void updateSearchList() {
    SearchItemComponent.this.list.updateSearch();
  }

  public SearchSpec getSearchItem() {
    final SearchSpec res;
    if (this.searchMode.getSelectedIndex() < MODES.length) {
      final TextSearchSpec textSpec =
          new TextSearchSpec(this.getText(), MODES[this.searchMode.getSelectedIndex()]);
      textSpec.setFormats(this.list.getFormats());
      res = textSpec;
    } else {
      res = new EmptySearchSpec();
    }
    return new ColumnSearchSpec(this.isExcluded(), res, this.getColIndex());
  }

  // *** state

  private final boolean isExcluded() {
    return this.invertSearch.isSelected();
  }

  private final int getColIndex() {
    return ((Column) this.comboColonnePourRecherche.getSelectedItem()).getIndex();
  }

  private final String getText() {
    return this.text;
  }

  public final void setText(String s) {
    this.textFieldRecherche.setText(s);
  }

  /** Reinitialise le composant de recherche */
  public void resetState() {
    this.setText("");
    selectAllColumnsItem();
    this.searchMode.setSelectedIndex(0);
    this.invertSearch.setSelected(false);
  }

  public void setSearchFullMode(boolean b) {
    this.invertSearch.setVisible(b);
    this.buttonAdd.setVisible(b);
    this.buttonRemove.setVisible(b);
    this.comboColonnePourRecherche.setVisible(b);
    this.searchMode.setVisible(b);
  }
}