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.inspector;
020
021import icy.gui.component.ImageComponent;
022import icy.gui.component.button.IcyButton;
023import icy.gui.main.GlobalPluginListener;
024import icy.gui.util.ComponentUtil;
025import icy.main.Icy;
026import icy.plugin.PluginDescriptor;
027import icy.plugin.abstract_.Plugin;
028import icy.resource.ResourceUtil;
029import icy.resource.icon.IcyIcon;
030import icy.system.thread.ThreadUtil;
031
032import java.awt.BorderLayout;
033import java.awt.Component;
034import java.awt.Dimension;
035import java.awt.event.ActionEvent;
036import java.awt.event.ActionListener;
037import java.lang.ref.WeakReference;
038
039import javax.swing.BorderFactory;
040import javax.swing.Box;
041import javax.swing.BoxLayout;
042import javax.swing.JComponent;
043import javax.swing.JLabel;
044import javax.swing.JPanel;
045import javax.swing.JScrollPane;
046
047/**
048 * @author Stephane
049 */
050public class PluginsPanel extends JPanel implements GlobalPluginListener, Runnable
051{
052    private class PluginComponent extends JPanel
053    {
054        /**
055         * 
056         */
057        private static final long serialVersionUID = -6723991851130108797L;
058
059        // we use a weak reference so the plugin can be released by GC
060        final WeakReference<Plugin> plugin;
061
062        /**
063         * internals
064         */
065        final PluginDescriptor descriptor;
066
067        /**
068         * 
069         */
070        public PluginComponent(Plugin plugin)
071        {
072            super(true);
073
074            this.plugin = new WeakReference<Plugin>(plugin);
075            descriptor = plugin.getDescriptor();
076
077            setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
078            setBorder(BorderFactory.createEtchedBorder());
079            ComponentUtil.setFixedHeight(this, 24);
080
081            build();
082        }
083
084        /**
085         * build the component
086         */
087        private void build()
088        {
089            removeAll();
090
091            final JComponent image = new ImageComponent(descriptor.getIconAsImage());
092            ComponentUtil.setFixedSize(image, new Dimension(20, 20));
093
094            final JLabel label = new JLabel(descriptor.getName());
095            label.setToolTipText(descriptor.getName() + " " + descriptor.getVersion());
096
097            final IcyButton killButton = new IcyButton(new IcyIcon(ResourceUtil.ICON_CLOSE, 16));
098            killButton.setFlat(true);
099            killButton.setEnabled(false);
100            killButton.setToolTipText("kill plugin");
101            ComponentUtil.setFixedSize(killButton, new Dimension(18, 18));
102            killButton.addActionListener(new ActionListener()
103            {
104                @Override
105                public void actionPerformed(ActionEvent e)
106                {
107                    // kill plugin, not possible with our current implementation...
108                }
109            });
110
111            add(image);
112            add(Box.createHorizontalStrut(4));
113            add(label);
114            add(Box.createHorizontalGlue());
115            add(killButton);
116            add(Box.createHorizontalStrut(2));
117
118            refresh();
119        }
120
121        void refresh()
122        {
123            validate();
124        }
125
126        /**
127         * @return the plugin
128         */
129        public Plugin getPlugin()
130        {
131            return plugin.get();
132        }
133    }
134
135    /**
136     * 
137     */
138    private static final long serialVersionUID = 8950935360929507468L;
139
140    private final JPanel pluginsPanel;
141
142    /**
143     * 
144     */
145    public PluginsPanel()
146    {
147        super(true);
148
149        pluginsPanel = new JPanel(true);
150        pluginsPanel.setLayout(new BoxLayout(pluginsPanel, BoxLayout.PAGE_AXIS));
151
152        setLayout(new BorderLayout());
153
154        add(new JScrollPane(pluginsPanel), BorderLayout.CENTER);
155
156        rebuildPluginPanel();
157
158        validate();
159        setVisible(true);
160    }
161
162    @Override
163    public void addNotify()
164    {
165        super.addNotify();
166
167        Icy.getMainInterface().addGlobalPluginListener(this);
168    }
169
170    @Override
171    public void removeNotify()
172    {
173        Icy.getMainInterface().removeGlobalPluginListener(this);
174
175        super.removeNotify();
176    }
177
178    void rebuildPluginPanel()
179    {
180        pluginsPanel.removeAll();
181
182        for (Plugin plugin : Icy.getMainInterface().getActivePlugins())
183            pluginsPanel.add(new PluginComponent(plugin));
184        pluginsPanel.add(Box.createVerticalGlue());
185
186        pluginsPanel.validate();
187        // as we use a scroll pane in tab, not nice...
188        pluginsPanel.getParent().validate();
189        pluginsPanel.getParent().repaint();
190    }
191
192    private PluginComponent getPluginComponent(Plugin plugin)
193    {
194        for (Component comp : pluginsPanel.getComponents())
195        {
196            if (comp instanceof PluginComponent)
197            {
198                final PluginComponent pluginComponent = (PluginComponent) comp;
199
200                if (pluginComponent.getPlugin() == plugin)
201                    return pluginComponent;
202            }
203        }
204
205        return null;
206    }
207
208    @Override
209    public void run()
210    {
211        // need to be done on EDT
212        ThreadUtil.invokeNow(new Runnable()
213        {
214
215            @Override
216            public void run()
217            {
218                rebuildPluginPanel();
219            }
220        });
221    }
222
223    @Override
224    public void pluginStarted(Plugin plugin)
225    {
226        ThreadUtil.runSingle(this);
227    }
228
229    @Override
230    public void pluginEnded(Plugin plugin)
231    {
232        ThreadUtil.runSingle(this);
233    }
234}