Skin implementation bases provided by Adam Netočný (work in progress).

cusax-fix
Yana Stamcheva 15 years ago
parent f6c822cc9e
commit 45cf662978

@ -894,6 +894,7 @@
bundle-slick-runner,bundle-sip,bundle-sip-slick,bundle-fileaccess,
bundle-fileaccess-slick,bundle-neomedia,
bundle-resource-manager,bundle-resources-defaultpack,
bundle-resources-skinpack,
bundle-protocol,bundle-protocol-media,bundle-icq,
bundle-icq-slick,bundle-mock,bundle-smacklib,
bundle-jabber,bundle-jabber-slick,bundle-swing-ui,bundle-ui-service,
@ -911,8 +912,8 @@
bundle-rss, bundle-rss-slick,bundle-plugin-rssaccregwizz,
bundle-zeroconf,bundle-plugin-zeroconfaccregwizz,bundle-plugin-whiteboard,
bundle-irc,bundle-plugin-ircaccregwizz,
bundle-pluginmanager,bundle-notification,bundle-notification-config,
bundle-ssh,bundle-plugin-sshaccregwizz,
bundle-pluginmanager,bundle-skinmanager,bundle-notification,
bundle-notification-config,bundle-ssh,bundle-plugin-sshaccregwizz,
bundle-contacteventhandler,bundle-plugin-contactinfo,
bundle-plugin-accountinfo,bundle-plugin-chatalerter, bundle-keybindings,
bundle-plugin-keybindingChooser,bundle-plugin-globalproxyconfig,
@ -1799,6 +1800,16 @@ javax.swing.event, javax.swing.border"/>
</jar>
</target>
<!-- BUNDLE-SKIN MANAGER -->
<target name="bundle-skinmanager">
<!-- Creates a bundle for the skin manager plugin.-->
<jar compress="false" destfile="${bundles.dest}/skinmanager.jar"
manifest="${src}/net/java/sip/communicator/plugin/skinmanager/skinmanager.manifest.mf">
<zipfileset dir="${dest}/net/java/sip/communicator/plugin/skinmanager"
prefix="net/java/sip/communicator/plugin/skinmanager"/>
</jar>
</target>
<!-- BUNDLE-RSS -->
<target name="bundle-rss">
<!-- Creates a bundle containing the Rss impl of the protocol provider.-->
@ -2165,6 +2176,16 @@ org.apache.http.util"/>
</jar>
</target>
<!--BUNDLE-SKIN-RESOURCES-->
<target name="bundle-resources-skinpack">
<jar
compress="false" destfile="${bundles.dest}/skinresources.jar"
manifest="${src}/net/java/sip/communicator/plugin/skinresourcepack/skinresourcepack.manifest.mf">
<zipfileset dir="${dest}/net/java/sip/communicator/plugin/skinresourcepack"
prefix="net/java/sip/communicator/plugin/skinresourcepack"/>
</jar>
</target>
<!--BUNDLE-RESOURCE-MANAGER-->
<target name="bundle-resource-manager">
<!-- Creates a bundle for the Resource Management Service Impl."-->

@ -109,6 +109,7 @@ felix.auto.start.66= \
felix.auto.start.67= \
reference:file:sc-bundles/pluginmanager.jar \
reference:file:sc-bundles/skinmanager.jar \
reference:file:sc-bundles/whiteboard.jar \
reference:file:sc-bundles/icqaccregwizz.jar \
reference:file:sc-bundles/aimaccregwizz.jar \

@ -762,6 +762,14 @@ plugin.sipaccregwizz.XCAP_USER=User
plugin.sipaccregwizz.XCAP_PASSWORD=Password
plugin.sipaccregwizz.XCAP_SERVER_URI=Server URI
# skin manager
plugin.skinmanager.INSTALL=Install
plugin.skinmanager.UNINSTALL=Uninstall
plugin.skinmanager.SKINS=Skins
plugin.skinmanager.URL=Url
plugin.skinmanager.CHOOSE_FILE=Select Zip
plugin.skinmanager.NEW=New
# ssh accregwizz
plugin.sshaccregwizz.PROTOCOL_NAME=SSH
plugin.sshaccregwizz.PROTOCOL_DESCRIPTION=A Protocol to connect to remote machines over SSH.

@ -13,6 +13,7 @@
import javax.swing.*;
import net.java.sip.communicator.impl.resources.util.*;
import net.java.sip.communicator.service.resources.*;
import net.java.sip.communicator.util.*;
@ -24,6 +25,7 @@
* @author Damian Minkov
* @author Yana Stamcheva
* @author Lubomir Marinov
* @author Adam Netocny, CircleTech, s.r.o.
*/
public class ResourceManagementServiceImpl
implements ResourceManagementService,
@ -54,6 +56,9 @@ public class ResourceManagementServiceImpl
private Map<String, String> soundResources;
private ResourcePack soundPack = null;
private Map<String, String> skinResources;
private SkinPack skinPack = null;
/**
* Initializes already registered default resource packs.
*/
@ -105,6 +110,16 @@ public class ResourceManagementServiceImpl
if (soundPack != null)
soundResources = getResources(soundPack);
skinPack = (SkinPack) getDefaultResourcePack(
SkinPack.class.getName(), SkinPack.RESOURCE_NAME_DEFAULT_VALUE);
if (skinPack != null)
{
skinResources = getResources(skinPack);
imageResources.putAll(skinPack.getImageResources());
colorResources.putAll(skinPack.getColorResources());
}
}
/**
@ -207,6 +222,24 @@ else if(resourcePack instanceof SoundPack && soundPack == null)
soundPack = resourcePack;
soundResources = resources;
}
else if(resourcePack instanceof SkinPack && skinPack == null)
{
skinPack = (SkinPack) resourcePack;
if(imagePack!=null)
{
imageResources = getResources(imagePack);
}
if(colorPack!=null)
{
colorResources = getResources(colorPack);
}
skinResources = resources;
imageResources.putAll(skinPack.getImageResources());
colorResources.putAll(skinPack.getColorResources());
}
}
else if (event.getType() == ServiceEvent.UNREGISTERING)
{
@ -258,6 +291,30 @@ else if(resourcePack instanceof SoundPack
if (soundPack != null)
soundResources = getResources(soundPack);
}
else if(resourcePack instanceof SkinPack
&& skinPack.equals(resourcePack))
{
if(imagePack!=null)
{
imageResources = getResources(imagePack);
}
if(colorPack!=null)
{
colorResources = getResources(colorPack);
}
skinPack = (SkinPack) getDefaultResourcePack(
SkinPack.class.getName(),
SkinPack.RESOURCE_NAME_DEFAULT_VALUE);
if (skinPack != null)
{
skinResources = getResources(skinPack);
imageResources.putAll(skinPack.getImageResources());
colorResources.putAll(skinPack.getColorResources());
}
}
}
}
@ -315,14 +372,24 @@ public String getColorString(String key)
*/
public InputStream getImageInputStreamForPath(String path)
{
return imagePack.getClass().getClassLoader().getResourceAsStream(path);
if(skinPack!=null)
{
if(skinPack.getClass().getClassLoader()
.getResourceAsStream(path)!=null)
{
return skinPack.getClass().getClassLoader()
.getResourceAsStream(path);
}
}
return imagePack.getClass().getClassLoader().getResourceAsStream(path);
}
/**
* Returns the <tt>InputStream</tt> of the image corresponding to the given
* key.
*
* @param streamKey The identifier of the image in the resource properties
* @param streamKey The identifier of the image in the resource properties¿
* file.
* @return the <tt>InputStream</tt> of the image corresponding to the given
* key.
@ -378,6 +445,14 @@ public String getImagePath(String key)
*/
public URL getImageURLForPath(String path)
{
if(skinPack!=null)
{
if(skinPack.getClass().getClassLoader().getResource(path)!=null)
{
return skinPack.getClass().getClassLoader().getResource(path);
}
}
return imagePack.getClass().getClassLoader().getResource(path);
}
@ -419,6 +494,7 @@ public String getI18NString(String key, Locale locale)
* Returns an internationalized string corresponding to the given key.
*
* @param key The identifier of the string.
* @param params the parameters to pass to the localized string
* @return An internationalized string corresponding to the given key.
*/
public String getI18NString(String key, String[] params)
@ -431,6 +507,7 @@ public String getI18NString(String key, String[] params)
*
* @param key The identifier of the string in the resources properties
* file.
* @param params the parameters to pass to the localized string
* @param locale The locale.
* @return An internationalized string corresponding to the given key.
*/
@ -616,6 +693,7 @@ public URL getSoundURL(String urlKey)
/**
* Returns the <tt>URL</tt> of the sound corresponding to the given path.
*
* @param path the path, for which we're looking for a sound URL
* @return the <tt>URL</tt> of the sound corresponding to the given path.
*/
public URL getSoundURLForPath(String path)
@ -627,6 +705,7 @@ public URL getSoundURLForPath(String path)
* Returns the path of the sound corresponding to the given
* property key.
*
* @param soundKey the key, for the sound path
* @return the path of the sound corresponding to the given
* property key.
*/
@ -678,4 +757,16 @@ public ImageIcon getImage(String imageID)
}
return new ImageIcon(imageURL);
}
/**
* Builds a new skin bundle from the zip file content.
* @param zipFile Zip file with skin information.
* @return <tt>File</tt> for the bundle.
* @throws Exception When something goes wrong.
*/
public File prepareSkinBundleFromZip(File zipFile)
throws Exception
{
return SkinJarBuilder.createBundleFromZip(zipFile);
}
}

