/* * Copyright 2003-2010 Tufts University Licensed under the * Educational Community 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.osedu.org/licenses/ECL-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 edu.tufts.vue.metadata.ui; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.DefaultCellEditor; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.SwingUtilities; import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; import tufts.vue.VueResources; import tufts.vue.VueUtil; import tufts.vue.gui.GUI; import edu.tufts.vue.metadata.CategoryModel; import edu.tufts.vue.ontology.OntType; import edu.tufts.vue.ontology.Ontology; //import tufts.vue.gui.DockWindow; /* * CategoryEditor.java * * Created on August 17, 2007, 2:05 PM * * @author dhelle01 */ public class CategoryEditor extends JPanel { private static final boolean DEBUG_LOCAL = false; // for best results: modify next two in tandem (at exchange rate of one pirxl from ROW_GAP for // each two in ROW_HEIGHT in order to maintain proper text box height public final static int ROW_HEIGHT = 39; public final static int ROW_GAP = 7; public final static int ROW_INSET = 0; public final static int BUTTON_COL_WIDTH = 35; //private JTable metadataSetTable; private JTable customCategoryTable; //private JPanel setPanel; private JPanel customPanel; private JPanel buttonPanel; private JButton cancelButton; private JButton doneButton; private boolean newCategoryRequested; private JDialog dialog; public CategoryEditor(JDialog dialog,final JComboBox categories, final MetadataEditor metadataEditor, final tufts.vue.LWComponent current, final int row, final int col) { this.dialog = dialog; setLayout(new BoxLayout(this,BoxLayout.Y_AXIS)); //setPanel = new JPanel(); //metadataSetTable = new JTable(new FullMetadataSetTableModel()); //metadataSetTable.setDefaultRenderer(java.lang.Object.class,new SetTableRenderer()); //metadataSetTable.setDefaultEditor(java.lang.Object.class,new SetTableEditor()); //setPanel.add(metadataSetTable); customPanel = new JPanel(new java.awt.BorderLayout()); customCategoryTable = new JTable(new MetadataCategoryTableModel()); customCategoryTable.setOpaque(false); customCategoryTable.setDefaultRenderer(java.lang.Object.class,new CustomCategoryTableRenderer()); customCategoryTable.setDefaultEditor(java.lang.Object.class,new CustomCategoryTableEditor()); ((DefaultCellEditor)customCategoryTable.getDefaultEditor(java.lang.Object.class)).setClickCountToStart(1); customCategoryTable.getColumnModel().getColumn(0).setHeaderRenderer(new CustomCategoryTableHeaderRenderer()); customCategoryTable.getColumnModel().getColumn(1).setHeaderRenderer(new CustomCategoryTableHeaderRenderer()); int editorWidth = getWidth(); customCategoryTable.getColumnModel().getColumn(0).setMinWidth(editorWidth-BUTTON_COL_WIDTH); customCategoryTable.getColumnModel().getColumn(1).setMaxWidth(BUTTON_COL_WIDTH); customCategoryTable.setRowHeight(ROW_HEIGHT); customCategoryTable.getTableHeader().setReorderingAllowed(false); //metadataSetTable.setRowHeight(ROW_HEIGHT); //metadataSetTable.getTableHeader().setReorderingAllowed(false); customCategoryTable.setGridColor(new java.awt.Color(getBackground().getRed(),getBackground().getBlue(),getBackground().getGreen(),0)); customCategoryTable.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); customCategoryTable.setIntercellSpacing(new java.awt.Dimension(0,0)); final JScrollPane scroll = new JScrollPane(customCategoryTable); scroll.setBackground(getBackground()); scroll.setBorder(BorderFactory.createEmptyBorder(10,20,10,20)); scroll.getViewport().setOpaque(false); customCategoryTable.getTableHeader().addMouseListener(new java.awt.event.MouseAdapter() { public void mousePressed(java.awt.event.MouseEvent evt) { if(evt.getX()>customCategoryTable.getWidth()-BUTTON_COL_WIDTH) { newCategoryRequested = true; /*if(customCategoryTable.getCellEditor() != null) { customCategoryTable.getCellEditor().stopCellEditing(); //scroll.requestFocus(); CategoryEditor.this.requestFocus(false); }*/ ((MetadataCategoryTableModel)customCategoryTable.getModel()).refresh(); SwingUtilities.invokeLater(new Runnable(){ public void run() { scroll.getVerticalScrollBar().setValue(scroll.getVerticalScrollBar().getMaximum()); } }); } } public void mouseEntered(java.awt.event.MouseEvent e) { // todo -- use mouse moved to make it any move near the add button.. if((customCategoryTable.getCellEditor() != null)/* && (e.getX()>customCategoryTable.getWidth()-BUTTON_COL_WIDTH)*/) { customCategoryTable.getCellEditor().stopCellEditing(); } } }); /*customCategoryTable.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseReleased(java.awt.event.MouseEvent evt) { if(evt.getX()>customCategoryTable.getWidth()-BUTTON_COL_WIDTH) { CategoryModel vueCategoryModel = tufts.vue.VUE.getCategoryModel(); java.util.List<OntType> ontTypes = vueCategoryModel.getCustomOntology().getOntTypes(); int selectedRow = customCategoryTable.getSelectedRow(); if(customCategoryTable.getSelectedColumn()== 1 && ontTypes.size() > selectedRow) { ontTypes.remove(selectedRow); customCategoryTable.repaint(); requestFocusInWindow(); tufts.vue.VUE.getCategoryModel().saveCustomOntology(); } } } });*/ //customPanel.setBorder(BorderFactory.createEmptyBorder(15,15,15,15)); customPanel.add(scroll); //add(setPanel); // todo: add separator add(customPanel); //if(DEBUG_LOCAL) //{ // System.out.println("scroll: " + scroll); // System.out.println("categoryTable: " + customCategoryTable); //} buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); buttonPanel.setBorder(BorderFactory.createEmptyBorder(0,0,5,15)); // cancelButton = new JButton(VueResources.getString("button.cancel.lable")); // cancelButton.setFont(GUI.LabelFace); doneButton = new JButton(VueResources.getString("button.close.label")); doneButton.setFont(GUI.LabelFace); //buttonPanel.add(cancelButton); //buttonPanel.add(cancelButton); buttonPanel.add(doneButton); add(buttonPanel); doneButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { ((CategoryComboBoxModel)categories.getModel()).refreshCategoryMenu(); CategoryEditor.this.dialog.dispose(); }}); //categories.setSelectedItem(categories.getSelectedItem()); //int n = categories.getModel().getSize(); // final String currentKey = metadataEditor.getKeyForRow(row); // if (currentKey != null) { // MetadataEditor.selectKnownCategory(currentKey, categories); // categories.repaint(); // } // Object currObject = null; // tufts.vue.LWComponent currComponent = null; // if (metadataEditor.getCurrentMultiples() !=null ) // currComponent = metadataEditor.getCurrentMultiples(); // else if(metadataEditor.getCurrent() !=null ) // currComponent = metadataEditor.getCurrent(); // else { CategoryEditor.this.dialog.dispose(); return; } // currObject = currComponent.getMetadataList().getMetadata().get(row).getObject(); // Object currValue = (((String[])currObject)[0]); } class CustomCategoryTableHeaderRenderer extends DefaultTableCellRenderer { public java.awt.Component getTableCellRendererComponent(JTable table, Object value,boolean isSelected,boolean hasFocus,int row,int col) { //setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); JComponent comp = new JPanel(); if(col == 0) { comp = new JLabel(VueResources.getString("addcustomcategory.label")); comp.setFont(tufts.vue.gui.GUI.LabelFace); } else if(col == 1) { //comp = new JLabel(); //((JLabel)comp).setIcon(tufts.vue.VueResources.getImageIcon("metadata.editor.add.up")); //comp.setBorder(BorderFactory.createEmptyBorder(5,0,0,0)); JPanel holder = new JPanel(); holder.add(new tufts.vue.gui.VueButton("keywords.button.add")); comp.add(holder); } else { comp = new JLabel(""); } comp.setOpaque(true); comp.setBackground(CategoryEditor.this.getBackground()); comp.setBorder(BorderFactory.createEmptyBorder(ROW_GAP,ROW_INSET,ROW_GAP,ROW_INSET)); return comp; } } /*class SetTableRenderer extends DefaultTableCellRenderer { JPanel checkPanel = new JPanel(); JCheckBox check = new JCheckBox(); JLabel label = new JLabel(); public java.awt.Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected, boolean hasFocus,int row,int col) { if(col == 0) { checkPanel.add(check); return checkPanel; } if(col == 1) { if(DEBUG_LOCAL) { System.out.println("CategoryEditor: " + value.getClass()); } if(value instanceof Ontology) { label.setText(((Ontology)value).getLabel()); } return label; } label.setText("ERROR"); return label; } } */ /*class SetTableEditor extends DefaultCellEditor { JPanel checkPanel = new JPanel(); JCheckBox check = new JCheckBox(); JLabel label = new JLabel(); public SetTableEditor() { super(new JTextField()); //label = (JTextField)getComponent(); } public java.awt.Component getTableCellEditorComponent(JTable table,Object value,boolean isSelected, int row,int col) { if(col == 0) { checkPanel.add(check); return checkPanel; } if(col == 1) { if(DEBUG_LOCAL) { System.out.println("CategoryEditor: " + value.getClass()); } if(value instanceof Ontology) { label.setText(((Ontology)value).getLabel()); } return label; } label.setText("ERROR"); return label; } }*/ class CustomCategoryTableRenderer extends DefaultTableCellRenderer { JPanel checkPanel = new JPanel(); //JCheckBox check = new JCheckBox(); JTextField label = new JTextField(); tufts.vue.gui.VueButton deleteButton = new tufts.vue.gui.VueButton("keywords.button.delete"); JPanel deletePanel = new JPanel(); public CustomCategoryTableRenderer() { deletePanel.setBorder(BorderFactory.createEmptyBorder(5,1,0,0)); deletePanel.add(deleteButton); label.setFont(tufts.vue.gui.GUI.LabelFace); } public java.awt.Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected, boolean hasFocus,int row,int col) { JPanel comp = new JPanel(new java.awt.BorderLayout()); if(col == 1) { // JLabel button = new JLabel(); // button.setIcon(tufts.vue.VueResources.getImageIcon("metadata.editor.delete.up")); // comp.add(button); //return checkPanel; /*if(DEBUG_LOCAL) { System.out.println("CE: in table renderer -- showing delete button: " + row); }*/ return deletePanel; } if(col == 0) { //label.setBorder(BorderFactory.createEmptyBorder(ROW_GAP,ROW_INSET,ROW_GAP,ROW_INSET)); //if(DEBUG_LOCAL) //{ // System.out.println("CategoryEditor: " + value.getClass() + " row: " + row + " col: " + col); //} if(value instanceof OntType) { label.setText(((OntType)value).getLabel()); //if(DEBUG_LOCAL) //{ // System.out.println("Label text in category component: " + label.getText()); //} } else { label.setText(value.toString()); } comp.add(label); //return label; } comp.setBorder(BorderFactory.createEmptyBorder(ROW_GAP,ROW_INSET,ROW_GAP,ROW_INSET)); //label.setText("ERROR"); return comp; } } class CustomCategoryTableEditor extends DefaultCellEditor { //JPanel checkPanel = new JPanel(); //JPanel deletePanel = new JPanel(); //JCheckBox check = new JCheckBox(); JTextField label = new JTextField(); //private int row; //private int col; public CustomCategoryTableEditor() { super(new JTextField()); label.setFont(GUI.LabelFace); label = (JTextField)getComponent(); /*label.addFocusListener(new java.awt.event.FocusAdapter(){ public void focusLost(java.awt.event.FocusEvent fe) { if( (row == customCategoryTable.getModel().getRowCount() - 1) && newCategoryRequested ) { CategoryModel cats = tufts.vue.VUE.getCategoryModel(); cats.addCustomCategory(label.getText()); ((MetadataCategoryTableModel)customCategoryTable.getModel()).refresh(); cats.saveCustomOntology(); newCategoryRequested = false; } else { CategoryModel cats = tufts.vue.VUE.getCategoryModel(); cats.addCustomCategory(label.getText(),cats.getCustomOntology().getOntTypes().get(row)); ((MetadataCategoryTableModel)customCategoryTable.getModel()).refresh(); cats.saveCustomOntology(); } } }); */ } public java.awt.Component getTableCellEditorComponent(final JTable table,Object value,boolean isSelected, final int row,int col) { JPanel comp = new JPanel(new java.awt.BorderLayout()); if(col == 1) { //if(DEBUG_LOCAL) //{ // System.out.println("CE - creating delete button editor " + row); //} //checkPanel.add(check); //comp.add(check); //return checkPanel; JPanel deletePanel = new JPanel(); deletePanel.setBorder(BorderFactory.createEmptyBorder(5,1,0,0)); tufts.vue.gui.VueButton deleteButton = new tufts.vue.gui.VueButton("keywords.button.delete"); deleteButton.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseReleased(java.awt.event.MouseEvent evt) { //if(evt.getX()>customCategoryTable.getWidth()-BUTTON_COL_WIDTH) //{ CategoryModel vueCategoryModel = tufts.vue.VUE.getCategoryModel(); java.util.List<OntType> ontTypes = vueCategoryModel.getCustomOntology().getOntTypes(); //int selectedRow = customCategoryTable.getSelectedRow(); //if(customCategoryTable.getSelectedColumn()== 1 && ontTypes.size() > selectedRow) //{ if(ontTypes.size() > row) ontTypes.remove(row); //customCategoryTable.repaint(); //requestFocusInWindow(); tufts.vue.VUE.getCategoryModel().saveCustomOntology(); ((MetadataCategoryTableModel)customCategoryTable.getModel()).refresh(); customCategoryTable.repaint(); requestFocusInWindow(); //} //} } }); deletePanel.add(deleteButton); return deletePanel; } if(col == 0) { final JTextField label = new JTextField(); label.setFont(GUI.LabelFace); //this.row = row; //this.col = col; //if(DEBUG_LOCAL) //{ // System.out.println("CategoryEditor: " + value.getClass()); //} if(value instanceof OntType) { label.setText(((OntType)value).getLabel()); } /*label.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseExited(java.awt.event.MouseEvent e) { if(customCategoryTable.getCellEditor() != null) { customCategoryTable.getCellEditor().stopCellEditing(); } } });*/ label.addFocusListener(new java.awt.event.FocusAdapter(){ public void focusLost(java.awt.event.FocusEvent fe) { if(DEBUG_LOCAL) { System.out.println("CE: label focus lost -- " + row); } if( (row == table.getModel().getRowCount() - 1) && newCategoryRequested ) { CategoryModel cats = tufts.vue.VUE.getCategoryModel(); cats.addCustomCategory(label.getText()); ((MetadataCategoryTableModel)customCategoryTable.getModel()).refresh(); cats.saveCustomOntology(); newCategoryRequested = false; } else { CategoryModel cats = tufts.vue.VUE.getCategoryModel(); cats.addCustomCategory(label.getText(),cats.getCustomOntology().getOntTypes().get(row)); ((MetadataCategoryTableModel)customCategoryTable.getModel()).refresh(); cats.saveCustomOntology(); } } }); comp.add(label); //return label; } comp.setBorder(BorderFactory.createEmptyBorder(ROW_GAP,ROW_INSET,ROW_GAP,ROW_INSET)); return comp; //label.setText("ERROR"); //return label; } } /*class FullMetadataSetTableModel extends AbstractTableModel { List<Boolean> selections = new ArrayList<Boolean>(); private CategoryModel vueCategoryModel = tufts.vue.VUE.getCategoryModel(); public int getRowCount() { return vueCategoryModel.size(); } // first column contains checkbox that will remove or add ontologies // second column contains ontology names public int getColumnCount() { return 2; } public Object getValueAt(int row,int col) { if(col == 1) { return vueCategoryModel.get(row); } else //if(col == 0) { //return selections.get(row); return Boolean.TRUE; } } }*/ class MetadataCategoryTableModel extends AbstractTableModel { private CategoryModel vueCategoryModel = tufts.vue.VUE.getCategoryModel(); /** * * column 1: category, which is an OntType and will appear * as a simple string * * column 2: remove button (should change CategoryModel) * **/ public int getColumnCount() { return 2; } public boolean isCellEditable(int row,int col) { return true; /*if(col == 0) return true; else return false; */ } public int getRowCount() { Ontology customOntology = vueCategoryModel.getCustomOntology(); if(customOntology == null || vueCategoryModel.getCustomOntology().getOntTypes().size() ==0) { newCategoryRequested = true; return 1; } if(/*(customOntology !=null) &&*/ !newCategoryRequested) return vueCategoryModel.getCustomOntology().getOntTypes().size(); else if(customOntology != null) return vueCategoryModel.getCustomOntology().getOntTypes().size() + 1; else return 0; // vueCategoryModel.getCustomCategories.getSize(); } public Object getValueAt(int row,int col) { if(col == 0 && vueCategoryModel.getCustomOntology() == null) { return ""; } if(col == 0 && row < vueCategoryModel.getCustomOntology().getOntTypes().size()) { OntType category = vueCategoryModel.getCustomOntology().getOntTypes().get(row); return category; } else if(col == 0 && row == vueCategoryModel.getCustomOntology().getOntTypes().size()) { return ""; } else //if(row == 1) { return "remove"; } } public void refresh() { fireTableDataChanged(); } } }