/edu/uncc/parsets/gui/GroupedDataSetList.java

https://code.google.com/p/parsets/ · Java · 312 lines · 199 code · 41 blank · 72 comment · 17 complexity · 8df99107ea3b2ab4a79c8954abc0a1ca MD5 · raw file

  1. package edu.uncc.parsets.gui;
  2. import java.awt.Color;
  3. import java.awt.Component;
  4. import java.awt.Font;
  5. import java.awt.GradientPaint;
  6. import java.awt.Graphics;
  7. import java.awt.Graphics2D;
  8. import java.awt.GridLayout;
  9. import java.awt.event.MouseEvent;
  10. import java.awt.event.MouseListener;
  11. import java.text.DecimalFormat;
  12. import java.util.Arrays;
  13. import java.util.List;
  14. import java.util.Map;
  15. import java.util.Vector;
  16. import javax.swing.Box;
  17. import javax.swing.BoxLayout;
  18. import javax.swing.JLabel;
  19. import javax.swing.JList;
  20. import javax.swing.JPanel;
  21. import javax.swing.ListCellRenderer;
  22. import javax.swing.ListSelectionModel;
  23. import javax.swing.event.ListSelectionEvent;
  24. import javax.swing.event.ListSelectionListener;
  25. import edu.uncc.parsets.data.DataSet;
  26. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
  27. * Copyright (c) 2009, Robert Kosara, Caroline Ziemkiewicz,
  28. * and others (see Authors.txt for full list)
  29. * All rights reserved.
  30. *
  31. * Redistribution and use in source and binary forms, with or without
  32. * modification, are permitted provided that the following conditions are met:
  33. *
  34. * * Redistributions of source code must retain the above copyright
  35. * notice, this list of conditions and the following disclaimer.
  36. * * Redistributions in binary form must reproduce the above copyright
  37. * notice, this list of conditions and the following disclaimer in the
  38. * documentation and/or other materials provided with the distribution.
  39. * * Neither the name of UNC Charlotte nor the names of its contributors
  40. * may be used to endorse or promote products derived from this software
  41. * without specific prior written permission.
  42. *
  43. * THIS SOFTWARE IS PROVIDED BY ITS AUTHORS ''AS IS'' AND ANY
  44. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  45. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  46. * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
  47. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  48. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  49. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  50. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  51. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  52. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  53. \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  54. /**
  55. * List that shows group headings, and is specific to DataSet. This is a very
  56. * simple adaptation that breaks a lot of JList's functionality.
  57. *
  58. * Only use {@link #setSectionData(Map)} to set the data for the list, and
  59. * {@link #getSelectedDataSet()} and the {@link DSListener} class to interact
  60. * with this class.
  61. *
  62. * Also, this currently only works with {@link ListSelectionModel#SINGLE_SELECTION},
  63. * as the functions that would handle multiple selection are not there yet.
  64. *
  65. */
  66. @SuppressWarnings("serial")
  67. public class GroupedDataSetList extends JList implements ListSelectionListener, MouseListener {
  68. public static interface DSListener {
  69. /**
  70. * Called when the user clicks somewhere in the list. The argument is
  71. * null if the user clicked on a heading.
  72. *
  73. * @param ds The selected {@link DataSet} or null
  74. */
  75. public void selectDataSet(DataSet ds);
  76. /**
  77. * Called when the user double-clicks on a dataset. This is only
  78. * called for actual {@link DataSet}s, never with null.
  79. *
  80. * @param ds The dataset to be opened
  81. */
  82. public void openDataSet(DataSet ds);
  83. }
  84. private static final int CELLWIDTH = 180;
  85. private Object dataSets[];
  86. private List<DSListener> dsListeners = new Vector<DSListener>();
  87. private static class DBTableCellRenderer implements ListCellRenderer {
  88. private static final Font TITLELABELFONT = new Font("Sans-Serif", Font.PLAIN, 14);
  89. private static final Font TITLEBOLDFONT = new Font("Sans-Serif", Font.BOLD, 14);
  90. private static final Font DETAILSLABELFONT = new Font("Sans-Serif", Font.PLAIN, 10);
  91. private static final Font DETAILSBOLDFONT = new Font("Sans-Serif", Font.BOLD, 10);
  92. private static final Color STRIPECOLOR = new Color(230, 230, 255);
  93. private static final Font SECTIONLABELFONT = new Font("Sans-Serif", Font.BOLD, 14);
  94. DecimalFormat format = new DecimalFormat("###,###,###");
  95. private JLabel titleLabel;
  96. private JLabel detailsLabel;
  97. private JLabel sectionLabel;
  98. private JPanel dsPanel;
  99. private JPanel labelPanel;
  100. protected static final Color GRADIENT_TOP = Color.WHITE;
  101. protected static final Color GRADIENT_BOTTOM = new Color(0xeeeeee); //new Color(0xF9E198);
  102. public DBTableCellRenderer() {
  103. dsPanel = new JPanel();
  104. dsPanel.setLayout(new GridLayout(2, 1));
  105. dsPanel.setOpaque(true);
  106. Box b = new Box(BoxLayout.X_AXIS);
  107. b.add(Box.createHorizontalStrut(2));
  108. b.add(titleLabel = new JLabel("DataSet Name"));
  109. titleLabel.setFont(TITLELABELFONT);
  110. dsPanel.add(b);
  111. b = new Box(BoxLayout.X_AXIS);
  112. b.add(Box.createHorizontalStrut(2));
  113. b.add(detailsLabel = new JLabel("DataSet Details"));
  114. detailsLabel.setFont(DETAILSLABELFONT);
  115. dsPanel.add(b);
  116. labelPanel = new JPanel() {
  117. protected void paintComponent(Graphics g) {
  118. super.paintComponent(g);
  119. GradientPaint gradientPaint = new GradientPaint(0, 0,
  120. GRADIENT_TOP, 0, getHeight(), GRADIENT_BOTTOM);
  121. Graphics2D g2 = (Graphics2D) g;
  122. g2.setPaint(gradientPaint);
  123. g2.fillRect(0, 0, getWidth(), getHeight()-1);
  124. }
  125. };
  126. labelPanel.setLayout(new BoxLayout(labelPanel, BoxLayout.Y_AXIS));
  127. labelPanel.setOpaque(true);
  128. labelPanel.setBackground(Color.WHITE);
  129. labelPanel.add(Box.createVerticalStrut(5));
  130. b = new Box(BoxLayout.X_AXIS);
  131. b.add(sectionLabel = new JLabel("Heading"));
  132. labelPanel.add(b);
  133. labelPanel.add(Box.createVerticalStrut(5));
  134. sectionLabel.setFont(SECTIONLABELFONT);
  135. }
  136. // @Override
  137. public Component getListCellRendererComponent(JList list, Object value,
  138. int index, boolean isSelected, boolean cellHasFocus) {
  139. if (value instanceof DataSet) {
  140. if (isSelected) {
  141. dsPanel.setBackground(list.getSelectionBackground());
  142. titleLabel.setForeground(list.getSelectionForeground());
  143. titleLabel.setFont(TITLEBOLDFONT);
  144. detailsLabel.setForeground(list.getSelectionForeground());
  145. detailsLabel.setFont(DETAILSBOLDFONT);
  146. } else {
  147. boolean stripe = (index & 1) == 1;
  148. Color bg = (stripe?STRIPECOLOR:Color.WHITE);
  149. dsPanel.setBackground(bg);
  150. titleLabel.setForeground(list.getForeground());
  151. titleLabel.setFont(TITLELABELFONT);
  152. detailsLabel.setForeground(list.getForeground());
  153. detailsLabel.setFont(DETAILSLABELFONT);
  154. }
  155. DataSet ds = (DataSet) value;
  156. titleLabel.setText(ds.getName());
  157. StringBuilder sb = new StringBuilder();
  158. sb.append(ds.getNumDimensions()+" dimensions, ");
  159. sb.append(format.format(ds.getNumRecords())+" items");
  160. detailsLabel.setText(sb.toString());
  161. return dsPanel;
  162. } else {
  163. String section = ((SectionLabel) value).getName();
  164. sectionLabel.setText(section);
  165. return labelPanel;
  166. }
  167. }
  168. }
  169. private static class SectionLabel {
  170. private String name;
  171. public SectionLabel(String sectionName) {
  172. name = sectionName;
  173. }
  174. public String getName() {
  175. return name;
  176. }
  177. }
  178. public GroupedDataSetList() {
  179. super();
  180. setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
  181. setCellRenderer(new DBTableCellRenderer());
  182. setFixedCellWidth(CELLWIDTH);
  183. addListSelectionListener(this);
  184. addMouseListener(this);
  185. }
  186. public GroupedDataSetList(Map<String, List<DataSet>> sections) {
  187. this();
  188. setSectionData(sections);
  189. }
  190. public void addDSListener(DSListener listener) {
  191. dsListeners.add(listener);
  192. }
  193. public void removeDSListener(DSListener listener) {
  194. dsListeners.remove(listener);
  195. }
  196. public void setSectionData(Map<String, List<DataSet>> sections) {
  197. String[] sectionNames = new String[sections.size()];
  198. sections.keySet().toArray(sectionNames);
  199. Arrays.sort(sectionNames);
  200. int numDataSets = 0;
  201. for (List<DataSet> dsList : sections.values())
  202. numDataSets += dsList.size();
  203. dataSets = new Object[numDataSets+sectionNames.length];
  204. int index = 0;
  205. for (String section : sectionNames) {
  206. dataSets[index++] = new SectionLabel(section);
  207. for (DataSet ds : sections.get(section))
  208. dataSets[index++] = ds;
  209. }
  210. setListData(dataSets);
  211. }
  212. /**
  213. * Returns true if the item at the given index is a {@link DataSet},
  214. * false if it is a heading.
  215. *
  216. * @param index the list index to check
  217. * @return true if item at index is a {@link DataSet}
  218. */
  219. private boolean isIndexActive(int index) {
  220. if (index >= 0)
  221. return dataSets[index] instanceof DataSet;
  222. else
  223. return false;
  224. }
  225. /**
  226. * calls {@link #getDataSet(int)} for the currently selected item.
  227. *
  228. * @return The selected {@link DataSet} or null
  229. */
  230. public DataSet getSelectedDataSet() {
  231. return getDataSet(getSelectedIndex());
  232. }
  233. /**
  234. * Returns the {@link DataSet} at the given index, or null if
  235. * that item is a heading.
  236. *
  237. * @param index The index of the item to return
  238. * @return The {@link DataSet} at the index or null.
  239. */
  240. private DataSet getDataSet(int index) {
  241. if (isIndexActive(index))
  242. return (DataSet) dataSets[index];
  243. else
  244. return null;
  245. }
  246. public void valueChanged(ListSelectionEvent e) {
  247. DataSet ds = getSelectedDataSet();
  248. for (DSListener listener : dsListeners)
  249. listener.selectDataSet(ds);
  250. }
  251. public void mouseClicked(MouseEvent e) {
  252. if (e.getClickCount() == 2) {
  253. int index = locationToIndex(e.getPoint());
  254. if (isIndexActive(index)) {
  255. ensureIndexIsVisible(index);
  256. DataSet ds = getDataSet(index);
  257. if (ds != null)
  258. for (DSListener listener : dsListeners)
  259. listener.openDataSet(ds);
  260. }
  261. }
  262. }
  263. public void mouseEntered(MouseEvent e) {
  264. }
  265. public void mouseExited(MouseEvent e) {
  266. }
  267. public void mousePressed(MouseEvent e) {
  268. }
  269. public void mouseReleased(MouseEvent e) {
  270. }
  271. }