@ -0,0 +1,302 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.resources.util;
import java.io.*;
import java.util.*;
import java.util.zip.*;
/**
* Class for building of skin bundles from zip files.
* @author Adam Netocny, CircleTech, s.r.o.
*/
public class SkinJarBuilder
{
/**
* Creates bundle from zip file.
* @param zip Zip file with skin contents.
* @return Jar <tt>File</tt>.
* @throws Exception When something goes wrong.
*/
public static File createBundleFromZip(File zip)
throws Exception
{
File tmpDir = unzipIntoTmp(zip);
if (!test(tmpDir))
{
deleteDir(tmpDir);
throw new Exception(
"Zip file doesn't contain all necessary files and folders.");
}
File jar = cpTmp();
insertIntoZip(jar, tmpDir);
deleteDir(tmpDir);
return jar;
}
private static File cpTmp()
throws IOException
{
File jar = new File(System.getProperty("user.dir"),
"sc-bundles/skinresources.jar");
if (!jar.exists())
{
throw new IOException("Cannot find skinresources.jar file");
}
File tmp = File.createTempFile("skinresources", ".jar");
InputStream in = new FileInputStream(jar);
OutputStream out = new FileOutputStream(tmp);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0)
{
out.write(buf, 0, len);
}
in.close();
out.close();
return tmp;
}
private static File unzipIntoTmp(File zip)
throws Exception
{
File dest = File.createTempFile("zip", null);
if (!dest.delete())
{
throw new IOException("Cannot unzip given zip file");
}
if (!dest.mkdirs())
{
throw new IOException("Cannot unzip given zip file");
}
ZipFile archive = new ZipFile(zip);
Enumeration<? extends ZipEntry> e = archive.entries();
while (e.hasMoreElements())
{
ZipEntry entry = (ZipEntry) e.nextElement();
File file = new File(dest, entry.getName());
if (entry.isDirectory() && !file.exists())
{
file.mkdirs();
}
else
{
if (!file.getParentFile().exists())
{
file.getParentFile().mkdirs();
}
InputStream in = archive.getInputStream(entry);
BufferedOutputStream out
= new BufferedOutputStream(new FileOutputStream(file));
byte[] buffer = new byte[8192];
int read;
while (-1 != (read = in.read(buffer)))
{
out.write(buffer, 0, read);
}
in.close();
out.close();
}
}
return dest;
}
private static void insertIntoZip(File jar, File tmpDir)
throws IOException
{
File tempFile = File.createTempFile(jar.getName(), null);
tempFile.delete();
boolean renameOk = jar.renameTo(tempFile);
if (!renameOk)
{
throw new IOException("Error moving file " + jar.getAbsolutePath()
+ " to " + tempFile.getAbsolutePath());
}
byte[] buf = new byte[8192];
ZipInputStream zin = new ZipInputStream(new FileInputStream(tempFile));
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(jar));
ZipEntry entry = zin.getNextEntry();
while (entry != null)
{
String name = entry.getName();
out.putNextEntry(new ZipEntry(name));
int len;
while ((len = zin.read(buf)) > 0)
{
out.write(buf, 0, len);
}
entry = zin.getNextEntry();
}
zin.close();
tempFile.delete();
zipDir(tmpDir.getAbsolutePath(), out);
out.close();
}
private static void zipDir(String dir2zip, ZipOutputStream zos)
throws IOException
{
File directory = new File(dir2zip);
zip(directory, directory, zos);
}
private static final void zip(File directory, File base, ZipOutputStream zos)
throws IOException
{
File[] files = directory.listFiles();
byte[] buffer = new byte[8192];
int read = 0;
for (int i = 0, n = files.length; i < n; i++)
{
if (files[i].isDirectory())
{
zip(files[i], base, zos);
}
else
{
FileInputStream in = new FileInputStream(files[i]);
ZipEntry entry = new ZipEntry(files[i].getPath().substring(
base.getPath().length() + 1));
zos.putNextEntry(entry);
while (-1 != (read = in.read(buffer))) {
zos.write(buffer, 0, read);
}
in.close();
}
}
}
private static void deleteDir(File tmp)
{
if (tmp.exists())
{
File[] files = tmp.listFiles();
for (int i = 0; i < files.length; i++)
{
if (files[i].isDirectory())
{
deleteDir(files[i]);
}
else
{
files[i].delete();
}
}
tmp.delete();
}
}
private static boolean test(File tmpDir)
{
boolean colors = false;
boolean images = false;
boolean styles = false;
File[] list = tmpDir.listFiles();
if (list == null)
{
return false;
}
for (File f : list)
{
if (f.getName().equals("info.properties"))
{
if (!f.isFile())
{
return false;
}
}
else if (f.getName().equals("colors"))
{
if (f.isFile())
{
return false;
}
File[] ff = f.listFiles();
if (ff == null)
{
return false;
}
for (File x : ff)
{
if (x.getName().equals("colors.properties"))
{
colors = true;
}
}
}
else if (f.getName().equals("images"))
{
if (f.isFile())
{
return false;
}
File[] ff = f.listFiles();
if (ff == null)
{
return false;
}
for (File x : ff)
{
if (x.getName().equals("images.properties"))
{
images = true;
}
}
}
else if (f.getName().equals("styles"))
{
if (f.isFile())
{
return false;
}
File[] ff = f.listFiles();
if (ff == null)
{
return false;
}
for (File x : ff)
{
if (x.getName().equals("styles.properties"))
{
styles = true;
}
}
}
else
{
return false;
}
}
return styles && (colors && images);
}
}

@ -27,7 +27,7 @@ public int compare(Bundle arg0, Bundle arg1)
{
String n1 = (String) arg0.getHeaders().get(Constants.BUNDLE_NAME);
String n2 = (String) arg1.getHeaders().get(Constants.BUNDLE_NAME);
if (n1 == null)
{
n1 = "unknown";
@ -36,8 +36,7 @@ public int compare(Bundle arg0, Bundle arg1)
{
n2 = "unknown";
}
return n1.compareTo(n2);
}
}

