001/*
002 * Copyright 2010-2015 Institut Pasteur.
003 * 
004 * This file is part of Icy.
005 * 
006 * Icy is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 * 
011 * Icy is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014 * GNU General Public License for more details.
015 * 
016 * You should have received a copy of the GNU General Public License
017 * along with Icy. If not, see <http://www.gnu.org/licenses/>.
018 */
019package icy.gui.preferences;
020
021import icy.gui.dialog.ConfirmDialog;
022import icy.plugin.PluginDescriptor;
023import icy.plugin.PluginInstaller;
024import icy.plugin.PluginInstaller.PluginInstallerListener;
025import icy.plugin.PluginLoader;
026import icy.plugin.PluginRepositoryLoader;
027import icy.plugin.PluginRepositoryLoader.PluginRepositoryLoaderListener;
028import icy.preferences.RepositoryPreferences.RepositoryInfo;
029import icy.system.thread.ThreadUtil;
030
031import java.util.ArrayList;
032import java.util.List;
033
034/**
035 * @author Stephane
036 */
037public class PluginOnlinePreferencePanel extends PluginListPreferencePanel implements PluginRepositoryLoaderListener,
038        PluginInstallerListener
039{
040    private enum PluginOnlineState
041    {
042        NULL, INSTALLING, REMOVING, HAS_INSTALL, INSTALLED, INSTALLED_FAULTY, OLDER, NEWER
043    }
044
045    /**
046     * 
047     */
048    private static final long serialVersionUID = 7737976340704271890L;
049
050    public static final String NODE_NAME = "Online Plugin";
051
052    PluginOnlinePreferencePanel(PreferenceFrame parent)
053    {
054        super(parent, NODE_NAME, PluginPreferencePanel.NODE_NAME);
055
056        PluginRepositoryLoader.addListener(this);
057        PluginInstaller.addListener(this);
058
059        // remove last column not used here
060        table.removeColumn(table.getColumn(columnIds[4]));
061
062        repositoryPanel.setVisible(true);
063        action1Button.setText("Delete");
064        action1Button.setVisible(true);
065        action2Button.setText("Install");
066        action2Button.setVisible(true);
067
068        updateButtonsState();
069        updateRepositories();
070    }
071
072    @Override
073    protected void closed()
074    {
075        super.closed();
076
077        PluginRepositoryLoader.removeListener(this);
078        PluginInstaller.removeListener(this);
079    }
080
081    private PluginOnlineState getPluginOnlineState(PluginDescriptor plugin)
082    {
083        if (plugin == null)
084            return PluginOnlineState.NULL;
085
086        if ((PluginInstaller.isInstallingPlugin(plugin)))
087            return PluginOnlineState.INSTALLING;
088        if ((PluginInstaller.isDesinstallingPlugin(plugin)))
089            return PluginOnlineState.REMOVING;
090
091        // has a local version ?
092        if (plugin.isInstalled())
093        {
094            // get local version
095            final PluginDescriptor localPlugin = PluginLoader.getPlugin(plugin.getClassName());
096
097            if (localPlugin != null)
098            {
099                if (plugin.equals(localPlugin))
100                    return PluginOnlineState.INSTALLED;
101                if (plugin.isOlder(localPlugin))
102                    return PluginOnlineState.OLDER;
103                if (plugin.isNewer(localPlugin))
104                    return PluginOnlineState.NEWER;
105            }
106
107            // local version not loaded --> faulty
108            return PluginOnlineState.INSTALLED_FAULTY;
109        }
110
111        return PluginOnlineState.HAS_INSTALL;
112    }
113
114    @Override
115    protected void doAction1()
116    {
117        final List<PluginDescriptor> selectedPlugins = getSelectedPlugins();
118        final List<PluginDescriptor> toRemove = new ArrayList<PluginDescriptor>();
119
120        for (PluginDescriptor plugin : selectedPlugins)
121        {
122            final PluginOnlineState state = getPluginOnlineState(plugin);
123
124            // remove plugin
125            if ((state == PluginOnlineState.INSTALLED) || (state == PluginOnlineState.INSTALLED_FAULTY))
126                toRemove.add(plugin);
127        }
128
129        // nothing to remove
130        if (toRemove.isEmpty())
131            return;
132
133        // get dependants plugins
134        final List<PluginDescriptor> dependants = PluginInstaller.getLocalDependenciesFrom(toRemove);
135        // delete the one we plan to remove
136        dependants.removeAll(toRemove);
137
138        String message = "<html>";
139
140        if (!dependants.isEmpty())
141        {
142            message = message + "The following plugin(s) won't work anymore :<br>";
143
144            for (PluginDescriptor depPlug : dependants)
145                message = message + depPlug.getName() + " " + depPlug.getVersion() + "<br>";
146
147            message = message + "<br>";
148        }
149
150        message = message + "Are you sure you want to remove selected plugin(s) ?</html>";
151
152        if (ConfirmDialog.confirm(message))
153        {
154            // remove plugins
155            for (PluginDescriptor plugin : toRemove)
156                PluginInstaller.desinstall(plugin, false, true);
157        }
158
159        // refresh state
160        refreshTableData();
161    }
162
163    @Override
164    protected void doAction2()
165    {
166        final List<PluginDescriptor> selectedPlugins = getSelectedPlugins();
167
168        for (PluginDescriptor plugin : selectedPlugins)
169        {
170            final PluginOnlineState state = getPluginOnlineState(plugin);
171
172            if ((state == PluginOnlineState.HAS_INSTALL) || (state == PluginOnlineState.NEWER)
173                    || (state == PluginOnlineState.OLDER))
174            {
175                final boolean doInstall;
176
177                if (state == PluginOnlineState.OLDER)
178                    doInstall = ConfirmDialog
179                            .confirm("You'll replace your plugin by an older version !\nAre you sure you want to continue ?");
180                else
181                    doInstall = true;
182
183                // install plugin
184                if (doInstall)
185                    PluginInstaller.install(plugin, true);
186            }
187        }
188
189        // refresh state
190        refreshTableData();
191    }
192
193    @Override
194    protected void repositoryChanged()
195    {
196        refreshPlugins();
197    }
198
199    @Override
200    protected void reloadPlugins()
201    {
202        PluginRepositoryLoader.reload();
203        // so we display the empty list during reload
204        pluginsChanged();
205    }
206
207    @Override
208    protected String getStateValue(PluginDescriptor plugin)
209    {
210        switch (getPluginOnlineState(plugin))
211        {
212            case INSTALLING:
213                return "installing...";
214
215            case REMOVING:
216                return "removing...";
217
218            case NEWER:
219                return "update available";
220
221            case OLDER:
222                return "outdated";
223
224            case INSTALLED:
225                return "installed";
226
227            case INSTALLED_FAULTY:
228                return "faulty";
229        }
230
231        return "";
232    }
233
234    @Override
235    protected List<PluginDescriptor> getPlugins()
236    {
237        // loading...
238        if (!PluginRepositoryLoader.isLoaded())
239            return new ArrayList<PluginDescriptor>();
240
241        // get selected repository
242        final Object selectedItem = repository.getSelectedItem();
243
244        // load plugins from repository
245        if (selectedItem != null)
246            return PluginRepositoryLoader.getPlugins((RepositoryInfo) selectedItem);
247
248        return PluginRepositoryLoader.getPlugins();
249    }
250
251    @Override
252    protected void updateButtonsStateInternal()
253    {
254        super.updateButtonsStateInternal();
255
256        final List<PluginDescriptor> selectedPlugins = getSelectedPlugins();
257        final boolean selected = (selectedPlugins.size() > 0);
258
259        if (PluginRepositoryLoader.isLoaded())
260        {
261            refreshButton.setText("Reload list");
262            refreshButton.setEnabled(true);
263            repository.setEnabled(true);
264        }
265        else
266        {
267            refreshButton.setText("Reloading...");
268            refreshButton.setEnabled(false);
269            repository.setEnabled(false);
270        }
271
272        if (!selected)
273        {
274            action1Button.setEnabled(false);
275            action2Button.setEnabled(false);
276            return;
277        }
278
279        PluginOnlineState state;
280
281        state = PluginOnlineState.NULL;
282        for (PluginDescriptor plugin : selectedPlugins)
283        {
284            switch (getPluginOnlineState(plugin))
285            {
286                case REMOVING:
287                    if (state == PluginOnlineState.NULL)
288                        state = PluginOnlineState.REMOVING;
289                    break;
290
291                case INSTALLED:
292                case INSTALLED_FAULTY:
293                    if ((state == PluginOnlineState.NULL) || (state == PluginOnlineState.REMOVING))
294                        state = PluginOnlineState.INSTALLED;
295                    break;
296            }
297        }
298
299        // some online plugins are already installed ?
300        switch (state)
301        {
302            case REMOVING:
303                // special case where plugins are currently begin removed
304                action1Button.setText("Deleting...");
305                action1Button.setEnabled(false);
306                break;
307
308            case INSTALLED:
309                action1Button.setText("Delete");
310                action1Button.setEnabled(true);
311                break;
312
313            case NULL:
314                action1Button.setText("Delete");
315                action1Button.setEnabled(false);
316                break;
317        }
318
319        state = PluginOnlineState.NULL;
320        for (PluginDescriptor plugin : selectedPlugins)
321        {
322            switch (getPluginOnlineState(plugin))
323            {
324                case INSTALLING:
325                    if (state == PluginOnlineState.NULL)
326                        state = PluginOnlineState.INSTALLING;
327                    break;
328
329                case OLDER:
330                    if ((state == PluginOnlineState.NULL) || (state == PluginOnlineState.INSTALLING))
331                        state = PluginOnlineState.OLDER;
332                    break;
333
334                case NEWER:
335                    if ((state == PluginOnlineState.NULL) || (state == PluginOnlineState.INSTALLING)
336                            || (state == PluginOnlineState.OLDER))
337                        state = PluginOnlineState.NEWER;
338                    break;
339
340                case HAS_INSTALL:
341                    state = PluginOnlineState.HAS_INSTALL;
342                    break;
343            }
344        }
345
346        switch (state)
347        {
348            case INSTALLING:
349                action2Button.setText("Installing...");
350                action2Button.setEnabled(false);
351                break;
352
353            case HAS_INSTALL:
354                action2Button.setText("Install");
355                action2Button.setEnabled(true);
356                break;
357
358            case OLDER:
359                action2Button.setText("Revert");
360                action2Button.setEnabled(true);
361                break;
362
363            case NEWER:
364                action2Button.setText("Update");
365                action2Button.setEnabled(true);
366                break;
367
368            case NULL:
369                action2Button.setText("Install");
370                action2Button.setEnabled(false);
371                break;
372        }
373    }
374
375    @Override
376    public void pluginRepositeryLoaderChanged(PluginDescriptor plugin)
377    {
378        if (plugin != null)
379        {
380            final int ind = getPluginModelIndex(plugin.getClassName());
381
382            if (ind != -1)
383            {
384                ThreadUtil.invokeNow(new Runnable()
385                {
386                    @Override
387                    public void run()
388                    {
389                        try
390                        {
391                            tableModel.fireTableRowsUpdated(ind, ind);
392                        }
393                        catch (Exception e)
394                        {
395                            // ignore possible exception here
396                        }
397                    }
398                });
399            }
400        }
401        else
402            pluginsChanged();
403    }
404
405    @Override
406    public void pluginInstalled(PluginDescriptor plugin, boolean success)
407    {
408        refreshTableData();
409    }
410
411    @Override
412    public void pluginRemoved(PluginDescriptor plugin, boolean success)
413    {
414        refreshTableData();
415    }
416}