1 22 23 package org.gjt.sp.jedit.pluginmgr; 24 25 import javax.swing.border.*; 27 import javax.swing.event.*; 28 import javax.swing.table.*; 29 import javax.swing.*; 30 import java.awt.event.*; 31 import java.awt.*; 32 import java.text.NumberFormat ; 33 import java.util.*; 34 import java.util.List ; 35 36 import org.gjt.sp.jedit.io.VFSManager; 37 import org.gjt.sp.jedit.*; 38 import org.gjt.sp.util.StandardUtilities; 39 41 44 class InstallPanel extends JPanel 45 { 46 InstallPanel(PluginManager window, boolean updates) 48 { 49 super(new BorderLayout(12,12)); 50 51 this.window = window; 52 this.updates = updates; 53 54 setBorder(new EmptyBorder(12,12,12,12)); 55 56 final JSplitPane split = new JSplitPane( 57 JSplitPane.VERTICAL_SPLIT, jEdit.getBooleanProperty("appearance.continuousLayout")); 58 59 60 table = new JTable(pluginModel = new PluginTableModel()); 61 table.setShowGrid(false); 62 table.setIntercellSpacing(new Dimension(0,0)); 63 table.setRowHeight(table.getRowHeight() + 2); 64 table.setPreferredScrollableViewportSize(new Dimension(500,200)); 65 table.setDefaultRenderer(Object .class, new TextRenderer( 66 (DefaultTableCellRenderer)table.getDefaultRenderer(Object .class))); 67 table.addFocusListener(new TableFocusHandler()); 68 InputMap tableInputMap = table.getInputMap(JComponent.WHEN_FOCUSED); 69 ActionMap tableActionMap = table.getActionMap(); 70 tableInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,0),"tabOutForward"); 71 tableActionMap.put("tabOutForward",new KeyboardAction(KeyboardCommand.TAB_OUT_FORWARD)); 72 tableInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,InputEvent.SHIFT_MASK),"tabOutBack"); 73 tableActionMap.put("tabOutBack",new KeyboardAction(KeyboardCommand.TAB_OUT_BACK)); 74 tableInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE,0),"editPlugin"); 75 tableActionMap.put("editPlugin",new KeyboardAction(KeyboardCommand.EDIT_PLUGIN)); 76 tableInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0),"closePluginManager"); 77 tableActionMap.put("closePluginManager",new KeyboardAction(KeyboardCommand.CLOSE_PLUGIN_MANAGER)); 78 79 TableColumn col1 = table.getColumnModel().getColumn(0); 80 TableColumn col2 = table.getColumnModel().getColumn(1); 81 TableColumn col3 = table.getColumnModel().getColumn(2); 82 TableColumn col4 = table.getColumnModel().getColumn(3); 83 TableColumn col5 = table.getColumnModel().getColumn(4); 84 85 col1.setPreferredWidth(30); 86 col1.setMinWidth(30); 87 col1.setMaxWidth(30); 88 col1.setResizable(false); 89 90 col2.setPreferredWidth(180); 91 col3.setPreferredWidth(130); 92 col4.setPreferredWidth(70); 93 col5.setPreferredWidth(70); 94 95 JTableHeader header = table.getTableHeader(); 96 header.setReorderingAllowed(false); 97 header.addMouseListener(new HeaderMouseHandler()); 98 99 scrollpane = new JScrollPane(table); 100 scrollpane.getViewport().setBackground(table.getBackground()); 101 split.setTopComponent(scrollpane); 102 103 104 JScrollPane infoPane = new JScrollPane( 105 infoBox = new PluginInfoBox()); 106 infoPane.setPreferredSize(new Dimension(500,100)); 107 split.setBottomComponent(infoPane); 108 109 SwingUtilities.invokeLater(new Runnable () 110 { 111 public void run() 112 { 113 split.setDividerLocation(0.75); 114 } 115 }); 116 117 add(BorderLayout.CENTER,split); 118 119 120 Box buttons = new Box(BoxLayout.X_AXIS); 121 122 buttons.add(new InstallButton()); 123 buttons.add(Box.createHorizontalStrut(12)); 124 buttons.add(new SelectallButton()); 125 buttons.add(Box.createGlue()); 126 buttons.add(new SizeLabel()); 127 128 add(BorderLayout.SOUTH,buttons); 129 } 131 public void updateModel() 133 { 134 final Set<String > savedChecked = new HashSet<String >(); 135 final Set<String > savedSelection = new HashSet<String >(); 136 pluginModel.saveSelection(savedChecked,savedSelection); 137 pluginModel.clear(); 138 infoBox.setText(jEdit.getProperty("plugin-manager.list-download")); 139 140 VFSManager.runInAWTThread(new Runnable () 141 { 142 public void run() 143 { 144 infoBox.setText(null); 145 pluginModel.update(); 146 pluginModel.restoreSelection(savedChecked,savedSelection); 147 } 148 }); 149 } 151 153 private final JTable table; 155 private JScrollPane scrollpane; 156 private PluginTableModel pluginModel; 157 private PluginManager window; 158 private PluginInfoBox infoBox; 159 160 private boolean updates; 161 163 private static String formatSize(int size) 165 { 166 NumberFormat df = NumberFormat.getInstance(); 167 df.setMaximumFractionDigits(1); 168 df.setMinimumFractionDigits(0); 169 String sizeText; 170 if (size < 1048576) 171 sizeText = (size >> 10) + "KB"; 172 else 173 sizeText = df.format(size/ 1048576.0d) + "MB"; 174 return sizeText; 175 } 177 179 181 public enum KeyboardCommand 183 { 184 NONE, 185 TAB_OUT_FORWARD, 186 TAB_OUT_BACK, 187 EDIT_PLUGIN, 188 CLOSE_PLUGIN_MANAGER 189 } 191 class PluginTableModel extends AbstractTableModel 193 { 194 195 private List entries = new ArrayList(); 196 private int sortType = EntryCompare.NAME; 197 198 public Class getColumnClass(int columnIndex) 200 { 201 switch (columnIndex) 202 { 203 case 0: return Boolean .class; 204 case 1: 205 case 2: 206 case 3: 207 case 4: return Object .class; 208 default: throw new Error ("Column out of range"); 209 } 210 } 212 public int getColumnCount() 214 { 215 return 5; 216 } 218 public String getColumnName(int column) 220 { 221 switch (column) 222 { 223 case 0: return " "; 224 case 1: return ' '+jEdit.getProperty("install-plugins.info.name"); 225 case 2: return ' '+jEdit.getProperty("install-plugins.info.category"); 226 case 3: return ' '+jEdit.getProperty("install-plugins.info.version"); 227 case 4: return ' '+jEdit.getProperty("install-plugins.info.size"); 228 default: throw new Error ("Column out of range"); 229 } 230 } 232 public int getRowCount() 234 { 235 return entries.size(); 236 } 238 public Object getValueAt(int rowIndex,int columnIndex) 240 { 241 Object obj = entries.get(rowIndex); 242 if(obj instanceof String ) 243 { 244 if(columnIndex == 1) 245 return obj; 246 else 247 return null; 248 } 249 else 250 { 251 Entry entry = (Entry)obj; 252 253 switch (columnIndex) 254 { 255 case 0: 256 return entry.install; 257 case 1: 258 return entry.name; 259 case 2: 260 return entry.set; 261 case 3: 262 if (updates) 263 return entry.installedVersion + "->" + entry.version; 264 return entry.version; 265 case 4: 266 return formatSize(entry.size); 267 default: 268 throw new Error ("Column out of range"); 269 } 270 } 271 } 273 public boolean isCellEditable(int rowIndex, int columnIndex) 275 { 276 return columnIndex == 0; 277 } 279 public void setSelectAll(boolean b) 281 { 282 if(isDownloadingList()) 283 return; 284 285 int length = getRowCount(); 286 for (int i = 0; i < length; i++) 287 { 288 if (b) 289 setValueAt(Boolean.TRUE,i,0); 290 else 291 { 292 Entry entry = (Entry)entries.get(i); 293 entry.parents = new LinkedList<Entry>(); 294 entry.install = false; 295 } 296 } 297 fireTableChanged(new TableModelEvent(this)); 298 } 300 public void setSortType(int type) 302 { 303 sortType = type; 304 sort(type); 305 } 307 private void deselectParents(Entry entry) 309 { 310 Entry[] parents = entry.getParents(); 311 312 if (parents.length == 0) 313 return; 314 315 String [] args = { entry.name }; 316 317 int result = GUIUtilities.listConfirm( 318 window,"plugin-manager.dependency", 319 args,parents); 320 if (result != JOptionPane.OK_OPTION) 321 { 322 entry.install = true; 323 return; 324 } 325 326 for(int i = 0; i < parents.length; i++) 327 parents[i].install = false; 328 329 fireTableRowsUpdated(0,getRowCount() - 1); 330 } 332 public void setValueAt(Object aValue, int row, int column) 334 { 335 if (column != 0) return; 336 337 Object obj = entries.get(row); 338 if(obj instanceof String ) 339 return; 340 341 Entry entry = (Entry)obj; 342 entry.install = Boolean.TRUE.equals(aValue); 343 344 if (!entry.install) 345 deselectParents(entry); 346 347 List <PluginList.Dependency> deps = entry.plugin.getCompatibleBranch().deps; 348 349 for (int i = 0; i < deps.size(); i++) 350 { 351 PluginList.Dependency dep = deps.get(i); 352 if (dep.what.equals("plugin")) 353 { 354 for (int j = 0; j < entries.size(); j++) 355 { 356 Entry temp = (Entry)entries.get(j); 357 if (temp.plugin == dep.plugin) 358 { 359 if (entry.install) 360 { 361 temp.parents.add(entry); 362 setValueAt(Boolean.TRUE,j,0); 363 } 364 else 365 temp.parents.remove(entry); 366 } 367 } 368 } 369 } 370 371 fireTableCellUpdated(row,column); 372 } 374 public void sort(int type) 376 { 377 Set<String > savedChecked = new HashSet<String >(); 378 Set<String > savedSelection = new HashSet<String >(); 379 saveSelection(savedChecked,savedSelection); 380 381 sortType = type; 382 383 if(isDownloadingList()) 384 return; 385 386 Collections.sort(entries,new EntryCompare(type)); 387 fireTableChanged(new TableModelEvent(this)); 388 restoreSelection(savedChecked,savedSelection); 389 } 390 392 private boolean isDownloadingList() 394 { 395 return entries.size() == 1 && entries.get(0) instanceof String ; 396 } 398 public void clear() 400 { 401 entries = new ArrayList(); 402 fireTableChanged(new TableModelEvent(this)); 403 } 405 public void update() 407 { 408 Set<String > savedChecked = new HashSet<String >(); 409 Set<String > savedSelection = new HashSet<String >(); 410 saveSelection(savedChecked,savedSelection); 411 412 PluginList pluginList = window.getPluginList(); 413 414 if (pluginList == null) return; 415 416 entries = new ArrayList(); 417 418 for(int i = 0; i < pluginList.pluginSets.size(); i++) 419 { 420 PluginList.PluginSet set = pluginList.pluginSets.get(i); 421 for(int j = 0; j < set.plugins.size(); j++) 422 { 423 PluginList.Plugin plugin = pluginList.pluginHash.get(set.plugins.get(j)); 424 PluginList.Branch branch = plugin.getCompatibleBranch(); 425 String installedVersion = 426 plugin.getInstalledVersion(); 427 if (updates) 428 { 429 if(branch != null 430 && branch.canSatisfyDependencies() 431 && installedVersion != null 432 && StandardUtilities.compareStrings(branch.version, 433 installedVersion,false) > 0) 434 { 435 entries.add(new Entry(plugin,set.name)); 436 } 437 } 438 else 439 { 440 if(installedVersion == null && plugin.canBeInstalled()) 441 entries.add(new Entry(plugin,set.name)); 442 } 443 } 444 } 445 446 sort(sortType); 447 448 fireTableChanged(new TableModelEvent(this)); 449 restoreSelection(savedChecked,savedSelection); 450 } 452 public void saveSelection(Set<String > savedChecked, Set<String > savedSelection) 454 { 455 if (entries.isEmpty()) 456 return; 457 for (int i=0, c=getRowCount() ; i<c ; i++) 458 { 459 if ((Boolean )getValueAt(i,0)) 460 { 461 savedChecked.add(entries.get(i).toString()); 462 } 463 } 464 int[] rows = table.getSelectedRows(); 465 for (int i=0 ; i<rows.length ; i++) 466 { 467 savedSelection.add(entries.get(rows[i]).toString()); 468 } 469 } 471 public void restoreSelection(Set<String > savedChecked, Set<String > savedSelection) 473 { 474 for (int i=0, c=getRowCount() ; i<c ; i++) 475 { 476 setValueAt(savedChecked.contains(entries.get(i).toString()),i,0); 477 } 478 479 if (null != table) 480 { 481 table.setColumnSelectionInterval(0,0); 482 if (!savedSelection.isEmpty()) 483 { 484 int i = 0; 485 int rowCount = getRowCount(); 486 for ( ; i<rowCount ; i++) 487 { 488 if (savedSelection.contains(entries.get(i).toString())) 489 { 490 table.setRowSelectionInterval(i,i); 491 break; 492 } 493 } 494 ListSelectionModel lsm = table.getSelectionModel(); 495 for ( ; i<rowCount ; i++) 496 { 497 if (savedSelection.contains(entries.get(i).toString())) 498 { 499 lsm.addSelectionInterval(i,i); 500 } 501 } 502 } 503 else 504 { 505 if (table.getRowCount() != 0) 506 table.setRowSelectionInterval(0,0); 507 JScrollBar scrollbar = scrollpane.getVerticalScrollBar(); 508 scrollbar.setValue(scrollbar.getMinimum()); 509 } 510 } 511 } } 514 class Entry 516 { 517 String name, installedVersion, version, author, date, description, set; 518 int size; 519 boolean install; 520 PluginList.Plugin plugin; 521 List <Entry> parents = new LinkedList<Entry>(); 522 523 Entry(PluginList.Plugin plugin, String set) 524 { 525 PluginList.Branch branch = plugin.getCompatibleBranch(); 526 boolean downloadSource = jEdit.getBooleanProperty("plugin-manager.downloadSource"); 527 int size = downloadSource ? branch.downloadSourceSize : branch.downloadSize; 528 529 this.name = plugin.name; 530 this.author = plugin.author; 531 this.installedVersion = plugin.getInstalledVersion(); 532 this.version = branch.version; 533 this.size = size; 534 this.date = branch.date; 535 this.description = plugin.description; 536 this.set = set; 537 this.install = false; 538 this.plugin = plugin; 539 } 540 541 private void getParents(List <Entry> list) 542 { 543 for (Entry entry : parents) 544 { 545 if (entry.install && !list.contains(entry)) 546 { 547 list.add(entry); 548 entry.getParents(list); 549 } 550 } 551 } 552 553 Entry[] getParents() 554 { 555 List <Entry> list = new ArrayList<Entry>(); 556 getParents(list); 557 Entry[] array = list.toArray(new Entry[list.size()]); 558 Arrays.sort(array,new MiscUtilities.StringICaseCompare()); 559 return array; 560 } 561 562 public String toString() 563 { 564 return name; 565 } 566 } 568 class PluginInfoBox extends JTextArea implements ListSelectionListener 570 { 571 PluginInfoBox() 572 { 573 setEditable(false); 574 setLineWrap(true); 575 setWrapStyleWord(true); 576 table.getSelectionModel().addListSelectionListener(this); 577 } 578 579 580 public void valueChanged(ListSelectionEvent e) 581 { 582 String text = ""; 583 if (table.getSelectedRowCount() == 1) 584 { 585 Entry entry = (Entry)pluginModel.entries 586 .get(table.getSelectedRow()); 587 text = jEdit.getProperty("install-plugins.info", 588 new String [] {entry.author,entry.date,entry.description}); 589 } 590 setText(text); 591 setCaretPosition(0); 592 } 593 } 595 class SizeLabel extends JLabel implements TableModelListener 597 { 598 private int size; 599 600 SizeLabel() 601 { 602 size = 0; 603 setText(jEdit.getProperty("install-plugins.totalSize")+formatSize(size)); 604 pluginModel.addTableModelListener(this); 605 } 606 607 public void tableChanged(TableModelEvent e) 608 { 609 if (e.getType() == TableModelEvent.UPDATE) 610 { 611 if(pluginModel.isDownloadingList()) 612 return; 613 614 size = 0; 615 int length = pluginModel.getRowCount(); 616 for (int i = 0; i < length; i++) 617 { 618 Entry entry = (Entry)pluginModel 619 .entries.get(i); 620 if (entry.install) 621 size += entry.size; 622 } 623 setText(jEdit.getProperty("install-plugins.totalSize")+formatSize(size)); 624 } 625 } 626 } 628 class SelectallButton extends JCheckBox implements ActionListener, TableModelListener 630 { 631 SelectallButton() 632 { 633 super(jEdit.getProperty("install-plugins.select-all")); 634 addActionListener(this); 635 pluginModel.addTableModelListener(this); 636 setEnabled(false); 637 } 638 639 public void actionPerformed(ActionEvent evt) 640 { 641 pluginModel.setSelectAll(isSelected()); 642 } 643 644 public void tableChanged(TableModelEvent e) 645 { 646 if(pluginModel.isDownloadingList()) 647 return; 648 649 setEnabled(pluginModel.getRowCount() != 0); 650 if (e.getType() == TableModelEvent.UPDATE) 651 { 652 int length = pluginModel.getRowCount(); 653 for (int i = 0; i < length; i++) 654 if (!((Boolean )pluginModel.getValueAt(i,0)).booleanValue()) 655 { 656 setSelected(false); 657 return; 658 } 659 if (length > 0) 660 setSelected(true); 661 } 662 } 663 } 665 class InstallButton extends JButton implements ActionListener, TableModelListener 667 { 668 InstallButton() 669 { 670 super(jEdit.getProperty("install-plugins.install")); 671 pluginModel.addTableModelListener(this); 672 addActionListener(this); 673 setEnabled(false); 674 } 675 676 public void actionPerformed(ActionEvent evt) 677 { 678 if(pluginModel.isDownloadingList()) 679 return; 680 681 boolean downloadSource = jEdit.getBooleanProperty( 682 "plugin-manager.downloadSource"); 683 boolean installUser = jEdit.getBooleanProperty( 684 "plugin-manager.installUser"); 685 Roster roster = new Roster(); 686 String installDirectory; 687 if(installUser) 688 { 689 installDirectory = MiscUtilities.constructPath( 690 jEdit.getSettingsDirectory(),"jars"); 691 } 692 else 693 { 694 installDirectory = MiscUtilities.constructPath( 695 jEdit.getJEditHome(),"jars"); 696 } 697 698 int length = pluginModel.getRowCount(); 699 int instcount = 0; 700 for (int i = 0; i < length; i++) 701 { 702 Entry entry = (Entry)pluginModel.entries.get(i); 703 if (entry.install) 704 { 705 entry.plugin.install(roster,installDirectory,downloadSource); 706 if (updates) 707 entry.plugin.getCompatibleBranch().satisfyDependencies( 708 roster,installDirectory,downloadSource); 709 instcount++; 710 } 711 } 712 713 if(roster.isEmpty()) 714 return; 715 716 boolean cancel = false; 717 if (updates && roster.getOperationCount() > instcount) 718 if (GUIUtilities.confirm(window, 719 "install-plugins.depend", 720 null, 721 JOptionPane.OK_CANCEL_OPTION, 722 JOptionPane.WARNING_MESSAGE) == JOptionPane.CANCEL_OPTION) 723 cancel = true; 724 725 if (!cancel) 726 { 727 new PluginManagerProgress(window,roster); 728 729 roster.performOperationsInAWTThread(window); 730 pluginModel.update(); 731 } 732 } 733 734 public void tableChanged(TableModelEvent e) 735 { 736 if(pluginModel.isDownloadingList()) 737 return; 738 739 if (e.getType() == TableModelEvent.UPDATE) 740 { 741 int length = pluginModel.getRowCount(); 742 for (int i = 0; i < length; i++) 743 if (((Boolean )pluginModel.getValueAt(i,0)).booleanValue()) 744 { 745 setEnabled(true); 746 return; 747 } 748 setEnabled(false); 749 } 750 } 751 } 753 static class EntryCompare implements Comparator 755 { 756 public static final int NAME = 0; 757 public static final int CATEGORY = 1; 758 759 private int type; 760 761 EntryCompare(int type) 762 { 763 this.type = type; 764 } 765 766 public int compare(Object o1, Object o2) 767 { 768 InstallPanel.Entry e1 = (InstallPanel.Entry)o1; 769 InstallPanel.Entry e2 = (InstallPanel.Entry)o2; 770 771 if (type == NAME) 772 return e1.name.compareToIgnoreCase(e2.name); 773 else 774 { 775 int result; 776 if ((result = e1.set.compareToIgnoreCase(e2.set)) == 0) 777 return e1.name.compareToIgnoreCase(e2.name); 778 return result; 779 } 780 } 781 } 783 class HeaderMouseHandler extends MouseAdapter 785 { 786 public void mouseClicked(MouseEvent evt) 787 { 788 switch(table.getTableHeader().columnAtPoint(evt.getPoint())) 789 { 790 case 1: 791 pluginModel.sort(EntryCompare.NAME); 792 break; 793 case 2: 794 pluginModel.sort(EntryCompare.CATEGORY); 795 break; 796 default: 797 } 798 } 799 } 801 static class TextRenderer extends DefaultTableCellRenderer 803 { 804 private DefaultTableCellRenderer tcr; 805 806 TextRenderer(DefaultTableCellRenderer tcr) 807 { 808 this.tcr = tcr; 809 } 810 811 public Component getTableCellRendererComponent(JTable table, Object value, 812 boolean isSelected, boolean hasFocus, int row, int column) 813 { 814 return tcr.getTableCellRendererComponent(table,value,isSelected,false,row,column); 815 } 816 } 818 class KeyboardAction extends AbstractAction 820 { 821 private KeyboardCommand command = KeyboardCommand.NONE; 822 823 KeyboardAction(KeyboardCommand command) 824 { 825 this.command = command; 826 } 827 828 public void actionPerformed(ActionEvent evt) 829 { 830 switch (command) 831 { 832 case TAB_OUT_FORWARD: 833 KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent(); 834 break; 835 case TAB_OUT_BACK: 836 KeyboardFocusManager.getCurrentKeyboardFocusManager().focusPreviousComponent(); 837 break; 838 case EDIT_PLUGIN: 839 int[] rows = table.getSelectedRows(); 840 Object [] state = new Object [rows.length]; 841 for (int i=0 ; i<rows.length ; i++) 842 { 843 state[i] = pluginModel.getValueAt(rows[i],0); 844 } 845 for (int i=0 ; i<rows.length ; i++) 846 { 847 pluginModel.setValueAt(state[i].equals(Boolean.FALSE),rows[i],0); 848 } 849 break; 850 case CLOSE_PLUGIN_MANAGER: 851 window.ok(); 852 break; 853 default: 854 throw new InternalError (); 855 } 856 } 857 } 859 class TableFocusHandler extends FocusAdapter 861 { 862 public void focusGained(FocusEvent fe) 863 { 864 if (-1 == table.getSelectedRow() && table.getRowCount() > 0) 865 { 866 table.setRowSelectionInterval(0,0); 867 JScrollBar scrollbar = scrollpane.getVerticalScrollBar(); 868 scrollbar.setValue(scrollbar.getMinimum()); 869 } 870 if (-1 == table.getSelectedColumn()) 871 { 872 table.setColumnSelectionInterval(0,0); 873 } 874 } 875 } 877 } 879 | Popular Tags |