@ -10,7 +10,6 @@
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.util.*;
@ -29,26 +28,51 @@ public class ManageButtonsPanel
{
private Logger logger = Logger.getLogger(ManageButtonsPanel.class);
/**
* The deactivate skin button.
*/
private JButton deactivateButton = new JButton(
Resources.getString("service.gui.DEACTIVATE"));
/**
* The activate skin button.
*/
private JButton activateButton = new JButton(
Resources.getString("service.gui.ACTIVATE"));
/**
* The uninstall button.
*/
private JButton uninstallButton = new JButton(
Resources.getString("plugin.pluginmanager.UNINSTALL"));
Resources.getString("plugin.skinmanager.UNINSTALL"));
/**
* The update button.
*/
private JButton updateButton = new JButton(
Resources.getString("plugin.pluginmanager.UPDATE"));
/**
* The new button.
*/
private JButton newButton
= new JButton(Resources.getString("plugin.pluginmanager.NEW"));
= new JButton(Resources.getString("plugin.skinmanager.NEW"));
private JPanel buttonsPanel =
new TransparentPanel(new GridLayout(0, 1, 8, 8));
/**
* The panel, containing all buttons.
*/
private JPanel buttonsPanel
= new TransparentPanel(new GridLayout(0, 1, 8, 8));
/**
* The plugins table.
*/
private JTable pluginTable;
/**
* Creates an instance of <tt>ManageButtonsPanel</tt>.
* @param pluginTable the table of bundles
*/
public ManageButtonsPanel(JTable pluginTable)
{
this.pluginTable = pluginTable;
@ -81,6 +105,10 @@ public ManageButtonsPanel(JTable pluginTable)
defaultButtonState();
}
/**
* Performs corresponding operations when a button is pressed.
* @param e the <tt>ActionEvent</tt> that notified us
*/
public void actionPerformed(ActionEvent e)
{
JButton sourceButton = (JButton) e.getSource();

@ -14,36 +14,73 @@
import javax.swing.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.swing.*;
import org.osgi.framework.*;
/**
* @author Yana Stamcheva
*/
public class NewBundleDialog
extends SIPCommDialog
implements ActionListener
{private static final long serialVersionUID = 7638976584338100969L;
{
/**
* The object used for logging.
*/
private Logger logger = Logger.getLogger(NewBundleDialog.class);
private static final long serialVersionUID = 7638976584338100969L;
/**
* The install button.
*/
private JButton installButton
= new JButton(Resources.getString("plugin.pluginmanager.INSTALL"));
/**
* The cancel button.
*/
private JButton cancelButton
= new JButton(Resources.getString("service.gui.CANCEL"));
/**
* The bundle path field.
*/
private JTextField bundlePathField = new JTextField();
/**
* The bundle path label.
*/
private JLabel bundlePathLabel
= new JLabel(Resources.getString("plugin.pluginmanager.URL") + ": ");
/**
* The panel, containing all buttons.
*/
private JPanel buttonsPanel
= new TransparentPanel(new FlowLayout(FlowLayout.CENTER));
/**
* The panel containing new bundle information.
*/
private JPanel dataPanel = new TransparentPanel(new BorderLayout(5, 5));
/**
* The main panel, where all other panels are added.
*/
private JPanel mainPanel = new TransparentPanel(new BorderLayout());
/**
* The button, from which to choose a file from the file system.
*/
private JButton fileChooserButton = new JButton(
Resources.getString("plugin.pluginmanager.CHOOSE_FILE"));
/**
* Creates an instance of <tt>NewBundleDialog</tt>.
*/
public NewBundleDialog ()
{
this.mainPanel.setPreferredSize(new Dimension(450, 150));
@ -70,10 +107,14 @@ public NewBundleDialog ()
this.dataPanel.add(fileChooserButton, BorderLayout.EAST);
}
/**
* Performs corresponding actions, when a buttons is pressed.
* @param e the <tt>ActionEvent</tt> that notified us
*/
public void actionPerformed (ActionEvent e)
{
JButton sourceButton = (JButton) e.getSource();
if (sourceButton.equals(installButton))
{
if (bundlePathField.getText().length() > 0)
@ -85,14 +126,14 @@ public void actionPerformed (ActionEvent e)
}
catch (BundleException ex)
{
ex.printStackTrace();
logger.info("Failed to install bundle.", ex);
PluginManagerActivator.getUIService().getPopupDialog()
.showMessagePopupDialog(ex.getMessage(), "Error",
PopupDialog.ERROR_MESSAGE);
}
catch (Throwable ex)
{
ex.printStackTrace();
logger.info("Failed to install bundle.", ex);
}
finally
{
@ -118,14 +159,18 @@ else if (sourceButton.equals(fileChooserButton))
}
catch (MalformedURLException ex)
{
ex.printStackTrace();
logger.info("Failed parse URL.", ex);
}
}
}
}
else
dispose();
}
/**
* Presses programatically the cancel button, when Esc key is pressed.
* @param isEscaped indicates if the Esc button was pressed on close
*/
protected void close(boolean isEscaped)
{
cancelButton.doClick();

@ -40,21 +40,46 @@ public class PluginListCellRenderer
private static final Color SELECTED_END_COLOR
= new Color(Resources.getColor("service.gui.GRADIENT_LIGHT_COLOR"));
/**
* The panel containing name and version information.
*/
private JPanel nameVersionPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
/**
* The name label.
*/
private JLabel nameLabel = new JLabel();
/**
* The version label.
*/
private JLabel versionLabel = new JLabel();
/**
* The description label.
*/
private JLabel descriptionLabel = new JLabel();
/**
* The state label.
*/
private JLabel stateLabel = new JLabel();
/**
* The icon label.
*/
private JLabel iconLabel = new JLabel();
/**
* The system label indicating that a bundle is system (i.e. not optional).
*/
private JLabel systemLabel
= new JLabel("( " + Resources.getString("plugin.pluginmanager.SYSTEM") + " )");
= new JLabel("( " + Resources.getString("plugin.pluginmanager.SYSTEM")
+ " )");
/**
* Indicates if a skin is selected.
*/
private boolean isSelected = false;
/**
@ -105,16 +130,23 @@ public PluginListCellRenderer()
/**
* Implements the <tt>ListCellRenderer</tt> method.
*
* Returns this panel that has been configured to display the meta contact
* and meta contact group cells.
* Returns this panel that has been configured to display bundle name,
* version and description.
* @param table the parent table
* @param value the value of the rendered cell
* @param isSelected indicates if the rendered cell is selected
* @param hasFocus indicates if the rendered cell has the focus
* @param rowIndex the row index of the rendered cell
* @param vColIndex the column index of the rendered cell
* @return the rendering component
*/
@SuppressWarnings("unchecked")
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int rowIndex, int vColIndex)
{
Bundle bundle = (Bundle) value;
Dictionary headers = bundle.getHeaders();
Dictionary<Object, Object> headers = bundle.getHeaders();
Object bundleName = headers.get(Constants.BUNDLE_NAME);
Object bundleVersion = headers.get(Constants.BUNDLE_VERSION);
Object bundleDescription = headers.get(Constants.BUNDLE_DESCRIPTION);
@ -149,6 +181,11 @@ public Component getTableCellRendererComponent(JTable table, Object value,
return this;
}
/**
* Returns an icon corresponding to the given <tt>state</tt>.
* @param state the state, for which we're looking for an icon
* @return the icon corresponding to the given state
*/
private ImageIcon getStateIcon(int state)
{
int cacheIndex;
@ -188,8 +225,10 @@ private ImageIcon getStateIcon(int state)
/**
* Paint a background for all groups and a round blue border and background
* when a cell is selected.
* @param g the <tt>Graphics</tt> object used for painting
*/
public void paintComponent(Graphics g) {
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g = g.create();
@ -203,6 +242,10 @@ public void paintComponent(Graphics g) {
}
}
/**
* Paints a custom gradient background for selected cells.
* @param g the <tt>Graphics</tt> object used for painting
*/
private void internalPaintComponent(Graphics g)
{
AntialiasingManager.activateAntialiasing(g);

@ -194,7 +194,36 @@ public void setShowSystemBundles(boolean showSystemBundles)
*/
private void refreshSortedBundlesList()
{
this.bundles = this.bundleContext.getBundles();
Bundle[] list = this.bundleContext.getBundles();
ArrayList<Bundle> show = new ArrayList<Bundle>();
if(list != null)
{
for(Bundle b : list)
{
Dictionary headers = b.getHeaders();
if(headers.get(Constants.BUNDLE_ACTIVATOR)!=null)
{
if(!headers.get(Constants.BUNDLE_ACTIVATOR).toString()
.equals("net.java.sip.communicator.plugin." +
"skinresourcepack.SkinResourcesPack"))
{
show.add(b);
}
}
else
{
show.add(b);
}
}
}
this.bundles = new Bundle[show.size()];
int i = 0;
for(Bundle b : show)
{
this.bundles[i] = b;
i++;
}
Arrays.sort(this.bundles, bundleComparator);
}
}

@ -0,0 +1,43 @@
/*
* SIP Communicator, 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 org.osgi.framework.*;
/**
* Comparator for bundle array sort
*
* @author ROTH Damien
*/
public class BundleComparator
implements Comparator<Bundle>
{
/**
* Compares the bundles using their "Bundle-Name"s.
* @param arg0 the first bundle to compare
* @param arg1 the second bundle to compare
* @return the result of the string comparison between the names of the two
* bundles
*/
public int compare(Bundle arg0, Bundle arg1)
{
String n1 = (String) arg0.getHeaders().get(Constants.BUNDLE_NAME);
String n2 = (String) arg1.getHeaders().get(Constants.BUNDLE_NAME);
if (n1 == null)
{
n1 = "unknown";
}
if (n2 == null)
{
n2 = "unknown";
}
return n1.compareTo(n2);
}
}

@ -0,0 +1,245 @@
/*
* SIP Communicator, 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.awt.*;
import java.awt.event.*;
import javax.swing.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.swing.*;
import org.osgi.framework.*;
/**
* The panel containing all buttons for the <tt>PluginManagerConfigForm</tt>.
*
* @author Yana Stamcheva
* @author Adam Netocony, CircleTech, s.r.o.
*/
public class ManageButtonsPanel
extends TransparentPanel
implements ActionListener
{
/**
* The object used for logging.
*/
private Logger logger = Logger.getLogger(ManageButtonsPanel.class);
/**
* The deactivate skin button.
*/
private JButton deactivateButton = new JButton(
Resources.getString("service.gui.DEACTIVATE"));
/**
* The activate skin button.
*/
private JButton activateButton = new JButton(
Resources.getString("service.gui.ACTIVATE"));
/**
* The uninstall button.
*/
private JButton uninstallButton = new JButton(
Resources.getString("plugin.skinmanager.UNINSTALL"));
/**
* The new button.
*/
private JButton newButton
= new JButton(Resources.getString("plugin.skinmanager.NEW"));
/**
* The panel, containing all buttons.
*/
private JPanel buttonsPanel
= new TransparentPanel(new GridLayout(0, 1, 8, 8));
/**
* The table of skins.
*/
private JTable skinTable;
/**
* Creates an instance of <tt>ManageButtonsPanel</tt>.
* @param pluginTable the table of skins
*/
public ManageButtonsPanel(JTable pluginTable)
{
this.skinTable = pluginTable;
this.setLayout(new BorderLayout());
this.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
this.newButton.setOpaque(false);
this.activateButton.setOpaque(false);
this.deactivateButton.setOpaque(false);
this.uninstallButton.setOpaque(false);
this.buttonsPanel.add(newButton);
this.buttonsPanel.add(activateButton);
this.buttonsPanel.add(deactivateButton);
this.buttonsPanel.add(uninstallButton);
this.add(buttonsPanel, BorderLayout.NORTH);
this.newButton.addActionListener(this);
this.activateButton.addActionListener(this);
this.deactivateButton.addActionListener(this);
this.uninstallButton.addActionListener(this);
//default as nothing is selected
defaultButtonState();
}
/**
* Performs corresponding operations when a button is pressed.
* @param e the <tt>ActionEvent</tt> that notified us
*/
public void actionPerformed(ActionEvent e)
{
JButton sourceButton = (JButton) e.getSource();
if (sourceButton.equals(newButton))
{
NewBundleDialog dialog = new NewBundleDialog(skinTable);
dialog.pack();
dialog.setLocation(
Toolkit.getDefaultToolkit().getScreenSize().width / 2
- dialog.getWidth() / 2,
Toolkit.getDefaultToolkit().getScreenSize().height / 2
- dialog.getHeight() / 2);
dialog.setVisible(true);
}
else if (sourceButton.equals(activateButton))
{
int[] selectedRows = skinTable.getSelectedRows();
for (int i = 0; i < skinTable.getModel().getRowCount(); i++)
{
try
{
((Bundle) skinTable.getModel().getValueAt(i, 0)).stop();
}
catch (BundleException ex) { }
}
for (int i = 0; i < selectedRows.length; i++)
{
try
{
((Bundle) skinTable.getModel()
.getValueAt(selectedRows[i], 0)).start();
}
catch (BundleException ex)
{
logger.error("Failed to activate bundle.", ex);
SkinManagerActivator.getUIService().getPopupDialog()
.showMessagePopupDialog(ex.getMessage(), "Error",
PopupDialog.ERROR_MESSAGE);
}
}
defaultButtonState();
}
else if (sourceButton.equals(deactivateButton))
{
int[] selectedRows = skinTable.getSelectedRows();
for (int i = 0; i < selectedRows.length; i++)
{
try
{
((Bundle) skinTable.getModel()
.getValueAt(selectedRows[i], 0)).stop();
}
catch (BundleException ex)
{
logger.error("Failed to desactivate bundle.", ex);
SkinManagerActivator.getUIService().getPopupDialog()
.showMessagePopupDialog(ex.getMessage(), "Error",
PopupDialog.ERROR_MESSAGE);
}
}
defaultButtonState();
}
else if (sourceButton.equals(uninstallButton))
{
int[] selectedRows = skinTable.getSelectedRows();
for (int i = selectedRows.length - 1; i >= 0; i--)
{
try
{
((Bundle) skinTable.getModel()
.getValueAt(selectedRows[i], 0)).uninstall();
}
catch (BundleException ex)
{
logger.error("Failed to uninstall bundle.", ex);
SkinManagerActivator.getUIService().getPopupDialog()
.showMessagePopupDialog(ex.getMessage(), "Error",
PopupDialog.ERROR_MESSAGE);
}
}
defaultButtonState();
}
}
/**
* Default state of buttons, as nothing is selected
*/
public void defaultButtonState()
{
enableActivateButton(false);
enableDeactivateButton(false);
enableUninstallButton(false);
}
/**
* Enable or disable the activate button.
*
* @param enable TRUE - to enable the activate button, FALSE - to disable it
*/
public void enableActivateButton(boolean enable)
{
this.activateButton.setEnabled(enable);
}
/**
* Enable or disable the deactivate button.
*
* @param enable TRUE - to enable the deactivate button, FALSE - to
* disable it
*/
public void enableDeactivateButton(boolean enable)
{
this.deactivateButton.setEnabled(enable);
}
/**
* Enable or disable the uninstall button.
*
* @param enable TRUE - to enable the uninstall button, FALSE - to
* disable it
*/
public void enableUninstallButton(boolean enable)
{
this.uninstallButton.setEnabled(enable);
}
}

@ -0,0 +1,260 @@
/*
* SIP Communicator, 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.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.zip.ZipFile;
import javax.swing.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.swing.*;
import org.osgi.framework.*;
/**
*
* @author Yana Stamcheva
* @author Adam Netcony
*/
public class NewBundleDialog
extends SIPCommDialog
implements ActionListener
{
private static final long serialVersionUID = 7638976584338100969L;
/**
* The object used for logging.
*/
private Logger logger = Logger.getLogger(NewBundleDialog.class);
/**
* The install button.
*/
private JButton installButton
= new JButton(Resources.getString("plugin.pluginmanager.INSTALL"));
/**
* The cancel button.
*/
private JButton cancelButton
= new JButton(Resources.getString("service.gui.CANCEL"));
/**
* The bundle path field.
*/
private JTextField bundlePathField = new JTextField();
/**
* The bundle path label.
*/
private JLabel bundlePathLabel
= new JLabel(Resources.getString("plugin.pluginmanager.URL") + ": ");
/**
* The panel, containing all buttons.
*/
private JPanel buttonsPanel
= new TransparentPanel(new FlowLayout(FlowLayout.CENTER));
/**
* The panel containing new bundle information.
*/
private JPanel dataPanel = new TransparentPanel(new BorderLayout(5, 5));
/**
* The main panel, where all other panels are added.
*/
private JPanel mainPanel = new TransparentPanel(new BorderLayout());
/**
* The button, from which to choose a file from the file system.
*/
private JButton fileChooserButton = new JButton(
Resources.getString("plugin.pluginmanager.CHOOSE_FILE"));
private JTable skinTable;
/**
* Creates an instance of <tt>NewBundleDialog</tt>.
* @param table the skin table
*/
public NewBundleDialog(JTable table)
{
skinTable = table;
this.mainPanel.setPreferredSize(new Dimension(450, 150));
this.getContentPane().add(mainPanel);
this.mainPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
this.mainPanel.add(dataPanel, BorderLayout.NORTH);
this.mainPanel.add(buttonsPanel, BorderLayout.SOUTH);
this.buttonsPanel.add(installButton);
this.buttonsPanel.add(cancelButton);
this.installButton.addActionListener(this);
this.cancelButton.addActionListener(this);
this.fileChooserButton.addActionListener(this);
this.fileChooserButton.setOpaque(false);
this.dataPanel.add(bundlePathLabel, BorderLayout.WEST);
this.dataPanel.add(bundlePathField, BorderLayout.CENTER);
this.dataPanel.add(fileChooserButton, BorderLayout.EAST);
}
/**
* Performs corresponding actions, when a buttons is pressed.
* @param e the <tt>ActionEvent</tt> that notified us
*/
public void actionPerformed(ActionEvent e)
{
JButton sourceButton = (JButton) e.getSource();
if (sourceButton.equals(installButton))
{
if (bundlePathField.getText().length() > 0)
{
try
{
File jar = null;
try
{
jar = Resources.getResources()
.prepareSkinBundleFromZip(
new File(bundlePathField.getText()));
}
catch (Exception ex)
{
logger.info("Failed to load skin from zip.", ex);
SkinManagerActivator.getUIService().getPopupDialog()
.showMessagePopupDialog(ex.getMessage(), "Error",
PopupDialog.ERROR_MESSAGE);
}
if (jar != null)
{
try
{
Bundle newBundle = SkinManagerActivator
.bundleContext.installBundle(
jar.toURI().toURL().toString());
for (int i = 0;
i < skinTable.getModel().getRowCount(); i++)
{
try
{
((Bundle) skinTable.getModel()
.getValueAt(i, 0)).stop();
}
catch (BundleException ex)
{
logger.info("Failed to stop bundle.", ex);
}
}
newBundle.start();
}
catch (MalformedURLException ex)
{
logger.info("Failed to load skin from zip.", ex);
}
}
}
catch (BundleException ex)
{
logger.info("Failed to install bundle.", ex);
SkinManagerActivator.getUIService().getPopupDialog()
.showMessagePopupDialog(ex.getMessage(), "Error",
PopupDialog.ERROR_MESSAGE);
}
catch (Throwable ex)
{
logger.info("Failed to install bundle.", ex);
}
finally
{
dispose();
}
}
}
else if (sourceButton.equals(fileChooserButton))
{
SipCommFileChooser chooser = GenericFileDialog.create(
null, "New bundle...",
SipCommFileChooser.LOAD_FILE_OPERATION);
chooser.addFilter(new SipCommFileFilter()
{
@Override
public boolean accept(File f)
{
if (f.isDirectory())
return true;
boolean good = true;
try
{
ZipFile zip = new ZipFile(f);
}
catch (IOException ex)
{
good = false;
}
if (!f.getName().toLowerCase().endsWith(".zip"))
{
good = false;
}
return good;
}
@Override
public String getDescription()
{
return "Zip files (*.zip)";
}
});
File newBundleFile = chooser.getFileFromDialog();
if (newBundleFile != null)
{
try
{
bundlePathField.setText(newBundleFile.getCanonicalPath());
}
catch (Exception ex)
{
bundlePathField.setText(newBundleFile.getAbsolutePath());
}
}
}
else
{
dispose();
}
}
/**
* Presses programatically the cancel button, when Esc key is pressed.
* @param isEscaped indicates if the Esc button was pressed on close
*/
protected void close(boolean isEscaped)
{
cancelButton.doClick();
}
}

@ -0,0 +1,57 @@
/*
* SIP Communicator, 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 net.java.sip.communicator.service.resources.*;
/**
* The <tt>Resources</tt> class manages the access to the internationalization
* properties files and the image resources used in this plugin.
*
* @author Yana Stamcheva
*/
public class Resources
{
private static ResourceManagementService resourcesService;
/**
* Returns an internationalized string corresponding to the given key.
*
* @param key The key of the string.
* @return An internationalized string corresponding to the given key.
*/
public static String getString(String key)
{
return getResources().getI18NString(key);
}
/**
* Returns an int RGB color corresponding to the given key.
*
* @param key The key of the string.
*
* @return An internationalized string corresponding to the given key.
*/
public static int getColor(String key)
{
return getResources().getColor(key);
}
/**
* Returns an instance of <tt>ResourceManagementService</tt> registered in
* the <tt>bundleContext</tt>.
* @return an instance of <tt>ResourceManagementService</tt>
*/
public static ResourceManagementService getResources()
{
if (resourcesService == null)
resourcesService =
ResourceManagementServiceUtils
.getService(SkinManagerActivator.bundleContext);
return resourcesService;
}
}

@ -0,0 +1,311 @@
/*
* SIP Communicator, 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.awt.*;
import java.io.IOException;
import java.net.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;
import net.java.sip.communicator.util.swing.*;
import org.osgi.framework.*;
/**
* The <tt>ContactListCellRenderer</tt> is the custom cell renderer used in the
* SIP-Communicator's <tt>ContactList</tt>. It extends JPanel instead of JLabel,
* which allows adding different buttons and icons to the contact cell.
* The cell border and background are repainted.
*
* @author Yana Stamcheva
* @author Adam Netocny, CircleTech, s.r.o.
*/
public class SkinListCellRenderer
extends JPanel
implements TableCellRenderer
{
/**
* The end color used to paint a gradient selected background.
*/
private static final Color SELECTED_START_COLOR
= new Color(Resources.getColor("service.gui.LIST_SELECTION_COLOR"));
/**
* The start color used to paint a gradient selected background.
*/
private static final Color SELECTED_END_COLOR
= new Color(Resources.getColor("service.gui.GRADIENT_LIGHT_COLOR"));
/**
* The panel containing name and version information.
*/
private JPanel nameVersionPanel
= new JPanel(new FlowLayout(FlowLayout.LEFT));
/**
* The name label.
*/
private JLabel nameLabel = new JLabel();
/**
* The version label.
*/
private JLabel versionLabel = new JLabel();
/**
* The description label.
*/
private JLabel descriptionLabel = new JLabel();
/**
* The state label.
*/
private JLabel stateLabel = new JLabel();
/**
* The icon label.
*/
private JLabel iconLabel = new JLabel();
/**
* Indicates if a skin is selected.
*/
private boolean isSelected = false;
/**
* The cache of the <code>ImageIcon</code> values returned by
* {@link #getStateIcon(int)} because the method in question is called
* whenever a table cell is painted and reading the image data out of a file
* and loading it into a new <code>ImageIcon</code> at such a time
* noticeably affects execution the speed.
*/
private final ImageIcon[] stateIconCache = new ImageIcon[5];
/**
* Initialize the panel containing the node.
*/
public SkinListCellRenderer()
{
super(new BorderLayout(8, 8));
JPanel mainPanel = new JPanel(new BorderLayout());
this.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
this.setBackground(Color.WHITE);
this.setOpaque(true);
mainPanel.setOpaque(false);
this.nameVersionPanel.setOpaque(false);
this.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
this.nameLabel.setIconTextGap(2);
this.nameLabel.setFont(this.getFont().deriveFont(Font.BOLD));
this.nameVersionPanel.add(nameLabel);
this.nameVersionPanel.add(versionLabel);
mainPanel.add(nameVersionPanel, BorderLayout.NORTH);
mainPanel.add(descriptionLabel, BorderLayout.CENTER);
this.add(iconLabel, BorderLayout.WEST);
this.add(mainPanel, BorderLayout.CENTER);
this.add(stateLabel, BorderLayout.WEST);
}
/**
* Implements the <tt>ListCellRenderer</tt> method.
* Returns this panel that has been configured to display bundle name,
* version and description.
* @param table the parent table
* @param value the value of the rendered cell
* @param isSelected indicates if the rendered cell is selected
* @param hasFocus indicates if the rendered cell has the focus
* @param rowIndex the row index of the rendered cell
* @param vColIndex the column index of the rendered cell
* @return the rendering component
*/
@SuppressWarnings("unchecked")
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int rowIndex, int vColIndex)
{
Bundle bundle = (Bundle) value;
URL res = bundle.getResource("info.properties");
Dictionary<Object, Object> headers = bundle.getHeaders();
Object bundleName = headers.get(Constants.BUNDLE_NAME);
Object bundleVersion = headers.get(Constants.BUNDLE_VERSION);
Object bundleDescription = headers.get(Constants.BUNDLE_DESCRIPTION);
if (res != null) {
Properties props = new Properties();
try {
props.load(res.openStream());
String disp = props.getProperty("display_name");
if (disp != null) {
bundleName = disp;
}
disp = props.getProperty("version");
if (disp != null) {
bundleVersion = disp;
}
disp = props.getProperty("author");
String desc = props.getProperty("description");
String bundString = "";
if (disp != null) {
bundString = disp;
}
if (desc != null) {
if (disp != null) {
bundString += " - ";
}
bundString += desc;
}
if(!bundString.equals("")){
bundleDescription = bundString;
}
} catch (IOException ex) {
}
}
Icon stateIcon = getStateIcon(bundle.getState());
if (bundleName != null)
{
this.nameLabel.setText(bundleName.toString());
}
else
{
this.nameLabel.setText("unknown");
}
if (bundleVersion != null)
{
this.versionLabel.setText(bundleVersion.toString());
}
else
{
this.versionLabel.setText("");
}
if (bundleDescription != null)
{
this.descriptionLabel.setText(bundleDescription.toString());
}
else
{
this.descriptionLabel.setText("");
}
if (stateIcon != null)
{
this.stateLabel.setIcon(stateIcon);
}
this.isSelected = isSelected;
return this;
}
/**
* Returns an icon corresponding to the given <tt>state</tt>.
* @param state the state, for which we're looking for an icon
* @return the icon corresponding to the given state
*/
private ImageIcon getStateIcon(int state)
{
int cacheIndex;
String imageID;
switch (state)
{
case Bundle.INSTALLED:
cacheIndex = 0;
imageID = "plugin.pluginmanager.INSTALLED_STATE";
break;
case Bundle.RESOLVED:
cacheIndex = 1;
imageID = "plugin.pluginmanager.DEACTIVATED_STATE";
break;
case Bundle.STARTING:
cacheIndex = 2;
imageID = "plugin.pluginmanager.STARTING_STATE";
break;
case Bundle.STOPPING:
cacheIndex = 3;
imageID = "plugin.pluginmanager.STOPPING_STATE";
break;
case Bundle.ACTIVE:
cacheIndex = 4;
imageID = "plugin.pluginmanager.ACTIVATE_STATE";
break;
default:
return null;
}
ImageIcon stateIcon = stateIconCache[cacheIndex];
if (stateIcon == null)
{
stateIconCache[cacheIndex]
= stateIcon = Resources.getResources().getImage(imageID);
}
return stateIcon;
}
/**
* Paints a custom background of the cell.
*/
@Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g = g.create();
try
{
internalPaintComponent(g);
}
finally
{
g.dispose();
}
}
/**
* Paints a custom gradient background for selected cells.
* @param g the <tt>Graphics</tt> object used for painting
*/
private void internalPaintComponent(Graphics g)
{
AntialiasingManager.activateAntialiasing(g);
Graphics2D g2 = (Graphics2D) g;
int width = getWidth();
int height = getHeight();
if (this.isSelected)
{
GradientPaint p =
new GradientPaint(width / 2, 0, SELECTED_START_COLOR,
width / 2, height, SELECTED_END_COLOR);
g2.setPaint(p);
g2.fillRoundRect(1, 1, width, height - 1, 7, 7);
}
g2.setColor(SELECTED_START_COLOR);
g2.drawLine(0, height - 1, width, height - 1);
}
}

