1 22 23 package org.gjt.sp.jedit.pluginmgr; 24 25 import java.awt.BorderLayout ; 27 import java.awt.Color ; 28 import java.awt.Component ; 29 import java.awt.Dimension ; 30 import java.awt.KeyboardFocusManager ; 31 32 import java.awt.event.ActionEvent ; 33 import java.awt.event.ActionListener ; 34 import java.awt.event.FocusAdapter ; 35 import java.awt.event.FocusEvent ; 36 import java.awt.event.InputEvent ; 37 import java.awt.event.KeyEvent ; 38 import java.awt.event.MouseAdapter ; 39 import java.awt.event.MouseEvent ; 40 41 import java.net.URL ; 42 43 import java.util.*; 44 45 import javax.swing.AbstractAction ; 46 import javax.swing.ActionMap ; 47 import javax.swing.Box ; 48 import javax.swing.BoxLayout ; 49 import javax.swing.InputMap ; 50 import javax.swing.JButton ; 51 import javax.swing.JCheckBox ; 52 import javax.swing.JComponent ; 53 import javax.swing.JOptionPane ; 54 import javax.swing.JPanel ; 55 import javax.swing.JScrollBar ; 56 import javax.swing.JScrollPane ; 57 import javax.swing.JTable ; 58 import javax.swing.KeyStroke ; 59 import javax.swing.ListSelectionModel ; 60 import javax.swing.UIManager ; 61 62 import javax.swing.border.EmptyBorder ; 63 64 import javax.swing.event.ListSelectionEvent ; 65 import javax.swing.event.ListSelectionListener ; 66 import javax.swing.event.TableModelEvent ; 67 68 import javax.swing.table.AbstractTableModel ; 69 import javax.swing.table.DefaultTableCellRenderer ; 70 import javax.swing.table.JTableHeader ; 71 import javax.swing.table.TableColumn ; 72 73 import org.gjt.sp.jedit.*; 74 75 import java.util.concurrent.ConcurrentHashMap ; 76 77 import org.gjt.sp.jedit.help.*; 78 79 import org.gjt.sp.util.Log; 80 82 public class ManagePanel extends JPanel 83 { 84 85 private final JCheckBox hideLibraries; 87 private final JTable table; 88 private final JScrollPane scrollpane; 89 private final PluginTableModel pluginModel; 90 private final PluginManager window; 91 93 public ManagePanel(PluginManager window) 95 { 96 super(new BorderLayout (12,12)); 97 98 this.window = window; 99 100 setBorder(new EmptyBorder (12,12,12,12)); 101 102 Box topBox = new Box (BoxLayout.X_AXIS); 103 topBox.add(hideLibraries = new HideLibrariesButton()); 104 add(BorderLayout.NORTH,topBox); 105 106 107 table = new JTable (pluginModel = new PluginTableModel()); 108 table.setShowGrid(false); 109 table.setIntercellSpacing(new Dimension (0,0)); 110 table.setRowHeight(table.getRowHeight() + 2); 111 table.setPreferredScrollableViewportSize(new Dimension (500,300)); 112 table.setDefaultRenderer(Object .class, new TextRenderer( 113 (DefaultTableCellRenderer )table.getDefaultRenderer(Object .class))); 114 table.addFocusListener(new TableFocusHandler()); 115 InputMap tableInputMap = table.getInputMap(JComponent.WHEN_FOCUSED); 116 ActionMap tableActionMap = table.getActionMap(); 117 tableInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,0),"tabOutForward"); 118 tableActionMap.put("tabOutForward",new KeyboardAction(KeyboardCommand.TAB_OUT_FORWARD)); 119 tableInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,InputEvent.SHIFT_MASK),"tabOutBack"); 120 tableActionMap.put("tabOutBack",new KeyboardAction(KeyboardCommand.TAB_OUT_BACK)); 121 tableInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE,0),"editPlugin"); 122 tableActionMap.put("editPlugin",new KeyboardAction(KeyboardCommand.EDIT_PLUGIN)); 123 tableInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0),"closePluginManager"); 124 tableActionMap.put("closePluginManager",new KeyboardAction(KeyboardCommand.CLOSE_PLUGIN_MANAGER)); 125 126 TableColumn col1 = table.getColumnModel().getColumn(0); 127 TableColumn col2 = table.getColumnModel().getColumn(1); 128 TableColumn col3 = table.getColumnModel().getColumn(2); 129 TableColumn col4 = table.getColumnModel().getColumn(3); 130 131 col1.setPreferredWidth(30); 132 col1.setMinWidth(30); 133 col1.setMaxWidth(30); 134 col1.setResizable(false); 135 136 col2.setPreferredWidth(300); 137 col3.setPreferredWidth(100); 138 col4.setPreferredWidth(100); 139 140 JTableHeader header = table.getTableHeader(); 141 header.setReorderingAllowed(false); 142 header.addMouseListener(new HeaderMouseHandler()); 143 144 scrollpane = new JScrollPane (table); 145 scrollpane.getViewport().setBackground(table.getBackground()); 146 add(BorderLayout.CENTER,scrollpane); 147 148 149 Box buttons = new Box (BoxLayout.X_AXIS); 150 151 buttons.add(new RemoveButton()); 152 buttons.add(Box.createGlue()); 153 buttons.add(new HelpButton()); 154 155 add(BorderLayout.SOUTH,buttons); 156 157 pluginModel.update(); 158 } 160 public void update() 162 { 163 pluginModel.update(); 164 } 166 168 public enum KeyboardCommand 170 { 171 NONE, 172 TAB_OUT_FORWARD, 173 TAB_OUT_BACK, 174 EDIT_PLUGIN, 175 CLOSE_PLUGIN_MANAGER 176 } 178 static class Entry 180 { 181 static final String ERROR = "error"; 182 static final String LOADED = "loaded"; 183 static final String NOT_LOADED = "not-loaded"; 184 185 final String status; 186 final String jar; 187 188 String clazz, name, version, author, docs; 189 final List<String > jars; 190 191 Entry(String jar) 192 { 193 jars = new LinkedList<String >(); 194 this.jar = jar; 195 jars.add(this.jar); 196 status = NOT_LOADED; 197 } 198 199 Entry(PluginJAR jar) 200 { 201 jars = new LinkedList<String >(); 202 this.jar = jar.getPath(); 203 jars.add(this.jar); 204 205 EditPlugin plugin = jar.getPlugin(); 206 if(plugin != null) 207 { 208 status = plugin instanceof EditPlugin.Broken 209 ? ERROR : LOADED; 210 clazz = plugin.getClassName(); 211 name = jEdit.getProperty("plugin."+clazz+".name"); 212 version = jEdit.getProperty("plugin."+clazz+".version"); 213 author = jEdit.getProperty("plugin."+clazz+".author"); 214 docs = jEdit.getProperty("plugin."+clazz+".docs"); 215 216 String jarsProp = jEdit.getProperty("plugin."+clazz+".jars"); 217 218 if(jarsProp != null) 219 { 220 String directory = MiscUtilities.getParentOfPath(this.jar); 221 222 StringTokenizer st = new StringTokenizer(jarsProp); 223 while(st.hasMoreElements()) 224 { 225 jars.add(MiscUtilities.constructPath( 226 directory,st.nextToken())); 227 } 228 } 229 } 230 else 231 status = LOADED; 232 } 233 } 235 class PluginTableModel extends AbstractTableModel 237 { 238 private final List<Entry> entries; 239 private int sortType = EntryCompare.NAME; 240 private ConcurrentHashMap <String , Object > unloaded; 241 243 PluginTableModel() 245 { 246 entries = new ArrayList<Entry>(); 247 } 249 public int getColumnCount() 251 { 252 return 4; 253 } 255 public Class getColumnClass(int columnIndex) 257 { 258 switch (columnIndex) 259 { 260 case 0: return Boolean .class; 261 default: return Object .class; 262 } 263 } 265 public String getColumnName(int column) 267 { 268 switch (column) 269 { 270 case 0: 271 return " "; 272 case 1: 273 return jEdit.getProperty("manage-plugins.info.name"); 274 case 2: 275 return jEdit.getProperty("manage-plugins.info.version"); 276 case 3: 277 return jEdit.getProperty("manage-plugins.info.status"); 278 default: 279 throw new Error ("Column out of range"); 280 } 281 } 283 public Entry getEntry(int rowIndex) 285 { 286 return entries.get(rowIndex); 287 } 289 public int getRowCount() 291 { 292 return entries.size(); 293 } 295 public Object getValueAt(int rowIndex,int columnIndex) 297 { 298 Entry entry = entries.get(rowIndex); 299 switch (columnIndex) 300 { 301 case 0: 302 return Boolean.valueOf(!entry.status.equals(Entry.NOT_LOADED)); 303 case 1: 304 if(entry.name == null) 305 { 306 return MiscUtilities.getFileName(entry.jar); 307 } 308 else 309 return entry.name; 310 case 2: 311 return entry.version; 312 case 3: 313 return jEdit.getProperty("plugin-manager.status." + entry.status); 314 default: 315 throw new Error ("Column out of range"); 316 } 317 } 319 public boolean isCellEditable(int rowIndex, int columnIndex) 321 { 322 return columnIndex == 0; 323 } 325 public void setValueAt(Object value, int rowIndex, 327 int columnIndex) 328 { 329 Entry entry = entries.get(rowIndex); 330 if(columnIndex == 0) 331 { 332 PluginJAR jar = jEdit.getPluginJAR(entry.jar); 333 if(jar == null) 334 { 335 if(value.equals(Boolean.FALSE)) 336 return; 337 338 PluginJAR.load(entry.jar, true); 339 } 340 else 341 { 342 if(value.equals(Boolean.TRUE)) 343 return; 344 345 unloadPluginJARWithDialog(jar); 346 } 347 } 348 349 update(); 350 } 352 public void setSortType(int type) 354 { 355 sortType = type; 356 sort(type); 357 } 359 public void sort(int type) 361 { 362 ArrayList<String > savedSelection = new ArrayList<String >(); 363 saveSelection(savedSelection); 364 Collections.sort(entries,new EntryCompare(type)); 365 fireTableChanged(new TableModelEvent (this)); 366 restoreSelection(savedSelection); 367 } 368 370 public void update() 372 { 373 ArrayList<String > savedSelection = new ArrayList<String >(); 374 saveSelection(savedSelection); 375 entries.clear(); 376 377 String systemJarDir = MiscUtilities.constructPath( 378 jEdit.getJEditHome(),"jars"); 379 String userJarDir; 380 if(jEdit.getSettingsDirectory() == null) 381 userJarDir = null; 382 else 383 { 384 userJarDir = MiscUtilities.constructPath( 385 jEdit.getSettingsDirectory(),"jars"); 386 } 387 388 PluginJAR[] plugins = jEdit.getPluginJARs(); 389 for(int i = 0; i < plugins.length; i++) 390 { 391 String path = plugins[i].getPath(); 392 if(path.startsWith(systemJarDir) 393 || (userJarDir != null 394 && path.startsWith(userJarDir))) 395 { 396 Entry e = new Entry(plugins[i]); 397 if(!hideLibraries.isSelected() 398 || e.clazz != null) 399 { 400 entries.add(e); 401 } 402 } 403 } 404 405 String [] newPlugins = jEdit.getNotLoadedPluginJARs(); 406 for(int i = 0; i < newPlugins.length; i++) 407 { 408 Entry e = new Entry(newPlugins[i]); 409 entries.add(e); 410 } 411 412 sort(sortType); 413 restoreSelection(savedSelection); 414 } 416 private void unloadPluginJARWithDialog(PluginJAR jar) 419 { 420 unloaded = new ConcurrentHashMap <String , Object >(); 422 String [] dependents = jar.getDependentPlugins(); 423 if(dependents.length == 0) 424 unloadPluginJAR(jar); 425 else 426 { 427 List<String > closureSet = new LinkedList<String >(); 428 PluginJAR.transitiveClosure(dependents, closureSet); 429 ArrayList<String > listModel = new ArrayList<String >(); 430 listModel.addAll(closureSet); 431 Collections.sort(listModel, new MiscUtilities.StringICaseCompare()); 432 433 int button = GUIUtilities.listConfirm(window,"plugin-manager.dependency", 434 new String [] { jar.getFile().getName() }, listModel.toArray()); 435 if(button == JOptionPane.YES_OPTION) 436 unloadPluginJAR(jar); 437 } 438 } 440 private void unloadPluginJAR(PluginJAR jar) 442 { 443 String [] dependents = jar.getDependentPlugins(); 444 for (String dependent : dependents) 445 { 446 if (!unloaded.containsKey(dependent)) 447 { 448 unloaded.put(dependent, Boolean.TRUE); 449 PluginJAR _jar = jEdit.getPluginJAR(dependent); 450 if(_jar != null) 451 unloadPluginJAR(_jar); 452 } 453 } 454 jEdit.removePluginJAR(jar,false); 455 jEdit.setBooleanProperty("plugin-blacklist."+MiscUtilities.getFileName(jar.getPath()),true); 456 } 458 public void saveSelection(List<String > savedSelection) 460 { 461 if (null != table) 462 { 463 int[] rows = table.getSelectedRows(); 464 for (int i=0 ; i<rows.length ; i++) 465 { 466 savedSelection.add(entries.get(rows[i]).jar); 467 } 468 } 469 } 471 public void restoreSelection(List<String > savedSelection) 473 { 474 if (null != table) 475 { 476 table.setColumnSelectionInterval(0,0); 477 if (!savedSelection.isEmpty()) 478 { 479 int i = 0; 480 int rowCount = getRowCount(); 481 for ( ; i<rowCount ; i++) 482 { 483 if (savedSelection.contains(entries.get(i).jar)) 484 { 485 table.setRowSelectionInterval(i,i); 486 break; 487 } 488 } 489 ListSelectionModel lsm = table.getSelectionModel(); 490 for ( ; i<rowCount ; i++) 491 { 492 if (savedSelection.contains(entries.get(i).jar)) 493 { 494 lsm.addSelectionInterval(i,i); 495 } 496 } 497 } 498 else 499 { 500 if (table.getRowCount() != 0) 501 table.setRowSelectionInterval(0,0); 502 JScrollBar scrollbar = scrollpane.getVerticalScrollBar(); 503 scrollbar.setValue(scrollbar.getMinimum()); 504 } 505 } 506 } } 509 class TextRenderer extends DefaultTableCellRenderer 511 { 512 private final DefaultTableCellRenderer tcr; 513 514 TextRenderer(DefaultTableCellRenderer tcr) 515 { 516 this.tcr = tcr; 517 } 518 519 public Component getTableCellRendererComponent(JTable table, Object value, 520 boolean isSelected, boolean hasFocus, int row, int column) 521 { 522 Entry entry = pluginModel.getEntry(row); 523 if (entry.status.equals(Entry.ERROR)) 524 tcr.setForeground(Color.red); 525 else 526 tcr.setForeground(UIManager.getColor("Table.foreground")); 527 return tcr.getTableCellRendererComponent(table,value,isSelected,false,row,column); 528 } 529 } 531 class HideLibrariesButton extends JCheckBox implements ActionListener 533 { 534 HideLibrariesButton() 535 { 536 super(jEdit.getProperty("plugin-manager.hide-libraries")); 537 setSelected(jEdit.getBooleanProperty( 538 "plugin-manager.hide-libraries.toggle")); 539 addActionListener(this); 540 } 541 542 public void actionPerformed(ActionEvent evt) 543 { 544 jEdit.setBooleanProperty( 545 "plugin-manager.hide-libraries.toggle", 546 isSelected()); 547 ManagePanel.this.update(); 548 } 549 } 551 class RemoveButton extends JButton implements ListSelectionListener , ActionListener 553 { 554 RemoveButton() 555 { 556 super(jEdit.getProperty("manage-plugins.remove")); 557 table.getSelectionModel().addListSelectionListener(this); 558 addActionListener(this); 559 setEnabled(false); 560 } 561 562 public void actionPerformed(ActionEvent evt) 563 { 564 int[] selected = table.getSelectedRows(); 565 566 List<String > listModel = new LinkedList<String >(); 567 Roster roster = new Roster(); 568 for(int i = 0; i < selected.length; i++) 569 { 570 Entry entry = pluginModel.getEntry(selected[i]); 571 for (String jar : entry.jars) 572 { 573 listModel.add(jar); 574 roster.addRemove(jar); 575 table.getSelectionModel().removeSelectionInterval(selected[i], selected[i]); 576 } 577 } 578 int button = GUIUtilities.listConfirm(window, 579 "plugin-manager.remove-confirm", 580 null,listModel.toArray()); 581 if(button == JOptionPane.YES_OPTION) 582 { 583 roster.performOperationsInAWTThread(window); 584 pluginModel.update(); 585 if (table.getRowCount() != 0) 586 table.setRowSelectionInterval(0,0); 587 table.setColumnSelectionInterval(0,0); 588 JScrollBar scrollbar = scrollpane.getVerticalScrollBar(); 589 scrollbar.setValue(scrollbar.getMinimum()); 590 } 591 } 592 593 public void valueChanged(ListSelectionEvent e) 594 { 595 if (table.getSelectedRowCount() == 0) 596 setEnabled(false); 597 else 598 setEnabled(true); 599 } 600 } 602 class HelpButton extends JButton implements ListSelectionListener , ActionListener 604 { 605 private URL docURL; 606 607 HelpButton() 608 { 609 super(jEdit.getProperty("manage-plugins.help")); 610 table.getSelectionModel().addListSelectionListener(this); 611 addActionListener(this); 612 setEnabled(false); 613 } 614 615 public void actionPerformed(ActionEvent evt) 616 { 617 new HelpViewer(docURL); 618 } 619 620 public void valueChanged(ListSelectionEvent e) 621 { 622 if (table.getSelectedRowCount() == 1) 623 { 624 try 625 { 626 Entry entry = pluginModel.getEntry(table.getSelectedRow()); 627 String label = entry.clazz; 628 String docs = entry.docs; 629 if (label != null) { 630 EditPlugin plug = jEdit.getPlugin(label, false); 631 PluginJAR jar = null; 632 if (plug != null) jar = plug.getPluginJAR(); 633 if(jar != null && docs != null) 634 { 635 URL url = jar.getClassLoader().getResource(docs); 636 if(url != null) 637 { 638 docURL = url; 639 setEnabled(true); 640 return; 641 } 642 } 643 } 644 } 645 catch (Exception ex) { 646 Log.log(Log.ERROR, this, "ManagePanel HelpButton Update", ex); 647 } 648 } 649 setEnabled(false); 650 } 651 } 653 private static class EntryCompare implements Comparator<ManagePanel.Entry> 655 { 656 public static final int NAME = 1; 657 public static final int STATUS = 2; 658 659 private final int type; 660 661 EntryCompare(int type) 662 { 663 this.type = type; 664 } 665 666 public int compare(ManagePanel.Entry e1, ManagePanel.Entry e2) 667 { 668 if (type == NAME) 669 return compareNames(e1,e2); 670 else 671 { 672 int result; 673 if ((result = e1.status.compareToIgnoreCase(e2.status)) == 0) 674 return compareNames(e1,e2); 675 return result; 676 } 677 } 678 679 private static int compareNames(ManagePanel.Entry e1, ManagePanel.Entry e2) 680 { 681 String s1; 682 if(e1.name == null) 683 s1 = MiscUtilities.getFileName(e1.jar); 684 else 685 s1 = e1.name; 686 String s2; 687 if(e2.name == null) 688 s2 = MiscUtilities.getFileName(e2.jar); 689 else 690 s2 = e2.name; 691 692 return s1.compareToIgnoreCase(s2); 693 } 694 } 696 class HeaderMouseHandler extends MouseAdapter 698 { 699 public void mouseClicked(MouseEvent evt) 700 { 701 switch(table.getTableHeader().columnAtPoint(evt.getPoint())) 702 { 703 case 1: 704 pluginModel.setSortType(EntryCompare.NAME); 705 break; 706 case 3: 707 pluginModel.setSortType(EntryCompare.STATUS); 708 break; 709 default: 710 break; 711 } 712 } 713 } 715 class KeyboardAction extends AbstractAction 717 { 718 private KeyboardCommand command = KeyboardCommand.NONE; 719 720 KeyboardAction(KeyboardCommand command) 721 { 722 this.command = command; 723 } 724 725 public void actionPerformed(ActionEvent evt) 726 { 727 switch (command) 728 { 729 case TAB_OUT_FORWARD: 730 KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent(); 731 break; 732 case TAB_OUT_BACK: 733 KeyboardFocusManager.getCurrentKeyboardFocusManager().focusPreviousComponent(); 734 break; 735 case EDIT_PLUGIN: 736 List<String > savedSelection = new ArrayList<String >(); 737 pluginModel.saveSelection(savedSelection); 738 int[] rows = table.getSelectedRows(); 739 Object [] state = new Object [rows.length]; 740 for (int i=0 ; i<rows.length ; i++) 741 { 742 state[i] = pluginModel.getValueAt(rows[i],0); 743 } 744 for (int i=0 ; i<rows.length ; i++) 745 { 746 for (int j=0, c=pluginModel.getRowCount() ; j<c ; j++) 747 { 748 if (pluginModel.entries.get(j).jar.equals(savedSelection.get(i))) 749 { 750 pluginModel.setValueAt(state[i].equals(Boolean.FALSE),j,0); 751 break; 752 } 753 } 754 } 755 pluginModel.restoreSelection(savedSelection); 756 break; 757 case CLOSE_PLUGIN_MANAGER: 758 window.ok(); 759 break; 760 default: 761 throw new InternalError (); 762 } 763 } 764 } 766 class TableFocusHandler extends FocusAdapter 768 { 769 public void focusGained(FocusEvent fe) 770 { 771 if (-1 == table.getSelectedRow()) 772 { 773 table.setRowSelectionInterval(0,0); 774 JScrollBar scrollbar = scrollpane.getVerticalScrollBar(); 775 scrollbar.setValue(scrollbar.getMinimum()); 776 } 777 if (-1 == table.getSelectedColumn()) 778 { 779 table.setColumnSelectionInterval(0,0); 780 } 781 } 782 } 784 } 786 | Popular Tags |