/*
* 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 tufts.vue;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collection;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.AbstractCellEditor;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.DefaultCellEditor;
import javax.swing.ImageIcon;
import javax.swing.AbstractButton;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.JComponent;
import javax.swing.Box;
import javax.swing.ButtonGroup;
import javax.swing.ButtonModel;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import tufts.Util;
import tufts.vue.gui.DockWindow;
import tufts.vue.gui.GUI;
import tufts.vue.gui.VueTextPane;
import tufts.vue.gui.Widget;
import tufts.vue.gui.WidgetStack;
import tufts.vue.gui.WindowDisplayAction;
import tufts.vue.gui.renderer.SavedSearchTableRenderer;
import tufts.vue.gui.renderer.SearchResultTableModel;
import edu.tufts.vue.metadata.VueMetadataElement;
import edu.tufts.vue.metadata.action.SearchAction;
import static edu.tufts.vue.metadata.action.SearchAction.*;
import edu.tufts.vue.metadata.ui.CategoryComboBoxModel;
import edu.tufts.vue.metadata.ui.CategoryComboBoxRenderer;
import edu.tufts.vue.ontology.OntType;
// todo: really need a "search even hidden/locked" button in the search UI
/**
* A tabbed-pane collection of property sheets that apply globally to a given
* map.
*
* @version $Revision: 1.61 $ / $Date: 2010-02-03 19:17:41 $ / $Author: Sheejo
* Rapheal $
*
*/
public class MetadataSearchMainGUI extends JPanel
implements ActiveListener<LWMap>
{
private static final org.apache.log4j.Logger Log = org.apache.log4j.Logger.getLogger(MetadataSearchMainGUI.class);
private static final Object[] SearchScopes = {
SearchAction.SEARCH_SCOPE_CURRENT_MAP,
SearchAction.SEARCH_SCOPE_ALL_OPEN_MAPS
};
private static final Object[] SearchDomainsLimited = {
SearchAction.SEARCH_EVERYTHING,
SearchAction.SEARCH_ONLY_LABELS,
SearchAction.SEARCH_ONLY_KEYWORDS
};
// Note: it turns out it can be crucial to access at least one of the value instances
// before calling All() or they may not have been initialized...
private static final Object[] SearchDomainsAll = SearchAction.SearchType.All();
private static final Object[] SearchDomains = DEBUG.TEST ? SearchDomainsLimited : SearchDomainsAll;
private static final Object[] ResultActionsAll = SearchAction.ResultOp.All();
private static final Object[] ResultActionsLimited = { SearchAction.RA_SELECT, SearchAction.RA_SHOW, SearchAction.RA_HIDE };
private static final Object[] ResultActions = DEBUG.TEST ? ResultActionsLimited : ResultActionsAll;
private static final Object[] ResultActionsMultiMap = { SearchAction.RA_COPY };
private static final Object[] LogicOps = { SearchAction.Operator.AND, SearchAction.Operator.OR };
private static final boolean DEBUG_LOCAL = false;
public final static int BUTTON_COL_WIDTH = 24;
public final static int ROW_HEIGHT = 30;
public List<VueMetadataElement> searchTerms = new ArrayList<VueMetadataElement>();
private /*final*/ SearchAction termsAction = new SearchAction(searchTerms);
private final JTextField allSearchField = new JTextField();
//private final SearchAction allSearch = new SearchAction(allSearchField); // not deployed
public final static int SHOW_OPTIONS = 1;
public final static int HIDE_OPTIONS = 0;
private int buttonColumn = 2;
private int comboColumn = 1;
private int categoryColumn = -1;
private int valueColumn = 0;
private int headerButtonColumn = 2;
private int headerComboColumn = 1;
private int headerCategoryColumn = -1;
private int headerValueColumn = 0;
private int conditionColumn = -1;
//private int searchType = EVERYTHING; // LOCAL search-type -- dupes SearchType semantics
private SearchType searchType = SEARCH_EVERYTHING;
// combo box numbers within optionsPanel
public final static int TYPES = 0;
public final static int LOCATIONS = 1;
public final static int RESULTS = 2;
private boolean singleLine = false;
static public final int ANY_MODE = 0;
static public final int ALL_MODE = 1;
static public final int NOT_ANY_MODE = 2;
static public final int NONE_MODE = 3;
private MetaSearchPanel mInfoPanel = null;
private MetadataPanel metadataPanel = null;
private final SearchResultTableModel searchResultModel = new SearchResultTableModel();
VueTextPane mDescriptionEditor = null;
JTextField mAuthorEditor = null;
private WidgetStack mapInfoStack = null;
static AbstractAction saveSearchAction;
static AbstractAction runSearchAction;
static AbstractAction renameAction;
static AbstractAction deleteAction;
private final List<JComboBox> comboBoxes = new ArrayList<JComboBox>();
private JPopupMenu popupMenu = new JPopupMenu();
private final String RENAME_STR = VueResources.local("searchgui.rename");
private final String DELETE_STR = VueResources.local("searchgui.delete");
private final String RESET_STR = VueResources.local("searchgui.resetmap");
private final String SEARCH_STR = VueResources.local("searchgui.search");
private final String SAVED_SEARCH_STR = VueResources.local("searchgui.savedsearches");
private final String SAVE_SEARCH_STR = VueResources.local("searchgui.savesearch");
private final String RUN_SEARCH_STR = VueResources.local("searchgui.runsearch");
//private String strAndOrType = VueResources.local("searchgui.or");
private SearchAction.Operator selectedOp = SearchAction.Operator.OR;
private JPanel topPanel;
private OptionsPanel optionsPanel;
private JPanel linePanel;
private JPanel tablePanel;
private JPanel searchPanel;
private JComponent choiceScope;
private JComponent choiceDomain;
private JComponent choiceResult;
private JTable searchTermsTbl;
private JTable searchHeaderTbl;
private JTable searchResultTbl;
private final JComboBox andOrCmbBox;
private final JComponent macLeopardAndOr;
private JButton saveButton;
private JButton resetButton;
private JButton searchButton;
private void runSaveAction(ActionEvent e) {
if(searchTermsTbl.isEditing())
searchTermsTbl.getCellEditor().stopCellEditing();
final SearchData data = new SearchData();
final List<SearchData> searchDataList = new ArrayList<SearchData>();
//searchDataList = new ArrayList<SearchData>();
final String searchName = getSearchName(searchResultModel.getRowCount());
if (searchName != null) {
// data.setSearchType(searchTypeCmbBox.getSelectedItem().toString().trim());
// data.setMapType(mapCmbBox.getSelectedItem().toString().trim());
// data.setResultType(resultCmbBox.getSelectedItem().toString().trim());
//data.setAndOrType(selectedOp.key);
//data.setAndOrType(strAndOrType);
data.setSearchSaveName(searchName);
data.setMapType(getChosenString(choiceScope)); // todo: use locale-independent string, tho I've a hard time imagining anyone saving an all-maps search...
data.setSearchType(getChosenString(choiceDomain));
data.putResultOp((SearchAction.ResultOp) getChosen(choiceResult));
data.putLogicalOp(selectedOp);
data.setDataList(searchTerms);
searchDataList.add(data);
searchResultModel.addRow(data);
searchTerms = new ArrayList<VueMetadataElement>();
((SearchTermsTableModel) searchTermsTbl.getModel()).refresh();
VUE.getActiveMap().markAsModified();
if (searchResultModel.getData() != null && VUE.getActiveMap() != null) {
VUE.getActiveMap().setSearchArrLst(searchResultModel.getData());
}
}
}
private String getSearchName(int rowCount){
String inputValue = (String) VueUtil.input
(null, VueResources.local("searchgui.entersearchname"),
null, JOptionPane.PLAIN_MESSAGE, null,
(VueResources.local("searchgui.search") + " "+ (rowCount+1)));
if (inputValue != null && inputValue.trim().length() == 0) {
inputValue = VueResources.local("searchgui.search") + " "+ (rowCount+1);
}
return inputValue;
}
public MetadataSearchMainGUI(DockWindow w) {
super();
if (Util.isMacLeopard() && DEBUG.TEST) {
macLeopardAndOr = getButtonBox(LogicOps);
andOrCmbBox = new JComboBox(LogicOps);
//andOrCmbBox = null;
} else {
andOrCmbBox = new JComboBox(LogicOps);
macLeopardAndOr = null;
}
JPopupMenu popup = new JPopupMenu();
mapInfoStack = new WidgetStack(SEARCH_STR);
VUE.addActiveListener(LWMap.class, this);
setMinimumSize(new Dimension(300, 250));
setLayout(new BorderLayout());
mInfoPanel = new MetaSearchPanel();
mInfoPanel.setName(SEARCH_STR);
metadataPanel = new MetadataPanel();
metadataPanel.setName(SAVED_SEARCH_STR);
//Widget.setWantsScroller(mapInfoStack, true);
adjustHeaderTableColumnModel();
// mTabbedPane.addTab(metadataPanel.getName(),metadataPanel);
// mapInfoStack.addPane(mInfoPanel, 1f);
// mapInfoStack.addPane(metadataPanel, 2f);
mapInfoStack.addPane(SEARCH_STR,mInfoPanel);
mapInfoStack.addPane(metadataPanel, 2f);
// Widget.setWantsScroller(mapInfoStack, true);
// SearchTextField.editSettingsMenuItem should have a WindowDisplayAction linked to the DockWindow
// so that it will be properly and automatically checked, but it was created before this DockWindow
// existed; now that the DockWindow exists, change the menu item's action to be a WindowDisplayAction.
if (SearchTextField.editSettingsMenuItem != null) {
WindowDisplayAction wda = new WindowDisplayAction(w);
wda.setTitle(VueResources.local("search.popup.edit.search.settings"));
wda.setLinkedButton(SearchTextField.editSettingsMenuItem);
SearchTextField.editSettingsMenuItem.setAction(wda);
}
saveSearchAction = new AbstractAction(SAVE_SEARCH_STR) {
public void actionPerformed(ActionEvent e) {
if (DEBUG.Enabled) Log.debug("saveSearchAction: " + e);
runSaveAction(e);
}
};
runSearchAction = new AbstractAction(RUN_SEARCH_STR)
{ public void actionPerformed(ActionEvent e) { runSavedSearch(); }};
renameAction = new AbstractAction(RENAME_STR) {
public void actionPerformed(ActionEvent e) {
searchResultModel.setEditableFlag(true);
int selectedIndex = searchResultTbl.getSelectedRow();
if (selectedIndex != -1){
searchResultTbl.editCellAt(selectedIndex, 0);
searchResultModel.setEditableFlag(false);
}
}
};
deleteAction = new AbstractAction(DELETE_STR) {
public void actionPerformed(ActionEvent e) {
int selectedIndex = searchResultTbl.getSelectedRow();
if (selectedIndex != -1){
searchResultModel.removeRow(selectedIndex);
}
}
};
Widget.setMenuActions(metadataPanel, new Action[] { saveSearchAction,
runSearchAction, renameAction, deleteAction });
Widget.setWantsScroller(mapInfoStack, true);
Widget.setWantsScrollerAlways(mapInfoStack, true);
w.setContent(mapInfoStack);
w.setHeight(350);
w.setWidth(300);
validate();
setVisible(true);
}
private static Box getButtonBox(Object[] stringables) {
final Box box;
//box = GUI.createButtonBox("segmented", stringables); // aqua buttons glossy blue
box = GUI.createButtonBox("segmentedCapsule", stringables); // big & dark
//box = GUI.createButtonBox("segmentedTextured", stringables); // big & dark (looks same)
//box = GUI.createButtonBox("segmentedRoundRect", stringables); // smallest (vertically)
return box;
}
private static final String CHOICE_NONE = "<choice:none>";
private Object getChosen(final JComponent jc) {
Object choice = CHOICE_NONE;
if (jc instanceof javax.swing.JComboBox) {
choice = ((JComboBox)jc).getSelectedItem();
} else if (jc instanceof javax.swing.Box) {
final ButtonGroup group = (ButtonGroup) jc.getClientProperty(ButtonGroup.class);
if (group != null) {
// was presumably created by GUI.createButtonBox
final ButtonModel bm = group.getSelection();
Log.debug("getChosen: group.getSelection: " + Util.tags(bm));
final Object objs[] = bm.getSelectedObjects();
Log.debug("getChosen: buttonModel.getSelectedObjects: " + Util.tags(objs));
// if (objs != null && objs.length > 0)
// choice = objs[0];
//for (AbstractButton ab : bm.getElements()) { }
for (Component c : jc.getComponents()) {
Log.debug("getChosen: examine: " + GUI.name(c));
if (c instanceof AbstractButton) {
if (((AbstractButton)c).isSelected()) {
Log.debug("getChosen: isSelec: " + GUI.name(c));
choice = ((JComponent)c).getClientProperty("segment.value"); // handle Strings as well as ComboKey's
//choice = ((JComponent)c).getClientProperty(GUI.ComboKey.class);
break;
}
}
}
}
}
Log.debug("getChosen: " + GUI.name(jc) + "=" + GUI.name(choice));
//Log.debug("getChosen: " + GUI.name(jc) + "=" + Util.tags(choice));
return choice;
}
private String getChosenString(JComponent jc) {
return getChosen(jc).toString().trim();
}
private JComponent getChooser(Object[] choices, ItemListener listener, String name) {
final JComponent jc;
if (DEBUG.TEST) {
jc = getButtonBox(choices); // TODO: no listeners
} else {
jc = getComboBox(choices, listener);
}
if (DEBUG.Enabled) {
Log.debug("getChooser " + Util.tags(name) + "; choices:");
Util.dump(choices);
}
jc.setName(name);
return jc;
}
private JComboBox getComboBox(Object[] choices, ItemListener listener) {
final JComboBox combo = new JComboBox(choices);
combo.setFont(tufts.vue.gui.GUI.LabelFace);
combo.addItemListener(listener);
if (true)
combo.setPreferredSize(combo.getMinimumSize());
comboBoxes.add(combo);
return combo;
}
// ///////////////
// Inner Classes
// //////////////////
/**
* InfoPanel This is the tab panel for displaying Map Info
**/
public class MetaSearchPanel extends JPanel implements PropertyChangeListener, FocusListener {
final ItemListener searchTypesListener = new ItemListener() {
public void itemStateChanged(ItemEvent ie) {
if (ie.getStateChange() != ItemEvent.SELECTED)
return;
// This would all better be handled via events instead
// of this direct calling into SearchTextField hack stuff.
final Object selected = ie.getItem();
if (SEARCH_EVERYTHING.equals(selected)) {
setEverythingSearch();
SearchTextField.searcheveryWhereMenuItem.setSelected(true);
} else if (SEARCH_ONLY_LABELS.equals(selected)) {
setLabelSearch();
SearchTextField.labelMenuItem.setSelected(true);
} else if (SEARCH_ONLY_KEYWORDS.equals(selected)) {
setAllMetadataSearch();
SearchTextField.keywordMenuItem.setSelected(true);
} else if (SEARCH_WITH_CATEGORIES.equals(selected)) {
setCategorySearch();
SearchTextField.categoryKeywordMenuItem.setSelected(true);
} else
Log.warn("Unknown selected search-type: " + Util.tags(selected));
SearchTextField.updateSearchType();
}
};
final ItemListener locationChoiceListener = new ItemListener() {
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
termsAction.setLocationType(e.getItem());
if (SEARCH_SCOPE_ALL_OPEN_MAPS.equals(e.getItem()))
optionsPanel.switchChoices(RESULTS, ResultActionsMultiMap);
else
optionsPanel.switchChoices(RESULTS, ResultActions);
}
}
};
final ItemListener resultsTypeListener = new ItemListener() {
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
if (termsAction != null && e.getItem() instanceof GUI.ComboKey) {
// This means the SearchAction won't be told about the "Create New Map"
// result action, but it doesn't need to -- currently, any search
// across all maps has only one fixed result action: create a new map.
termsAction.setResultAction(e.getItem());
}
}
}
};
private final static int HALF_GUTTER = 4;
private final static int GUTTER = HALF_GUTTER * 2;
final Insets
labelInsets = new Insets(HALF_GUTTER, HALF_GUTTER, HALF_GUTTER, 0),
textFieldInsets = new Insets(HALF_GUTTER, HALF_GUTTER, HALF_GUTTER, HALF_GUTTER);
private void addPair(GridBagConstraints g, JComponent label, JComponent chooser)
{
label.setFont(tufts.vue.gui.GUI.LabelFace);
if (DEBUG.TEST) {
;
} else {
g.gridx = 0;
g.insets = labelInsets;
//g.insets = GUI.EmptyInsets;
g.weightx = 0.0;
optionsPanel.add(label, g); // only member reference (enclosing class)
}
g.gridx = 1;
g.insets = textFieldInsets;
//g.insets = GUI.EmptyInsets;
g.weightx = 1.0;
optionsPanel.add(chooser, g);
g.gridy++;
if (DEBUG.BOXES) {
label.setBackground(Color.YELLOW);
label.setOpaque(true);
chooser.setBackground(Color.YELLOW);
chooser.setOpaque(true);
}
}
public MetaSearchPanel() {
final JLabel labelScope, labelDomain, labelResult;
final GridBagConstraints gb = new GridBagConstraints();
optionsPanel = new OptionsPanel(new GridBagLayout()); // on MDSMGU
gb.fill = GridBagConstraints.HORIZONTAL;
gb.gridy = 0; // first row starts at 0
labelScope = new JLabel(VueResources.local("searchgui.maps"), SwingConstants.RIGHT);
//labelDomain = new JLabel(VueResources.local("searchgui.searchtype"), SwingConstants.RIGHT); // too long
labelDomain = new JLabel(VueResources.local("searchgui.search")+":", SwingConstants.RIGHT); // short & sweet
labelResult = new JLabel(GUI.ensureColon(VueResources.local("searchgui.results")), SwingConstants.RIGHT);
choiceScope = getChooser(SearchScopes, locationChoiceListener, "searchScope");
choiceDomain = getChooser(SearchDomains, searchTypesListener, "searchDomain");
choiceResult = getChooser(ResultActions, resultsTypeListener, "resultAction");
if (DEBUG.TEST) {
addPair(gb, labelScope, choiceScope);
addPair(gb, labelDomain, choiceDomain);
} else {
addPair(gb, labelDomain, choiceDomain);
addPair(gb, labelScope, choiceScope);
}
addPair(gb, labelResult, choiceResult);
if (DEBUG.BOXES || DEBUG_LOCAL) optionsPanel.setBackground(Color.BLUE);
linePanel = new JPanel() {
protected void paintComponent(java.awt.Graphics g) {
if (isOpaque()) {
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
}
g.setColor(java.awt.Color.DARK_GRAY);
g.drawLine(HALF_GUTTER, getHeight() / 2, getWidth() - HALF_GUTTER - 1, getHeight() / 2);
}
};
searchHeaderTbl = new JTable(new SearchHeaderTableModel());
searchHeaderTbl.setOpaque(false);
searchHeaderTbl.setRowHeight(ROW_HEIGHT);
if (DEBUG.BOXES) {
searchHeaderTbl.setShowGrid(true);
searchHeaderTbl.setGridColor(Color.red);
} else
searchHeaderTbl.setShowGrid(false);
searchHeaderTbl.setIntercellSpacing(new Dimension(GUTTER, GUTTER));
searchTermsTbl = new JTable(new SearchTermsTableModel());
adjustColumnModel();
searchTermsTbl.setDefaultRenderer(java.lang.Object.class, new SearchTermsTableRenderer());
searchTermsTbl.setDefaultEditor(java.lang.Object.class, new SearchTermsTableEditor());
((DefaultCellEditor) searchTermsTbl .getDefaultEditor(java.lang.Object.class)).setClickCountToStart(1);
searchTermsTbl.setRowHeight(ROW_HEIGHT);
searchTermsTbl.getTableHeader().setReorderingAllowed(false);
searchTermsTbl.setGridColor(new java.awt.Color(getBackground()
.getRed(), getBackground().getBlue(), getBackground()
.getGreen(), 0));
searchTermsTbl.setBackground(getBackground());
searchTermsTbl.setIntercellSpacing(new Dimension(GUTTER, GUTTER));
searchTermsTbl.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseReleased(java.awt.event.MouseEvent evt) {
if (evt.getX() > searchTermsTbl.getWidth() - BUTTON_COL_WIDTH) {
// java.util.List<VueMetadataElement>
// searchTermsList =
// MetadataSearchMainGUI.this.searchTerms;
int selectedRow = searchTermsTbl.getSelectedRow();
if (searchTermsTbl.getSelectedColumn() == buttonColumn
&& searchTerms.size() > selectedRow) {
searchTerms.remove(selectedRow);
searchTermsTbl.repaint();
requestFocusInWindow();
}
}
}
});
tablePanel = new JPanel(new GridBagLayout());
final GridBagConstraints tablePanelGBC = new GridBagConstraints();
tablePanelGBC.fill = GridBagConstraints.HORIZONTAL;
tablePanelGBC.insets = new Insets(0, 0, 0, 0);
tablePanelGBC.weightx = 1.0;
tablePanelGBC.gridx = 0;
tablePanelGBC.gridy = 0;
// if (macLeopardAndOr != null) {
// tablePanel.add(new JLabel("HERE MY BUDDY"), tablePanelGBC);
// tablePanelGBC.fill = GridBagConstraints.REMAINDER;
// tablePanelGBC.anchor = GridBagConstraints.EAST;
// tablePanel.add(macLeopardAndOr, tablePanelGBC);
// tablePanelGBC.gridy++;
// tablePanelGBC.fill = GridBagConstraints.HORIZONTAL;
// }
tablePanel.add(searchHeaderTbl, tablePanelGBC);
tablePanelGBC.gridy++;
tablePanel.add(searchTermsTbl, tablePanelGBC);
tablePanelGBC.gridy++;
if (DEBUG_LOCAL || DEBUG.BOXES) {
searchHeaderTbl.setOpaque(true);
searchHeaderTbl.setBackground(Color.BLUE);
searchTermsTbl.setOpaque(true);
searchTermsTbl.setBackground(Color.BLUE);
tablePanel.setOpaque(true);
tablePanel.setBackground(Color.BLUE);
}
saveButton = new JButton(VueResources.local("searchgui.save"));
saveButton.setFont(tufts.vue.gui.GUI.LabelFace);
saveButton.addActionListener(new ActionListener() { // TODO: CHRIST: MORE REPEATED CODE???
public void actionPerformed(ActionEvent e) {
if (DEBUG.Enabled) Log.debug("saveButton action: " + e);
runSaveAction(e);
}
});
resetButton = new JButton(VueResources.local("searchgui.resetmap"));
resetButton.setFont(tufts.vue.gui.GUI.LabelFace);
resetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
SearchAction.revertGlobalSearchSelectionFromMSGUI();
updateEnabled();
VUE.getActiveViewer().repaint();
}
});
searchButton = new JButton(VueResources.local("searchgui.search"));
searchButton.setFont(tufts.vue.gui.GUI.LabelFace);
searchButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (searchTermsTbl.isEditing())
searchTermsTbl.getCellEditor().stopCellEditing();
MetadataSearchMainGUI.this.searchType = (SearchType) getChosen(choiceDomain);
MetadataSearchMainGUI.this.termsAction = new SearchAction(searchTerms);
termsAction.setLocationType(getChosen(choiceScope));
termsAction.setOperator(getSelectedOperator());
termsAction.setParamsByType(searchType);
termsAction.setResultAction(getChosen(choiceResult));
termsAction.fire(this, "from.searchButton");
updateEnabled();
}
});
termsAction.setResultAction(SearchAction.RA_SELECT);
//setResultsTypeInActions("Select");
searchPanel = new JPanel(new GridBagLayout());
GridBagConstraints searchPanelGBC = new GridBagConstraints();
searchPanelGBC.insets = new Insets(HALF_GUTTER, HALF_GUTTER, HALF_GUTTER, HALF_GUTTER);
searchPanelGBC.fill = GridBagConstraints.HORIZONTAL;
searchPanelGBC.weightx = 0.0;
searchPanelGBC.gridy = 0;
searchPanelGBC.gridx = 0;
searchPanel.add(saveButton, searchPanelGBC);
// An empty panel to take up the space between saveButton to the left and the other
// two buttons to the right.
searchPanelGBC.gridx = 1;
searchPanelGBC.weightx = 1.0;
searchPanel.add(new JPanel(), searchPanelGBC);
searchPanelGBC.gridx = 2;
searchPanelGBC.weightx = 0.0;
searchPanel.add(resetButton, searchPanelGBC);
searchPanelGBC.gridx = 3;
searchPanel.add(searchButton, searchPanelGBC);
searchPanel.setOpaque(true);
searchPanel.setBackground(getBackground());
if (DEBUG_LOCAL || DEBUG.BOXES) {
saveButton.setOpaque(true);
saveButton.setBackground(Color.YELLOW);
resetButton.setOpaque(true);
resetButton.setBackground(Color.YELLOW);
searchButton.setOpaque(true);
searchButton.setBackground(Color.YELLOW);
searchPanel.setBackground(Color.CYAN);
}
topPanel = new JPanel(new GridBagLayout());
GridBagConstraints topPanelGBC = new GridBagConstraints();
topPanelGBC.fill = GridBagConstraints.HORIZONTAL;
topPanelGBC.weightx = 1.0;
topPanelGBC.insets = new java.awt.Insets(HALF_GUTTER, HALF_GUTTER, 0, HALF_GUTTER);
topPanelGBC.gridx = 0;
topPanelGBC.gridy = 0;
topPanel.add(optionsPanel, topPanelGBC);
topPanelGBC.insets = new java.awt.Insets(0, HALF_GUTTER, 0, HALF_GUTTER);
topPanelGBC.gridy = 1;
topPanel.add(linePanel, topPanelGBC);
topPanelGBC.gridy = 2;
topPanel.add(tablePanel, topPanelGBC);
topPanelGBC.gridy = 3;
topPanelGBC.insets = new java.awt.Insets(0, HALF_GUTTER, HALF_GUTTER, HALF_GUTTER);
topPanel.add(searchPanel, topPanelGBC);
if (DEBUG_LOCAL || DEBUG.BOXES) {
linePanel.setBackground(Color.CYAN);
linePanel.setOpaque(true);
topPanel.setBackground(Color.ORANGE);
}
setLayout(new BorderLayout());
add(topPanel);
}
// public void setResultsTypeInActions(String resultsTypeChoice) {
// // String resultsTypeChoice = e.getItem().toString();
// if (resultsTypeChoice != null /*&& allSearch != null*/ && termsAction != null) {
// //allSearch.setResultsType(resultsTypeChoice);
// termsAction.setResultsType(resultsTypeChoice);
// }
// }
public String getName() {
return VueResources.local("searchgui.search");
}
private void saveInfo() {
// System.out.println("MIP saveInfo " +
// mDescriptionEditor.getText());
// if( mMap != null) {
// // for now, only description/notes needs saving, and it handles
// that it itself
// // add back in Author until/unless synched with metadata list:
// VUE-951
// //mMap.setLabel( mTitleEditor.getText() );
// //mMap.setAuthor( mAuthorEditor.getText() );
// //mMap.setNotes(mDescriptionEditor.getText());
// //mMap.setDescription(mDescriptionEditor.getText());
// }
}
/**
* public void actionPerformed( ActionEvent pEvent) { Object source =
* pEvent.getSource(); System.out.println("Action Performed :"+source);
* if( (source == saveButton) || (source == mTitleEditor) || (source ==
* mAuthorEditor) || (source == mDescriptionEditor) ) { saveInfo(); } }
**/
public void propertyChange(PropertyChangeEvent pEvent) {
}
public void focusGained(FocusEvent e) {
}
public void focusLost(FocusEvent e) {
saveInfo();
}
}
/**
* MetadataPanel This is the Result Set Display Panel
*
**/
public class MetadataPanel extends JPanel implements ActionListener,
PropertyChangeListener {
PropertiesEditor propertiesEditor = null;
public MetadataPanel() {
searchResultTbl = new JTable(searchResultModel);
searchResultModel.setEditableFlag(false);
//searchResultTbl.setOpaque(true);
searchResultTbl
.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
searchResultTbl.setDefaultRenderer(java.lang.Object.class,
new SavedSearchTableRenderer(searchResultModel));
//searchResultTbl.setCellEditor( new SearchResultTableEditor(new JCheckBox()));
((DefaultCellEditor) searchResultTbl
.getDefaultEditor(java.lang.Object.class))
.setClickCountToStart(1);
JMenuItem resetMenuItem = new JMenuItem(RESET_STR);
popupMenu.add(resetMenuItem);
popupMenu.addSeparator();
resetMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
SearchAction.revertGlobalSearchSelectionFromMSGUI();
VUE.getActiveViewer().repaint();
}
});
JMenuItem renameMenuItem = new JMenuItem(RENAME_STR);
popupMenu.add(renameMenuItem);
popupMenu.addSeparator();
JMenuItem deleteMenuItem = new JMenuItem(DELETE_STR);
popupMenu.add(deleteMenuItem);
deleteMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
int selectedIndex = searchResultTbl.getSelectedRow();
if (selectedIndex != -1){
searchResultModel.removeRow(selectedIndex);
}
}
});
renameMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
searchResultModel.setEditableFlag(true);
int selectedIndex = searchResultTbl.getSelectedRow();
if (selectedIndex != -1){
searchResultTbl.editCellAt(selectedIndex, 0);
searchResultModel.setEditableFlag(false);
}
}
});
// add the listener to the jtable
MouseListener popupListener = new PopupListener();
// add the listener specifically to the header
searchResultTbl.addMouseListener(popupListener);
searchResultTbl.setIntercellSpacing(new Dimension(0,1));
searchResultTbl.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
searchResultTbl.setShowGrid(true);
searchResultTbl.setGridColor(Color.LIGHT_GRAY);
searchResultTbl.setRowHeight(23);
//searchResultTbl.setBackground(this.getBackground());
//searchResultTbl.getColumnModel().getColumn(1).setMaxWidth(30);
//searchResultTbl.getColumnModel().getColumn(1).setMinWidth(30);
searchResultTbl.getColumnModel().getColumn(1).setPreferredWidth(100);
//searchResultTbl.setOpaque(true);
// searchResultTbl.setMinimumSize(new Dimension(300,80));
GridBagLayout gridBag = new GridBagLayout();
GridBagConstraints gBC = new GridBagConstraints();
gBC.fill = GridBagConstraints.HORIZONTAL;
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
gBC.gridx = 0;
gBC.gridy = 0;
gBC.weightx = 1.0;
gridBag.setConstraints(searchResultTbl, gBC);
panel.add(searchResultTbl,BorderLayout.NORTH);
panel.add(new JLabel(DEBUG.BOXES ? "x" : " "), BorderLayout.SOUTH);
setLayout(new BorderLayout());
add(panel);
// add(searchResultTbl);
setName(VueResources.local("searchgui.keywords"));
}
public void actionPerformed(ActionEvent e) {
}
public void propertyChange(PropertyChangeEvent evt) {
}
}
class SearchTermsTableModel extends AbstractTableModel {
private int columns = 3;
public int getRowCount() {
if (searchTerms.size() > 0)
return searchTerms.size();
else
return 1;
}
public int getColumnCount() {
return columns;
}
public void setColumns(int columns) {
this.columns = columns;
fireTableStructureChanged();
}
public boolean isCellEditable(int row, int col) {
if ((col == valueColumn) || (col == categoryColumn)
|| (col == conditionColumn) || (col == comboColumn))
return true;
else
return false;
}
public Object getValueAt(int row, int col) {
if (row == 0 && searchTerms.size() == 0) {
VueMetadataElement vme = new VueMetadataElement();
String statementObject[] = {
edu.tufts.vue.rdf.RDFIndex.VueTermOntologyNone,
//VueResources.local("metadata.vue.url") + "#none",
"",
edu.tufts.vue.rdf.Query.Qualifier.CONTAINS.toString() };
vme.setObject(statementObject);
vme.setType(VueMetadataElement.SEARCH_STATEMENT);
searchTerms.add(vme);
}
if (col == buttonColumn)
return "delete button";
else if (col == valueColumn)
return searchTerms.get(row).getValue();
else if (col == conditionColumn) {
String[] statement = (String[]) searchTerms.get(row)
.getObject();
if (statement.length > 2){
return ((String[]) (searchTerms.get(row)).getObject())[2];
}
else{
return "";
}
} else
return searchTerms.get(row).getKey();
}
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
VueMetadataElement searchTerm = searchTerms.get(rowIndex);
if (searchTerm.getObject() instanceof String[]) {
// ((String[]) searchTerms.get(rowIndex).getObject())[1] = aValue.toString();
String[] newStatement = {
((String[]) searchTerms.get(rowIndex).getObject())[0],
aValue.toString(),
((String[]) searchTerms.get(rowIndex).getObject())[2] };
searchTerm.setObject(newStatement);
}
}
public void refresh() {
fireTableDataChanged();
}
}
class SearchHeaderTableModel extends AbstractTableModel {
private int columns = 3;
public int getRowCount() {
return 1;
}
public int getColumnCount() {
return columns;
}
public void setColumns(int columns) {
this.columns = columns;
fireTableStructureChanged();
}
public boolean isCellEditable(int row, int col) {
if(this.getColumnCount() == 3){
if (col == 0) {
return false;
} else {
return true;
}
}else if(this.getColumnCount() == 4){
if (col == 0 || col == 1) {
return false;
} else {
return true;
}
}
return false;
}
public Object getValueAt(int row, int col) {
return null;
}
public void refresh() {
fireTableDataChanged();
}
}
public void adjustHeaderTableColumnModel() {
if (searchHeaderTbl == null)
return;
int editorWidth = searchHeaderTbl.getWidth();
if (searchHeaderTbl.getModel().getColumnCount() == 3) {
searchHeaderTbl.getColumnModel().getColumn(0).setCellRenderer(new SearchTermsTableHeaderRenderer());
searchHeaderTbl.getColumnModel().getColumn(1).setCellRenderer(new ComboBoxAndOrRenderer(andOrCmbBox));
searchHeaderTbl.getColumnModel().getColumn(2).setCellRenderer(new SearchTermsTableHeaderRenderer());
searchHeaderTbl.getColumnModel().getColumn(1).setCellEditor(new ComboBoxAndOrEditor(andOrCmbBox));
searchHeaderTbl.getColumnModel().getColumn(2).setCellEditor(new AddButtonTableCellEditor());
if (Util.isMacLeopard()) {
searchHeaderTbl.getColumnModel().getColumn(1).setMaxWidth(78);
searchHeaderTbl.getColumnModel().getColumn(1).setMinWidth(78);
} else {
searchHeaderTbl.getColumnModel().getColumn(1).setMaxWidth(60);
searchHeaderTbl.getColumnModel().getColumn(1).setMinWidth(60);
}
searchHeaderTbl.getColumnModel().getColumn(2).setMaxWidth(BUTTON_COL_WIDTH);
searchHeaderTbl.getColumnModel().getColumn(2).setMinWidth(BUTTON_COL_WIDTH);
} else if (searchHeaderTbl.getModel().getColumnCount() == 4) {
searchHeaderTbl.getColumnModel().getColumn(0).setCellRenderer(new SearchTermsTableHeaderRenderer());
searchHeaderTbl.getColumnModel().getColumn(1).setCellRenderer(new SearchTermsTableHeaderRenderer());
searchHeaderTbl.getColumnModel().getColumn(2).setCellRenderer(new ComboBoxAndOrRenderer(andOrCmbBox));
searchHeaderTbl.getColumnModel().getColumn(3).setCellRenderer(new SearchTermsTableHeaderRenderer());
searchHeaderTbl.getColumnModel().getColumn(2).setCellEditor(new ComboBoxAndOrEditor(andOrCmbBox));
searchHeaderTbl.getColumnModel().getColumn(3).setCellEditor(new AddButtonTableCellEditor());
searchHeaderTbl.getColumnModel().getColumn(0).setPreferredWidth(145);
if (Util.isMacLeopard()) {
searchHeaderTbl.getColumnModel().getColumn(2).setMaxWidth(78);
searchHeaderTbl.getColumnModel().getColumn(2).setMinWidth(78);
} else {
searchHeaderTbl.getColumnModel().getColumn(2).setMaxWidth(60);
searchHeaderTbl.getColumnModel().getColumn(2).setMinWidth(60);
}
searchHeaderTbl.getColumnModel().getColumn(3).setMaxWidth(BUTTON_COL_WIDTH);
searchHeaderTbl.getColumnModel().getColumn(3).setMinWidth(BUTTON_COL_WIDTH);
}
}
final static JLabel EmptyLabel = new JLabel(DEBUG.BOXES ? "(hid)" : "");
public class ComboBoxAndOrEditor extends DefaultCellEditor {
final JComboBox combo;
public ComboBoxAndOrEditor(JComboBox combo) {
super(combo);
this.combo = combo;
}
public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int rowIndex,
int vColIndex) {
if(table.isEditing()){
table.getCellEditor().stopCellEditing();
}
selectedOp = (SearchAction.Operator) this.combo.getSelectedItem();
// //if(isSelected){
// if(this.combo.getSelectedItem().toString().equals(VueResources.local("searchgui.and"))){
// strAndOrType = VueResources.local("searchgui.or");
// }else{
// strAndOrType = VueResources.local("searchgui.and");
// }
// //}
if(vColIndex == 1 || vColIndex == 2){
SearchTermsTableModel model = (SearchTermsTableModel)searchTermsTbl.getModel();
if(model.getRowCount()<2){
return EmptyLabel;
}else{
return this.combo;
}
}
return EmptyLabel;
}
public boolean stopCellEditing() {
return super.stopCellEditing();
}
}
/** for debug tracking */
private static class MDAddLabel extends JLabel {}
private static class MDDeleteLabel extends JLabel {}
public class AddButtonTableCellEditor extends AbstractCellEditor
implements TableCellEditor {
// This is the component that will handle the editing of the cell
// value
final JLabel component = new MDAddLabel();
// This method is called when a cell value is edited by the user.
public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int rowIndex,
int vColIndex) {
if(searchTermsTbl.isEditing()){
searchTermsTbl.getCellEditor().stopCellEditing();
}
if (vColIndex == 2 || vColIndex == 3) {
component.setIcon(tufts.vue.VueResources.getImageIcon("metadata.editor.add.up"));
final VueMetadataElement newElement = new VueMetadataElement();
final String statementObject[] = {
edu.tufts.vue.rdf.RDFIndex.VueTermOntologyNone,
"",
edu.tufts.vue.rdf.Query.Qualifier.CONTAINS.toString() };
// Don't know why this had STARTS_WITH as a default -- tho
// later on down the line this value is currently ignored
// as we force to always doing CONTAINS searches in SearchAction.
//edu.tufts.vue.rdf.Query.Qualifier.STARTS_WITH.toString() };
newElement.setObject(statementObject);
newElement.setType(VueMetadataElement.SEARCH_STATEMENT);
searchTerms.add(newElement);
((SearchTermsTableModel) searchTermsTbl.getModel()).refresh();
((SearchHeaderTableModel) searchHeaderTbl.getModel()).refresh();
}
if (DEBUG_LOCAL || DEBUG.BOXES) {
component.setBackground(Color.YELLOW);
component.setOpaque(true);
}
// Return the configured component
return component;
}
// This method is called when editing is completed.
// It must return the new value to be stored in the cell.
public Object getCellEditorValue() {
return (JLabel) component;
}
}
public class ComboBoxAndOrRenderer implements TableCellRenderer {
JComboBox combo = null;
public ComboBoxAndOrRenderer(JComboBox combo) {
this.combo = combo;
}
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
if (searchTermsTbl.getModel().getRowCount() > 1) {
//Don't ask me how or why but this makes the combo box paint correctly on leopard.
if (Util.isMacLeopard())
combo.putClientProperty("JComboBox.isTableCellEditor",Boolean.FALSE);
// combo.setPreferredSize(new Dimension(60,30));
combo.setFont(tufts.vue.gui.GUI.LabelFace);
combo.setVisible(true);
//combo.repaint();
// combo.invalidate();
if (DEBUG_LOCAL || DEBUG.BOXES) {
combo.setOpaque(true);
combo.setBackground(Color.YELLOW);
}
table.revalidate();
table.repaint();
} else {
JLabel label = EmptyLabel;
label.setOpaque(true);
label.setEnabled(false);
if (DEBUG_LOCAL || DEBUG.BOXES) { label.setBackground(Color.YELLOW); }
return EmptyLabel;
}
return combo;
}
}
public void adjustColumnModel() {
if (searchTermsTbl == null)
return;
int editorWidth = this.getWidth();
if (searchTermsTbl.getModel().getColumnCount() == 3) {
searchTermsTbl.getColumnModel().getColumn(1).setMaxWidth(0);
searchTermsTbl.getColumnModel().getColumn(1).setMinWidth(0);
searchTermsTbl.getColumnModel().getColumn(1).setPreferredWidth(0);
searchTermsTbl.getColumnModel().getColumn(2).setMaxWidth(24);
searchTermsTbl.getColumnModel().getColumn(2).setMinWidth(24);
} else if (searchTermsTbl.getModel().getColumnCount() == 4) {
searchTermsTbl.getColumnModel().getColumn(0).setPreferredWidth(80);
//searchTermsTbl.getColumnModel().getColumn(1).setPreferredWidth(150);
searchTermsTbl.getColumnModel().getColumn(2).setMaxWidth(0);
searchTermsTbl.getColumnModel().getColumn(2).setMinWidth(0);
searchTermsTbl.getColumnModel().getColumn(2).setPreferredWidth(0);
searchTermsTbl.getColumnModel().getColumn(3).setMaxWidth(BUTTON_COL_WIDTH);
searchTermsTbl.getColumnModel().getColumn(3).setMinWidth(BUTTON_COL_WIDTH);
}
}
// public void setCategorySearchWithNoneCase() {
// if (DEBUG_LOCAL || DEBUG.SEARCH) Log.debug("setCategorySearchWithNoneCase()");
// singleLine = false;
// SearchTermsTableModel model = (SearchTermsTableModel) searchTermsTbl.getModel();
// buttonColumn = 2;
// valueColumn = 1;
// categoryColumn = 0;
// conditionColumn = -1;
// model.setColumns(3);
// adjustColumnModel();
// headerButtonColumn = 2;
// headerComboColumn = 1;
// headerCategoryColumn = -1;
// headerValueColumn = 0;
// //termsAction = new SearchAction(searchTerms);
// adjustHeaderTableColumnModel();
// // treatNoneSpecially = true;
// termsAction.setNoneIsSpecial(true);
// termsAction.setTextOnly(false);
// termsAction.setBasic(false);
// termsAction.setMetadataOnly(false);
// termsAction.setOperator(getSelectedOperator());
// termsAction.setEverything(false);
// // termsAction.setOperator(andOrGroup.getSelection().getModel().getActionCommand());
// }
/**
* the root kind of search for this is functionally the same as search-everything, EXCEPT
* that it turns on the keyword field boxes (labeled "categories"). That also means
* it doesn't really make sense to have it as an option in the main search text field
* pull-down.
*/
public void setCategorySearch() {
if (DEBUG_LOCAL || DEBUG.SEARCH) Log.debug("setCategorySearch()");
singleLine = false;
searchType = SEARCH_WITH_CATEGORIES;
SearchTermsTableModel model = (SearchTermsTableModel) searchTermsTbl.getModel();
SearchHeaderTableModel headerModel = (SearchHeaderTableModel) searchHeaderTbl
.getModel();
headerModel.setColumns(4);
buttonColumn = 3;
valueColumn = 1;
categoryColumn = 0;
conditionColumn = -1;
model.setColumns(4);
adjustColumnModel();
adjustHeaderTableColumnModel();
headerButtonColumn = 3;
headerComboColumn = 2;
headerCategoryColumn = 0;
headerValueColumn = 1;
adjustHeaderTableColumnModel();
//termsAction = new SearchAction(searchTerms);
termsAction.setBasic(false);
termsAction.setTextOnly(false);
termsAction.setMetadataOnly(false);
termsAction.setOperator(getSelectedOperator());
termsAction.setEverything(false);
// termsAction.setOperator(andOrGroup.getSelection().getModel().getActionCommand());
}
public void setEverythingSearch() {
if (DEBUG_LOCAL || DEBUG.SEARCH) Log.debug("setEverythingSearch()");
searchType = SEARCH_EVERYTHING;
singleLine = false;
SearchTermsTableModel model = (SearchTermsTableModel) searchTermsTbl.getModel();
SearchHeaderTableModel headerModel = (SearchHeaderTableModel) searchHeaderTbl
.getModel();
headerModel.setColumns(3);
buttonColumn = 2;
valueColumn = 0;
categoryColumn = -1;
conditionColumn = -1;
model.setColumns(3);
adjustColumnModel();
adjustHeaderTableColumnModel();
headerButtonColumn = 2;
headerComboColumn = 1;
headerCategoryColumn = -1;
headerValueColumn = 0;
//termsAction = new SearchAction(searchTerms);
termsAction.setBasic(false);
termsAction.setTextOnly(true);
termsAction.setMetadataOnly(false);
termsAction.setOperator(getSelectedOperator());
termsAction.setEverything(true);
// termsAction.setOperator(andOrGroup.getSelection().getModel().getActionCommand());
}
// public String getSelectedOperator() {
// if(strAndOrType.equals(VueResources.local("searchgui.and"))){
// return SearchAction.AND;
// }else{
// return SearchAction.OR;
// }
// }
public SearchAction.Operator getSelectedOperator() {
return selectedOp;
}
public void setLabelSearch() {
if (DEBUG_LOCAL || DEBUG.SEARCH) Log.debug("setLabelSearch()");
searchType = SEARCH_ONLY_LABELS;
singleLine = false;
SearchTermsTableModel model = (SearchTermsTableModel) searchTermsTbl.getModel();
SearchHeaderTableModel headerModel = (SearchHeaderTableModel) searchHeaderTbl
.getModel();
headerModel.setColumns(3);
buttonColumn = 2;
comboColumn = 1;
valueColumn = 0;
categoryColumn = -1;
conditionColumn = -1;
model.setColumns(3);
headerButtonColumn = 2;
headerComboColumn = 1;
headerCategoryColumn = -1;
headerValueColumn = 0;
adjustColumnModel();
adjustHeaderTableColumnModel();
//termsAction = new SearchAction(searchTerms);
termsAction.setBasic(true);
termsAction.setTextOnly(false);
termsAction.setMetadataOnly(false);
termsAction.setOperator(getSelectedOperator());
termsAction.setEverything(false);
// termsAction.setOperator(andOrGroup.getSelection().getModel().getActionCommand());
}
/** "keywords" search, which means leave OUT node fields like labels and notes */
public void setAllMetadataSearch() {
if (DEBUG_LOCAL || DEBUG.SEARCH) Log.debug("setAllMetadataSearch()");
searchType = SEARCH_ONLY_KEYWORDS;
singleLine = false;
SearchTermsTableModel model = (SearchTermsTableModel) searchTermsTbl.getModel();
SearchHeaderTableModel headerModel = (SearchHeaderTableModel) searchHeaderTbl
.getModel();
headerModel.setColumns(3);
buttonColumn = 2;
comboColumn = 1;
valueColumn = 0;
categoryColumn = -1;
conditionColumn = -1;
headerButtonColumn = 2;
headerComboColumn = 1;
headerCategoryColumn = -1;
headerValueColumn = 0;
model.setColumns(3);
adjustColumnModel();
adjustHeaderTableColumnModel();
// termsAction = new SearchAction(searchTerms);
termsAction.setBasic(false);
termsAction.setTextOnly(true);
termsAction.setMetadataOnly(true);
termsAction.setOperator(getSelectedOperator());
termsAction.setEverything(false);
// termsAction.setOperator(andOrGroup.getSelection().getModel().getActionCommand());
}
public void setConditionSearch() {
if (DEBUG_LOCAL || DEBUG.SEARCH) Log.debug("setConditionSearch()");
singleLine = false;
SearchTermsTableModel model = (SearchTermsTableModel) searchTermsTbl.getModel();
SearchHeaderTableModel headerModel = (SearchHeaderTableModel) searchHeaderTbl
.getModel();
headerModel.setColumns(3);
buttonColumn = 4;
comboColumn = 3;
valueColumn = 2;
categoryColumn = 0;
conditionColumn = 1;
model.setColumns(5);
adjustColumnModel();
adjustHeaderTableColumnModel();
//termsAction = new SearchAction(searchTerms);
termsAction.setBasic(false);
termsAction.setTextOnly(false);
termsAction.setMetadataOnly(false);
termsAction.setOperator(getSelectedOperator());
termsAction.setEverything(false);
// termsAction.setOperator(andOrGroup.getSelection().getModel().getActionCommand());
}
public void setAllSearch() {
if (DEBUG_LOCAL || DEBUG.SEARCH) Log.debug("setAllSearch()");
SearchTermsTableModel model = (SearchTermsTableModel) searchTermsTbl.getModel();
buttonColumn = 2;
comboColumn = 1;
valueColumn = 0;
categoryColumn = -1;
conditionColumn = -1;
model.setColumns(3);
headerButtonColumn = 2;
headerComboColumn = 1;
headerCategoryColumn = -1;
headerValueColumn = 0;
adjustColumnModel();
SearchHeaderTableModel headerModel = (SearchHeaderTableModel) searchHeaderTbl
.getModel();
headerModel.setColumns(3);
adjustHeaderTableColumnModel();
// allSearchField.setText("FF");
// allSearch.setResultsType(resultsTypeChoice.getSelectedItem().toString());
// allSearch = new SearchAction(allSearchField);
singleLine = true;
}
class SearchTermsTableHeaderRenderer extends DefaultTableCellRenderer {
public java.awt.Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int col) {
JLabel comp = new JLabel();
comp.setFont(tufts.vue.gui.GUI.LabelFace);
if (col == headerButtonColumn) {
comp.setIcon(tufts.vue.VueResources.getIcon("metadata.editor.add.up"));
} else if (table.getModel().getColumnCount() == 3
&& col == headerValueColumn) {
if (searchType == SEARCH_EVERYTHING) {
comp.setText(VueResources.local("advancedSearch.searcheverything"));
}
if (searchType == SEARCH_ONLY_LABELS) {
comp.setText(VueResources.local("advancedSearch.label"));
}
if (searchType == SEARCH_ONLY_KEYWORDS) {
comp.setText(VueResources.local("advancedSearch.keywords"));
}
if(searchType == SEARCH_WITH_CATEGORIES){
comp.setText(VueResources.local("advancedSearch.category"));
}
} else if ((table.getModel().getColumnCount() == 4)
&& col == headerCategoryColumn) {
comp.setText(VueResources.local("advancedSearch.category"));
} else if ((table.getModel().getColumnCount() == 4 )
&& col == headerValueColumn){
comp.setText(VueResources.local("advancedSearch.keywords"));
}
comp.setOpaque(true);
comp.setBackground(MetadataSearchMainGUI.this.getBackground());
if (DEBUG_LOCAL || DEBUG.BOXES) {
comp.setBackground(Color.YELLOW);
}
return comp;
}
}
class SearchTermsTableRenderer extends DefaultTableCellRenderer {
JPanel comp = new JPanel();
JTextField field = new JTextField();
public SearchTermsTableRenderer() {
comp.setLayout(new java.awt.BorderLayout());
field.setFont(tufts.vue.gui.GUI.LabelFace);
if (DEBUG_LOCAL || DEBUG.BOXES) {
comp.setBackground(Color.YELLOW);
comp.setOpaque(true);
}
comp.add(field);
}
public java.awt.Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int col) {
if (col == (valueColumn)) {
String val = ((String[]) searchTerms.get(row).getObject())[1];
field.setText(val);
return comp;
} else {
return createRendererComponent(table, value, row, col);
}
}
}
class SearchTermsTableEditor extends DefaultCellEditor {
JPanel comp;
public SearchTermsTableEditor() {
super(new JTextField());
super.editorComponent.setName(getClass().getSimpleName());
comp = new JPanel();
comp.setLayout(new java.awt.BorderLayout());
if (DEBUG_LOCAL || DEBUG.BOXES) {
comp.setBackground(Color.YELLOW);
comp.setOpaque(true);
}
}
public java.awt.Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int col) {
if (searchHeaderTbl != null && searchHeaderTbl.getCellEditor() != null){
searchHeaderTbl.getCellEditor().stopCellEditing();
}
if(table.isEditing()){
table.getCellEditor().stopCellEditing();
}
if (col == (valueColumn)) {
JTextField field = (JTextField) super
.getTableCellEditorComponent(table, value, isSelected,
row, col);
field.setFont(tufts.vue.gui.GUI.LabelFace);
String val = ((String[]) searchTerms.get(row).getObject())[1];
field.setText(val);
field.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent actionEvent){
searchButton.doClick();
}
});
comp.add(field);
return comp;
} else {
return createRendererComponent(table, value, row, col);
}
}
public Object getCellEditorValue() {
Object obj = super.getCellEditorValue();
return obj;
}
public boolean stopCellEditing() {
return super.stopCellEditing();
}
}
// class SearchTermsTableRenderer extends DefaultTableCellRenderer {
// public java.awt.Component getTableCellRendererComponent(JTable table,
// Object value, boolean isSelected, boolean hasFocus, int row,
// int col) {
// return createRendererComponent(table, value, row, col);
// }
// }
//
// class SearchTermsTableEditor extends DefaultCellEditor {
// public SearchTermsTableEditor() {
// super(new JTextField());
// }
//
// public java.awt.Component getTableCellEditorComponent(JTable table,
// Object value, boolean isSelected, int row, int col) {
// return createRendererComponent(table, value, row, col);
// }
// }
public java.awt.Component createRendererComponent(JTable table,
Object value, final int row, int col) {
JPanel comp = new JPanel();
if(table.isEditing()){
//table.getCellEditor().stopCellEditing();
}
comp.setLayout(new java.awt.BorderLayout());
if (col == (valueColumn)) {
final JTextField field = new JTextField();
field.setFont(tufts.vue.gui.GUI.LabelFace);
field.addFocusListener(new FocusAdapter() {
public void focusLost(FocusEvent fe) {
VueMetadataElement searchTerm = searchTerms.get(row);
// Object searchTerm = searchTerms.get(row).getObject();
if (searchTerm.getObject() instanceof String[]) {
String[] newStatement = {
((String[]) searchTerms.get(row).getObject())[0],
field.getText(),
((String[]) searchTerms.get(row).getObject())[2] };
searchTerm.setObject(newStatement);
field.setText(field.getText());
}
}
});
String val = ((String[]) searchTerms.get(row).getObject())[1];
field.setText(val);
// #VUE-887 -- whoops -- metadataeditor not here
comp.add(field);
} else if (col == (categoryColumn)) {
final JComboBox categories = new JComboBox();
categories.setFont(tufts.vue.gui.GUI.LabelFace);
categories.setModel(new CategoryComboBoxModel());
categories.setRenderer(new CategoryComboBoxRenderer());
categories.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent ie) {
if (ie.getStateChange() == ItemEvent.SELECTED) {
if (!(categories.getSelectedItem() instanceof OntType))
return;
OntType type = (OntType) categories.getSelectedItem();
String[] statement = {
type.getBase() + "#" + type.getLabel(),
searchTerms.get(row).getValue(),
((String[]) (searchTerms.get(row).getObject()))[2] };
VueMetadataElement ele = new VueMetadataElement();
ele.setObject(statement);
ele.setType(VueMetadataElement.SEARCH_STATEMENT);
searchTerms.set(row, ele);
}
}
});
Object currValueObject = searchTerms.get(row).getObject();
if (currValueObject instanceof String[]) {
findCategory(searchTerms.get(row).getKey(), row, col,
categories);
}
comp.add(categories);
} else if (col == buttonColumn) {
JLabel buttonLabel = new MDDeleteLabel();
buttonLabel.setIcon(tufts.vue.VueResources.getIcon("metadata.editor.delete.up"));
comp.add(buttonLabel);
} else if (col == conditionColumn) {
// conditionCombo does not appear to be UI deployed at moment...
// String [] conditions = {"starts with","contains"};
String[] conditions = { "contains", "starts with" };
final JComboBox conditionCombo = new JComboBox(conditions);
conditionCombo.setFont(tufts.vue.gui.GUI.LabelFace);
conditionCombo.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent ie) {
if (ie.getStateChange() == ItemEvent.SELECTED) {
String condition = conditionCombo.getSelectedItem()
.toString();
if (condition.equals("starts with")) {
condition = "STARTS_WITH";
} else {
condition = "CONTAINS";
}
String[] statement = {
((String[]) (searchTerms.get(row).getObject()))[0],
searchTerms.get(row).getValue(), condition };
VueMetadataElement ele = new VueMetadataElement();
ele.setObject(statement);
ele.setType(VueMetadataElement.SEARCH_STATEMENT);
searchTerms.set(row, ele);
}
}
});
String currentCondition = ((String[]) (searchTerms.get(row)
.getObject()))[2];
if (currentCondition.equals("CONTAINS"))
conditionCombo.setSelectedIndex(1);
comp.add(conditionCombo);
}
if (DEBUG_LOCAL || DEBUG.BOXES) {
comp.setBackground(Color.YELLOW);
comp.setOpaque(true);
}
return comp;
}
public void findCategory(Object currValue, int row, int col,
JComboBox categories) {
// System.out.println("MetadataSearchGUI: find category");
if (!(currValue instanceof String)) {
if (DEBUG_LOCAL) {
System.out
.println("MetadataSearchGUI - findCategory - currValue not instance of String -- returning ");
}
return;
}
int n = categories.getModel().getSize();
for (int i = 0; i < n; i++) {
Object item = categories.getModel().getElementAt(i);
if (DEBUG_LOCAL) {
System.out.println("i: " + i);
if (item instanceof OntType) {
System.out
.println("MetadataSearchGUI - find category - item.getBase() and currValue - "
+ "i :"
+ i
+ ":"
+ ((OntType) item).getBase()
+ ","
+ currValue);
System.out
.println("MetadataSearchGUI - ((OntType)item).getBase() + # + ((OntType)item).getLabel() "
+ ((OntType) item).getBase()
+ "#"
+ ((OntType) item).getLabel());
}
}
if (item instanceof OntType
&& (((OntType) item).getBase() + "#" + ((OntType) item)
.getLabel()).equals(currValue)) {
// System.out.println("MetadataSearchGUI: find category - found - "
// + i);
categories.setSelectedIndex(i);
}
}
}
class OptionsPanel extends JPanel {
GridBagLayout optionsGrid;
GridBagConstraints optionsConstraints;
// in case easy access to the labels is ever needed:
// they can also be found in the layout
// List<JLabel> labels = new ArrayList<JLabel>();
// in case easy access to the combo boxes is ever needed:
// they can also be found in the layout
// ** now needed for switching choices in the results combo
// on location switch
OptionsPanel(LayoutManager layout) {
super(layout);
}
public void switchChoices(int i, Object[] choices) {
// note: doesn't bother to check if already has this set of choices
final JComboBox box = comboBoxes.get(i);
box.removeAllItems();
for (int j = 0; j < choices.length; j++)
box.addItem(choices[j]);
box.setEnabled(choices.length > 1);
if (choices.length > 2 && i == RESULTS) {
box.setSelectedIndex(2);
} else if (choices.length > 1) {
box.setSelectedItem(0);
}
}
}
class PopupListener extends MouseAdapter {
public void mousePressed(MouseEvent e) {
//Bug #: 1302
if(/*e.getClickCount()==2 &&*/ e.getX()>(searchResultTbl.getWidth()-40)){
runSavedSearch();
}
showPopup(e);
}
public void mouseReleased(MouseEvent e) {
showPopup(e);
}
private void showPopup(MouseEvent e) {
if (e.isPopupTrigger()) {
popupMenu.show(e.getComponent(), e.getX(), e.getY());
}
}
}
private LWMap loadedMap;
public void activeChanged(ActiveEvent<LWMap> e) {
loadActiveMapState(e.active);
}
public void fillSavedSearch() { // called only by VUE.java (init I presume)
loadActiveMapState(VUE.getActiveMap());
}
private static final String ResetLabel = VueResources.local("button.reset.label") + " (";
private static final String RedoLabel = VueResources.local("action.redo") + " (";
public void updateEnabled() {
if (loadedMap != null && loadedMap.hasClientData(SearchAction.RevertableState)) {
int hideCount = (Integer) loadedMap.getClientData(SearchAction.RevertableState);
resetButton.setLabel(ResetLabel + hideCount + ")");
resetButton.setVisible(true);
} else {
// Note: however, this means can no longer use this button to clear the selection....
GUI.invokeAfterAWT(new Runnable() { public void run() { // delay hiding it a tad
resetButton.setVisible(false);
}});
//resetButton.setLabel(RedoLabel + );
}
}
private void loadActiveMapState(final LWMap map)
{
this.loadedMap = map;
updateEnabled();
List savedList =null;
if (map != null) {
savedList = map.getSearchArrLst();
if (DEBUG.SEARCH && DEBUG.RDF) Util.dump(savedList);
}
if (savedList!=null){
searchResultModel.setData((ArrayList)savedList);
} else {
searchResultModel.setData(null);
}
}
/** Handle any click at the far right of the saved searches table (the _run_ "button") */
public void runSavedSearch()
{
final int selectedRow = searchResultTbl.getSelectedRow();
final SearchData data = searchResultModel.getSearchData(selectedRow);
if (DEBUG.SEARCH) Log.debug("runSavedSearch; selectedRow=" + selectedRow + "; data:\n" + Util.tags(data));
//searchTerms = data.getDataList();
if (data.getDataList() != null) {
// What would be a saved search w/out a data-list, and what would
// the rest of this code go on to do if it didn't have one??
// It's re-using the old SearchAction...
termsAction = new SearchAction(data.getDataList());
// Does this mean if the saved search was somehow of just a type,
// but had no terms, we'd what -- just search with the saved OP???
}
termsAction.setOperator(data.logicalOp());
termsAction.setResultAction(data.resultOp());
// Christ: this means that all existing saved searches up till now (Summer 2012) have used the localized values
// for search action result type, and wont restore properly under different localizations.
if (termsAction.getResultAction() == SearchAction.RA_SELECT) {
// Special case: if saved type was select, allow overriding of the saved action with
// the user selected action. This is a cheap squirrely way of allowing a nice feature:
// using a different action with a saved search, which isn't something we have UI for,
// or are likely to.
termsAction.setResultAction(getChosen(choiceResult));
}
termsAction.setParamsByType(searchType);
termsAction.fire(this, "from.runSavedSearch");
updateEnabled();
}
}