@ -0,0 +1,86 @@
/*
* SIP Communicator, 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 net.java.sip.communicator.service.gui.*;
import org.osgi.framework.*;
/**
* The <tt>BundleActivator</tt> of the SkinManager plugin.
*
* @author Yana Stamcheva
* @author Adam Netocny, CircleTech, s.r.o.
*/
public class SkinManagerActivator
implements BundleActivator
{
/**
* The bundle context.
*/
public static BundleContext bundleContext;
/**
* The user interface service.
*/
private static UIService uiService;
/**
* Starts this bundle and adds the
* <td>SkinManagerConfigForm</tt> contained in it to the configuration
* window obtained from the <tt>UIService</tt>.
* @param bc the <tt>BundleContext</tt>
* @throws Exception if one of the operation executed in the start method
* fails
*/
public void start(BundleContext bc) throws Exception
{
bundleContext = bc;
Dictionary<String, String> properties = new Hashtable<String, String>();
properties.put( ConfigurationForm.FORM_TYPE,
ConfigurationForm.ADVANCED_TYPE);
bundleContext.registerService(
ConfigurationForm.class.getName(),
new LazyConfigurationForm(
"net.java.sip.communicator.plugin.skinmanager.SkinManagerPanel",
getClass().getClassLoader(),
"plugin.skinmanager.PLUGIN_ICON",
"plugin.skinmanager.SKINS",
1001, true),
properties);
}
/**
* Stops this bundles.
* @param bc the <tt>BundleContext</tt>
* @throws Exception if one of the operation executed in the stop method
* fails
*/
public void stop(BundleContext bc) throws Exception {}
/**
* Returns the <tt>UIService</tt> obtained from the bundle context.
*
* @return the <tt>UIService</tt> obtained from the bundle context
*/
public static UIService getUIService()
{
if (uiService == null)
{
ServiceReference uiReference =
bundleContext.getServiceReference(UIService.class.getName());
uiService =
(UIService) bundleContext
.getService(uiReference);
}
return uiService;
}
}

