001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.gui.inspector; 020 021import icy.gui.component.IcyTextField; 022import icy.gui.component.IcyTextField.TextChangeListener; 023import icy.main.Icy; 024import icy.resource.ResourceUtil; 025import icy.swimmingPool.SwimmingObject; 026import icy.swimmingPool.SwimmingPool; 027import icy.swimmingPool.SwimmingPoolEvent; 028import icy.swimmingPool.SwimmingPoolListener; 029import icy.system.thread.ThreadUtil; 030import icy.util.StringUtil; 031 032import java.awt.event.ActionEvent; 033import java.awt.event.ActionListener; 034import java.util.ArrayList; 035 036import javax.swing.BorderFactory; 037import javax.swing.Box; 038import javax.swing.BoxLayout; 039import javax.swing.DefaultComboBoxModel; 040import javax.swing.ImageIcon; 041import javax.swing.JButton; 042import javax.swing.JComboBox; 043import javax.swing.JLabel; 044import javax.swing.JPanel; 045import javax.swing.JScrollPane; 046import javax.swing.JTable; 047import javax.swing.ListSelectionModel; 048import javax.swing.event.ListSelectionEvent; 049import javax.swing.event.ListSelectionListener; 050import javax.swing.table.AbstractTableModel; 051import javax.swing.table.TableColumn; 052import javax.swing.table.TableColumnModel; 053 054/** 055 * @author Stephane 056 */ 057public class SwimmingPoolPanel extends JPanel implements TextChangeListener, ListSelectionListener, 058 SwimmingPoolListener 059{ 060 /** 061 * 062 */ 063 private static final long serialVersionUID = 1565643301342039659L; 064 065 static final String[] columnNames = {"", "Name", "Type"}; 066 067 final SwimmingPool swimmingPool; 068 ArrayList<SwimmingObject> objects; 069 070 final AbstractTableModel tableModel; 071 final JTable table; 072 073 final JComboBox objectType; 074 final JPanel objectTypePanel; 075 final IcyTextField nameFilter; 076 final JButton refreshButton; 077 final JButton deleteAllButton; 078 final JButton deleteButton; 079 080 public SwimmingPoolPanel(boolean showTypeFilter, boolean showNameFilter, boolean showButtons) 081 { 082 super(); 083 084 swimmingPool = Icy.getMainInterface().getSwimmingPool(); 085 if (swimmingPool != null) 086 swimmingPool.addListener(this); 087 088 objects = new ArrayList<SwimmingObject>(); 089 090 // GUI 091 092 objectType = new JComboBox(new DefaultComboBoxModel()); 093 objectType.setToolTipText("Select type to display"); 094 objectType.addActionListener(new ActionListener() 095 { 096 @Override 097 public void actionPerformed(ActionEvent e) 098 { 099 if (objectType.getSelectedIndex() != -1) 100 { 101 refreshObjects(); 102 refreshTableData(); 103 } 104 } 105 }); 106 107 objectTypePanel = new JPanel(); 108 objectTypePanel.setLayout(new BoxLayout(objectTypePanel, BoxLayout.PAGE_AXIS)); 109 objectTypePanel.setVisible(showTypeFilter); 110 111 final JPanel internalRepPanel = new JPanel(); 112 internalRepPanel.setLayout(new BoxLayout(internalRepPanel, BoxLayout.LINE_AXIS)); 113 114 internalRepPanel.add(new JLabel("Object type :")); 115 internalRepPanel.add(Box.createHorizontalStrut(8)); 116 internalRepPanel.add(objectType); 117 internalRepPanel.add(Box.createHorizontalGlue()); 118 119 objectTypePanel.add(internalRepPanel); 120 objectTypePanel.add(Box.createVerticalStrut(8)); 121 122 // need filter before load() 123 nameFilter = new IcyTextField(); 124 nameFilter.addTextChangeListener(this); 125 nameFilter.setVisible(showNameFilter); 126 127 // build buttons panel 128 129 refreshButton = new JButton("Refresh"); 130 refreshButton.addActionListener(new ActionListener() 131 { 132 @Override 133 public void actionPerformed(ActionEvent e) 134 { 135 // refresh list 136 refreshObjectTypeList(); 137 refreshObjects(); 138 } 139 }); 140 141 deleteAllButton = new JButton("Delete all"); 142 deleteAllButton.addActionListener(new ActionListener() 143 { 144 @Override 145 public void actionPerformed(ActionEvent e) 146 { 147 // delete all objects 148 swimmingPool.removeAll(); 149 } 150 }); 151 152 deleteButton = new JButton("Delete"); 153 deleteButton.addActionListener(new ActionListener() 154 { 155 @Override 156 public void actionPerformed(ActionEvent e) 157 { 158 // delete selected objects 159 for (SwimmingObject so : getSelectedObjects()) 160 swimmingPool.remove(so); 161 } 162 }); 163 164 final JPanel buttonsPanel = new JPanel(); 165 buttonsPanel.setBorder(BorderFactory.createEmptyBorder(4, 8, 8, 8)); 166 buttonsPanel.setLayout(new BoxLayout(buttonsPanel, BoxLayout.LINE_AXIS)); 167 buttonsPanel.setVisible(showButtons); 168 169 buttonsPanel.add(refreshButton); 170 buttonsPanel.add(Box.createHorizontalStrut(64)); 171 buttonsPanel.add(deleteAllButton); 172 buttonsPanel.add(Box.createHorizontalStrut(8)); 173 buttonsPanel.add(deleteButton); 174 buttonsPanel.add(Box.createHorizontalGlue()); 175 176 // build table 177 tableModel = new AbstractTableModel() 178 { 179 /** 180 * 181 */ 182 private static final long serialVersionUID = -8573364273165723214L; 183 184 @Override 185 public int getColumnCount() 186 { 187 return columnNames.length; 188 } 189 190 @Override 191 public String getColumnName(int column) 192 { 193 return columnNames[column]; 194 } 195 196 @Override 197 public int getRowCount() 198 { 199 return objects.size(); 200 } 201 202 @Override 203 public Object getValueAt(int row, int column) 204 { 205 final SwimmingObject so = objects.get(row); 206 207 switch (column) 208 { 209 case 0: 210 return ResourceUtil.scaleIcon(so.getIcon(), 24); 211 212 case 1: 213 return so.getName(); 214 215 case 2: 216 return so.getObjectSimpleClassName(); 217 } 218 219 return ""; 220 } 221 222 @Override 223 public boolean isCellEditable(int row, int column) 224 { 225 return false; 226 } 227 228 @Override 229 public Class<?> getColumnClass(int columnIndex) 230 { 231 if (columnIndex == 0) 232 return ImageIcon.class; 233 234 return String.class; 235 } 236 }; 237 238 table = new JTable(tableModel); 239 240 final TableColumnModel colModel = table.getColumnModel(); 241 TableColumn col; 242 243 // columns setting 244 col = colModel.getColumn(0); 245 col.setPreferredWidth(32); 246 col.setMinWidth(32); 247 col.setResizable(false); 248 249 col = colModel.getColumn(1); 250 col.setPreferredWidth(100); 251 col.setMinWidth(60); 252 253 col = colModel.getColumn(2); 254 col.setPreferredWidth(80); 255 col.setMinWidth(40); 256 257 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 258 table.getSelectionModel().addListSelectionListener(this); 259 table.setRowHeight(24); 260 table.setColumnSelectionAllowed(false); 261 table.setRowSelectionAllowed(true); 262 table.setShowVerticalLines(false); 263 table.setAutoCreateRowSorter(true); 264 table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 265 266 setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); 267 268 add(Box.createVerticalStrut(2)); 269 if (showTypeFilter) 270 add(objectTypePanel); 271 if (showNameFilter) 272 add(nameFilter); 273 if (showTypeFilter || showNameFilter) 274 add(Box.createVerticalStrut(8)); 275 add(table.getTableHeader()); 276 add(new JScrollPane(table)); 277 if (showButtons) 278 add(buttonsPanel); 279 280 validate(); 281 282 refreshObjectTypeList(); 283 refreshObjects(); 284 } 285 286 public void setTypeFilter(String type) 287 { 288 objectType.setSelectedItem(type); 289 } 290 291 public void setNameFilter(String name) 292 { 293 nameFilter.setText(name); 294 } 295 296 protected void refreshObjects() 297 { 298 if (swimmingPool != null) 299 objects = filterList(swimmingPool.getObjects(), nameFilter.getText()); 300 else 301 objects.clear(); 302 } 303 304 protected int getObjectIndex(SwimmingObject object) 305 { 306 return objects.indexOf(object); 307 } 308 309 protected int getObjectModelIndex(SwimmingObject object) 310 { 311 return getObjectIndex(object); 312 } 313 314 protected int getObjectTableIndex(SwimmingObject object) 315 { 316 final int ind = getObjectModelIndex(object); 317 318 if (ind == -1) 319 return ind; 320 321 try 322 { 323 return table.convertRowIndexToView(ind); 324 } 325 catch (IndexOutOfBoundsException e) 326 { 327 return -1; 328 } 329 } 330 331 public ArrayList<SwimmingObject> getSelectedObjects() 332 { 333 final ArrayList<SwimmingObject> result = new ArrayList<SwimmingObject>(); 334 335 for (int rowIndex : table.getSelectedRows()) 336 { 337 int index = -1; 338 339 if (rowIndex != -1) 340 { 341 try 342 { 343 index = table.convertRowIndexToModel(rowIndex); 344 } 345 catch (IndexOutOfBoundsException e) 346 { 347 // ignore 348 } 349 } 350 351 if ((index >= 0) || (index < objects.size())) 352 result.add(objects.get(index)); 353 } 354 355 return result; 356 } 357 358 public void setSelectedObjects(ArrayList<SwimmingObject> sos) 359 { 360 table.clearSelection(); 361 362 for (SwimmingObject so : sos) 363 { 364 final int index = getObjectTableIndex(so); 365 366 if (index > -1) 367 table.getSelectionModel().setSelectionInterval(index, index); 368 } 369 } 370 371 protected void refreshObjectTypeList() 372 { 373 final DefaultComboBoxModel model = (DefaultComboBoxModel) objectType.getModel(); 374 final Object savedItem = model.getSelectedItem(); 375 376 model.removeAllElements(); 377 model.addElement("ALL"); 378 379 if (swimmingPool != null) 380 { 381 for (String type : SwimmingObject.getObjectTypes(swimmingPool.getObjects())) 382 model.addElement(type); 383 } 384 385 if (savedItem != null) 386 model.setSelectedItem(savedItem); 387 else 388 objectType.setSelectedIndex(0); 389 } 390 391 private ArrayList<SwimmingObject> filterList(ArrayList<SwimmingObject> list, String nameFilterText) 392 { 393 final ArrayList<SwimmingObject> result = new ArrayList<SwimmingObject>(); 394 395 final boolean typeEmpty = objectType.getSelectedIndex() == 0; 396 final boolean nameEmpty = StringUtil.isEmpty(nameFilterText, true); 397 final String typeFilter; 398 final String nameFilterUp; 399 400 if (!typeEmpty) 401 typeFilter = objectType.getSelectedItem().toString(); 402 else 403 typeFilter = ""; 404 if (!nameEmpty) 405 nameFilterUp = nameFilterText.toUpperCase(); 406 else 407 nameFilterUp = ""; 408 409 for (SwimmingObject so : list) 410 { 411 // search in name and type 412 if ((typeEmpty || so.getObjectSimpleClassName().equals(typeFilter)) 413 && (nameEmpty || (so.getName().indexOf(nameFilterUp) != -1))) 414 result.add(so); 415 } 416 417 return result; 418 } 419 420 protected void refreshTableData() 421 { 422 ThreadUtil.invokeLater(new Runnable() 423 { 424 @Override 425 public void run() 426 { 427 final ArrayList<SwimmingObject> sos = getSelectedObjects(); 428 429 tableModel.fireTableDataChanged(); 430 431 // restore previous selected objects if possible 432 setSelectedObjects(sos); 433 } 434 }); 435 } 436 437 protected void refreshButtonsPanel() 438 { 439 deleteButton.setEnabled(getSelectedObjects().size() > 0); 440 deleteAllButton.setEnabled(objects.size() > 0); 441 } 442 443 protected void pluginsChanged() 444 { 445 refreshObjects(); 446 refreshTableData(); 447 refreshButtonsPanel(); 448 } 449 450 @Override 451 public void textChanged(IcyTextField source, boolean validate) 452 { 453 pluginsChanged(); 454 } 455 456 @Override 457 public void valueChanged(ListSelectionEvent e) 458 { 459 refreshButtonsPanel(); 460 461 // TODO : send event to notify selection change 462 } 463 464 @Override 465 public void swimmingPoolChangeEvent(SwimmingPoolEvent swimmingPoolEvent) 466 { 467 refreshObjectTypeList(); 468 refreshObjects(); 469 } 470}