/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.plugin.skinmanager;
import java.util.*;
import javax.swing.*;
import org.osgi.framework.*;
/**
* SkinSelector is extending a JComboBox and represents
* a selector for selecting of SIP Communicator skins.
*
* @author Adam Netocny
* @author Yana Stamcheva
*/
public class SkinSelector
extends JComboBox
implements BundleListener
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
/**
* Text for the default skin menu item.
*/
public static final String DEFAULT_TEXT
= Resources.getString("plugin.skinmanager.DEFAULT_SKIN");
/**
* Text for the default skin menu item description section.
*/
public static final String DEFAULT_DESCRIPTION_TEXT
= Resources.getString("plugin.skinmanager.DEFAULT_SKIN_DESCRIPTION");
/**
* Text for the add skin menu item.
*/
public static final String ADD_TEXT
= Resources.getString("plugin.skinmanager.ADD_NEW_SKIN");
/**
* Action listener for skin selection.
*/
private SkinSelectionListener listener;
/**
* Thread lock.
*/
private final Object lock = new Object();
/**
* Casts the data model to DefaultComboBoxModel.
*/
private final DefaultComboBoxModel dataModel
= (DefaultComboBoxModel) super.dataModel;
/**
* Constructor.
*/
public SkinSelector()
{
SkinManagerActivator.bundleContext.addBundleListener(this);
listener = new SkinSelectionListener();
addActionListener(listener);
setRenderer(new SkinSelectorRenderer());
init();
}
/**
* Reloads the skin list.
*/
private void init()
{
if(listener != null)
listener.suppressAction(true);
synchronized(lock)
{
removeAllItems();
addItem(DEFAULT_TEXT);
addSkinBundles();
addItem(SkinSelectorRenderer.SEPARATOR);
addItem(ADD_TEXT);
}
selectActiveSkin();
SwingUtilities.invokeLater(
new Runnable()
{
public void run()
{
if(listener != null)
listener.suppressAction(false);
}
});
}
/**
* Selects the active skin.
*/
public void selectActiveSkin()
{
// If we're not in the event dispatch thread should first move to it.
if(!SwingUtilities.isEventDispatchThread())
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
selectActiveSkin();
}
});
if(listener != null)
listener.suppressAction(true);
synchronized(lock)
{
boolean found = false;
for (int i = 0; i < dataModel.getSize(); i++)
{
Object o = dataModel.getElementAt(i);
if (!(o instanceof Bundle))
continue;
Bundle b = (Bundle) o;
if(b.getState() == Bundle.ACTIVE
|| b.getState() == Bundle.STARTING)
{
setSelectedItem(b);
found = true;
}
}
if(!found)
setSelectedIndex(0);
}
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
if(listener != null)
listener.suppressAction(false);
}
});
}
/**
* Selects the default skin(no-skin).
*/
public void selectNoSkin()
{
// If we're not in the event dispatch thread should first move to it.
if(!SwingUtilities.isEventDispatchThread())
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
selectNoSkin();
}
});
setSelectedIndex(0);
synchronized(lock)
{
for (int i = 0; i < getModel().getSize(); i++)
{
Object o = getModel().getElementAt(i);
if (!(o instanceof Bundle))
continue;
Bundle b = (Bundle) o;
try
{
if (b.getState() == Bundle.ACTIVE)
b.stop();
}
catch (BundleException ex)
{
//ex.printStackTrace();
}
}
}
}
/**
* Adds all selectable skin bundles into the list.
*/
private void addSkinBundles()
{
Bundle[] list = SkinManagerActivator.bundleContext.getBundles();
Arrays.sort(list, new BundleComparator());
if (list != null && list.length != 0)
{
for (Bundle b : list)
{
if(isSkin(b))
addItem(b);
}
}
}
/**
* Bundle listener implementation. Reloads the list.
*
* @param be BundleEvent.
*/
public void bundleChanged(final BundleEvent be)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
Bundle b = be.getBundle();
int eventType = be.getType();
if (eventType == BundleEvent.INSTALLED && isSkin(b))
{
insertItemAt(b, dataModel.getSize() - 2);
return;
}
else if (eventType == BundleEvent.UNINSTALLED && isSkin(b))
{
if (getSelectedItem().equals(b))
{
selectNoSkin();
removeItem(b);
}
return;
}
// We're only interested in bundle events related to our
// skin list.
if (dataModel.getIndexOf(b) < 0)
return;
if ((eventType == BundleEvent.STOPPING
|| eventType == BundleEvent.STARTING)
&& getSelectedItem().equals(b))
{
selectNoSkin();
}
else if (eventType == BundleEvent.STARTED
&& !getSelectedItem().equals(b))
{
selectActiveSkin();
}
}
});
}
/**
* Checks if the given bundle is a skin.
*
* @param bundle the Bundle to check
* @return true if the given bundle is a skin,
* false otherwise
*/
private boolean isSkin(Bundle bundle)
{
Dictionary, ?> headers = bundle.getHeaders();
if (headers.get(Constants.BUNDLE_ACTIVATOR) != null)
{
if (headers.get(Constants.BUNDLE_ACTIVATOR).toString()
.equals("net.java.sip.communicator.plugin." +
"skinresourcepack.SkinResourcePack"))
{
return true;
}
}
return false;
}
}