@ -0,0 +1,131 @@
/*
* SIP Communicator, 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.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import net.java.sip.communicator.util.swing.*;
import org.osgi.framework.*;
/**
* @author Yana Stamcheva
* @author Adam Netocny, CircleTech, s.r.o.
*/
public class SkinManagerPanel
extends TransparentPanel
{
/**
* The table containing all skins.
*/
private final JTable skinTable = new JTable();
/**
* The table model.
*/
private final SkinTableModel tableModel = new SkinTableModel();
/**
* The panel containing manage buttons.
*/
private final ManageButtonsPanel buttonsPanel;
/**
* Creates an instance of <tt>SkinManagerPanel</tt>.
*/
public SkinManagerPanel()
{
super(new BorderLayout());
JScrollPane pluginListScrollPane = new JScrollPane();
skinTable.setModel(tableModel);
TableColumn col = skinTable.getColumnModel().getColumn(0);
col.setCellRenderer(new SkinListCellRenderer());
SkinListSelectionListener selectionListener =
new SkinListSelectionListener();
skinTable.getSelectionModel().addListSelectionListener(
selectionListener);
skinTable.getColumnModel().getSelectionModel()
.addListSelectionListener(selectionListener);
skinTable.setRowHeight(48);
skinTable.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
skinTable.setTableHeader(null);
buttonsPanel = new ManageButtonsPanel(skinTable);
this.add(pluginListScrollPane, BorderLayout.CENTER);
this.add(buttonsPanel, BorderLayout.EAST);
pluginListScrollPane.getViewport().add(skinTable);
pluginListScrollPane.getVerticalScrollBar().setUnitIncrement(30);
SkinManagerActivator.bundleContext
.addBundleListener(new SkinListBundleListener());
}
/**
* Listens for events triggered when a selection is made in the plugin list.
*/
private class SkinListSelectionListener
implements ListSelectionListener
{
public void valueChanged(ListSelectionEvent e)
{
int selectedRow = skinTable.getSelectedRow();
if (selectedRow == -1)
return;
Bundle selectedBundle
= (Bundle) skinTable.getValueAt(selectedRow, 0);
buttonsPanel.enableUninstallButton(true);
if (selectedBundle.getState() != Bundle.ACTIVE)
{
buttonsPanel.enableActivateButton(true);
buttonsPanel.enableDeactivateButton(false);
}
else
{
buttonsPanel.enableActivateButton(false);
buttonsPanel.enableDeactivateButton(true);
}
}
}
/**
* Listens for <tt>BundleEvents</tt> triggered by the bundle context.
*/
private class SkinListBundleListener
implements BundleListener
{
public void bundleChanged(BundleEvent event)
{
tableModel.update();
if (event.getType() == BundleEvent.INSTALLED)
{
skinTable.scrollRectToVisible(
new Rectangle( 0, skinTable.getHeight(),
1, skinTable.getHeight()));
}
}
}
}

