Changeset 2817 in josm


Ignore:
Timestamp:
11.01.2010 21:06:49 (2 years ago)
Author:
Gubaer
Message:

fixed #3063: Downloading a plugin yields 3 dialogs at the same time: Downloading plugin / You should restart JOSM / Plugin downloaded
fixed #3628: JOSM blocking itself updating broken plugin
fixed #4187: JOSM deleted random files from disk after start (data loss)
fixed #4199: new version - plugins update vs josm start [should be fixed. Be careful if you have two JOSM instances running. Auto-update of plugins in the second instance will fail because plugin files are locked by the first instance]
fixed #4034: JOSM should auto-download plugin list when it hasn't been downloaded before [JOSM now displays a hint]

fixed: splash screen showing again even if plugins are auto-updated
new: progress indication integrated in splash screen
new: cancelable, asynchronous download of plugins from preferences
new: cancelable, asynchronous download of plugin list from plugin download sites
new: asynchronous loading of plugin information, launch of preferences dialog accelerated
refactored: clean up, documentation of plugin management code (PluginHandler)

Location:
trunk/src/org/openstreetmap/josm
Files:
9 added
2 deleted
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/Main.java

    r2801 r2817  
    4747import org.openstreetmap.josm.gui.MainMenu; 
    4848import org.openstreetmap.josm.gui.MapFrame; 
    49 import org.openstreetmap.josm.gui.SplashScreen; 
    5049import org.openstreetmap.josm.gui.dialogs.LayerListDialog; 
    5150import org.openstreetmap.josm.gui.io.SaveLayersDialog; 
     
    174173        Main.map = map; 
    175174 
    176         PluginHandler.setMapFrame(old, map); 
     175        PluginHandler.notifyMapFrameChanged(old, map); 
    177176    } 
    178177 
     
    192191 
    193192    public Main() { 
    194         this(null); 
    195     } 
    196  
    197     public Main(SplashScreen splash) { 
    198193        main = this; 
    199194        //        platform = determinePlatformHook(); 
     
    201196        contentPane.add(panel, BorderLayout.CENTER); 
    202197        panel.add(gettingStarted, BorderLayout.CENTER); 
    203  
    204         if(splash != null) { 
    205             splash.setStatus(tr("Creating main GUI")); 
    206         } 
    207198        menu = new MainMenu(); 
    208199 
  • trunk/src/org/openstreetmap/josm/data/Preferences.java

    r2711 r2817  
    202202    } 
    203203 
    204     public File getPluginsDirFile() { 
     204    public File getPluginsDirectory() { 
    205205        return new File(getPreferencesDirFile(), "plugins"); 
    206206    } 
     
    748748        System.setProperties(sysProp); 
    749749    } 
     750 
     751    /** 
     752     * The default plugin site 
     753     */ 
     754    private final static String[] DEFAULT_PLUGIN_SITE = {"http://josm.openstreetmap.de/plugin"}; 
     755 
     756    /** 
     757     * Replies the collection of plugin site URLs from where plugin lists can be downloaded 
     758     *  
     759     * @return 
     760     */ 
     761    public Collection<String> getPluginSites() { 
     762        return getCollection("pluginmanager.sites", Arrays.asList(DEFAULT_PLUGIN_SITE)); 
     763    } 
     764 
     765    /** 
     766     * Sets the collection of plugin site URLs. 
     767     *  
     768     * @param sites the site URLs 
     769     */ 
     770    public void setPluginSites(Collection<String> sites) { 
     771        putCollection("pluginmanager.sites", sites); 
     772    } 
     773 
    750774} 
  • trunk/src/org/openstreetmap/josm/gui/MainApplication.java

    r2801 r2817  
    2222import org.openstreetmap.josm.Main; 
    2323import org.openstreetmap.josm.gui.preferences.server.OAuthAccessTokenHolder; 
     24import org.openstreetmap.josm.gui.progress.ProgressMonitor; 
    2425import org.openstreetmap.josm.io.DefaultProxySelector; 
    2526import org.openstreetmap.josm.io.auth.CredentialsManagerFactory; 
    2627import org.openstreetmap.josm.io.auth.DefaultAuthenticator; 
    2728import org.openstreetmap.josm.plugins.PluginHandler; 
     29import org.openstreetmap.josm.plugins.PluginInformation; 
    2830import org.openstreetmap.josm.tools.BugReportExceptionHandler; 
    2931import org.openstreetmap.josm.tools.I18n; 
     
    4547     * display the frame. 
    4648     */ 
    47     public MainApplication(JFrame mainFrame, SplashScreen splash) { 
    48         super(splash); 
     49    public MainApplication(JFrame mainFrame) { 
     50        super(); 
    4951        mainFrame.setContentPane(contentPane); 
    5052        mainFrame.setJMenuBar(menu); 
     
    151153        } 
    152154 
    153         SplashScreen splash = new SplashScreen(Main.pref.getBoolean("draw.splashscreen", true)); 
    154  
    155         splash.setStatus(tr("Activating updated plugins")); 
    156         PluginHandler.earlyCleanup(); 
    157  
    158         splash.setStatus(tr("Loading early plugins")); 
    159         PluginHandler.loadPlugins(true); 
    160  
    161         splash.setStatus(tr("Setting defaults")); 
     155        SplashScreen splash = new SplashScreen(); 
     156        ProgressMonitor monitor = splash.getProgressMonitor(); 
     157        monitor.beginTask(tr("Initializing")); 
     158        monitor.setTicksCount(7); 
     159        splash.setVisible(Main.pref.getBoolean("draw.splashscreen", true)); 
     160 
     161        List<PluginInformation> pluginsToLoad = PluginHandler.buildListOfPluginsToLoad(monitor.createSubTaskMonitor(1, false)); 
     162        if (!pluginsToLoad.isEmpty() && PluginHandler.checkAndConfirmPluginUpdate()) { 
     163            monitor.subTask(tr("Updating plugins...")); 
     164            PluginHandler.updatePlugins(pluginsToLoad, monitor.createSubTaskMonitor(1, false)); 
     165        } 
     166        monitor.worked(1); 
     167 
     168        monitor.subTask(tr("Installing updated plugins")); 
     169        PluginHandler.installDownloadedPlugins(); 
     170        monitor.worked(1); 
     171 
     172        monitor.subTask(tr("Loading early plugins")); 
     173        PluginHandler.loadEarlyPlugins(pluginsToLoad, monitor.createSubTaskMonitor(1, false)); 
     174        monitor.worked(1); 
     175 
     176        monitor.subTask(tr("Setting defaults")); 
    162177        preConstructorInit(args); 
    163178        removeObsoletePreferences(); 
    164         splash.setStatus(tr("Creating main GUI")); 
     179        monitor.worked(1); 
     180 
     181        monitor.indeterminateSubTask(tr("Creating main GUI")); 
    165182        JFrame mainFrame = new JFrame(tr("Java OpenStreetMap Editor")); 
    166183        Main.parent = mainFrame; 
    167         final Main main = new MainApplication(mainFrame, splash); 
    168         splash.setStatus(tr("Loading plugins")); 
    169         PluginHandler.loadPlugins(false); 
     184        final Main main = new MainApplication(mainFrame); 
     185        monitor.worked(1); 
     186 
     187        monitor.subTask(tr("Loading plugins")); 
     188        PluginHandler.loadLatePlugins(pluginsToLoad,  monitor.createSubTaskMonitor(1, false)); 
     189        monitor.worked(1); 
    170190        toolbar.refreshToolbarControl(); 
    171  
     191        splash.setVisible(false); 
     192        splash.dispose(); 
    172193        mainFrame.setVisible(true); 
    173         splash.closeSplash(); 
    174194 
    175195        if (((!args.containsKey("no-maximize") && !args.containsKey("geometry") 
  • trunk/src/org/openstreetmap/josm/gui/SplashScreen.java

    r2358 r2817  
    44import static org.openstreetmap.josm.tools.I18n.tr; 
    55 
    6 import java.awt.AWTEvent; 
    76import java.awt.Color; 
    87import java.awt.Dimension; 
     
    1211import java.awt.Insets; 
    1312import java.awt.Toolkit; 
    14 import java.awt.event.AWTEventListener; 
    1513import java.awt.event.MouseAdapter; 
    1614import java.awt.event.MouseEvent; 
     
    1816import javax.swing.JLabel; 
    1917import javax.swing.JPanel; 
     18import javax.swing.JProgressBar; 
    2019import javax.swing.JSeparator; 
    2120import javax.swing.JWindow; 
    22 import javax.swing.SwingUtilities; 
    2321import javax.swing.border.Border; 
    2422import javax.swing.border.EmptyBorder; 
    2523import javax.swing.border.EtchedBorder; 
    2624 
    27 import org.openstreetmap.josm.actions.AboutAction; 
    2825import org.openstreetmap.josm.data.Version; 
     26import org.openstreetmap.josm.gui.progress.ProgressMonitor; 
     27import org.openstreetmap.josm.gui.progress.ProgressRenderer; 
     28import org.openstreetmap.josm.gui.progress.SwingRenderingProgressMonitor; 
    2929import org.openstreetmap.josm.tools.ImageProvider; 
    3030 
     
    3232 * Show a splash screen so the user knows what is happening during startup. 
    3333 * 
    34  * @author cbrill 
    3534 */ 
    3635public class SplashScreen extends JWindow { 
    3736 
    38     private JLabel status; 
    39     private boolean visible; 
     37    private SplashScreenProgressRenderer progressRenderer; 
     38    private SwingRenderingProgressMonitor progressMonitor; 
    4039 
    41     private Runnable closerRunner; 
    42  
    43     public SplashScreen(boolean visible) { 
     40    public SplashScreen() { 
    4441        super(); 
    45         this.visible=visible; 
    46  
    47         if (!visible) 
    48             return; 
    4942 
    5043        // Add a nice border to the main splash screen 
     
    8982 
    9083        // Add a status message 
    91         status = new JLabel(); 
     84        progressRenderer = new SplashScreenProgressRenderer(); 
    9285        gbc.gridy = 3; 
    93         gbc.insets = new Insets(0, 0, 0, 0); 
    94         innerContentPane.add(status, gbc); 
    95         setStatus(tr("Initializing")); 
     86        gbc.insets = new Insets(5, 5, 10, 5); 
     87        innerContentPane.add(progressRenderer, gbc); 
     88        progressMonitor = new SwingRenderingProgressMonitor(progressRenderer); 
    9689 
    9790        pack(); 
     
    10396                screenSize.height / 2 - (labelSize.height / 2)); 
    10497 
    105         // Method to close the splash screen when being clicked or when closeSplash is called 
    106         closerRunner = new Runnable() { 
    107             public void run() { 
    108                 setVisible(false); 
    109                 dispose(); 
    110             } 
    111         }; 
    112  
    11398        // Add ability to hide splash screen by clicking it 
    11499        addMouseListener(new MouseAdapter() { 
     100            @Override 
    115101            public void mousePressed(MouseEvent event) { 
    116                 try { 
    117                     closerRunner.run(); 
    118                 } catch (Exception e) { 
    119                     e.printStackTrace(); 
    120                     // can catch InvocationTargetException 
    121                     // can catch InterruptedException 
    122                 } 
     102                setVisible(false); 
    123103            } 
    124104        }); 
    125  
    126         // Hide splashscreen when other window is created 
    127         Toolkit.getDefaultToolkit().addAWTEventListener(awtListener, AWTEvent.WINDOW_EVENT_MASK); 
    128  
    129         setVisible(true); 
    130105    } 
    131106 
    132     private AWTEventListener awtListener = new AWTEventListener() { 
    133         public void eventDispatched(AWTEvent event) { 
    134             if (event.getSource() != SplashScreen.this) { 
    135                 closeSplash(); 
    136             } 
    137         } 
    138     }; 
    139  
    140     /** 
    141      * This method sets the status message. It should be called prior to 
    142      * actually doing the action. 
    143      * 
    144      * @param message 
    145      *            the message to be displayed 
    146      */ 
    147     public void setStatus(String message) { 
    148         if (!visible) 
    149             return; 
    150         status.setText(message + "..."); 
     107    public ProgressMonitor getProgressMonitor() { 
     108        return progressMonitor; 
    151109    } 
    152110 
    153     /** 
    154      * Closes the splashscreen. Call once you are done starting. 
    155      */ 
    156     public void closeSplash() { 
    157         if (!visible) 
    158             return; 
    159         Toolkit.getDefaultToolkit().removeAWTEventListener(awtListener); 
    160         try { 
    161             SwingUtilities.invokeLater(closerRunner); 
    162         } catch (Exception e) { 
    163             e.printStackTrace(); 
    164             // can catch InvocationTargetException 
    165             // can catch InterruptedException 
     111    static private class SplashScreenProgressRenderer extends JPanel implements ProgressRenderer { 
     112        private JLabel lblTaskTitle; 
     113        private JLabel lblCustomText; 
     114        private JProgressBar progressBar; 
     115 
     116        protected void build() { 
     117            setLayout(new GridBagLayout()); 
     118            GridBagConstraints gc = new GridBagConstraints(); 
     119            gc.gridx = 0; 
     120            gc.gridy = 0; 
     121            gc.fill = GridBagConstraints.HORIZONTAL; 
     122            gc.weightx = 1.0; 
     123            gc.weighty = 0.0; 
     124            gc.insets = new Insets(5,0,0,5); 
     125            add(lblTaskTitle = new JLabel(""), gc); 
     126 
     127            gc.gridx = 0; 
     128            gc.gridy = 1; 
     129            gc.fill = GridBagConstraints.HORIZONTAL; 
     130            gc.weightx = 1.0; 
     131            gc.weighty = 0.0; 
     132            gc.insets = new Insets(5,0,0,5); 
     133            add(lblCustomText = new JLabel(""), gc); 
     134 
     135            gc.gridx = 0; 
     136            gc.gridy = 2; 
     137            gc.fill = GridBagConstraints.HORIZONTAL; 
     138            gc.weightx = 1.0; 
     139            gc.weighty = 0.0; 
     140            gc.insets = new Insets(5,0,0,5); 
     141            add(progressBar = new JProgressBar(JProgressBar.HORIZONTAL), gc); 
     142        } 
     143 
     144        public SplashScreenProgressRenderer() { 
     145            build(); 
     146        } 
     147 
     148        public void setCustomText(String message) { 
     149            lblCustomText.setText(message); 
     150            repaint(); 
     151        } 
     152 
     153        public void setIndeterminate(boolean indeterminate) { 
     154            progressBar.setIndeterminate(indeterminate); 
     155            repaint(); 
     156        } 
     157 
     158        public void setMaximum(int maximum) { 
     159            progressBar.setMaximum(maximum); 
     160            repaint(); 
     161        } 
     162 
     163        public void setTaskTitle(String taskTitle) { 
     164            lblTaskTitle.setText(taskTitle); 
     165            repaint(); 
     166        } 
     167 
     168        public void setValue(int value) { 
     169            progressBar.setValue(value); 
     170            repaint(); 
    166171        } 
    167172    } 
  • trunk/src/org/openstreetmap/josm/gui/preferences/PluginPreference.java

    r2745 r2817  
    33 
    44import static org.openstreetmap.josm.tools.I18n.tr; 
    5  
    6 import java.awt.Dimension; 
     5import static org.openstreetmap.josm.tools.I18n.trn; 
     6 
     7import java.awt.BorderLayout; 
     8import java.awt.Component; 
     9import java.awt.FlowLayout; 
     10import java.awt.GridBagConstraints; 
    711import java.awt.GridBagLayout; 
    8 import java.awt.Rectangle; 
     12import java.awt.Insets; 
    913import java.awt.event.ActionEvent; 
    10 import java.awt.event.ActionListener; 
     14import java.awt.event.ComponentAdapter; 
     15import java.awt.event.ComponentEvent; 
    1116import java.util.Collection; 
    1217import java.util.LinkedList; 
     18import java.util.List; 
     19import java.util.logging.Logger; 
    1320 
    1421import javax.swing.AbstractAction; 
     22import javax.swing.BorderFactory; 
    1523import javax.swing.DefaultListModel; 
    1624import javax.swing.JButton; 
    1725import javax.swing.JLabel; 
    1826import javax.swing.JList; 
    19 import javax.swing.JTextField; 
    2027import javax.swing.JOptionPane; 
    2128import javax.swing.JPanel; 
    2229import javax.swing.JScrollPane; 
    23 import javax.swing.Scrollable; 
     30import javax.swing.JTabbedPane; 
     31import javax.swing.JTextField; 
     32import javax.swing.SwingUtilities; 
     33import javax.swing.UIManager; 
     34import javax.swing.event.ChangeEvent; 
     35import javax.swing.event.ChangeListener; 
    2436import javax.swing.event.DocumentEvent; 
    2537import javax.swing.event.DocumentListener; 
    2638 
    2739import org.openstreetmap.josm.Main; 
    28 import org.openstreetmap.josm.plugins.PluginDownloader; 
    29 import org.openstreetmap.josm.plugins.PluginSelection; 
     40import org.openstreetmap.josm.gui.HelpAwareOptionPane; 
     41import org.openstreetmap.josm.gui.help.HelpUtil; 
     42import org.openstreetmap.josm.gui.preferences.plugin.PluginPreferencesModel; 
     43import org.openstreetmap.josm.gui.preferences.plugin.PluginPreferencesPanel; 
     44import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator; 
     45import org.openstreetmap.josm.plugins.PluginDownloadTask; 
     46import org.openstreetmap.josm.plugins.PluginInformation; 
     47import org.openstreetmap.josm.plugins.ReadLocalPluginInformationTask; 
     48import org.openstreetmap.josm.plugins.ReadRemotePluginInformationTask; 
    3049import org.openstreetmap.josm.tools.GBC; 
     50import org.openstreetmap.josm.tools.ImageProvider; 
    3151 
    3252public class PluginPreference implements PreferenceSetting { 
     53    private final static Logger logger = Logger.getLogger(PluginPreference.class.getName()); 
    3354 
    3455    public static class Factory implements PreferenceSettingFactory { 
     
    3859    } 
    3960 
    40     private JPanel plugin; 
    41     private JPanel pluginPanel = new NoHorizontalScrollPanel(new GridBagLayout()); 
    42     private PreferenceTabbedPane gui; 
    43     private JScrollPane pluginPane; 
    44     private PluginSelection selection = new PluginSelection(); 
    45     private JTextField txtFilter; 
     61    public static String buildDownloadSummary(PluginDownloadTask task) { 
     62        Collection<PluginInformation> downloaded = task.getDownloadedPlugins(); 
     63        Collection<PluginInformation> failed = task.getFailedPlugins(); 
     64        StringBuilder sb = new StringBuilder(); 
     65        if (! downloaded.isEmpty()) { 
     66            sb.append(trn( 
     67                    "The following plugin has been downloaded <strong>successfully</strong>:", 
     68                    "The following {0} plugins have been downloaded successfully:", 
     69                    downloaded.size(), 
     70                    downloaded.size() 
     71            )); 
     72            sb.append("<ul>"); 
     73            for(PluginInformation pi: downloaded) { 
     74                sb.append("<li>").append(pi.name).append("</li>"); 
     75            } 
     76            sb.append("</ul>"); 
     77        } 
     78        if (! failed.isEmpty()) { 
     79            sb.append(trn( 
     80                    "Downloading the following plugin has <strong>failed</strong>:", 
     81                    "Downloading the following {0} plugins has <strong>failed</strong>:", 
     82                    failed.size(), 
     83                    failed.size() 
     84            )); 
     85            sb.append("<ul>"); 
     86            for(PluginInformation pi: failed) { 
     87                sb.append("<li>").append(pi.name).append("</li>"); 
     88            } 
     89            sb.append("</ul>"); 
     90        } 
     91        return sb.toString(); 
     92    } 
     93 
     94    private JTextField tfFilter; 
     95    private PluginPreferencesPanel pnlPluginPreferences; 
     96    private PluginPreferencesModel model; 
     97    private JScrollPane spPluginPreferences; 
     98 
     99    protected JPanel buildSearchFieldPanel() { 
     100        JPanel pnl  = new JPanel(new GridBagLayout()); 
     101        pnl.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); 
     102        GridBagConstraints gc = new GridBagConstraints(); 
     103 
     104        gc.anchor = GridBagConstraints.NORTHWEST; 
     105        gc.fill = GridBagConstraints.HORIZONTAL; 
     106        gc.weightx = 0.0; 
     107        gc.insets = new Insets(0,0,0,3); 
     108        pnl.add(new JLabel(tr("Search:")), gc); 
     109 
     110        gc.gridx = 1; 
     111        gc.weightx = 1.0; 
     112        pnl.add(tfFilter = new JTextField(), gc); 
     113        tfFilter.setToolTipText(tr("Enter a search expression")); 
     114        SelectAllOnFocusGainedDecorator.decorate(tfFilter); 
     115        tfFilter.getDocument().addDocumentListener(new SearchFieldAdapter()); 
     116        return pnl; 
     117    } 
     118 
     119    protected JPanel buildActionPanel() { 
     120        JPanel pnl = new JPanel(new FlowLayout(FlowLayout.CENTER)); 
     121 
     122        pnl.add(new JButton(new DownloadAvailablePluginsAction())); 
     123        pnl.add(new JButton(new UpdateSelectedPluginsAction())); 
     124        pnl.add(new JButton(new ConfigureSitesAction())); 
     125        return pnl; 
     126    } 
     127 
     128    protected JPanel buildContentPane() { 
     129        JPanel pnl = new JPanel(new BorderLayout()); 
     130        pnl.add(buildSearchFieldPanel(), BorderLayout.NORTH); 
     131        model  = new PluginPreferencesModel(); 
     132        spPluginPreferences = new JScrollPane(pnlPluginPreferences = new PluginPreferencesPanel(model)); 
     133        spPluginPreferences.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 
     134        spPluginPreferences.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); 
     135        spPluginPreferences.getVerticalScrollBar().addComponentListener( 
     136                new ComponentAdapter(){ 
     137                    @Override 
     138                    public void componentShown(ComponentEvent e) { 
     139                        spPluginPreferences.setBorder(UIManager.getBorder("ScrollPane.border")); 
     140                    } 
     141                    @Override 
     142                    public void componentHidden(ComponentEvent e) { 
     143                        spPluginPreferences.setBorder(null); 
     144                    } 
     145                } 
     146        ); 
     147 
     148        pnl.add(spPluginPreferences, BorderLayout.CENTER); 
     149        pnl.add(buildActionPanel(), BorderLayout.SOUTH); 
     150        return pnl; 
     151    } 
    46152 
    47153    public void addGui(final PreferenceTabbedPane gui) { 
    48         this.gui = gui; 
    49         plugin = gui.createPreferenceTab("plugin", tr("Plugins"), tr("Configure available plugins."), false); 
    50  
    51         txtFilter = new JTextField(); 
    52         JLabel lbFilter = new JLabel(tr("Search: ")); 
    53         lbFilter.setLabelFor(txtFilter); 
    54         plugin.add(lbFilter); 
    55         plugin.add(txtFilter, GBC.eol().fill(GBC.HORIZONTAL)); 
    56         txtFilter.getDocument().addDocumentListener(new DocumentListener(){ 
    57             public void changedUpdate(DocumentEvent e) { 
    58                 action(); 
    59             } 
    60  
    61             public void insertUpdate(DocumentEvent e) { 
    62                 action(); 
    63             } 
    64  
    65             public void removeUpdate(DocumentEvent e) { 
    66                 action(); 
    67             } 
    68  
    69             private void action() { 
    70                 selection.drawPanel(pluginPanel); 
    71             } 
    72         }); 
    73         plugin.add(GBC.glue(0,10), GBC.eol()); 
    74  
    75         /* main plugin area */ 
    76         pluginPane = new JScrollPane(pluginPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); 
    77         pluginPane.setBorder(null); 
    78         plugin.add(pluginPane, GBC.eol().fill(GBC.BOTH)); 
    79         plugin.add(GBC.glue(0,10), GBC.eol()); 
    80  
    81         /* buttons at the bottom */ 
    82         JButton morePlugins = new JButton(tr("Download List")); 
    83         morePlugins.addActionListener(new ActionListener(){ 
    84             public void actionPerformed(ActionEvent e) { 
    85                 selection.updateDescription(pluginPanel); 
    86             } 
    87         }); 
    88         plugin.add(morePlugins, GBC.std().insets(0,0,10,0)); 
    89  
    90         JButton update = new JButton(tr("Update")); 
    91         update.addActionListener(new ActionListener(){ 
    92             public void actionPerformed(ActionEvent e) { 
    93                 selection.update(pluginPanel); 
    94             } 
    95         }); 
    96         plugin.add(update, GBC.std().insets(0,0,10,0)); 
    97  
    98         JButton configureSites = new JButton(tr("Configure Sites...")); 
    99         configureSites.addActionListener(new ActionListener(){ 
    100             public void actionPerformed(ActionEvent e) { 
    101                 configureSites(); 
    102             } 
    103         }); 
    104         plugin.add(configureSites, GBC.std()); 
    105  
    106         selection.passTxtFilter(txtFilter); 
    107         selection.loadPlugins(); 
    108         selection.drawPanel(pluginPanel); 
     154        GridBagConstraints gc = new GridBagConstraints(); 
     155        gc.weightx = 1.0; 
     156        gc.weighty = 1.0; 
     157        gc.anchor = GridBagConstraints.NORTHWEST; 
     158        gc.fill = GridBagConstraints.BOTH; 
     159        gui.plugins.add(buildContentPane(), gc); 
     160        pnlPluginPreferences.refreshView(); 
     161        gui.addChangeListener(new PluginPreferenceActivationListener(gui.plugins)); 
    109162    } 
    110163 
     
    113166        p.add(new JLabel(tr("Add JOSM Plugin description URL.")), GBC.eol()); 
    114167        final DefaultListModel model = new DefaultListModel(); 
    115         for (String s : PluginDownloader.getSites()) { 
     168        for (String s : Main.pref.getPluginSites()) { 
    116169            model.addElement(s); 
    117170        } 
     
    122175            public void actionPerformed(ActionEvent e) { 
    123176                String s = JOptionPane.showInputDialog( 
    124                         gui, 
     177                        JOptionPane.getFrameForComponent(pnlPluginPreferences), 
    125178                        tr("Add JOSM Plugin description URL."), 
    126179                        tr("Enter URL"), 
     
    136189                if (list.getSelectedValue() == null) { 
    137190                    JOptionPane.showMessageDialog( 
    138                             gui, 
     191                            JOptionPane.getFrameForComponent(pnlPluginPreferences), 
    139192                            tr("Please select an entry."), 
    140193                            tr("Warning"), 
     
    159212                if (list.getSelectedValue() == null) { 
    160213                    JOptionPane.showMessageDialog( 
    161                             gui, 
     214                            JOptionPane.getFrameForComponent(pnlPluginPreferences), 
    162215                            tr("Please select an entry."), 
    163216                            tr("Warning"), 
     
    171224        p.add(buttons, GBC.eol()); 
    172225        int answer = JOptionPane.showConfirmDialog( 
    173                 gui, 
     226                JOptionPane.getFrameForComponent(pnlPluginPreferences), 
    174227                p, 
    175228                tr("Configure Plugin Sites"), JOptionPane.OK_CANCEL_OPTION, 
     
    181234            sites.add((String)model.getElementAt(i)); 
    182235        } 
    183         PluginDownloader.setSites(sites); 
     236        Main.pref.setPluginSites(sites); 
     237    } 
     238 
     239    /** 
     240     * Replies the list of plugins waiting for update or download 
     241     *  
     242     * @return the list of plugins waiting for update or download 
     243     */ 
     244    public List<PluginInformation> getPluginsScheduledForUpdateOrDownload() { 
     245        return model.getPluginsScheduledForUpdateOrDownload(); 
    184246    } 
    185247 
    186248    public boolean ok() { 
    187         return selection.finish(); 
    188     } 
    189  
    190     private static class NoHorizontalScrollPanel extends JPanel implements Scrollable { 
    191         public NoHorizontalScrollPanel(GridBagLayout gridBagLayout) { 
    192             super(gridBagLayout); 
    193         } 
    194  
    195         public Dimension getPreferredScrollableViewportSize() { 
    196             return super.getPreferredSize(); 
    197         } 
    198  
    199         public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) { 
    200             return 30; 
    201         } 
    202  
    203         public boolean getScrollableTracksViewportHeight() { 
    204             return false; 
    205         } 
    206  
    207         public boolean getScrollableTracksViewportWidth() { 
     249        if (model.isActivePluginsChanged()) { 
     250            Main.pref.putCollection("plugins", model.getSelectedPluginNames()); 
    208251            return true; 
    209252        } 
    210  
    211         public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) { 
    212             return 10; 
     253        return false; 
     254    } 
     255 
     256    public void readLocalPluginInformation() { 
     257        final ReadLocalPluginInformationTask task = new ReadLocalPluginInformationTask(); 
     258        Runnable r = new Runnable() { 
     259            public void run() { 
     260                if (task.isCanceled()) return; 
     261                SwingUtilities.invokeLater(new Runnable() { 
     262                    public void run() { 
     263                        model.setAvailablePlugins(task.getAvailablePlugins()); 
     264                        pnlPluginPreferences.refreshView(); 
     265                    } 
     266                }); 
     267            }; 
     268        }; 
     269        Main.worker.submit(task); 
     270        Main.worker.submit(r); 
     271    } 
     272 
     273    /** 
     274     * The action for downloading the list of available plugins 
     275     * 
     276     */ 
     277    class DownloadAvailablePluginsAction extends AbstractAction { 
     278 
     279        public DownloadAvailablePluginsAction() { 
     280            putValue(NAME,tr("Download list")); 
     281            putValue(SHORT_DESCRIPTION, tr("Download the list of available plugins")); 
     282            putValue(SMALL_ICON, ImageProvider.get("download")); 
     283        } 
     284 
     285        public void actionPerformed(ActionEvent e) { 
     286            final ReadRemotePluginInformationTask task = new ReadRemotePluginInformationTask(Main.pref.getPluginSites()); 
     287            Runnable continuation = new Runnable() { 
     288                public void run() { 
     289                    if (task.isCanceled()) return; 
     290                    SwingUtilities.invokeLater(new Runnable() { 
     291                        public void run() { 
     292                            model.setAvailablePlugins(task.getAvailabePlugins()); 
     293                            pnlPluginPreferences.refreshView(); 
     294 
     295                        } 
     296                    }); 
     297                } 
     298            }; 
     299            Main.worker.submit(task); 
     300            Main.worker.submit(continuation); 
     301        } 
     302    } 
     303 
     304    /** 
     305     * The action for downloading the list of available plugins 
     306     * 
     307     */ 
     308    class UpdateSelectedPluginsAction extends AbstractAction { 
     309        public UpdateSelectedPluginsAction() { 
     310            putValue(NAME,tr("Update plugins")); 
     311            putValue(SHORT_DESCRIPTION, tr("Update the selected plugins")); 
     312            putValue(SMALL_ICON, ImageProvider.get("dialogs", "refresh")); 
     313        } 
     314 
     315        protected void notifyDownloadResults(PluginDownloadTask task) { 
     316            Collection<PluginInformation> downloaded = task.getDownloadedPlugins(); 
     317            Collection<PluginInformation> failed = task.getFailedPlugins(); 
     318            StringBuilder sb = new StringBuilder(); 
     319            sb.append("<html>"); 
     320            sb.append(buildDownloadSummary(task)); 
     321            if (!downloaded.isEmpty()) { 
     322                sb.append("Please restart JOSM to activate the downloaded plugins."); 
     323            } 
     324            sb.append("</html>"); 
     325            HelpAwareOptionPane.showOptionDialog( 
     326                    pnlPluginPreferences, 
     327                    sb.toString(), 
     328                    tr("Update plugins"), 
     329                    failed.isEmpty() ? JOptionPane.WARNING_MESSAGE : JOptionPane.INFORMATION_MESSAGE, 
     330                            // FIXME: check help topic 
     331                            HelpUtil.ht("/Preferences/Plugin") 
     332            ); 
     333        } 
     334 
     335        public void actionPerformed(ActionEvent e) { 
     336            List<PluginInformation> toUpdate = model.getSelectedPlugins(); 
     337            final PluginDownloadTask task = new PluginDownloadTask( 
     338                    pnlPluginPreferences, 
     339                    toUpdate, 
     340                    tr("Update plugins") 
     341            ); 
     342            Runnable r = new Runnable() { 
     343                public void run() { 
     344                    if (task.isCanceled()) 
     345                        return; 
     346                    notifyDownloadResults(task); 
     347                    model.refreshLocalPluginVersion(task.getDownloadedPlugins()); 
     348                    pnlPluginPreferences.refreshView(); 
     349                } 
     350            }; 
     351            Main.worker.submit(task); 
     352            Main.worker.submit(r); 
     353        } 
     354    } 
     355 
     356 
     357    /** 
     358     * The action for configuring the plugin download sites 
     359     * 
     360     */ 
     361    class ConfigureSitesAction extends AbstractAction { 
     362        public ConfigureSitesAction() { 
     363            putValue(NAME,tr("Configure sites...")); 
     364            putValue(SHORT_DESCRIPTION, tr("Configure the list of sites where plugins are downloaded from")); 
     365        } 
     366 
     367        public void actionPerformed(ActionEvent e) { 
     368            configureSites(); 
     369        } 
     370    } 
     371 
     372    /** 
     373     * Listens to the activation of the plugin preferences tab. On activation it 
     374     * reloads plugin information from the local file system. 
     375     * 
     376     */ 
     377    class PluginPreferenceActivationListener implements ChangeListener { 
     378        private Component pane; 
     379        public PluginPreferenceActivationListener(Component preferencesPane) { 
     380            pane = preferencesPane; 
     381        } 
     382 
     383        public void stateChanged(ChangeEvent e) { 
     384            JTabbedPane tp = (JTabbedPane)e.getSource(); 
     385            if (tp.getSelectedComponent() == pane) { 
     386                readLocalPluginInformation(); 
     387            } 
     388        } 
     389    } 
     390 
     391    /** 
     392     * Applies the current filter condition in the filter text field to the 
     393     * model 
     394     */ 
     395    class SearchFieldAdapter implements DocumentListener { 
     396        public void filter() { 
     397            String expr = tfFilter.getText().trim(); 
     398            if (expr.equals("")) { 
     399                expr = null; 
     400            } 
     401            model.filterDisplayedPlugins(expr); 
     402            pnlPluginPreferences.refreshView(); 
     403        } 
     404 
     405        public void changedUpdate(DocumentEvent arg0) { 
     406            filter(); 
     407        } 
     408 
     409        public void insertUpdate(DocumentEvent arg0) { 
     410            filter(); 
     411        } 
     412 
     413        public void removeUpdate(DocumentEvent arg0) { 
     414            filter(); 
    213415        } 
    214416    } 
  • trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceTabbedPane.java

    r2745 r2817  
    2323import javax.swing.JScrollPane; 
    2424import javax.swing.JTabbedPane; 
     25import javax.swing.SwingUtilities; 
    2526 
    2627import org.openstreetmap.josm.Main; 
     28import org.openstreetmap.josm.plugins.PluginDownloadTask; 
    2729import org.openstreetmap.josm.plugins.PluginHandler; 
     30import org.openstreetmap.josm.plugins.PluginInformation; 
    2831import org.openstreetmap.josm.tools.BugReportExceptionHandler; 
    2932import org.openstreetmap.josm.tools.GBC; 
     
    4750    public final JPanel map = createPreferenceTab("map", I18n.tr("Map Settings"), I18n.tr("Settings for the map projection and data interpretation.")); 
    4851    public final JPanel audio = createPreferenceTab("audio", I18n.tr("Audio Settings"), I18n.tr("Settings for the audio player and audio markers.")); 
     52    public final JPanel plugins = createPreferenceTab("plugin", tr("Plugins"), tr("Configure available plugins."), false); 
    4953 
    5054    public final javax.swing.JTabbedPane displaycontent = new javax.swing.JTabbedPane(); 
     
    9599    } 
    96100 
     101    protected PluginPreference getPluginPreference() { 
     102        for (PreferenceSetting setting: settings) { 
     103            if (setting instanceof PluginPreference) 
     104                return (PluginPreference) setting; 
     105        } 
     106        return null; 
     107    } 
     108 
    97109    public void savePreferences() { 
    98         boolean requiresRestart = false; 
    99         for (PreferenceSetting setting : settings) 
    100         { 
    101             if(setting.ok()) { 
    102                 requiresRestart = true; 
     110 
     111        // create a task for downloading plugins if the user has activated, yet not downloaded, 
     112        // new plugins 
     113        // 
     114        final PluginPreference preference = getPluginPreference(); 
     115        final List<PluginInformation> toDownload = preference.getPluginsScheduledForUpdateOrDownload(); 
     116        final PluginDownloadTask task; 
     117        if (! toDownload.isEmpty()) { 
     118            task = new PluginDownloadTask(this, toDownload, tr("Download plugins")); 
     119        } else { 
     120            task = null; 
     121        } 
     122 
     123        // this is the task which will run *after* the plugins are downloaded 
     124        // 
     125        final Runnable continuation = new Runnable() { 
     126            public void run() { 
     127                boolean requiresRestart = false; 
     128                if (task != null && !task.isCanceled()) { 
     129                    if (!task.getDownloadedPlugins().isEmpty()) { 
     130                        requiresRestart = true; 
     131                    } 
     132                } 
     133 
     134                for (PreferenceSetting setting : settings) { 
     135                    if (setting.ok()) { 
     136                        requiresRestart = true; 
     137                    } 
     138                } 
     139 
     140                // build the messages. We only display one message, including the status 
     141                // information from the plugin download task and - if necessary - a hint 
     142                // to restart JOSM 
     143                // 
     144                StringBuffer sb = new StringBuffer(); 
     145                sb.append("<html>"); 
     146                if (task != null && !task.isCanceled()) { 
     147                    sb.append(PluginPreference.buildDownloadSummary(task)); 
     148                } 
     149                if (requiresRestart) { 
     150                    sb.append(tr("You have to restart JOSM for some settings to take effect.")); 
     151                } 
     152                sb.append("</html>"); 
     153 
     154                // display the message, if necessary 
     155                // 
     156                if ((task != null && !task.isCanceled()) || requiresRestart) { 
     157                    JOptionPane.showMessageDialog( 
     158                            Main.parent, 
     159                            sb.toString(), 
     160                            tr("Warning"), 
     161                            JOptionPane.WARNING_MESSAGE 
     162                    ); 
     163                } 
     164                Main.parent.repaint(); 
    103165            } 
    104         } 
    105         if (requiresRestart) { 
    106             JOptionPane.showMessageDialog( 
    107                     Main.parent, 
    108                     tr("You have to restart JOSM for some settings to take effect."), 
    109                     tr("Warning"), 
    110                     JOptionPane.WARNING_MESSAGE 
     166        }; 
     167 
     168        if (task != null) { 
     169            // if we have to launch a plugin download task we do it asynchronously, followed 
     170            // by the remaining "save preferences" activites run on the Swing EDT. 
     171            // 
     172            Main.worker.submit(task); 
     173            Main.worker.submit( 
     174                    new Runnable() { 
     175                        public void run() { 
     176                            SwingUtilities.invokeLater(continuation); 
     177                        } 
     178                    } 
    111179            ); 
    112         } 
    113         Main.parent.repaint(); 
     180        } else { 
     181            // no need for asynchronous activities. Simply run the remaining "save preference" 
     182            // activities on this thread (we are already on the Swing EDT 
     183            // 
     184            continuation.run(); 
     185        } 
    114186    } 
    115187 
  • trunk/src/org/openstreetmap/josm/io/CacheFiles.java

    r2711 r2817  
    5959 
    6060    public CacheFiles(String ident, boolean isPlugin) { 
    61         String pref = isPlugin ? Main.pref.getPluginsDirFile().getPath() : Main.pref.getPreferencesDir(); 
     61        String pref = isPlugin ? Main.pref.getPluginsDirectory().getPath() : Main.pref.getPreferencesDir(); 
    6262 
    6363        boolean dir_writeable; 
  • trunk/src/org/openstreetmap/josm/plugins/Plugin.java

    r1169 r2817  
    5353     */ 
    5454    public final String getPluginDir() { 
    55         return new File(Main.pref.getPluginsDirFile(), info.name).getPath(); 
     55        return new File(Main.pref.getPluginsDirectory(), info.name).getPath(); 
    5656    } 
    5757 
     
    8181        String pluginDirName = Main.pref.getPreferencesDir()+"plugins/"+info.name+"/"; 
    8282        File pluginDir = new File(pluginDirName); 
    83         if (!pluginDir.exists()) 
     83        if (!pluginDir.exists()) { 
    8484            pluginDir.mkdirs(); 
     85        } 
    8586        FileOutputStream out = new FileOutputStream(pluginDirName+to); 
    8687        InputStream in = getClass().getResourceAsStream(from); 
    8788        byte[] buffer = new byte[8192]; 
    88         for(int len = in.read(buffer); len > 0; len = in.read(buffer)) 
     89        for(int len = in.read(buffer); len > 0; len = in.read(buffer)) { 
    8990            out.write(buffer, 0, len); 
     91        } 
    9092        in.close(); 
    9193        out.close(); 
  • trunk/src/org/openstreetmap/josm/plugins/PluginException.java

    r2512 r2817  
    1111 * @author Immanuel.Scholz 
    1212 */ 
    13 public class PluginException extends RuntimeException { 
     13public class PluginException extends Exception { 
    1414    public final PluginProxy plugin; 
    1515    public final String name; 
     
    2020        this.name = name; 
    2121    } 
     22 
     23    public PluginException(String name, String message) { 
     24        super(message); 
     25        this.plugin = null; 
     26        this.name = name; 
     27    } 
     28 
     29    public PluginException(String name, Throwable cause) { 
     30        super(tr("An error occurred in plugin {0}", name), cause); 
     31        this.plugin = null; 
     32        this.name = name; 
     33    } 
    2234} 
  • trunk/src/org/openstreetmap/josm/plugins/PluginHandler.java

    r2584 r2817  
    44import static org.openstreetmap.josm.gui.help.HelpUtil.ht; 
    55import static org.openstreetmap.josm.tools.I18n.tr; 
     6import static org.openstreetmap.josm.tools.I18n.trn; 
    67 
    78import java.awt.Font; 
    89import java.awt.GridBagLayout; 
    910import java.awt.event.ActionEvent; 
     11import java.io.File; 
     12import java.io.FilenameFilter; 
    1013import java.net.URL; 
    1114import java.net.URLClassLoader; 
     
    1417import java.util.Collection; 
    1518import java.util.Collections; 
     19import java.util.Comparator; 
     20import java.util.HashMap; 
     21import java.util.HashSet; 
     22import java.util.Iterator; 
    1623import java.util.LinkedList; 
    1724import java.util.List; 
    18 import java.util.SortedMap; 
    19 import java.util.TreeMap; 
     25import java.util.Map; 
     26import java.util.Set; 
    2027import java.util.Map.Entry; 
     28import java.util.concurrent.ExecutionException; 
     29import java.util.concurrent.ExecutorService; 
     30import java.util.concurrent.Executors; 
     31import java.util.concurrent.Future; 
    2132 
    2233import javax.swing.AbstractAction; 
     
    3748import org.openstreetmap.josm.gui.download.DownloadSelection; 
    3849import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory; 
     50import org.openstreetmap.josm.gui.progress.NullProgressMonitor; 
     51import org.openstreetmap.josm.gui.progress.ProgressMonitor; 
     52import org.openstreetmap.josm.tools.CheckParameterUtil; 
    3953import org.openstreetmap.josm.tools.GBC; 
    4054import org.openstreetmap.josm.tools.ImageProvider; 
    4155 
     56/** 
     57 * PluginHandler is basically a collection of static utility functions used to bootstrap 
     58 * and manage the loaded plugins. 
     59 *  
     60 */ 
    4261public class PluginHandler { 
    4362 
    44     public static String [] oldplugins = new String[] {"mappaint", "unglueplugin", 
    45                 "lang-de", "lang-en_GB", "lang-fr", "lang-it", "lang-pl", "lang-ro", 
    46                 "lang-ru", "ewmsplugin", "ywms", "tways-0.2", "geotagged", "landsat", 
    47                 "namefinder", "waypoints", "slippy_map_chooser", "tcx-support", "usertools", 
    48                 "AgPifoJ", "utilsplugin"}; 
    49     public static String [] unmaintained = new String[] {"gpsbabelgui", "Intersect_way"}; 
     63    final public static String [] DEPRECATED_PLUGINS = new String[] {"mappaint", "unglueplugin", 
     64        "lang-de", "lang-en_GB", "lang-fr", "lang-it", "lang-pl", "lang-ro", 
     65        "lang-ru", "ewmsplugin", "ywms", "tways-0.2", "geotagged", "landsat", 
     66        "namefinder", "waypoints", "slippy_map_chooser", "tcx-support", "usertools", 
     67        "AgPifoJ", "utilsplugin"}; 
     68 
     69    final public static String [] UNMAINTAINED_PLUGINS = new String[] {"gpsbabelgui", "Intersect_way"}; 
    5070 
    5171    /** 
     
    5373     */ 
    5474    public final static Collection<PluginProxy> pluginList = new LinkedList<PluginProxy>(); 
    55     /** 
    56      * Load all plugins specified in preferences. If the parameter is 
    57      * <code>true</code>, all early plugins are loaded (before constructor). 
    58      */ 
    59     public static void loadPlugins(boolean early) { 
    60         List<String> plugins = new LinkedList<String>(); 
    61         Collection<String> cp = Main.pref.getCollection("plugins", null); 
    62         if (cp != null) { 
    63             plugins.addAll(cp); 
    64         } 
    65         if (System.getProperty("josm.plugins") != null) { 
    66             plugins.addAll(Arrays.asList(System.getProperty("josm.plugins").split(","))); 
    67         } 
    68  
    69         for (String p : oldplugins) { 
     75 
     76 
     77    /** 
     78     * Removes deprecated plugins from a collection of plugins. Modifies the 
     79     * collection <code>plugins</code>. 
     80     *  
     81     * Also notifies the user about removed deprecated plugins 
     82     *  
     83     * @param plugins the collection of plugins 
     84     */ 
     85    private static void filterDeprecatedPlugins(Collection<String> plugins) { 
     86        Set<String> removedPlugins = new HashSet<String>(); 
     87        for (String p : DEPRECATED_PLUGINS) { 
    7088            if (plugins.contains(p)) { 
    7189                plugins.remove(p); 
    7290                Main.pref.removeFromCollection("plugins", p); 
    73                 JOptionPane.showMessageDialog( 
    74                         Main.parent, 
    75                         tr("Plugin {0} is no longer necessary and has been deactivated.", p), 
    76                         tr("Warning"), 
    77                         JOptionPane.WARNING_MESSAGE 
    78                 ); 
    79             } 
    80         } 
    81         if(early) 
    82         { 
    83             for (String p : unmaintained) { 
    84                 if (plugins.contains(p) && disablePlugin(tr("<html>Loading of {0} plugin was requested." 
    85                         +"<br>This plugin is no longer developed and very likely will produce errors." 
    86                         +"<br>It should be disabled.<br>Delete from preferences?</html>", p), p)) { 
    87                     plugins.remove(p); 
    88                 } 
    89             } 
    90         } 
    91  
    92         if (plugins.isEmpty()) 
     91                removedPlugins.add(p); 
     92            } 
     93        } 
     94        if (removedPlugins.isEmpty()) 
    9395            return; 
    9496 
    95         if(early) 
    96         { 
    97             String doUpdate = null; 
    98             String check = null; 
    99             int v = Version.getInstance().getVersion(); 
    100             if(Main.pref.getInteger("pluginmanager.version", 0) < v) 
    101             { 
    102                 doUpdate = tr("You updated your JOSM software.\nTo prevent problems the plugins should be updated as well.\n" 
    103                         + "Update plugins now?"); 
    104                 check = "pluginmanger.version"; 
    105             } 
    106             else 
    107             { 
    108                 long tim = System.currentTimeMillis(); 
    109                 long last = Main.pref.getLong("pluginmanager.lastupdate", 0); 
    110                 Integer maxTime = Main.pref.getInteger("pluginmanager.warntime", 60); 
    111                 long d = (tim - last)/(24*60*60*1000l); 
    112                 if ((last <= 0) || (maxTime <= 0)) { 
    113                     Main.pref.put("pluginmanager.lastupdate",Long.toString(tim)); 
    114                 } else if (d > maxTime) { 
    115                     doUpdate = tr("Last plugin update more than {0} days ago.", d); 
    116                     check = "pluginmanager.time"; 
    117                 } 
    118             } 
    119             if(doUpdate != null) 
    120             { 
    121                 ExtendedDialog dialog = new ExtendedDialog( 
    122                         Main.parent, 
    123                         tr("Update plugins"), 
    124                         new String[] {tr("Update plugins"), tr("Skip update")} 
    125                 ); 
    126                 dialog.setContent(doUpdate); 
    127                 dialog.toggleEnable(check); 
    128                 dialog.setButtonIcons( new String[] {"dialogs/refresh.png", "cancel.png"}); 
    129                 dialog.configureContextsensitiveHelp(ht("/Plugin/AutomaticUpdate"), true /* show help button */); 
    130                 dialog.showDialog(); 
    131                 if(dialog.getValue() == 1) { 
    132                     new PluginSelection().update(); 
    133                 } 
    134             } 
    135         } 
    136  
    137         SortedMap<Integer, Collection<PluginInformation>> p = new TreeMap<Integer, Collection<PluginInformation>>(); 
    138         for (String pluginName : plugins) { 
    139             PluginInformation info = PluginInformation.findPlugin(pluginName); 
    140             if (info != null) { 
    141                 if (info.early != early) { 
    142                     continue; 
    143                 } 
    144                 int josmVersion = Version.getInstance().getVersion(); 
    145                 if (info.mainversion > josmVersion && josmVersion != Version.JOSM_UNKNOWN_VERSION) { 
    146                     JOptionPane.showMessageDialog( 
    147                             Main.parent, 
    148                             tr("Plugin {0} requires JOSM update to version {1}.", pluginName, 
    149                                     info.mainversion), 
    150                                     tr("Warning"), 
    151                                     JOptionPane.WARNING_MESSAGE 
    152                     ); 
    153                     continue; 
    154                 } 
    155  
    156                 if(info.requires != null) 
    157                 { 
    158                     String warn = null; 
    159                     for(String n : info.requires.split(";")) 
    160                     { 
    161                         if(!plugins.contains(n)) 
    162                         { warn = n; break; } 
    163                     } 
    164                     if(warn != null) 
    165                     { 
    166                         JOptionPane.showMessageDialog(Main.parent, 
    167                                 tr("Plugin {0} is required by plugin {1} but was not found.", 
    168                                         warn, pluginName), 
    169                                         tr("Error"), 
    170                                         JOptionPane.ERROR_MESSAGE 
    171                         ); 
    172                         continue; 
    173                     } 
    174                 } 
    175                 if (!p.containsKey(info.stage)) { 
    176                     p.put(info.stage, new LinkedList<PluginInformation>()); 
    177                 } 
    178                 p.get(info.stage).add(info); 
    179             } else if(early) { 
    180                 JOptionPane.showMessageDialog( 
    181                         Main.parent, 
    182                         tr("Plugin not found: {0}.", pluginName), 
    183                         tr("Error"), 
    184                         JOptionPane.ERROR_MESSAGE 
    185                 ); 
    186             } 
    187         } 
    188  
     97        // notify user about removed deprecated plugins 
     98        // 
     99        StringBuffer sb = new StringBuffer(); 
     100        sb.append("<html>"); 
     101        sb.append(trn( 
     102                "The following plugin is no longer necessary and has been deactivated:", 
     103                "The following plugins are no longer necessary and have been deactivated:", 
     104                removedPlugins.size() 
     105        )); 
     106        sb.append("<ul>"); 
     107        for (String name: removedPlugins) { 
     108            sb.append("<li>").append(name).append("</li>"); 
     109        } 
     110        sb.append("</ul>"); 
     111        sb.append("</html>"); 
     112        JOptionPane.showMessageDialog( 
     113                Main.parent, 
     114                sb.toString(), 
     115                tr("Warning"), 
     116                JOptionPane.WARNING_MESSAGE 
     117        ); 
     118    } 
     119 
     120    /** 
     121     * Removes unmaintained plugins from a collection of plugins. Modifies the 
     122     * collection <code>plugins</code>. Also removes the plugin from the list 
     123     * of plugins in the preferences, if necessary. 
     124     *  
     125     * Asks the user for every unmaintained plugin whether it should be removed. 
     126     *  
     127     * @param plugins the collection of plugins 
     128     */ 
     129    private static void filterUnmaintainedPlugins(Collection<String> plugins) { 
     130        for (String unmaintained : UNMAINTAINED_PLUGINS) { 
     131            if (!plugins.contains(unmaintained)) { 
     132                continue; 
     133            } 
     134            String msg =  tr("<html>Loading of {0} plugin was requested." 
     135                    + "<br>This plugin is no longer developed and very likely will produce errors." 
     136                    +"<br>It should be disabled.<br>Delete from preferences?</html>", unmaintained); 
     137            if (confirmDisablePlugin(msg,unmaintained)) { 
     138                Main.pref.removeFromCollection("plugins", unmaintained); 
     139                plugins.remove(unmaintained); 
     140            } 
     141        } 
     142    } 
     143 
     144    /** 
     145     * Checks whether the locally available plugins should be updated and 
     146     * asks the user if running an update is OK. An update is advised if 
     147     * JOSM was updated to a new version since the last plugin updates or 
     148     * if the plugins were last updated a long time ago. 
     149     *  
     150     * @return true if a plugin update should be run; false, otherwise 
     151     */ 
     152    public static boolean checkAndConfirmPluginUpdate() { 
     153        String message = null; 
     154        String togglePreferenceKey = null; 
     155        int v = Version.getInstance().getVersion(); 
     156        if (Main.pref.getInteger("pluginmanager.version", 0) < v) { 
     157            message = tr("<html>You updated your JOSM software.<br>" 
     158                    + "To prevent problems the plugins should be updated as well.<br><br>" 
     159                    + "Update plugins now?" 
     160                    + "</html>" 
     161            ); 
     162            togglePreferenceKey = "pluginmanger.version"; 
     163        }  else { 
     164            long tim = System.currentTimeMillis(); 
     165            long last = Main.pref.getLong("pluginmanager.lastupdate", 0); 
     166            Integer maxTime = Main.pref.getInteger("pluginmanager.warntime", 60); 
     167            long d = (tim - last) / (24 * 60 * 60 * 1000l); 
     168            if ((last <= 0) || (maxTime <= 0)) { 
     169                Main.pref.put("pluginmanager.lastupdate", Long.toString(tim)); 
     170            } else if (d > maxTime) { 
     171                message = tr("Last plugin update more than {0} days ago.", d); 
     172                togglePreferenceKey = "pluginmanager.time"; 
     173            } 
     174        } 
     175        if (message == null) return false; 
     176 
     177        // ask whether update is fine 
     178        // 
     179        ExtendedDialog dialog = new ExtendedDialog( 
     180                Main.parent, 
     181                tr("Update plugins"), 
     182                new String[] { 
     183                    tr("Update plugins"), tr("Skip update") 
     184                } 
     185        ); 
     186        dialog.setContent(message); 
     187        dialog.toggleEnable(togglePreferenceKey); 
     188        dialog.setButtonIcons( new String[] {"dialogs/refresh.png", "cancel.png"}); 
     189        dialog.configureContextsensitiveHelp(ht("/Plugin/AutomaticUpdate"), true /* show help button */); 
     190        dialog.showDialog(); 
     191        return dialog.getValue() == 1; 
     192    } 
     193 
     194    /** 
     195     * Alerts the user if a plugin required by another plugin is missing 
     196     *  
     197     * @param plugin the the plugin 
     198     * @param missingRequiredPlugin the missing required plugin 
     199     */ 
     200    private static void alertMissingRequiredPlugin(String plugin, Set<String> missingRequiredPlugin) { 
     201        StringBuilder sb = new StringBuilder(); 
     202        sb.append("<html>"); 
     203        sb.append(trn("A required plugin for plugin {0} was not found. The required plugin is:", 
     204                "{1} required plugins for plugin {0} were not found. The required plugins are:", 
     205                missingRequiredPlugin.size(), 
     206                plugin, 
     207                missingRequiredPlugin.size() 
     208        )); 
     209        sb.append("<ul>"); 
     210        for (String p: missingRequiredPlugin) { 
     211            sb.append("<li>").append(p).append("</li>"); 
     212        } 
     213        sb.append("</ul>").append("</html>"); 
     214        JOptionPane.showMessageDialog( 
     215                Main.parent, 
     216                sb.toString(), 
     217                tr("Error"), 
     218                JOptionPane.ERROR_MESSAGE 
     219        ); 
     220    } 
     221 
     222    /** 
     223     * Checks whether all preconditions for loading the plugin <code>plugin</code> are met. The 
     224     * current JOSM version must be compatible with the plugin and no other plugins this plugin 
     225     * depends on should be missing. 
     226     *  
     227     * @param plugins the collection of all loaded plugins 
     228     * @param plugin the plugin for which preconditions are checked 
     229     * @return true, if the preconditions are met; false otherwise 
     230     */ 
     231    public static boolean checkLoadPreconditions(Collection<PluginInformation> plugins, PluginInformation plugin) { 
     232 
     233        // make sure the plugin is compatible with the current JOSM version 
     234        // 
     235        int josmVersion = Version.getInstance().getVersion(); 
     236        if (plugin.mainversion > josmVersion && josmVersion != Version.JOSM_UNKNOWN_VERSION) { 
     237            JOptionPane.showMessageDialog( 
     238                    Main.parent, 
     239                    tr("Plugin {0} requires JOSM update to version {1}.", plugin.name, 
     240                            plugin.mainversion), 
     241                            tr("Warning"), 
     242                            JOptionPane.WARNING_MESSAGE 
     243            ); 
     244            return false; 
     245        } 
     246 
     247        // make sure the dependencies to other plugins are not broken 
     248        // 
     249        if(plugin.requires != null){ 
     250            Set<String> pluginNames = new HashSet<String>(); 
     251            for (PluginInformation pi: plugins) { 
     252                pluginNames.add(pi.name); 
     253            } 
     254            Set<String> missingPlugins = new HashSet<String>(); 
     255            for (String requiredPlugin : plugin.requires.split(";")) { 
     256                if (!pluginNames.contains(requiredPlugin)) { 
     257                    missingPlugins.add(requiredPlugin); 
     258                } 
     259            } 
     260            if (!missingPlugins.isEmpty()) { 
     261                alertMissingRequiredPlugin(plugin.name, missingPlugins); 
     262                return false; 
     263            } 
     264        } 
     265        return true; 
     266    } 
     267 
     268    /** 
     269     * Creates a class loader for loading plugin code. 
     270     *  
     271     * @param plugins the collection of plugins which are going to be loaded with this 
     272     * class loader 
     273     * @return the class loader 
     274     */ 
     275    public static ClassLoader createClassLoader(Collection<PluginInformation> plugins) { 
    189276        // iterate all plugins and collect all libraries of all plugins: 
    190         List<URL> allPluginLibraries = new ArrayList<URL>(); 
    191         for (Collection<PluginInformation> c : p.values()) { 
    192             for (PluginInformation info : c) { 
    193                 allPluginLibraries.addAll(info.libraries); 
    194             } 
    195         } 
     277        List<URL> allPluginLibraries = new LinkedList<URL>(); 
     278        File pluginDir = Main.pref.getPluginsDirectory(); 
     279        for (PluginInformation info : plugins) { 
     280            if (info.libraries == null) { 
     281                continue; 
     282            } 
     283            allPluginLibraries.addAll(info.libraries); 
     284            File pluginJar = new File(pluginDir, info.name + ".jar"); 
     285            URL pluginJarUrl = PluginInformation.fileToURL(pluginJar); 
     286            allPluginLibraries.add(pluginJarUrl); 
     287        } 
     288 
    196289        // create a classloader for all plugins: 
    197290        URL[] jarUrls = new URL[allPluginLibraries.size()]; 
    198291        jarUrls = allPluginLibraries.toArray(jarUrls); 
    199292        URLClassLoader pluginClassLoader = new URLClassLoader(jarUrls, Main.class.getClassLoader()); 
    200         ImageProvider.sources.add(0, pluginClassLoader); 
    201  
    202         for (Collection<PluginInformation> c : p.values()) { 
    203             for (PluginInformation info : c) { 
    204                 try { 
    205                     Class<?> klass = info.loadClass(pluginClassLoader); 
    206                     if (klass != null) { 
    207                         System.out.println("loading "+info.name); 
    208                         pluginList.add(info.load(klass)); 
     293        return pluginClassLoader; 
     294    } 
     295 
     296    /** 
     297     * Loads and instantiates the plugin described by <code>plugin</code> using 
     298     * the class loader <code>pluginClassLoader</code>. 
     299     *  
     300     * @param plugin the plugin 
     301     * @param pluginClassLoader the plugin class loader 
     302     */ 
     303    public static void loadPlugin(PluginInformation plugin, ClassLoader pluginClassLoader) { 
     304        try { 
     305            Class<?> klass = plugin.loadClass(pluginClassLoader); 
     306            if (klass != null) { 
     307                System.out.println(tr("loading plugin ''{0}''", plugin.name)); 
     308                pluginList.add(plugin.load(klass)); 
     309            } 
     310        } catch (Throwable e) { 
     311            e.printStackTrace(); 
     312            String msg = tr("Could not load plugin {0}. Delete from preferences?", plugin.name); 
     313            if (confirmDisablePlugin(msg, plugin.name)) { 
     314                Main.pref.removeFromCollection("plugins", plugin.name); 
     315            } 
     316        } 
     317    } 
     318 
     319    /** 
     320     * Loads the plugin in <code>plugins</code> from locally available jar files into 
     321     * memory. 
     322     *  
     323     * @param plugins the list of plugins 
     324     * @param monitor the progress monitor. Defaults to {@see NullProgressMonitor#INSTANCE} if null. 
     325     */ 
     326    public static void loadPlugins(Collection<PluginInformation> plugins, ProgressMonitor monitor) { 
     327        if (monitor == null) { 
     328            monitor = NullProgressMonitor.INSTANCE; 
     329        } 
     330        try { 
     331            monitor.beginTask(tr("Loading plugins ...")); 
     332            List<PluginInformation> toLoad = new LinkedList<PluginInformation>(); 
     333            // sort the plugins according to their "staging" equivalence class. The 
     334            // lower the value of "stage" the earlier the plugin should be loaded. 
     335            // 
     336            Collections.sort( 
     337                    toLoad, 
     338                    new Comparator<PluginInformation>() { 
     339                        public int compare(PluginInformation o1, PluginInformation o2) { 
     340                            if (o1.stage < o2.stage) return -1; 
     341                            if (o1.stage == o2.stage) return 0; 
     342                            return 1; 
     343                        } 
    209344                    } 
    210                 } catch (Throwable e) { 
    211                     e.printStackTrace(); 
    212                     disablePlugin(tr("Could not load plugin {0}. Delete from preferences?", info.name), info.name); 
    213                 } 
    214             } 
    215         } 
    216     } 
    217     public static boolean disablePlugin(String reason, String name) 
    218     { 
     345            ); 
     346            monitor.subTask(tr("Checking plugin preconditions...")); 
     347            for (PluginInformation pi: plugins) { 
     348                if (checkLoadPreconditions(plugins, pi)) { 
     349                    toLoad.add(pi); 
     350                } 
     351            } 
     352            if (toLoad.isEmpty()) 
     353                return; 
     354 
     355            ClassLoader pluginClassLoader = createClassLoader(toLoad); 
     356            ImageProvider.sources.add(0, pluginClassLoader); 
     357            monitor.setTicksCount(toLoad.size()); 
     358            for (PluginInformation info : toLoad) { 
     359                monitor.setExtraText(tr("Loading plugin ''{0}''...", info.name)); 
     360                loadPlugin(info, pluginClassLoader); 
     361                monitor.worked(1); 
     362            } 
     363        } finally { 
     364            monitor.finishTask(); 
     365        } 
     366    } 
     367 
     368    /** 
     369     * Loads plugins from <code>plugins</code> which have the flag {@see PluginInformation#early} 
     370     * set to true. 
     371     *  
     372     * @param plugins the collection of plugins 
     373     * @param monitor the progress monitor. Defaults to {@see NullProgressMonitor#INSTANCE} if null. 
     374     */ 
     375    public static void loadEarlyPlugins(Collection<PluginInformation> plugins, ProgressMonitor monitor) { 
     376        List<PluginInformation> earlyPlugins = new ArrayList<PluginInformation>(plugins.size()); 
     377        for (PluginInformation pi: plugins) { 
     378            if (pi.early) { 
     379                earlyPlugins.add(pi); 
     380            } 
     381        } 
     382        loadPlugins(earlyPlugins, monitor); 
     383    } 
     384 
     385    /** 
     386     * Loads plugins from <code>plugins</code> which have the flag {@see PluginInformation#early} 
     387     * set to false. 
     388     *  
     389     * @param plugins the collection of plugins 
     390     * @param monitor the progress monitor. Defaults to {@see NullProgressMonitor#INSTANCE} if null. 
     391     */ 
     392    public static void loadLatePlugins(Collection<PluginInformation> plugins, ProgressMonitor monitor) { 
     393        List<PluginInformation> latePlugins = new ArrayList<PluginInformation>(plugins.size()); 
     394        for (PluginInformation pi: plugins) { 
     395            if (!pi.early) { 
     396                latePlugins.add(pi); 
     397            } 
     398        } 
     399        loadPlugins(latePlugins, monitor); 
     400    } 
     401 
     402    /** 
     403     * Loads locally available plugin information from local plugin jars and from cached 
     404     * plugin lists. 
     405     * 
     406     * @param monitor the progress monitor. Defaults to {@see NullProgressMonitor#INSTANCE} if null. 
     407     * @return the list of locally available plugin information 
     408     *  
     409     */ 
     410    private static Map<String, PluginInformation> loadLocallyAvailablePluginInformation(ProgressMonitor monitor) { 
     411        if (monitor == null) { 
     412            monitor = NullProgressMonitor.INSTANCE; 
     413        } 
     414        try { 
     415            ReadLocalPluginInformationTask task = new ReadLocalPluginInformationTask(monitor); 
     416            ExecutorService service = Executors.newSingleThreadExecutor(); 
     417            Future<?> future = service.submit(task); 
     418            try { 
     419                future.get(); 
     420            } catch(ExecutionException e) { 
     421                e.printStackTrace(); 
     422                return null; 
     423            } catch(InterruptedException e) { 
     424                e.printStackTrace(); 
     425                return null; 
     426            } 
     427            HashMap<String, PluginInformation> ret = new HashMap<String, PluginInformation>(); 
     428            for (PluginInformation pi: task.getAvailablePlugins()) { 
     429                ret.put(pi.name, pi); 
     430            } 
     431            return ret; 
     432        } finally { 
     433            monitor.finishTask(); 
     434        } 
     435    } 
     436 
     437    private static void alertMissingPluginInformation(Collection<String> plugins) { 
     438        StringBuilder sb = new StringBuilder(); 
     439        sb.append("<html>"); 
     440        sb.append(trn("JOSM could not find information about the following plugin:", 
     441                "JOSM could not find information about the following plugins:", 
     442                plugins.size())); 
     443        sb.append("<ul>"); 
     444        for (String plugin: plugins) { 
     445            sb.append("<li>").append(plugin).append("</li>"); 
     446        } 
     447        sb.append("</ul>"); 
     448        sb.append(trn("The plugin is not going to be loaded.", 
     449                "The plugins are not going to be loaded.", 
     450                plugins.size())); 
     451        sb.append("</html>"); 
     452        JOptionPane.showMessageDialog( 
     453                Main.parent, 
     454                sb.toString(), 
     455                tr("Warning"), 
     456                JOptionPane.WARNING_MESSAGE 
     457        ); 
     458    } 
     459 
     460    /** 
     461     * Builds the set of plugins to load. Deprecated and unmaintained plugins are filtered 
     462     * out. This involves user interaction. This method displays alert and confirmation 
     463     * messages. 
     464     * 
     465     * @param monitor the progress monitor. Defaults to {@see NullProgressMonitor#INSTANCE} if null. 
     466     * @return the set of plugins to load (as set of plugin names) 
     467     */ 
     468    public static List<PluginInformation> buildListOfPluginsToLoad(ProgressMonitor monitor) { 
     469        if (monitor == null) { 
     470            monitor = NullProgressMonitor.INSTANCE; 
     471        } 
     472        try { 
     473            monitor.beginTask(tr("Determine plugins to load...")); 
     474            Set<String> plugins = new HashSet<String>(); 
     475            plugins.addAll(Main.pref.getCollection("plugins",  new LinkedList<String>())); 
     476            if (System.getProperty("josm.plugins") != null) { 
     477                plugins.addAll(Arrays.asList(System.getProperty("josm.plugins").split(","))); 
     478            } 
     479            monitor.subTask(tr("Removing deprecated plugins...")); 
     480            filterDeprecatedPlugins(plugins); 
     481            monitor.subTask(tr("Removing umaintained plugins...")); 
     482            filterUnmaintainedPlugins(plugins); 
     483            Map<String, PluginInformation> infos = loadLocallyAvailablePluginInformation(monitor.createSubTaskMonitor(1,false)); 
     484            List<PluginInformation> ret = new LinkedList<PluginInformation>(); 
     485            for (Iterator<String> it = plugins.iterator(); it.hasNext();) { 
     486                String plugin = it.next(); 
     487                if (infos.containsKey(plugin)) { 
     488                    ret.add(infos.get(plugin)); 
     489                    it.remove(); 
     490                } 
     491            } 
     492            if (!plugins.isEmpty()) { 
     493                alertMissingPluginInformation(plugins); 
     494            } 
     495            return ret; 
     496        } finally { 
     497            monitor.finishTask(); 
     498        } 
     499    } 
     500 
     501    private static void alertFailedPluginUpdate(Collection<PluginInformation> plugins) { 
     502        StringBuffer sb = new StringBuffer(); 
     503        sb.append("<html>"); 
     504        sb.append(trn( 
     505                "Updating the following plugin has failed:", 
     506                "Updating the following plugins has failed:", 
     507                plugins.size() 
     508        ) 
     509        ); 
     510        sb.append("<ul>"); 
     511        for (PluginInformation pi: plugins) { 
     512            sb.append("<li>").append(pi.name).append("</li>"); 
     513        } 
     514        sb.append("</ul>"); 
     515        sb.append(tr("Please open the Preference Dialog after JOSM has started and try to update them manually.")); 
     516        sb.append("</html>"); 
     517        JOptionPane.showMessageDialog( 
     518                Main.parent, 
     519                sb.toString(), 
     520                tr("Plugin update failed"), 
     521                JOptionPane.ERROR_MESSAGE 
     522        ); 
     523    } 
     524 
     525    /** 
     526     * Updates the plugins in <code>plugins</code>. 
     527     *  
     528     * @param plugins the collection of plugins to update. Must not be null. 
     529     * @param monitor the progress monitor. Defaults to {@see NullProgressMonitor#INSTANCE} if null. 
     530     * @throws IllegalArgumentException thrown if plugins is null 
     531     */ 
     532    public static void updatePlugins(Collection<PluginInformation> plugins, ProgressMonitor monitor) throws IllegalArgumentException{ 
     533        CheckParameterUtil.ensureParameterNotNull(plugins, "plugins"); 
     534        if (monitor == null) { 
     535            monitor = NullProgressMonitor.INSTANCE; 
     536        } 
     537        try { 
     538            PluginDownloadTask task = new PluginDownloadTask( 
     539                    monitor, 
     540                    plugins, 
     541                    tr("Update plugins") 
     542            ); 
     543            ExecutorService service = Executors.newSingleThreadExecutor(); 
     544            Future<?> future = service.submit(task); 
     545            try { 
     546                future.get(); 
     547            } catch(ExecutionException e) { 
     548                e.printStackTrace(); 
     549            } catch(InterruptedException e) { 
     550                e.printStackTrace(); 
     551            } 
     552            if (! task.getFailedPlugins().isEmpty()) { 
     553                alertFailedPluginUpdate(task.getFailedPlugins()); 
     554                return; 
     555            } 
     556        } finally { 
     557            monitor.finishTask(); 
     558        } 
     559        // remember the update because it was successful 
     560        // 
     561        Main.pref.putInteger("pluginmanager.version", Version.getInstance().getVersion()); 
     562        Main.pref.put("pluginmanager.lastupdate", Long.toString(System.currentTimeMillis())); 
     563    } 
     564 
     565    /** 
     566     * Ask the user for confirmation that a plugin shall be disabled. 
     567     *  
     568     * @param reason the reason for disabling the plugin 
     569     * @param name the plugin name 
     570     * @return true, if the plugin shall be disabled; false, otherwise 
     571     */ 
     572    public static boolean confirmDisablePlugin(String reason, String name) { 
    219573        ExtendedDialog dialog = new ExtendedDialog( 
    220574                Main.parent, 
    221575                tr("Disable plugin"), 
    222                 new String[] {tr("Disable plugin"), tr("Keep plugin")} 
     576                new String[] { 
     577                    tr("Disable plugin"), tr("Keep plugin") 
     578                } 
    223579        ); 
    224580        dialog.setContent(reason); 
    225         dialog.setButtonIcons( new String[] {"dialogs/delete.png", "cancel.png"}); 
     581        dialog.setButtonIcons(new String[] { "dialogs/delete.png", "cancel.png" }); 
    226582        dialog.showDialog(); 
    227         int result = dialog.getValue(); 
    228  
    229         if(result == 1) 
    230         { 
    231             Main.pref.removeFromCollection("plugins", name); 
    232             return true; 
    233         } 
    234         return false; 
    235     } 
    236  
    237     public static void setMapFrame(MapFrame old, MapFrame map) { 
     583        return dialog.getValue() == 1; 
     584    } 
     585 
     586    /** 
     587     * Notified loaded plugins about a new map frame 
     588     *  
     589     * @param old the old map frame 
     590     * @param map the new map frame 
     591     */ 
     592    public static void notifyMapFrameChanged(MapFrame old, MapFrame map) { 
    238593        for (PluginProxy plugin : pluginList) { 
    239594            plugin.mapFrameInitialized(old, map); 
     
    248603    } 
    249604 
    250     public static void addDownloadSelection(List<DownloadSelection> downloadSelections) 
    251     { 
     605    public static void addDownloadSelection(List<DownloadSelection> downloadSelections) { 
    252606        for (PluginProxy p : pluginList) { 
    253607            p.addDownloadSelection(downloadSelections); 
    254608        } 
    255609    } 
    256     public static void getPreferenceSetting(Collection<PreferenceSettingFactory> settings) 
    257     { 
     610 
     611    public static void getPreferenceSetting(Collection<PreferenceSettingFactory> settings) { 
    258612        for (PluginProxy plugin : pluginList) { 
    259613            settings.add(new PluginPreferenceFactory(plugin)); 
     
    261615    } 
    262616 
    263     public static void earlyCleanup() 
    264     { 
    265         if (!PluginDownloader.moveUpdatedPlugins()) { 
    266             JOptionPane.showMessageDialog( 
    267                     Main.parent, 
    268                     tr("Activating the updated plugins failed. Check if JOSM has the permission to overwrite the existing ones."), 
    269                     tr("Plugins"), JOptionPane.ERROR_MESSAGE); 
    270         } 
    271     } 
    272     public static Boolean checkException(Throwable e) 
     617    /** 
     618     * Installs downloaded plugins. Moves files with the suffix ".jar.new" to the corresponding 
     619     * ".jar" files. 
     620     *  
     621     */ 
     622    public static void installDownloadedPlugins() { 
     623        File pluginDir = Main.pref.getPluginsDirectory(); 
     624        if (! pluginDir.exists() || ! pluginDir.isDirectory() || ! pluginDir.canWrite()) 
     625            return; 
     626 
     627        final File[] files = pluginDir.listFiles(new FilenameFilter() { 
     628            public boolean accept(File dir, String name) { 
     629                return name.endsWith(".jar.new"); 
     630            }}); 
     631 
     632        for (File updatedPlugin : files) { 
     633            final String filePath = updatedPlugin.getPath(); 
     634            File plugin = new File(filePath.substring(0, filePath.length() - 4)); 
     635            String pluginName = updatedPlugin.getName().substring(0, updatedPlugin.getName().length() - 8); 
     636            if (plugin.exists()) { 
     637                if (!plugin.delete()) { 
     638                    System.err.println(tr("Warning: failed to delete outdated plugin ''{0}''.", plugin.toString())); 
     639                    System.err.println(tr("Warning: failed to install already downloaded plugin ''{0}''. Skipping installation. JOSM still going to load the old plugin version.", pluginName)); 
     640                    continue; 
     641                } 
     642            } 
     643            if (!updatedPlugin.renameTo(plugin)) { 
     644                System.err.println(tr("Warning: failed to install plugin ''{0}'' from temporary download file ''{1}''. Renaming failed.", plugin.toString(), updatedPlugin.toString())); 
     645                System.err.println(tr("Warning: failed to install already downloaded plugin ''{0}''. Skipping installation. JOSM still going to load the old plugin version.", pluginName)); 
     646            } 
     647        } 
     648        return; 
     649    } 
     650 
     651    public static boolean checkException(Throwable e) 
    273652    { 
    274653        PluginProxy plugin = null; 
     
    350729        return false; 
    351730    } 
    352     public static String getBugReportText() 
    353     { 
     731 
     732    public static String getBugReportText() { 
    354733        String text = ""; 
    355734        String pl = Main.pref.getCollectionAsString("plugins"); 
    356         if(pl != null && pl.length() != 0) { 
    357             text += "Plugins: "+pl+"\n"; 
     735        if (pl != null && pl.length() != 0) { 
     736            text += "Plugins: " + pl + "\n"; 
    358737        } 
    359738        for (final PluginProxy pp : pluginList) { 
    360             text += "Plugin " + pp.info.name + (pp.info.version != null && !pp.info.version.equals("") ? " Version: "+pp.info.version+"\n" : "\n"); 
     739            text += "Plugin " 
     740                + pp.info.name 
     741                + (pp.info.version != null && !pp.info.version.equals("") ? " Version: " + pp.info.version + "\n" 
     742                        : "\n"); 
    361743        } 
    362744        return text; 
    363745    } 
    364     public static JPanel getInfoPanel() 
    365     { 
     746 
     747    public static JPanel getInfoPanel() { 
    366748        JPanel pluginTab = new JPanel(new GridBagLayout()); 
    367749        for (final PluginProxy p : pluginList) { 
    368             String name = p.info.name + (p.info.version != null && !p.info.version.equals("") ? " Version: "+p.info.version : ""); 
     750            String name = p.info.name 
     751            + (p.info.version != null && !p.info.version.equals("") ? " Version: " + p.info.version : ""); 
    369752            pluginTab.add(new JLabel(name), GBC.std()); 
    370753            pluginTab.add(Box.createHorizontalGlue(), GBC.std().fill(GBC.HORIZONTAL)); 
    371             pluginTab.add(new JButton(new AbstractAction(tr("Information")){ 
     754            pluginTab.add(new JButton(new AbstractAction(tr("Information")) { 
    372755                public void actionPerformed(ActionEvent event) { 
    373756                    StringBuilder b = new StringBuilder(); 
    374                     for (Entry<String,String> e : p.info.attr.entrySet()) { 
     757                    for (Entry<String, String> e : p.info.attr.entrySet()) { 
    375758                        b.append(e.getKey()); 
    376759                        b.append(": "); 
     
    378761                        b.append("\n"); 
    379762                    } 
    380                     JTextArea a = new JTextArea(10,40); 
     763                    JTextArea a = new JTextArea(10, 40); 
    381764                    a.setEditable(false); 
    382765                    a.setText(b.toString()); 
    383                     JOptionPane.showMessageDialog( 
    384                             Main.parent, 
    385                             new JScrollPane(a), 
    386                             tr("Plugin information"), 
    387                             JOptionPane.INFORMATION_MESSAGE 
    388                     ); 
     766                    JOptionPane.showMessageDialog(Main.parent, new JScrollPane(a), tr("Plugin information"), 
     767                            JOptionPane.INFORMATION_MESSAGE); 
    389768                } 
    390769            }), GBC.eol()); 
    391770 
    392             JTextArea description = new JTextArea((p.info.description==null? tr("no description available"):p.info.description)); 
     771            JTextArea description = new JTextArea((p.info.description == null ? tr("no description available") 
     772                    : p.info.description)); 
    393773            description.setEditable(false); 
    394774            description.setFont(new JLabel().getFont().deriveFont(Font.ITALIC)); 
    395775            description.setLineWrap(true); 
    396776            description.setWrapStyleWord(true); 
    397             description.setBorder(BorderFactory.createEmptyBorder(0,20,0,0)); 
     777            description.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 0)); 
    398778            description.setBackground(UIManager.getColor("Panel.background")); 
    399779 
  • trunk/src/org/openstreetmap/josm/plugins/PluginInformation.java

    r2620 r2817  
    4343    public int stage = 50; 
    4444    public String version = null; 
     45    public String localversion = null; 
    4546    public String downloadlink = null; 
    4647    public List<URL> libraries = new LinkedList<URL>(); 
     
    6061     * @param file the plugin jar file. 
    6162     */ 
    62     public PluginInformation(File file) { 
     63    public PluginInformation(File file) throws PluginException{ 
    6364        this(file, file.getName().substring(0, file.getName().length()-4)); 
    6465    } 
    6566 
    66     public PluginInformation(File file, String name) { 
     67    public PluginInformation(File file, String name) throws PluginException{ 
    6768        this.name = name; 
    6869        this.file = file; 
     70        JarInputStream jar = null; 
    6971        try { 
    70             JarInputStream jar = new JarInputStream(new FileInputStream(file)); 
     72            jar = new JarInputStream(new FileInputStream(file)); 
    7173            Manifest manifest = jar.getManifest(); 
    7274            if (manifest == null) 
    73                 throw new IOException(file+" contains no manifest."); 
     75                throw new PluginException(name, tr("The plugin file ''{0}'' doesn't include a Manifest.", file.toString())); 
    7476            scanManifest(manifest, false); 
    7577            libraries.add(0, fileToURL(file)); 
    76             jar.close(); 
    7778        } catch (IOException e) { 
    78             throw new PluginException(null, name, e); 
    79         } 
    80     } 
    81  
    82     public PluginInformation(InputStream manifestStream, String name, String url) { 
     79            throw new PluginException(name, e); 
     80        } finally { 
     81            if (jar != null) { 
     82                try { 
     83                    jar.close(); 
     84                } catch(IOException e) { /* ignore */ } 
     85            } 
     86        } 
     87    } 
     88 
     89    public PluginInformation(InputStream manifestStream, String name, String url) throws PluginException { 
    8390        this.name = name; 
    8491        try { 
     
    9097            scanManifest(manifest, url != null); 
    9198        } catch (IOException e) { 
    92             throw new PluginException(null, name, e); 
     99            throw new PluginException(name, e); 
    93100        } 
    94101    } 
     
    167174    } 
    168175 
    169     public String getLinkDescription() 
    170     { 
    171         String d = description == null ? tr("no description available") : description; 
    172         if(link != null) { 
    173             d += " <A HREF=\""+link+"\">"+tr("More details")+"</A>"; 
    174         } 
    175         return d; 
     176    /** 
     177     * Replies the description as HTML document, including a link to a web page with 
     178     * more information, provided such a link is available. 
     179     *  
     180     * @return the description as HTML document 
     181     */ 
     182    public String getDescriptionAsHtml() { 
     183        StringBuilder sb = new StringBuilder(); 
     184        sb.append("<html><body>"); 
     185        sb.append(description == null ? tr("no description available") : description); 
     186        if (link != null) { 
     187            sb.append(" <a href=\"").append(link).append("\">").append(tr("More info...")).append("</a>"); 
     188        } 
     189        sb.append("</body></html>"); 
     190        return sb.toString(); 
    176191    } 
    177192 
     
    179194     * Load and instantiate the plugin 
    180195     */ 
    181     public PluginProxy load(Class<?> klass) { 
     196    public PluginProxy load(Class<?> klass) throws PluginException{ 
    182197        try { 
    183198            currentPluginInitialization = this; 
    184199            return new PluginProxy(klass.newInstance(), this); 
    185         } catch (Exception e) { 
    186             throw new PluginException(null, name, e); 
     200        } catch(IllegalAccessException e) { 
     201            throw new PluginException(name, e); 
     202        } catch (InstantiationException e) { 
     203            throw new PluginException(name, e); 
    187204        } 
    188205    } 
     
    191208     * Load the class of the plugin 
    192209     */ 
    193     public Class<?> loadClass(ClassLoader classLoader) { 
     210    public Class<?> loadClass(ClassLoader classLoader) throws PluginException { 
    194211        if (className == null) 
    195212            return null; 
    196         try { 
     213        try{ 
    197214            Class<?> realClass = Class.forName(className, true, classLoader); 
    198215            return realClass; 
    199         } catch (Exception e) { 
    200             throw new PluginException(null, name, e); 
     216        } catch (ClassNotFoundException e) { 
     217            throw new PluginException(name, e); 
    201218        } 
    202219    } 
     
    272289        return all; 
    273290    } 
     291 
     292    /** 
     293     * Replies true if the plugin with the given information is most likely outdated with 
     294     * respect to the referenceVersion. 
     295     *  
     296     * @param referenceVersion the reference version. Can be null if we don't know a 
     297     * reference version 
     298     *  
     299     * @return true, if the plugin needs to be updated; false, otherweise 
     300     */ 
     301    public boolean isUpdateRequired(String referenceVersion) { 
     302        if (this.version == null && referenceVersion!= null) 
     303            return true; 
     304        if (this.version != null && !this.version.equals(referenceVersion)) 
     305            return true; 
     306        return false; 
     307    } 
     308 
     309    /** 
     310     * Replies true if this this plugin should be updated/downloaded because either 
     311     * it is not available locally (its local version is null) or its local version is 
     312     * older than the available version on the server. 
     313     *  
     314     * @return true if the plugin should be updated 
     315     */ 
     316    public boolean isUpdateRequired() { 
     317        if (this.localversion == null) return false; 
     318        return isUpdateRequired(this.localversion); 
     319    } 
     320 
     321    protected boolean matches(String filter, String value) { 
     322        if (filter == null) return true; 
     323        if (value == null) return false; 
     324        return value.toLowerCase().contains(filter.toLowerCase()); 
     325    } 
     326 
     327    /** 
     328     * Replies true if either the name, the description, or the version match (case insensitive) 
     329     * one of the words in filter. Replies true if filter is null. 
     330     *  
     331     * @param filter the filter expression 
     332     * @return true if this plugin info matches with the filter 
     333     */ 
     334    public boolean matches(String filter) { 
     335        if (filter == null) return true; 
     336        String words[] = filter.split("\\s+"); 
     337        for (String word: words) { 
     338            if (matches(word, name) 
     339                    || matches(word, description) 
     340                    || matches(word, version) 
     341                    || matches(word, localversion)) 
     342                return true; 
     343        } 
     344        return false; 
     345    } 
     346 
     347    /** 
     348     * Replies the name of the plugin 
     349     */ 
     350    public String getName() { 
     351        return name; 
     352    } 
     353 
     354    /** 
     355     * Sets the name 
     356     * @param name 
     357     */ 
     358    public void setName(String name) { 
     359        this.name = name; 
     360    } 
     361 
    274362} 
Note: See TracChangeset for help on using the changeset viewer.