PageRenderTime 63ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-5-pre1/org/gjt/sp/jedit/pluginmgr/InstallPanel.java

#
Java | 1319 lines | 1087 code | 135 blank | 97 comment | 164 complexity | 62e080c19f453e994b6db702d62b0b28 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * InstallPanel.java - For installing plugins
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2002 Kris Kopicki
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. */
  22. package org.gjt.sp.jedit.pluginmgr;
  23. //{{{ Imports
  24. import org.gjt.sp.jedit.*;
  25. import org.gjt.sp.jedit.browser.VFSBrowser;
  26. import org.gjt.sp.jedit.gui.RolloverButton;
  27. import org.gjt.sp.jedit.io.VFS;
  28. import org.gjt.sp.jedit.io.VFSManager;
  29. import org.gjt.sp.util.Log;
  30. import org.gjt.sp.util.StandardUtilities;
  31. import org.gjt.sp.util.ThreadUtilities;
  32. import org.gjt.sp.util.XMLUtilities;
  33. import org.xml.sax.Attributes;
  34. import org.xml.sax.SAXException;
  35. import org.xml.sax.helpers.DefaultHandler;
  36. import javax.swing.*;
  37. import javax.swing.border.EmptyBorder;
  38. import javax.swing.event.ListSelectionEvent;
  39. import javax.swing.event.ListSelectionListener;
  40. import javax.swing.event.DocumentEvent;
  41. import javax.swing.event.DocumentListener;
  42. import javax.swing.event.TableModelEvent;
  43. import javax.swing.event.TableModelListener;
  44. import javax.swing.table.AbstractTableModel;
  45. import javax.swing.table.DefaultTableCellRenderer;
  46. import javax.swing.table.JTableHeader;
  47. import javax.swing.table.TableColumn;
  48. import javax.swing.text.html.HTMLEditorKit;
  49. import java.awt.*;
  50. import java.awt.event.*;
  51. import java.io.File;
  52. import java.io.InputStream;
  53. import java.text.NumberFormat;
  54. import java.text.ParseException;
  55. import java.text.SimpleDateFormat;
  56. import java.util.*;
  57. import java.util.List;
  58. //}}}
  59. /**
  60. * @version $Id: InstallPanel.java 19765 2011-08-08 12:41:01Z kpouer $
  61. */
  62. class InstallPanel extends JPanel implements EBComponent
  63. {
  64. //{{{ Variables
  65. private final JTable table;
  66. private final JScrollPane scrollpane;
  67. private final PluginTableModel pluginModel;
  68. private final PluginManager window;
  69. private final PluginInfoBox infoBox;
  70. private final ChoosePluginSet chooseButton;
  71. private final boolean updates;
  72. private final Collection<String> pluginSet = new HashSet<String>();
  73. //}}}
  74. //{{{ InstallPanel constructor
  75. InstallPanel(PluginManager window, boolean updates)
  76. {
  77. super(new BorderLayout(12,12));
  78. this.window = window;
  79. this.updates = updates;
  80. setBorder(new EmptyBorder(12,12,12,12));
  81. final JSplitPane split = new JSplitPane(
  82. JSplitPane.VERTICAL_SPLIT, jEdit.getBooleanProperty("appearance.continuousLayout"));
  83. split.setResizeWeight(0.75);
  84. /* Setup the table */
  85. table = new JTable(pluginModel = new PluginTableModel());
  86. table.setShowGrid(false);
  87. table.setIntercellSpacing(new Dimension(0,0));
  88. table.setRowHeight(table.getRowHeight() + 2);
  89. table.setPreferredScrollableViewportSize(new Dimension(500,200));
  90. table.setDefaultRenderer(Object.class, new TextRenderer(
  91. (DefaultTableCellRenderer)table.getDefaultRenderer(Object.class)));
  92. table.addFocusListener(new TableFocusHandler());
  93. InputMap tableInputMap = table.getInputMap(JComponent.WHEN_FOCUSED);
  94. ActionMap tableActionMap = table.getActionMap();
  95. tableInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,0),"tabOutForward");
  96. tableActionMap.put("tabOutForward",new KeyboardAction(KeyboardCommand.TAB_OUT_FORWARD));
  97. tableInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,InputEvent.SHIFT_MASK),"tabOutBack");
  98. tableActionMap.put("tabOutBack",new KeyboardAction(KeyboardCommand.TAB_OUT_BACK));
  99. tableInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE,0),"editPlugin");
  100. tableActionMap.put("editPlugin",new KeyboardAction(KeyboardCommand.EDIT_PLUGIN));
  101. tableInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0),"closePluginManager");
  102. tableActionMap.put("closePluginManager",new KeyboardAction(KeyboardCommand.CLOSE_PLUGIN_MANAGER));
  103. TableColumn col1 = table.getColumnModel().getColumn(0);
  104. TableColumn col2 = table.getColumnModel().getColumn(1);
  105. TableColumn col3 = table.getColumnModel().getColumn(2);
  106. TableColumn col4 = table.getColumnModel().getColumn(3);
  107. TableColumn col5 = table.getColumnModel().getColumn(4);
  108. col1.setPreferredWidth(30);
  109. col1.setMinWidth(30);
  110. col1.setMaxWidth(30);
  111. col1.setResizable(false);
  112. col2.setPreferredWidth(180);
  113. col3.setPreferredWidth(130);
  114. col4.setPreferredWidth(70);
  115. col5.setPreferredWidth(70);
  116. JTableHeader header = table.getTableHeader();
  117. header.setReorderingAllowed(false);
  118. header.addMouseListener(new HeaderMouseHandler());
  119. header.setDefaultRenderer(new HeaderRenderer(
  120. (DefaultTableCellRenderer)header.getDefaultRenderer()));
  121. scrollpane = new JScrollPane(table);
  122. scrollpane.getViewport().setBackground(table.getBackground());
  123. split.setTopComponent(scrollpane);
  124. /* Create description */
  125. JScrollPane infoPane = new JScrollPane(
  126. infoBox = new PluginInfoBox());
  127. infoPane.setPreferredSize(new Dimension(500,100));
  128. split.setBottomComponent(infoPane);
  129. EventQueue.invokeLater(new Runnable()
  130. {
  131. @Override
  132. public void run()
  133. {
  134. split.setDividerLocation(0.75);
  135. }
  136. });
  137. final JTextField searchField = new JTextField();
  138. searchField.addKeyListener(new KeyAdapter()
  139. {
  140. @Override
  141. public void keyPressed(KeyEvent e)
  142. {
  143. if (e.getKeyCode() == KeyEvent.VK_DOWN || e.getKeyCode() == KeyEvent.VK_UP)
  144. {
  145. table.dispatchEvent(e);
  146. table.requestFocus();
  147. }
  148. }
  149. });
  150. searchField.getDocument().addDocumentListener(new DocumentListener()
  151. {
  152. void update()
  153. {
  154. pluginModel.setFilterString(searchField.getText());
  155. }
  156. @Override
  157. public void changedUpdate(DocumentEvent e)
  158. {
  159. update();
  160. }
  161. @Override
  162. public void insertUpdate(DocumentEvent e)
  163. {
  164. update();
  165. }
  166. @Override
  167. public void removeUpdate(DocumentEvent e)
  168. {
  169. update();
  170. }
  171. });
  172. table.addKeyListener(new KeyAdapter()
  173. {
  174. @Override
  175. public void keyPressed(KeyEvent e)
  176. {
  177. int i = table.getSelectedRow(), n = table.getModel().getRowCount();
  178. if (e.getKeyCode() == KeyEvent.VK_DOWN && i == (n - 1) ||
  179. e.getKeyCode() == KeyEvent.VK_UP && i == 0)
  180. {
  181. searchField.requestFocus();
  182. searchField.selectAll();
  183. }
  184. }
  185. });
  186. Box filterBox = Box.createHorizontalBox();
  187. filterBox.add(new JLabel("Filter : "));
  188. filterBox.add(searchField);
  189. add(BorderLayout.NORTH,filterBox);
  190. add(BorderLayout.CENTER,split);
  191. /* Create buttons */
  192. Box buttons = new Box(BoxLayout.X_AXIS);
  193. buttons.add(new InstallButton());
  194. buttons.add(Box.createHorizontalStrut(12));
  195. buttons.add(new SelectallButton());
  196. buttons.add(chooseButton = new ChoosePluginSet());
  197. buttons.add(new ClearPluginSet());
  198. buttons.add(Box.createGlue());
  199. buttons.add(new SizeLabel());
  200. add(BorderLayout.SOUTH,buttons);
  201. String path = jEdit.getProperty(PluginManager.PROPERTY_PLUGINSET, "");
  202. if (!path.isEmpty())
  203. {
  204. loadPluginSet(path);
  205. }
  206. } //}}}
  207. //{{{ loadPluginSet() method
  208. /** loads a pluginSet xml file and updates the model to reflect
  209. certain checked selections
  210. @since jEdit 4.3pre10
  211. @author Alan Ezust
  212. */
  213. boolean loadPluginSet(String path)
  214. {
  215. pluginSet.clear();
  216. pluginModel.restoreSelection(new HashSet<String>(), new HashSet<String>());
  217. VFS vfs = VFSManager.getVFSForPath(path);
  218. Object session = vfs.createVFSSession(path, InstallPanel.this);
  219. try
  220. {
  221. InputStream is = vfs._createInputStream(session, path, false, InstallPanel.this);
  222. XMLUtilities.parseXML(is, new StringMapHandler());
  223. }
  224. catch (Exception e)
  225. {
  226. Log.log(Log.WARNING, this, "Loading Pluginset failed:" + e.getMessage());
  227. return false;
  228. }
  229. pluginModel.update();
  230. return true;
  231. } //}}}
  232. //{{{ updateModel() method
  233. public void updateModel()
  234. {
  235. final Set<String> savedChecked = new HashSet<String>();
  236. final Set<String> savedSelection = new HashSet<String>();
  237. pluginModel.saveSelection(savedChecked, savedSelection);
  238. pluginModel.clear();
  239. infoBox.setText(jEdit.getProperty("plugin-manager.list-download"));
  240. ThreadUtilities.runInDispatchThread(new Runnable()
  241. {
  242. @Override
  243. public void run()
  244. {
  245. infoBox.setText(null);
  246. pluginModel.update();
  247. pluginModel.restoreSelection(savedChecked, savedSelection);
  248. }
  249. });
  250. } //}}}
  251. //{{{ handleMessage() method
  252. @Override
  253. public void handleMessage(EBMessage message)
  254. {
  255. if (message.getSource() == PluginManager.getInstance())
  256. {
  257. chooseButton.path = jEdit.getProperty(PluginManager.PROPERTY_PLUGINSET, "");
  258. if (chooseButton.path.length() > 0)
  259. {
  260. loadPluginSet(chooseButton.path);
  261. pluginModel.restoreSelection(new HashSet<String>(), new HashSet<String>());
  262. chooseButton.updateUI();
  263. }
  264. }
  265. } //}}}
  266. //{{{ Private members
  267. //{{{ formatSize() method
  268. private static String formatSize(int size)
  269. {
  270. NumberFormat df = NumberFormat.getInstance();
  271. df.setMaximumFractionDigits(1);
  272. df.setMinimumFractionDigits(0);
  273. String sizeText;
  274. if (size < 1048576)
  275. sizeText = (size >> 10) + "KB";
  276. else
  277. sizeText = df.format(size/ 1048576.0d) + "MB";
  278. return sizeText;
  279. } //}}}
  280. //}}}
  281. //{{{ Inner classes
  282. //{{{ PluginTableModel class
  283. private class PluginTableModel extends AbstractTableModel
  284. {
  285. /** This List can contain String or Entry. */
  286. private final List entries = new ArrayList();
  287. private final List filteredEntries = new ArrayList();
  288. private int sortType = EntryCompare.COLUMN_NAME;
  289. private String filterString;
  290. int sortDirection = 1;
  291. //{{{ setFilterString() method
  292. public void setFilterString(String filterString)
  293. {
  294. this.filterString = filterString;
  295. updateFilteredEntries();
  296. } //}}}
  297. //{{{ updateFilteredEntries() method
  298. void updateFilteredEntries()
  299. {
  300. filteredEntries.clear();
  301. if (filterString == null)
  302. filteredEntries.addAll(entries);
  303. else
  304. {
  305. String[] words = filterString.toLowerCase().split("\\s+");
  306. for (Object o : entries)
  307. {
  308. if (!(o instanceof Entry))
  309. continue;
  310. Entry e = (Entry)o;
  311. if (e.install)
  312. {
  313. filteredEntries.add(e);
  314. continue;
  315. }
  316. String s = (e.name + ' ' + e.set + ' ' + e.description).toLowerCase();
  317. boolean hasAll = true;
  318. boolean negative = false;
  319. for (String word : words)
  320. {
  321. if (word.startsWith("-"))
  322. {
  323. word = word.substring(1);
  324. negative = true;
  325. }
  326. if (word.length() == 0)
  327. continue;
  328. if (negative == s.contains(word))
  329. {
  330. hasAll = false;
  331. break;
  332. }
  333. negative = false;
  334. }
  335. if (hasAll)
  336. filteredEntries.add(e);
  337. }
  338. }
  339. fireTableChanged(new TableModelEvent(PluginTableModel.this));
  340. } //}}}
  341. //{{{ getColumnClass() method
  342. @Override
  343. public Class getColumnClass(int columnIndex)
  344. {
  345. switch (columnIndex)
  346. {
  347. case 0: return Boolean.class;
  348. case 1:
  349. case 2:
  350. case 3:
  351. case 4:
  352. case 5: return Object.class;
  353. default: throw new Error("Column out of range");
  354. }
  355. } //}}}
  356. //{{{ getColumnCount() method
  357. @Override
  358. public int getColumnCount()
  359. {
  360. return 6;
  361. } //}}}
  362. //{{{ getColumnName() method
  363. @Override
  364. public String getColumnName(int column)
  365. {
  366. switch (column)
  367. {
  368. case 0: return " ";
  369. case 1: return ' '+jEdit.getProperty("install-plugins.info.name");
  370. case 2: return ' '+jEdit.getProperty("install-plugins.info.category");
  371. case 3: return ' '+jEdit.getProperty("install-plugins.info.version");
  372. case 4: return ' '+jEdit.getProperty("install-plugins.info.size");
  373. case 5: return ' '+jEdit.getProperty("install-plugins.info.releaseDate");
  374. default: throw new Error("Column out of range");
  375. }
  376. } //}}}
  377. //{{{ getRowCount() method
  378. @Override
  379. public int getRowCount()
  380. {
  381. return filteredEntries.size();
  382. } //}}}
  383. //{{{ getValueAt() method
  384. @Override
  385. public Object getValueAt(int rowIndex,int columnIndex)
  386. {
  387. Object obj = filteredEntries.get(rowIndex);
  388. if(obj instanceof String)
  389. {
  390. if(columnIndex == 1)
  391. return obj;
  392. else
  393. return null;
  394. }
  395. else
  396. {
  397. Entry entry = (Entry)obj;
  398. switch (columnIndex)
  399. {
  400. case 0:
  401. return entry.install;
  402. case 1:
  403. return entry.name;
  404. case 2:
  405. return entry.set;
  406. case 3:
  407. if (updates)
  408. return entry.installedVersion + "->" + entry.version;
  409. return entry.version;
  410. case 4:
  411. return formatSize(entry.size);
  412. case 5:
  413. return entry.date;
  414. default:
  415. throw new Error("Column out of range");
  416. }
  417. }
  418. } //}}}
  419. //{{{ isCellEditable() method
  420. @Override
  421. public boolean isCellEditable(int rowIndex, int columnIndex)
  422. {
  423. return columnIndex == 0;
  424. } //}}}
  425. //{{{ setSelectAll() method
  426. public void setSelectAll(boolean b)
  427. {
  428. if(isDownloadingList())
  429. return;
  430. int length = getRowCount();
  431. for (int i = 0; i < length; i++)
  432. {
  433. if (b)
  434. setValueAt(Boolean.TRUE,i,0);
  435. else
  436. {
  437. Entry entry = (Entry)filteredEntries.get(i);
  438. entry.parents = new LinkedList<Entry>();
  439. entry.install = false;
  440. }
  441. }
  442. fireTableChanged(new TableModelEvent(this));
  443. } //}}}
  444. //{{{ setSortType() method
  445. public void setSortType(int type)
  446. {
  447. sortType = type;
  448. sort(type);
  449. } //}}}
  450. //{{{ deselectParents() method
  451. private void deselectParents(Entry entry)
  452. {
  453. Entry[] parents = entry.getParents();
  454. if (parents.length == 0)
  455. return;
  456. String[] args = { entry.name };
  457. int result = GUIUtilities.listConfirm(
  458. window,"plugin-manager.dependency",
  459. args,parents);
  460. if (result != JOptionPane.OK_OPTION)
  461. {
  462. entry.install = true;
  463. return;
  464. }
  465. for(int i = 0; i < parents.length; i++)
  466. parents[i].install = false;
  467. fireTableRowsUpdated(0,getRowCount() - 1);
  468. } //}}}
  469. //{{{ setValueAt() method
  470. @Override
  471. public void setValueAt(Object aValue, int row, int column)
  472. {
  473. if (column != 0) return;
  474. Object obj = filteredEntries.get(row);
  475. if(obj instanceof String)
  476. return;
  477. Entry entry = (Entry)obj;
  478. boolean before = entry.install;
  479. entry.install = Boolean.TRUE.equals(aValue);
  480. if (before == entry.install) return;
  481. if (!entry.install)
  482. deselectParents(entry);
  483. List<PluginList.Dependency> deps = entry.plugin.getCompatibleBranch().deps;
  484. for (int i = 0; i < deps.size(); i++)
  485. {
  486. PluginList.Dependency dep = deps.get(i);
  487. if ("plugin".equals(dep.what))
  488. {
  489. boolean found = false;
  490. for (int j = 0; j < filteredEntries.size(); j++)
  491. {
  492. Entry temp = (Entry)filteredEntries.get(j);
  493. if (temp.plugin == dep.plugin)
  494. {
  495. found = true;
  496. if (entry.install)
  497. {
  498. temp.parents.add(entry);
  499. setValueAt(Boolean.TRUE,j,0);
  500. }
  501. else
  502. temp.parents.remove(entry);
  503. break;
  504. }
  505. }
  506. if (!found)
  507. {
  508. // the dependency was not found in the filtered list so we search in
  509. // global list.
  510. for (int a = 0;a<entries.size();a++)
  511. {
  512. Entry temp = (Entry) entries.get(a);
  513. if (temp.plugin == dep.plugin)
  514. {
  515. if (entry.install)
  516. {
  517. temp.parents.add(entry);
  518. temp.install = true;
  519. }
  520. else
  521. temp.parents.remove(entry);
  522. break;
  523. }
  524. }
  525. }
  526. }
  527. }
  528. updateFilteredEntries();
  529. } //}}}
  530. //{{{ sort() method
  531. public void sort(int type)
  532. {
  533. Set<String> savedChecked = new HashSet<String>();
  534. Set<String> savedSelection = new HashSet<String>();
  535. saveSelection(savedChecked,savedSelection);
  536. if (sortType != type)
  537. {
  538. sortDirection = 1;
  539. }
  540. sortType = type;
  541. if(isDownloadingList())
  542. return;
  543. Collections.sort(entries,new EntryCompare(type, sortDirection));
  544. updateFilteredEntries();
  545. restoreSelection(savedChecked,savedSelection);
  546. table.getTableHeader().repaint();
  547. }
  548. //}}}
  549. //{{{ isDownloadingList() method
  550. private boolean isDownloadingList()
  551. {
  552. return entries.size() == 1 && entries.get(0) instanceof String;
  553. } //}}}
  554. //{{{ clear() method
  555. public void clear()
  556. {
  557. entries.clear();
  558. updateFilteredEntries();
  559. } //}}}
  560. //{{{ update() method
  561. public void update()
  562. {
  563. Set<String> savedChecked = new HashSet<String>();
  564. Set<String> savedSelection = new HashSet<String>();
  565. saveSelection(savedChecked,savedSelection);
  566. PluginList pluginList = window.getPluginList();
  567. if (pluginList == null) return;
  568. entries.clear();
  569. for(int i = 0; i < pluginList.pluginSets.size(); i++)
  570. {
  571. PluginList.PluginSet set = pluginList.pluginSets.get(i);
  572. for(int j = 0; j < set.plugins.size(); j++)
  573. {
  574. PluginList.Plugin plugin = pluginList.pluginHash.get(set.plugins.get(j));
  575. PluginList.Branch branch = plugin.getCompatibleBranch();
  576. String installedVersion =
  577. plugin.getInstalledVersion();
  578. if (updates)
  579. {
  580. if(branch != null
  581. && branch.canSatisfyDependencies()
  582. && installedVersion != null
  583. && StandardUtilities.compareStrings(branch.version,
  584. installedVersion,false) > 0)
  585. {
  586. entries.add(new Entry(plugin, set.name));
  587. }
  588. }
  589. else
  590. {
  591. if(installedVersion == null && plugin.canBeInstalled())
  592. entries.add(new Entry(plugin,set.name));
  593. }
  594. }
  595. }
  596. sort(sortType);
  597. updateFilteredEntries();
  598. restoreSelection(savedChecked, savedSelection);
  599. } //}}}
  600. //{{{ saveSelection() method
  601. public void saveSelection(Set<String> savedChecked, Set<String> savedSelection)
  602. {
  603. if (entries.isEmpty())
  604. return;
  605. for (int i=0, c=getRowCount() ; i<c ; i++)
  606. {
  607. if ((Boolean)getValueAt(i,0))
  608. {
  609. savedChecked.add(filteredEntries.get(i).toString());
  610. }
  611. }
  612. int[] rows = table.getSelectedRows();
  613. for (int i=0 ; i<rows.length ; i++)
  614. {
  615. savedSelection.add(filteredEntries.get(rows[i]).toString());
  616. }
  617. } //}}}
  618. //{{{ restoreSelection() method
  619. public void restoreSelection(Set<String> savedChecked, Set<String> savedSelection)
  620. {
  621. for (int i=0, c=getRowCount() ; i<c ; i++)
  622. {
  623. Object obj = filteredEntries.get(i);
  624. String name = obj.toString();
  625. if (obj instanceof Entry)
  626. {
  627. name = ((Entry)obj).plugin.jar;
  628. }
  629. if (pluginSet.contains(name))
  630. setValueAt(true, i, 0);
  631. else setValueAt(savedChecked.contains(name), i, 0);
  632. }
  633. if (table == null) return;
  634. table.setColumnSelectionInterval(0,0);
  635. if (!savedSelection.isEmpty())
  636. {
  637. int i = 0;
  638. int rowCount = getRowCount();
  639. for ( ; i<rowCount ; i++)
  640. {
  641. String name = filteredEntries.get(i).toString();
  642. if (savedSelection.contains(name))
  643. {
  644. table.setRowSelectionInterval(i,i);
  645. break;
  646. }
  647. }
  648. ListSelectionModel lsm = table.getSelectionModel();
  649. for ( ; i<rowCount ; i++)
  650. {
  651. String name = filteredEntries.get(i).toString();
  652. if (savedSelection.contains(name))
  653. {
  654. lsm.addSelectionInterval(i,i);
  655. }
  656. }
  657. }
  658. else
  659. {
  660. if (table.getRowCount() != 0)
  661. table.setRowSelectionInterval(0,0);
  662. JScrollBar scrollbar = scrollpane.getVerticalScrollBar();
  663. scrollbar.setValue(scrollbar.getMinimum());
  664. }
  665. } //}}}
  666. } //}}}
  667. //{{{ Entry class
  668. private static class Entry
  669. {
  670. String name, installedVersion, version, author, date, description, set;
  671. long timestamp;
  672. int size;
  673. boolean install;
  674. PluginList.Plugin plugin;
  675. List<Entry> parents = new LinkedList<Entry>();
  676. Entry(PluginList.Plugin plugin, String set)
  677. {
  678. PluginList.Branch branch = plugin.getCompatibleBranch();
  679. boolean downloadSource = jEdit.getBooleanProperty("plugin-manager.downloadSource");
  680. int size = downloadSource ? branch.downloadSourceSize : branch.downloadSize;
  681. this.name = plugin.name;
  682. this.author = plugin.author;
  683. this.installedVersion = plugin.getInstalledVersion();
  684. this.version = branch.version;
  685. this.size = size;
  686. this.date = branch.date;
  687. this.description = plugin.description;
  688. this.set = set;
  689. this.install = false;
  690. this.plugin = plugin;
  691. SimpleDateFormat format = new SimpleDateFormat("d MMMM yyyy", Locale.ENGLISH);
  692. try
  693. {
  694. timestamp = format.parse(date).getTime();
  695. }
  696. catch (ParseException e)
  697. {
  698. Log.log(Log.ERROR, this, e);
  699. }
  700. }
  701. private void getParents(List<Entry> list)
  702. {
  703. for (Entry entry : parents)
  704. {
  705. if (entry.install && !list.contains(entry))
  706. {
  707. list.add(entry);
  708. entry.getParents(list);
  709. }
  710. }
  711. }
  712. Entry[] getParents()
  713. {
  714. List<Entry> list = new ArrayList<Entry>();
  715. getParents(list);
  716. Entry[] array = list.toArray(new Entry[list.size()]);
  717. Arrays.sort(array,new StandardUtilities.StringCompare<Entry>(true));
  718. return array;
  719. }
  720. @Override
  721. public String toString()
  722. {
  723. return name;
  724. }
  725. } //}}}
  726. //{{{ PluginInfoBox class
  727. /**
  728. * @TODO refactor to use the PluginDetailPanel?
  729. */
  730. private class PluginInfoBox extends JTextPane implements ListSelectionListener
  731. {
  732. private final String[] params;
  733. PluginInfoBox()
  734. {
  735. setBackground(jEdit.getColorProperty("view.bgColor"));
  736. setForeground(jEdit.getColorProperty("view.fgColor"));
  737. putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, true);
  738. setEditable(false);
  739. setEditorKit(new HTMLEditorKit());
  740. // setLineWrap(true);
  741. // setWrapStyleWord(true);
  742. params = new String[3];
  743. table.getSelectionModel().addListSelectionListener(this);
  744. }
  745. @Override
  746. public void valueChanged(ListSelectionEvent e)
  747. {
  748. String text = "";
  749. if (table.getSelectedRowCount() == 1)
  750. {
  751. Entry entry = (Entry) pluginModel.filteredEntries
  752. .get(table.getSelectedRow());
  753. params[0] = entry.author;
  754. params[1] = entry.date;
  755. params[2] = entry.description;
  756. text = jEdit.getProperty("install-plugins.info", params);
  757. text = text.replace("\n", "<br>");
  758. text = "<html>" + text + "</html>";
  759. }
  760. setText(text);
  761. setCaretPosition(0);
  762. }
  763. } //}}}
  764. //{{{ SizeLabel class
  765. private class SizeLabel extends JLabel implements TableModelListener
  766. {
  767. private int size;
  768. private int nbPlugins;
  769. SizeLabel()
  770. {
  771. update();
  772. pluginModel.addTableModelListener(this);
  773. }
  774. @Override
  775. public void tableChanged(TableModelEvent e)
  776. {
  777. if (e.getType() == TableModelEvent.UPDATE)
  778. {
  779. if(pluginModel.isDownloadingList())
  780. return;
  781. size = 0;
  782. nbPlugins = 0;
  783. int length = pluginModel.entries.size();
  784. for (int i = 0; i < length; i++)
  785. {
  786. Entry entry = (Entry)pluginModel
  787. .entries.get(i);
  788. if (entry.install)
  789. {
  790. nbPlugins++;
  791. size += entry.size;
  792. }
  793. }
  794. update();
  795. }
  796. }
  797. private void update()
  798. {
  799. Object[] args = {nbPlugins, formatSize(size)};
  800. setText(jEdit.getProperty("install-plugins.totalSize", args));
  801. }
  802. } //}}}
  803. //{{{ SelectallButton class
  804. private class SelectallButton extends JCheckBox implements ActionListener, TableModelListener
  805. {
  806. SelectallButton()
  807. {
  808. super(jEdit.getProperty("install-plugins.select-all"));
  809. addActionListener(this);
  810. pluginModel.addTableModelListener(this);
  811. setEnabled(false);
  812. }
  813. @Override
  814. public void actionPerformed(ActionEvent evt)
  815. {
  816. pluginModel.setSelectAll(isSelected());
  817. }
  818. @Override
  819. public void tableChanged(TableModelEvent e)
  820. {
  821. if(pluginModel.isDownloadingList())
  822. return;
  823. setEnabled(pluginModel.getRowCount() != 0);
  824. if (e.getType() == TableModelEvent.UPDATE)
  825. {
  826. int length = pluginModel.getRowCount();
  827. for (int i = 0; i < length; i++)
  828. if (!((Boolean)pluginModel.getValueAt(i,0)).booleanValue())
  829. {
  830. setSelected(false);
  831. return;
  832. }
  833. if (length > 0)
  834. setSelected(true);
  835. }
  836. }
  837. } //}}}
  838. //{{{ StringMapHandler class
  839. /** For parsing the pluginset xml files into pluginSet */
  840. private class StringMapHandler extends DefaultHandler
  841. {
  842. StringMapHandler()
  843. {
  844. pluginSet.clear();
  845. }
  846. @Override
  847. public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException
  848. {
  849. if ("plugin".equals(localName))
  850. {
  851. pluginSet.add(attrs.getValue("jar"));
  852. }
  853. }
  854. } //}}}
  855. //{{{ ChoosePluginSet class
  856. private class ChoosePluginSet extends RolloverButton implements ActionListener
  857. {
  858. private String path;
  859. //{{{ ChoosePluginSet constructor
  860. ChoosePluginSet()
  861. {
  862. setIcon(GUIUtilities.loadIcon(jEdit.getProperty("install-plugins.choose-plugin-set.icon")));
  863. addActionListener(this);
  864. updateUI();
  865. } //}}}
  866. //{{{ updateUI method
  867. @Override
  868. public void updateUI()
  869. {
  870. path = jEdit.getProperty(PluginManager.PROPERTY_PLUGINSET, "");
  871. if (path.length()<1) setToolTipText ("Click here to choose a predefined plugin set");
  872. else setToolTipText ("Choose pluginset (" + path + ')');
  873. super.updateUI();
  874. }//}}}
  875. //{{{ actionPerformed() method
  876. @Override
  877. public void actionPerformed(ActionEvent ae)
  878. {
  879. path = jEdit.getProperty(PluginManager.PROPERTY_PLUGINSET,
  880. jEdit.getSettingsDirectory() + File.separator);
  881. String[] selectedFiles = GUIUtilities.showVFSFileDialog(InstallPanel.this.window,
  882. jEdit.getActiveView(), path, VFSBrowser.OPEN_DIALOG, false);
  883. if (selectedFiles == null || selectedFiles.length != 1) return;
  884. path = selectedFiles[0];
  885. boolean success = loadPluginSet(path);
  886. if (success)
  887. {
  888. jEdit.setProperty(PluginManager.PROPERTY_PLUGINSET, path);
  889. }
  890. updateUI();
  891. } //}}}
  892. }//}}}
  893. //{{{ ClearPluginSet class
  894. private class ClearPluginSet extends RolloverButton implements ActionListener
  895. {
  896. //{{{ ClearPluginSet constructor
  897. ClearPluginSet()
  898. {
  899. setIcon(GUIUtilities.loadIcon(jEdit.getProperty("install-plugins.clear-plugin-set.icon")));
  900. setToolTipText("clear plugin set");
  901. addActionListener(this);
  902. } //}}}
  903. //{{{ actionPerformed() method
  904. @Override
  905. public void actionPerformed(ActionEvent e)
  906. {
  907. pluginSet.clear();
  908. pluginModel.restoreSelection(new HashSet<String>(), new HashSet<String>());
  909. jEdit.unsetProperty(PluginManager.PROPERTY_PLUGINSET);
  910. chooseButton.updateUI();
  911. } //}}}
  912. } //}}}
  913. //{{{ InstallButton class
  914. private class InstallButton extends JButton implements ActionListener, TableModelListener
  915. {
  916. InstallButton()
  917. {
  918. super(jEdit.getProperty("install-plugins.install"));
  919. pluginModel.addTableModelListener(this);
  920. addActionListener(this);
  921. setEnabled(false);
  922. }
  923. @Override
  924. public void actionPerformed(ActionEvent evt)
  925. {
  926. if(pluginModel.isDownloadingList())
  927. return;
  928. boolean downloadSource = jEdit.getBooleanProperty(
  929. "plugin-manager.downloadSource");
  930. boolean installUser = jEdit.getBooleanProperty(
  931. "plugin-manager.installUser");
  932. Roster roster = new Roster();
  933. String installDirectory;
  934. if(installUser)
  935. {
  936. installDirectory = MiscUtilities.constructPath(
  937. jEdit.getSettingsDirectory(),"jars");
  938. }
  939. else
  940. {
  941. installDirectory = MiscUtilities.constructPath(
  942. jEdit.getJEditHome(),"jars");
  943. }
  944. int length = pluginModel.entries.size();
  945. int instcount = 0;
  946. for (int i = 0; i < length; i++)
  947. {
  948. Entry entry = (Entry)pluginModel.entries.get(i);
  949. if (entry.install)
  950. {
  951. entry.plugin.install(roster,installDirectory,downloadSource);
  952. if (updates)
  953. entry.plugin.getCompatibleBranch().satisfyDependencies(
  954. roster,installDirectory,downloadSource);
  955. instcount++;
  956. }
  957. }
  958. if(roster.isEmpty())
  959. return;
  960. boolean cancel = false;
  961. if (updates && roster.getOperationCount() > instcount)
  962. if (GUIUtilities.confirm(window,
  963. "install-plugins.depend",
  964. null,
  965. JOptionPane.OK_CANCEL_OPTION,
  966. JOptionPane.WARNING_MESSAGE) == JOptionPane.CANCEL_OPTION)
  967. cancel = true;
  968. if (!cancel)
  969. {
  970. new PluginManagerProgress(window,roster);
  971. roster.performOperationsInAWTThread(window);
  972. pluginModel.update();
  973. }
  974. }
  975. @Override
  976. public void tableChanged(TableModelEvent e)
  977. {
  978. if(pluginModel.isDownloadingList())
  979. return;
  980. if (e.getType() == TableModelEvent.UPDATE)
  981. {
  982. int length = pluginModel.getRowCount();
  983. for (int i = 0; i < length; i++)
  984. if (((Boolean)pluginModel.getValueAt(i,0)).booleanValue())
  985. {
  986. setEnabled(true);
  987. return;
  988. }
  989. setEnabled(false);
  990. }
  991. }
  992. } //}}}
  993. //{{{ EntryCompare class
  994. private static class EntryCompare implements Comparator<Entry>
  995. {
  996. private static final int COLUMN_INSTALL = 0;
  997. private static final int COLUMN_NAME = 1;
  998. private static final int COLUMN_CATEGORY = 2;
  999. private static final int COLUMN_VERSION = 3;
  1000. private static final int COLUMN_SIZE = 4;
  1001. private static final int COLUMN_RELEASE = 5;
  1002. private final int type;
  1003. /** 1=up, -1=down */
  1004. private final int sortDirection;
  1005. EntryCompare(int type, int sortDirection)
  1006. {
  1007. this.type = type;
  1008. this.sortDirection = sortDirection;
  1009. }
  1010. @Override
  1011. public int compare(Entry e1, Entry e2)
  1012. {
  1013. int result;
  1014. switch (type)
  1015. {
  1016. case COLUMN_INSTALL:
  1017. result = (e1.install == e2.install) ? 0 : (e1.install ? 1 : -1);
  1018. break;
  1019. case COLUMN_NAME:
  1020. result = e1.name.compareToIgnoreCase(e2.name);
  1021. break;
  1022. case COLUMN_CATEGORY:
  1023. result = e1.set.compareToIgnoreCase(e2.set);
  1024. if (result == 0)
  1025. {
  1026. result = e1.name.compareToIgnoreCase(e2.name);
  1027. }
  1028. break;
  1029. case COLUMN_VERSION:
  1030. // lets avoid NPE. Maybe we should move
  1031. // this code to StandardUtilities.compareStrings
  1032. if (e1.version == e2.version)
  1033. {
  1034. result = 0;
  1035. }
  1036. else if (e1.version == null)
  1037. {
  1038. result = -1;
  1039. }
  1040. else if(e2.version == null)
  1041. {
  1042. result = 1;
  1043. }
  1044. else
  1045. {
  1046. result = StandardUtilities.compareStrings(e1.version,
  1047. e2.version,
  1048. true);
  1049. }
  1050. break;
  1051. case COLUMN_SIZE:
  1052. result = (e1.size < e2.size)
  1053. ? -1
  1054. : ((e1.size == e2.size)
  1055. ? 0
  1056. : 1);
  1057. break;
  1058. case COLUMN_RELEASE:
  1059. result = (e1.timestamp < e2.timestamp)
  1060. ? -1
  1061. : ((e1.timestamp == e2.timestamp)
  1062. ? 0
  1063. : 1);
  1064. break;
  1065. default:
  1066. result = 0;
  1067. }
  1068. return result * sortDirection;
  1069. }
  1070. } //}}}
  1071. //{{{ HeaderMouseHandler class
  1072. private class HeaderMouseHandler extends MouseAdapter
  1073. {
  1074. @Override
  1075. public void mouseClicked(MouseEvent evt)
  1076. {
  1077. int column = table.getTableHeader().columnAtPoint(evt.getPoint());
  1078. pluginModel.sortDirection *= -1;
  1079. pluginModel.sort(column);
  1080. }
  1081. } //}}}
  1082. //{{{ TextRenderer
  1083. private static class TextRenderer extends DefaultTableCellRenderer
  1084. {
  1085. private final DefaultTableCellRenderer tcr;
  1086. TextRenderer(DefaultTableCellRenderer tcr)
  1087. {
  1088. this.tcr = tcr;
  1089. }
  1090. @Override
  1091. public Component getTableCellRendererComponent(JTable table, Object value,
  1092. boolean isSelected, boolean hasFocus, int row, int column)
  1093. {
  1094. if (column == 5)
  1095. tcr.setHorizontalAlignment(TRAILING);
  1096. else
  1097. tcr.setHorizontalAlignment(LEADING);
  1098. return tcr.getTableCellRendererComponent(table,value,isSelected,false,row,column);
  1099. }
  1100. } //}}}
  1101. //{{{ KeyboardAction class
  1102. private class KeyboardAction extends AbstractAction
  1103. {
  1104. private KeyboardCommand command = KeyboardCommand.NONE;
  1105. KeyboardAction(KeyboardCommand command)
  1106. {
  1107. this.command = command;
  1108. }
  1109. @Override
  1110. public void actionPerformed(ActionEvent evt)
  1111. {
  1112. switch (command)
  1113. {
  1114. case TAB_OUT_FORWARD:
  1115. KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent();
  1116. break;
  1117. case TAB_OUT_BACK:
  1118. KeyboardFocusManager.getCurrentKeyboardFocusManager().focusPreviousComponent();
  1119. break;
  1120. case EDIT_PLUGIN:
  1121. int[] rows = table.getSelectedRows();
  1122. Object[] state = new Object[rows.length];
  1123. for (int i=0 ; i<rows.length ; i++)
  1124. {
  1125. state[i] = pluginModel.getValueAt(rows[i],0);
  1126. }
  1127. for (int i=0 ; i<rows.length ; i++)
  1128. {
  1129. pluginModel.setValueAt(state[i].equals(Boolean.FALSE),rows[i],0);
  1130. }
  1131. break;
  1132. case CLOSE_PLUGIN_MANAGER:
  1133. window.ok();
  1134. break;
  1135. default:
  1136. throw new InternalError();
  1137. }
  1138. }
  1139. } //}}}
  1140. //{{{ TableFocusHandler class
  1141. private class TableFocusHandler extends FocusAdapter
  1142. {
  1143. @Override
  1144. public void focusGained(FocusEvent fe)
  1145. {
  1146. if (-1 == table.getSelectedRow() && table.getRowCount() > 0)
  1147. {
  1148. table.setRowSelectionInterval(0,0);
  1149. JScrollBar scrollbar = scrollpane.getVerticalScrollBar();
  1150. scrollbar.setValue(scrollbar.getMinimum());
  1151. }
  1152. if (-1 == table.getSelectedColumn())
  1153. {
  1154. table.setColumnSelectionInterval(0,0);
  1155. }
  1156. }
  1157. } //}}}
  1158. //{{{ HeaderRenderer
  1159. private static class HeaderRenderer extends DefaultTableCellRenderer
  1160. {
  1161. private final DefaultTableCellRenderer tcr;
  1162. HeaderRenderer(DefaultTableCellRenderer tcr)
  1163. {
  1164. this.tcr = tcr;
  1165. }
  1166. @Override
  1167. public Component getTableCellRendererComponent(JTable table, Object value,
  1168. boolean isSelected, boolean hasFocus,
  1169. int row, int column)
  1170. {
  1171. JLabel l = (JLabel)tcr.getTableCellRendererComponent(table,value,isSelected,hasFocus,row,column);
  1172. PluginTableModel model = (PluginTableModel) table.getModel();
  1173. Icon icon = (column == model.sortType)
  1174. ? (model.sortDirection == 1) ? ASC_ICON : DESC_ICON
  1175. : null;
  1176. l.setIcon(icon);
  1177. // l.setHorizontalTextPosition(l.LEADING);
  1178. return l;
  1179. }
  1180. } //}}}
  1181. //}}}
  1182. static final Icon ASC_ICON = GUIUtilities.loadIcon("arrow-asc.png");
  1183. static final Icon DESC_ICON = GUIUtilities.loadIcon("arrow-desc.png");
  1184. }