@ -0,0 +1,171 @@
/*
* SIP Communicator, 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.table.*;
import org.osgi.framework.*;
/**
* The <tt>TableModel</tt> of the table containing all plug-ins.
*
* @author Yana Stamcheva
* @author Adam Netocny, CircleTech, s.r.o.
*/
public class SkinTableModel
extends AbstractTableModel
{
/**
* The bundle context.
*/
private BundleContext bundleContext = SkinManagerActivator.bundleContext;
/**
* The array of bundles.
*/
private Bundle[] bundles = null;
/**
* A bundle comparator.
*/
private final BundleComparator bundleComparator = new BundleComparator();
/**
* Create an instance of <tt>SkinTableModel</tt>
*/
public SkinTableModel()
{
refreshSortedBundlesList();
}
/**
* Returns the count of table rows.
* @return int the count of table rows
*/
public int getRowCount()
{
if (bundles == null)
{
return 0;
}
else
{
return bundles.length;
}
}
/**
* Returns TRUE if the given <tt>Bundle</tt> is contained in this table,
* FALSE - otherwise.
* @param bundle the <tt>Bundle</tt> to search for
* @return TRUE if the given <tt>Bundle</tt> is contained in this table,
* FALSE - otherwise.
*/
public boolean contains(Bundle bundle)
{
for (int i = 0; i < bundles.length; i++)
{
Bundle b = bundles[i];
if (b.equals(bundle))
{
return true;
}
}
return false;
}
/**
* Returns the count of table columns.
* @return int the count of table columns
*/
public int getColumnCount()
{
return 1;
}
/**
* Returns FALSE for all cells in this table.
* @param row the row number to check
* @param column the column number to check
* @return false
*/
public boolean isCellEditable(int row, int column)
{
return false;
}
/**
* Returns the value in the cell given by row and column.
* @param row the row number of the cell, which value we're looking for
* @param column the column of the cell, which value we're looking for
* @return the value of the cell given by <tt>row</tt> and <tt>column</tt>
*/
public Object getValueAt(int row, int column)
{
int bundleCounter = 0;
for (int i = 0; i < bundles.length; i++)
{
if (bundleCounter == row)
{
return bundles[i];
}
bundleCounter++;
}
return null;
}
/**
* Updates the table content.
*/
public void update()
{
refreshSortedBundlesList();
fireTableDataChanged();
}
/**
* Synchronizes the content of the bundle list with the bundles currently
* available in the bundle context and sorts it again.
*/
private void refreshSortedBundlesList()
{
Bundle[] list = this.bundleContext.getBundles();
ArrayList<Bundle> show = new ArrayList<Bundle>();
if (list != null)
{
for (Bundle b : list)
{
Dictionary headers = b.getHeaders();
if (headers.get(Constants.BUNDLE_ACTIVATOR) != null)
{
if (headers.get(Constants.BUNDLE_ACTIVATOR).toString()
.equals("net.java.sip.communicator.plugin." +
"skinresourcepack.SkinResourcesPack"))
{
show.add(b);
}
}
}
}
this.bundles = new Bundle[show.size()];
int i = 0;
for (Bundle b : show)
{
this.bundles[i] = b;
i++;
}
Arrays.sort(this.bundles, bundleComparator);
}
}

