/**
* Copyright Plugtree LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.plugtree.solrmeter.view.component;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import javax.swing.DefaultCellEditor;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.border.LineBorder;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableModel;
import com.plugtree.solrmeter.model.SolrMeterConfiguration;
import com.plugtree.solrmeter.view.I18n;
import com.plugtree.solrmeter.view.SolrPropertyObserver;
import com.plugtree.solrmeter.view.listener.PropertyChangeListener;
public class PropertiesTable extends JTable implements SolrPropertyObserver, Iterable<String>{
private static final long serialVersionUID = -7064199936721464923L;
private List<PropertyChangeListener> propListeners;
private PropertiesTableModel model;
private boolean canAdd;
public boolean isSorted() {
return this.model.sorted;
}
public void setSorted(boolean sorted) {
this.model.sorted = sorted;
}
public PropertiesTable(PropertyChangeListener l, boolean canAdd, Map<String, String> values){
super();
this.canAdd = canAdd;
if(values != null){
model = new PropertiesTableModel(this.canAdd, values);
} else {
model = new PropertiesTableModel(this.canAdd);
}
this.addKeyListener(new ProperitesTableKeyListener(this));
model.addPropertyChangeListener(l);
this.setModel(model);
this.setDefaultRenderer(Object.class, new DefaultTableCellRenderer(){
private static final long serialVersionUID = 3979746239295239039L;
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column){
JLabel c = (JLabel)super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if(column == 0){
Font f = c.getFont();
if(row < model.keys.size()){
c.setFont(f.deriveFont(Font.BOLD));
} else {
c.setFont(f.deriveFont(Font.ITALIC));
}
}
return c;
}
});
DefaultCellEditor cellEditorProperty = new DefaultCellEditor(new JTextField()){
private static final long serialVersionUID = 1L;
@Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected,
int row, int column){
return super.getTableCellEditorComponent(table, "", isSelected, row, column);
}
};
cellEditorProperty.setClickCountToStart(1);
((JComponent)cellEditorProperty.getComponent()).setBorder(new LineBorder(Color.black));
this.getColumnModel().getColumn(0).setCellEditor(cellEditorProperty);
DefaultCellEditor cellEditorValue = new DefaultCellEditor(new JTextField());
((JComponent)cellEditorValue.getComponent()).setBorder(new LineBorder(Color.black));
cellEditorValue.setClickCountToStart(1);
this.getColumnModel().getColumn(1).setCellEditor(cellEditorValue);
}
public PropertiesTable(PropertyChangeListener l){
this(l, true, null);
}
public PropertiesTable(PropertyChangeListener l, Map<String, String> values){
this(l, true, values);
}
protected class PropertiesTableModel extends AbstractTableModel implements TableModelListener{
private static final long serialVersionUID = -2045687583721284694L;
private List<String> keys;
private Map<String, String> values;
private boolean canAdd;
private boolean sorted = true;
private String newText;
public PropertiesTableModel(boolean canAdd, Map<String, String> v){
this.canAdd = canAdd;
newText = I18n.get("propertiesTable.newText");
keys = new ArrayList<String>(v.size());
for(String key:v.keySet()){
keys.add(key);
}
sortKeys();
values= new HashMap<String, String>(keys.size());
for(String key: keys){
values.put(key, v.get(key));
}
this.addTableModelListener(this);
}
public PropertiesTableModel(boolean canAdd){
this.canAdd = canAdd;
newText = I18n.get("propertiesTable.newText");
keys = SolrMeterConfiguration.getKeys(Pattern.compile(".*"));
sortKeys();
values= new HashMap<String, String>(keys.size());
for(String key: keys){
values.put(key, SolrMeterConfiguration.getProperty(key));
}
this.addTableModelListener(this);
}
private void sortKeys(){
if(this.sorted){
Collections.sort(keys);
}
}
@Override
public int getRowCount() {
int extraRow = this.canAdd?1:0;
return keys.size() + extraRow;
}
@Override
public int getColumnCount() {
return 2;
}
@Override
public String getColumnName(int column) {
switch(column){
case 0:
return I18n.get("settings.advanced.table.property");
case 1:
return I18n.get("settings.advanced.table.value");
default:
return "";
}
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if(this.canAdd && columnIndex==0 && rowIndex == keys.size()){
if(((String)aValue).isEmpty()){
return;
}
this.keys.add((String)aValue);
fireTableCellUpdated(rowIndex, columnIndex);
} else if(columnIndex == 1){
values.put(keys.get(rowIndex), (String)aValue);
fireTableCellUpdated(rowIndex, columnIndex);
}
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
if(this.canAdd && rowIndex == keys.size()){
return columnIndex == 0;
} else {
return columnIndex == 1;
}
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
if(this.canAdd && rowIndex == keys.size()){
if(columnIndex == 0){
return newText;
} else {
return "";
}
}
switch (columnIndex) {
case 0:
return keys.get(rowIndex);
case 1:
return values.get(keys.get(rowIndex));
default:
return null;
}
}
@Override
public void tableChanged(TableModelEvent e) {
int column = e.getColumn();
int row = e.getFirstRow();
if(column == 1 || (canAdd && column == 0 && row == keys.size() - 1)){
TableModel model = (TableModel)e.getSource();
String propName = (String) model.getValueAt(row, 0);
String propValue = (String) model.getValueAt(row, 1);
if(propValue == null){
propValue = "";
}
notifyListeners(propName, propValue);
return;
}
//Deleted column
if(e.getType() == TableModelEvent.DELETE && e.getColumn() == TableModelEvent.ALL_COLUMNS){
TableModel model = (TableModel)e.getSource();
String propName = (String) model.getValueAt(row, 0);
if(row >= this.keys.size()){
return;
}
String key = this.keys.get(row);
this.values.remove(key);
this.keys.remove(row);
notifyListeners(propName, null);
}
}
public void addPropertyChangeListener(PropertyChangeListener l){
if(propListeners == null){
propListeners = new ArrayList<PropertyChangeListener>();
}
propListeners.add(l);
}
protected void notifyListeners(String propertyChanged, String value){
for(PropertyChangeListener l: propListeners){
l.onPropertyChanged(propertyChanged, value);
}
}
}
private class ProperitesTableKeyListener implements KeyListener {
private PropertiesTable parent;
public ProperitesTableKeyListener(PropertiesTable parent){
this.parent = parent;
}
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_DELETE){
parent.deleteSelected();
}
}
@Override
public void keyReleased(KeyEvent e) {}
@Override
public void keyTyped(KeyEvent e) {}
}
@Override
public void solrPropertyChanged(String prop, String value) {
this.setProperty(prop, value);
}
protected void deleteSelected() {
int row = this.getSelectedRow();
if (row >= 0) {
this.model.fireTableRowsDeleted(row, row);
}
}
public void removeAll(){
model.values.clear();
model.keys.clear();
this.tableChanged(new TableModelEvent(model));
}
public void setProperty(String prop, String value) {
if (model.values.get(prop) == null) {
model.keys.add(prop);
}
model.values.put(prop, value);
int row = 0;
for (String property : model.keys) {
if (property.equals(prop))
break;
row++;
}
TableModelEvent e = new TableModelEvent(model, row, row, 1);
this.tableChanged(e);
}
public Map<String, String> getProperties(){
Map<String, String> propMap = new HashMap<String, String>();
for(String key: model.keys){
propMap.put(key, model.values.get(key));
}
return propMap;
}
public List<String> getPropertiesNames(){
List<String> l = new ArrayList<String>(model.keys.size());
for(String s: model.keys){
l.add(s);
}
return l;
}
@Override
public Iterator<String> iterator() {
return model.keys.iterator();
}
}