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.preferences; 020 021import icy.gui.component.IcyTable; 022import icy.gui.component.IcyTextField; 023import icy.gui.component.IcyTextField.TextChangeListener; 024import icy.gui.util.ComponentUtil; 025import icy.preferences.RepositoryPreferences; 026import icy.preferences.RepositoryPreferences.RepositoryInfo; 027import icy.system.thread.ThreadUtil; 028import icy.util.StringUtil; 029import icy.workspace.Workspace; 030 031import java.awt.BorderLayout; 032import java.awt.Dimension; 033import java.awt.event.ActionEvent; 034import java.awt.event.ActionListener; 035import java.util.ArrayList; 036import java.util.List; 037 038import javax.swing.BorderFactory; 039import javax.swing.Box; 040import javax.swing.BoxLayout; 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 abstract class WorkspaceListPreferencePanel extends PreferencePanel implements TextChangeListener, 058 ListSelectionListener 059{ 060 /** 061 * 062 */ 063 private static final long serialVersionUID = -264986966623111155L; 064 065 private static final String BOTTOM_MESS = "*Workspace modification need application restart to take effect"; 066 067 static final String[] columnNames = {"Name", "Description", "", "Enabled"}; 068 069 // protected final Preferences preferences; 070 List<Workspace> workspaces; 071 072 final AbstractTableModel tableModel; 073 final JTable table; 074 075 final JComboBox repository; 076 final JPanel repositoryPanel; 077 final IcyTextField filter; 078 final JButton refreshButton; 079 final JButton action1Button; 080 081 private final Runnable buttonsStateUpdater; 082 private final Runnable tableDataRefresher; 083 private final Runnable workspaceListRefresher; 084 private final Runnable repositoriesUpdater; 085 086 final ActionListener repositoryActionListener; 087 088 WorkspaceListPreferencePanel(PreferenceFrame parent, String nodeName) 089 { 090 super(parent, nodeName, WorkspacePreferencePanel.NODE_NAME); 091 092 // preferences = Preferences.userRoot().node(preferencesId); 093 workspaces = new ArrayList<Workspace>(); 094 095 buttonsStateUpdater = new Runnable() 096 { 097 @Override 098 public void run() 099 { 100 // need to be done on EDT 101 ThreadUtil.invokeNow(new Runnable() 102 { 103 @Override 104 public void run() 105 { 106 updateButtonsStateInternal(); 107 } 108 }); 109 } 110 }; 111 tableDataRefresher = new Runnable() 112 { 113 @Override 114 public void run() 115 { 116 // need to be done on EDT 117 ThreadUtil.invokeNow(new Runnable() 118 { 119 @Override 120 public void run() 121 { 122 refreshTableDataInternal(); 123 } 124 }); 125 } 126 }; 127 workspaceListRefresher = new Runnable() 128 { 129 @Override 130 public void run() 131 { 132 refreshWorkspacesInternal(); 133 } 134 }; 135 repositoriesUpdater = new Runnable() 136 { 137 @Override 138 public void run() 139 { 140 // need to be done on EDT 141 ThreadUtil.invokeNow(new Runnable() 142 { 143 @Override 144 public void run() 145 { 146 updateRepositoriesInternal(); 147 } 148 }); 149 } 150 }; 151 152 repositoryActionListener = new ActionListener() 153 { 154 @Override 155 public void actionPerformed(ActionEvent e) 156 { 157 repositoryChanged(); 158 } 159 }; 160 161 // build repository comboBox 162 repository = new JComboBox(); 163 repository.setToolTipText("Select a repository"); 164 repository.addActionListener(repositoryActionListener); 165 166 repositoryPanel = new JPanel(); 167 repositoryPanel.setLayout(new BoxLayout(repositoryPanel, BoxLayout.PAGE_AXIS)); 168 repositoryPanel.setVisible(false); 169 170 final JPanel internalRepPanel = new JPanel(); 171 internalRepPanel.setLayout(new BoxLayout(internalRepPanel, BoxLayout.LINE_AXIS)); 172 173 internalRepPanel.add(new JLabel("Repository :")); 174 internalRepPanel.add(Box.createHorizontalStrut(8)); 175 internalRepPanel.add(repository); 176 internalRepPanel.add(Box.createHorizontalGlue()); 177 178 repositoryPanel.add(internalRepPanel); 179 repositoryPanel.add(Box.createVerticalStrut(8)); 180 181 // need filter before load() 182 filter = new IcyTextField(); 183 filter.addTextChangeListener(this); 184 185 load(); 186 187 // build buttons panel 188 final Dimension buttonsDim = new Dimension(100, 24); 189 190 refreshButton = new JButton("Reload list"); 191 refreshButton.addActionListener(new ActionListener() 192 { 193 @Override 194 public void actionPerformed(ActionEvent e) 195 { 196 reloadWorkspaces(); 197 } 198 }); 199 ComponentUtil.setFixedSize(refreshButton, buttonsDim); 200 201 action1Button = new JButton("null"); 202 action1Button.addActionListener(new ActionListener() 203 { 204 @Override 205 public void actionPerformed(ActionEvent e) 206 { 207 doAction1(getSelectedWorkspace()); 208 } 209 }); 210 action1Button.setVisible(false); 211 ComponentUtil.setFixedSize(action1Button, buttonsDim); 212 213 final JPanel buttonsPanel = new JPanel(); 214 buttonsPanel.setBorder(BorderFactory.createEmptyBorder(4, 8, 8, 8)); 215 buttonsPanel.setLayout(new BoxLayout(buttonsPanel, BoxLayout.PAGE_AXIS)); 216 217 buttonsPanel.add(refreshButton); 218 buttonsPanel.add(Box.createVerticalStrut(64)); 219 buttonsPanel.add(action1Button); 220 buttonsPanel.add(Box.createVerticalStrut(8)); 221 buttonsPanel.add(Box.createVerticalGlue()); 222 223 // build table 224 tableModel = new AbstractTableModel() 225 { 226 /** 227 * 228 */ 229 private static final long serialVersionUID = -8573364273165723214L; 230 231 @Override 232 public int getColumnCount() 233 { 234 return WorkspaceListPreferencePanel.this.getColumnCount(); 235 } 236 237 @Override 238 public String getColumnName(int column) 239 { 240 return columnNames[column]; 241 } 242 243 @Override 244 public int getRowCount() 245 { 246 return workspaces.size(); 247 } 248 249 @Override 250 public Object getValueAt(int row, int column) 251 { 252 final Workspace workspace = workspaces.get(row); 253 254 switch (column) 255 { 256 case 0: 257 return workspace.getName(); 258 259 case 1: 260 return workspace.getDescription(); 261 262 case 2: 263 return getStateValue(workspace); 264 265 case 3: 266 return isWorkspaceEnable(workspace); 267 } 268 269 return ""; 270 } 271 272 @Override 273 public boolean isCellEditable(int row, int column) 274 { 275 return (column == 3); 276 } 277 278 @Override 279 public Class<?> getColumnClass(int columnIndex) 280 { 281 if (columnIndex == 3) 282 return Boolean.class; 283 284 return String.class; 285 } 286 287 @Override 288 public void setValueAt(Object aValue, int rowIndex, int columnIndex) 289 { 290 final Workspace workspace = workspaces.get(rowIndex); 291 292 if ((columnIndex == 3) && (aValue instanceof Boolean)) 293 setWorkspaceEnable(workspace, (Boolean) aValue); 294 295 // workspace setting changed, restart needed 296 getPreferenceFrame().setNeedRestart(); 297 } 298 }; 299 300 table = new IcyTable(tableModel); 301 302 final TableColumnModel colModel = table.getColumnModel(); 303 TableColumn col; 304 305 // columns setting 306 col = colModel.getColumn(0); 307 col.setMinWidth(80); 308 col.setPreferredWidth(100); 309 col.setMaxWidth(120); 310 311 col = colModel.getColumn(1); 312 col.setMinWidth(160); 313 col.setPreferredWidth(240); 314 col.setMaxWidth(500); 315 316 col = colModel.getColumn(2); 317 col.setMinWidth(60); 318 col.setPreferredWidth(70); 319 col.setMaxWidth(80); 320 321 if (colModel.getColumnCount() > 3) 322 { 323 col = colModel.getColumn(3); 324 col.setMinWidth(60); 325 col.setPreferredWidth(60); 326 col.setMaxWidth(60); 327 } 328 329 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 330 table.getSelectionModel().addListSelectionListener(this); 331 table.setColumnSelectionAllowed(false); 332 table.setRowSelectionAllowed(true); 333 table.setRowHeight(24); 334 table.setShowVerticalLines(false); 335 table.setAutoCreateRowSorter(true); 336 table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); 337 338 final JPanel tableTopPanel = new JPanel(); 339 340 tableTopPanel.setLayout(new BoxLayout(tableTopPanel, BoxLayout.PAGE_AXIS)); 341 342 tableTopPanel.add(Box.createVerticalStrut(2)); 343 tableTopPanel.add(repositoryPanel); 344 tableTopPanel.add(filter); 345 tableTopPanel.add(Box.createVerticalStrut(8)); 346 tableTopPanel.add(table.getTableHeader()); 347 348 final JPanel tablePanel = new JPanel(); 349 350 tablePanel.setLayout(new BorderLayout()); 351 352 tablePanel.add(tableTopPanel, BorderLayout.NORTH); 353 tablePanel.add(new JScrollPane(table), BorderLayout.CENTER); 354 355 mainPanel.setLayout(new BorderLayout()); 356 357 mainPanel.add(tablePanel, BorderLayout.CENTER); 358 mainPanel.add(buttonsPanel, BorderLayout.EAST); 359 mainPanel.add(new JLabel(BOTTOM_MESS), BorderLayout.SOUTH); 360 361 mainPanel.validate(); 362 } 363 364 @Override 365 protected void closed() 366 { 367 super.closed(); 368 369 // do not retains workspaces when frame is closed 370 workspaces.clear(); 371 } 372 373 private List<Workspace> filterList(List<Workspace> list, String filter) 374 { 375 final List<Workspace> result = new ArrayList<Workspace>(); 376 final boolean empty = StringUtil.isEmpty(filter, true); 377 final String filterUp; 378 379 if (!empty) 380 filterUp = filter.toUpperCase(); 381 else 382 filterUp = ""; 383 384 for (Workspace workspace : list) 385 { 386 final String name = workspace.getName().toUpperCase(); 387 final String desc = workspace.getDescription().toUpperCase(); 388 389 // search in name and description 390 if (empty || (name.indexOf(filterUp) != -1) || (desc.indexOf(filterUp) != -1)) 391 result.add(workspace); 392 } 393 394 return result; 395 } 396 397 protected abstract void doAction1(Workspace workspace); 398 399 protected abstract void repositoryChanged(); 400 401 protected abstract void reloadWorkspaces(); 402 403 protected abstract String getStateValue(Workspace workspace); 404 405 protected abstract int getColumnCount(); 406 407 protected abstract List<Workspace> getWorkspaces(); 408 409 protected abstract void updateButtonsStateInternal(); 410 411 protected final void updateButtonsState() 412 { 413 ThreadUtil.runSingle(buttonsStateUpdater); 414 } 415 416 protected void updateRepositoriesInternal() 417 { 418 // final RepositoryPreferencePanel panel = (RepositoryPreferencePanel) 419 // getPreferencePanel(RepositoryPreferencePanel.class); 420 // // refresh repositories list (use list from GUI) 421 // final ArrayList<RepositoryInfo> repositeries = panel.repositories; 422 423 // refresh repositories list 424 final ArrayList<RepositoryInfo> repositeries = RepositoryPreferences.getRepositeries(); 425 426 final RepositoryInfo savedRepository = (RepositoryInfo) repository.getSelectedItem(); 427 428 // needed to disable events during update time 429 repository.removeActionListener(repositoryActionListener); 430 431 repository.removeAllItems(); 432 for (RepositoryInfo repos : repositeries) 433 if (repos.isEnabled()) 434 repository.addItem(repos); 435 repository.setEnabled(true); 436 437 repository.addActionListener(repositoryActionListener); 438 439 boolean selected = false; 440 441 // try to set back the old selected repository 442 if (savedRepository != null) 443 { 444 final String repositoryName = savedRepository.getName(); 445 446 for (int ind = 0; ind < repository.getItemCount(); ind++) 447 { 448 final RepositoryInfo repo = (RepositoryInfo) repository.getItemAt(ind); 449 450 if ((repo != null) && (repo.getName().equals(repositoryName))) 451 { 452 repository.setSelectedIndex(ind); 453 selected = true; 454 break; 455 } 456 } 457 } 458 459 // manually launch the action 460 if (!selected) 461 repository.setSelectedIndex((repository.getItemCount() > 0) ? 0 : -1); 462 463 // avoid automatic minimum size here 464 repository.setMinimumSize(new Dimension(48, 18)); 465 } 466 467 protected final void updateRepositories() 468 { 469 ThreadUtil.runSingle(repositoriesUpdater); 470 } 471 472 protected Boolean isWorkspaceEnable(Workspace workspace) 473 { 474 return Boolean.FALSE; 475 } 476 477 protected void setWorkspaceEnable(Workspace workspace, Boolean value) 478 { 479 // ignore 480 } 481 482 protected void refreshWorkspacesInternal() 483 { 484 workspaces = filterList(getWorkspaces(), filter.getText()); 485 // refresh table data 486 refreshTableData(); 487 } 488 489 protected final void refreshWorkspaces() 490 { 491 ThreadUtil.runSingle(workspaceListRefresher); 492 } 493 494 protected int getWorkspaceIndex(Workspace workspace) 495 { 496 return workspaces.indexOf(workspace); 497 } 498 499 protected int getWorkspaceModelIndex(Workspace workspace) 500 { 501 return getWorkspaceIndex(workspace); 502 } 503 504 protected int getWorkspaceTableIndex(Workspace workspace) 505 { 506 final int ind = getWorkspaceModelIndex(workspace); 507 508 if (ind == -1) 509 return ind; 510 511 try 512 { 513 514 return table.convertRowIndexToView(ind); 515 } 516 catch (IndexOutOfBoundsException e) 517 { 518 return -1; 519 } 520 } 521 522 Workspace getSelectedWorkspace() 523 { 524 int index; 525 526 index = table.getSelectedRow(); 527 if (index == -1) 528 return null; 529 530 try 531 { 532 index = table.convertRowIndexToModel(index); 533 } 534 catch (IndexOutOfBoundsException e) 535 { 536 index = -1; 537 } 538 539 if ((index < 0) || (index >= workspaces.size())) 540 return null; 541 542 return workspaces.get(index); 543 } 544 545 void setSelectedWorkspace(Workspace workspace) 546 { 547 final int index = getWorkspaceTableIndex(workspace); 548 549 if (index > -1) 550 { 551 table.clearSelection(); 552 table.getSelectionModel().setSelectionInterval(index, index); 553 } 554 } 555 556 @Override 557 protected void load() 558 { 559 560 } 561 562 @Override 563 protected void save() 564 { 565 // reload repositories as some parameter as beta flag can have changed 566 updateRepositories(); 567 } 568 569 protected void refreshTableDataInternal() 570 { 571 final Workspace workspace = getSelectedWorkspace(); 572 573 tableModel.fireTableDataChanged(); 574 575 // restore previous selected workspace if possible 576 setSelectedWorkspace(workspace); 577 578 // update buttons state 579 updateButtonsState(); 580 } 581 582 protected final void refreshTableData() 583 { 584 ThreadUtil.runSingle(tableDataRefresher); 585 } 586 587 protected void workspacesChanged() 588 { 589 refreshWorkspaces(); 590 } 591 592 @Override 593 public void textChanged(IcyTextField source, boolean validate) 594 { 595 workspacesChanged(); 596 } 597 598 @Override 599 public void valueChanged(ListSelectionEvent e) 600 { 601 updateButtonsState(); 602 } 603}