@ -0,0 +1,125 @@
/*
* SIP Communicator, 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.awt.*;
import javax.swing.*;
/**
* The <tt>TitlePanel</tt> is a decorated panel, that could be used for a
* header or a title area. This panel is used for example in the
* <tt>ConfigurationFrame</tt>.
*
* @author Yana Stamcheva
*/
public class TitlePanel
extends JPanel
{
/**
* A color between blue and gray used to paint some borders.
*/
public static final Color BORDER_COLOR
= new Color(Resources.getColor("service.gui.BORDER_COLOR"));
/**
* The size of the gradient used for painting the background.
*/
private static final int GRADIENT_SIZE = 10;
/**
* The start color used to paint a gradient mouse over background.
*/
private static final Color GRADIENT_DARK_COLOR
= new Color(Resources.getColor("service.gui.GRADIENT_DARK_COLOR"));
/**
* The end color used to paint a gradient mouse over background.
*/
private static final Color GRADIENT_LIGHT_COLOR
= new Color(Resources.getColor("service.gui.GRADIENT_LIGHT_COLOR"));
private JLabel titleLabel = new JLabel();
/**
* Creates an instance of <tt>TitlePanel</tt>.
*/
public TitlePanel()
{
super(new FlowLayout(FlowLayout.CENTER));
this.setPreferredSize(new Dimension(0, 30));
this.titleLabel.setFont(this.getFont().deriveFont(Font.BOLD, 14));
}
/**
* Creates an instance of <tt>TitlePanel</tt> by specifying the title
* String.
*
* @param title A String title.
*/
public TitlePanel(String title)
{
super(new FlowLayout(FlowLayout.CENTER));
this.titleLabel.setFont(this.getFont().deriveFont(Font.BOLD, 14));
this.titleLabel.setText(title);
this.add(titleLabel);
}
/**
* Overrides the <code>paintComponent</code> method of <tt>JPanel</tt>
* to paint a gradient background of this panel.
* @param g the <tt>Graphics</tt> object used for painting
*/
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
GradientPaint p = new GradientPaint(this.getWidth() / 2, 0,
GRADIENT_DARK_COLOR, this.getWidth() / 2,
GRADIENT_SIZE,
GRADIENT_LIGHT_COLOR);
GradientPaint p1 = new GradientPaint(this.getWidth() / 2, this
.getHeight()
- GRADIENT_SIZE,
GRADIENT_LIGHT_COLOR, this.getWidth() / 2,
this.getHeight(), GRADIENT_DARK_COLOR);
g2.setPaint(p);
g2.fillRect(0, 0, this.getWidth(), GRADIENT_SIZE);
g2.setColor(GRADIENT_LIGHT_COLOR);
g2.fillRect(0, GRADIENT_SIZE, this.getWidth(),
this.getHeight() - GRADIENT_SIZE);
g2.setPaint(p1);
g2.fillRect(0, this.getHeight() - GRADIENT_SIZE
- 1, this.getWidth(), this.getHeight() - 1);
g2.setColor(BORDER_COLOR);
g2.drawRoundRect(0, 0, this.getWidth() - 1, this.getHeight() - 1, 5, 5);
}
/**
* Sets the title String.
* @param title The title String.
*/
public void setTitleText(String title)
{
this.titleLabel.setText(title);
this.add(titleLabel);
}
}

@ -0,0 +1,27 @@
Bundle-Activator: net.java.sip.communicator.plugin.skinmanager.SkinManagerActivator
Bundle-Name: Skin Manager plugin
Bundle-Description: Manage all SIP Communicator skins.
Bundle-Vendor: sip-communicator.org, Adam Netocny, CircleTech, s.r.o.
Bundle-Version: 0.0.1
System-Bundle: yes
Import-Package: org.osgi.framework,
net.java.sip.communicator.service.configuration,
net.java.sip.communicator.service.gui,
net.java.sip.communicator.service.gui.event,
net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
net.java.sip.communicator.util.swing,
javax.swing,
javax.swing.event,
javax.swing.table,
javax.swing.text,
javax.swing.text.html,
javax.accessibility,
javax.swing.plaf,
javax.swing.plaf.metal,
javax.swing.plaf.basic,
javax.imageio,
javax.swing.filechooser,
javax.swing.tree,
javax.swing.undo,
javax.swing.border

@ -0,0 +1,383 @@
/*
* SIP Communicator, 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.skinresourcepack;
import java.net.*;
import java.util.*;
import org.osgi.framework.*;
import net.java.sip.communicator.service.resources.*;
/**
* The skin resource pack.
* @author Adam Netocny, CircleTech, s.r.o.
*/
public class SkinResourcesPack
implements BundleActivator, SkinPack
{
/**
* The default resource path.
*/
private static final String DEFAULT_RESOURCE_PATH = "info";
/**
* The resource path of skin images.
*/
private static final String DEFAULT_IMAGE_RESOURCE_PATH = "images.images";
/**
* The resource path of skin colors.
*/
private static final String DEFAULT_COLOR_RESOURCE_PATH = "colors.colors";
/**
* The resource path f skin styles.
*/
private static final String DEFAULT_STYLE_RESOURCE_PATH = "styles.styles";
/**
* The bundle context.
*/
private static BundleContext bundleContext;
/**
* Buffer for resource files found.
*/
private static Hashtable<String, Iterator<String>> ressourcesFiles
= new Hashtable<String, Iterator<String>>();
/**
* A map of all skin image resources.
*/
private Map<String, String> imageResources = null;
/**
* A map of all skin style resources.
*/
private Map<String, String> styleResources = null;
/**
* A map of all skin color resources.
*/
private Map<String, String> colorResources = null;
/**
* Starts the bundle.
* @param bc BundleContext
* @throws Exception -
*/
public void start(BundleContext bc)
throws Exception
{
bundleContext = bc;
Hashtable<String, String> props = new Hashtable<String, String>();
props.put(ResourcePack.RESOURCE_NAME,
SkinPack.RESOURCE_NAME_DEFAULT_VALUE);
bundleContext.registerService(SkinPack.class.getName(),
this,
props);
}
/**
* Stops the bundle.
* @param bc BundleContext
* @throws Exception -
*/
public void stop(BundleContext bc) throws Exception {}
/**
* Returns a <tt>Map</tt>, containing all [key, value] pairs for image
* resource pack.
*
* @return a <tt>Map</tt>, containing all [key, value] pairs for image
* resource pack.
*/
public Map<String, String> getImageResources()
{
if(imageResources != null)
{
return imageResources;
}
ResourceBundle resourceBundle
= ResourceBundle.getBundle(DEFAULT_IMAGE_RESOURCE_PATH);
Map<String, String> resources = new TreeMap<String, String>();
this.initResources(resourceBundle, resources);
this.initImagePluginResources(resources);
imageResources = resources;
return resources;
}
/**
* Returns a <tt>Map</tt>, containing all [key, value] pairs for style
* resource pack.
*
* @return a <tt>Map</tt>, containing all [key, value] pairs for style
* resource pack.
*/
public Map<String, String> getStyleResources()
{
if(styleResources != null)
{
return styleResources;
}
ResourceBundle resourceBundle
= ResourceBundle.getBundle(DEFAULT_STYLE_RESOURCE_PATH);
Map<String, String> resources = new TreeMap<String, String>();
this.initResources(resourceBundle, resources);
this.initStylePluginResources(resources);
styleResources = resources;
return resources;
}
/**
* Returns a <tt>Map</tt>, containing all [key, value] pairs for color
* resource pack.
*
* @return a <tt>Map</tt>, containing all [key, value] pairs for color
* resource pack.
*/
public Map<String, String> getColorResources()
{
if(colorResources != null)
{
return colorResources;
}
ResourceBundle resourceBundle
= ResourceBundle.getBundle(DEFAULT_COLOR_RESOURCE_PATH);
Map<String, String> resources = new TreeMap<String, String>();
this.initResources(resourceBundle, resources);
this.initColorPluginResources(resources);
colorResources = resources;
return resources;
}
/**
* Returns a <tt>Map</tt>, containing all [key, value] pairs for this
* resource pack.
*
* @return a <tt>Map</tt>, containing all [key, value] pairs for this
* resource pack.
*/
public Map<String, String> getResources()
{
ResourceBundle resourceBundle
= ResourceBundle.getBundle(DEFAULT_RESOURCE_PATH);
Map<String, String> resources = new TreeMap<String, String>();
this.initResources(resourceBundle, resources);
resources.putAll(getImageResources());
resources.putAll(getStyleResources());
resources.putAll(getColorResources());
return resources;
}
/**
* Returns the name of this resource pack.
*
* @return the name of this resource pack.
*/
public String getName()
{
Map<String, String> resources = getResources();
String name = resources.get("display_name");
if(name != null)
{
return name + " Skin Resources";
}
else
{
return "Skin Resources";
}
}
/**
* Returns the description of this resource pack.
*
* @return the description of this resource pack.
*/
public String getDescription()
{
Map<String, String> resources = getResources();
String name = resources.get("display_name");
if(name != null)
{
return "Provide SIP Communicator " + name + " skin resource pack.";
}
else
{
return "Provide SIP Communicator skin resource pack.";
}
}
/**
* Fills the given resource map with all (key,value) pairs obtained from the
* given <tt>ResourceBundle</tt>. This method will look in the properties
* files for references to other properties files and will include in the
* final map data from all referenced files.
*
* @param resourceBundle The initial <tt>ResourceBundle</tt>, corresponding
* to the "main" properties file.
* @param resources A <tt>Map</tt> that would store the data.
*/
private void initResources( ResourceBundle resourceBundle,
Map<String, String> resources)
{
Enumeration<String> colorKeys = resourceBundle.getKeys();
while (colorKeys.hasMoreElements())
{
String key = colorKeys.nextElement();
String value = resourceBundle.getString(key);
resources.put(key, value);
}
}
/**
* Finds all plugin image resources, matching the "images-*.properties"
* pattern and adds them to this resource pack.
* @param resources the map of key, value image resource pairs
*/
private void initImagePluginResources(Map<String, String> resources)
{
Iterator<String> pluginProperties
= findResourcePaths("images", "images-*.properties");
while (pluginProperties.hasNext())
{
String resourceBundleName = pluginProperties.next();
ResourceBundle resourceBundle
= ResourceBundle.getBundle(
resourceBundleName.substring(
0, resourceBundleName.indexOf(".properties")));
initResources(resourceBundle, resources);
}
}
/**
* Finds all plugin style resources, matching the "styles-*.properties"
* pattern and adds them to this resource pack.
* @param resources the map of key, value stype resource pairs
*/
private void initStylePluginResources(Map<String, String> resources)
{
Iterator<String> pluginProperties
= findResourcePaths("styles", "styles-*.properties");
while (pluginProperties.hasNext())
{
String resourceBundleName = pluginProperties.next();
ResourceBundle resourceBundle
= ResourceBundle.getBundle(
resourceBundleName.substring(
0, resourceBundleName.indexOf(".properties")));
initResources(resourceBundle, resources);
}
}
/**
* Finds all plugin color resources, matching the "colors-*.properties"
* pattern and adds them to this resource pack.
* @param resources the map of key, value color resource pairs
*/
private void initColorPluginResources(Map<String, String> resources)
{
Iterator<String> pluginProperties
= findResourcePaths("colors", "colors-*.properties");
while (pluginProperties.hasNext())
{
String resourceBundleName = pluginProperties.next();
ResourceBundle resourceBundle
= ResourceBundle.getBundle(
resourceBundleName.substring(
0, resourceBundleName.indexOf(".properties")));
initResources(resourceBundle, resources);
}
}
/**
* Finds all properties files for the given path in this bundle.
*
* @param path the path pointing to the properties files.
* @param pattern the pattern for properties files
* (ex. "colors-*.properties")
* @return an <tt>Iterator</tt> over a list of all properties files found
* for the given path and pattern
*/
protected static Iterator<String> findResourcePaths(String path,
String pattern)
{
Iterator<String> bufferedResult
= ressourcesFiles.get(path + "/" + pattern);
if (bufferedResult != null) {
return bufferedResult;
}
ArrayList<String> propertiesList = new ArrayList<String>();
@SuppressWarnings ("unchecked")
Enumeration<URL> propertiesUrls = bundleContext.getBundle()
.findEntries(path,
pattern,
false);
if (propertiesUrls != null)
{
while (propertiesUrls.hasMoreElements())
{
URL propertyUrl = propertiesUrls.nextElement();
// Remove the first slash.
String propertyFilePath
= propertyUrl.getPath().substring(1);
// Replace all slashes with dots.
propertyFilePath = propertyFilePath.replaceAll("/", ".");
propertiesList.add(propertyFilePath);
}
}
Iterator<String> result = propertiesList.iterator();
ressourcesFiles.put(path + pattern, result);
return result;
}
}

@ -0,0 +1,8 @@
Bundle-Activator: net.java.sip.communicator.plugin.skinresourcepack.SkinResourcesPack
Bundle-Name: Skin Resource Pack
Bundle-Description: The plugin offering skin related data.
Bundle-Vendor: sip-communicator.org, Adam Netocny, CircleTech, s.r.o.
Bundle-Version: 0.0.1
System-Bundle: no
Import-Package: org.osgi.framework,
net.java.sip.communicator.service.resources

@ -18,6 +18,7 @@
* some configurations.
*
* @author Damian Minkov
* @author Adam Netocny, CircleTech, s.r.o.
*/
public interface ResourceManagementService
{
@ -237,4 +238,12 @@ public interface ResourceManagementService
* @return A byte array containing the image with the given identifier.
*/
public byte[] getImageInBytes(String imageID);
/**
* Builds a new skin bundle from the zip file content.
* @param zipFile Zip file with skin information.
* @return <tt>File</tt> for the bundle.
* @throws Exception When something goes wrong.
*/
public File prepareSkinBundleFromZip(File zipFile) throws Exception;
}

@ -0,0 +1,49 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.service.resources;
import java.util.*;
/**
* Default Skin Pack interface.
* @author Adam Netocny, CircleTech, s.r.o.
*/
public interface SkinPack
extends ResourcePack
{
/**
* Default resource name.
*/
public String RESOURCE_NAME_DEFAULT_VALUE = "SkinPack";
/**
* Returns a <tt>Map</tt>, containing all [key, value] pairs for image
* resource pack.
*
* @return a <tt>Map</tt>, containing all [key, value] pairs for image
* resource pack.
*/
public Map<String, String> getImageResources();
/**
* Returns a <tt>Map</tt>, containing all [key, value] pairs for style
* resource pack.
*
* @return a <tt>Map</tt>, containing all [key, value] pairs for style
* resource pack.
*/
public Map<String, String> getStyleResources();
/**
* Returns a <tt>Map</tt>, containing all [key, value] pairs for color
* resource pack.
*
* @return a <tt>Map</tt>, containing all [key, value] pairs for color
* resource pack.
*/
public Map<String, String> getColorResources();
}
Loading…
Cancel
Save