diff options
author | Yana Stamcheva <yana@jitsi.org> | 2010-09-02 22:50:23 +0000 |
---|---|---|
committer | Yana Stamcheva <yana@jitsi.org> | 2010-09-02 22:50:23 +0000 |
commit | 45cf66297884d51760202c3213fde1e909a8d482 (patch) | |
tree | a93fa8aab3fb949ae0c24ddd5c819da166cf96bf /src/net/java/sip/communicator | |
parent | f6c822cc9e1486b59575fdc48a9b0e223e584a16 (diff) | |
download | jitsi-45cf66297884d51760202c3213fde1e909a8d482.zip jitsi-45cf66297884d51760202c3213fde1e909a8d482.tar.gz jitsi-45cf66297884d51760202c3213fde1e909a8d482.tar.bz2 |
Skin implementation bases provided by Adam Netočný (work in progress).
Diffstat (limited to 'src/net/java/sip/communicator')
21 files changed, 2473 insertions, 31 deletions
diff --git a/src/net/java/sip/communicator/impl/resources/ResourceManagementServiceImpl.java b/src/net/java/sip/communicator/impl/resources/ResourceManagementServiceImpl.java index 45d27b5..31da767 100644 --- a/src/net/java/sip/communicator/impl/resources/ResourceManagementServiceImpl.java +++ b/src/net/java/sip/communicator/impl/resources/ResourceManagementServiceImpl.java @@ -13,6 +13,7 @@ import java.util.*; 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 @@ import org.osgi.framework.*; * @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 @@ public class ResourceManagementServiceImpl 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 @@ public class ResourceManagementServiceImpl 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 class ResourceManagementServiceImpl */ 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 class ResourceManagementServiceImpl */ 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 class ResourceManagementServiceImpl * 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 class ResourceManagementServiceImpl * * @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 class ResourceManagementServiceImpl /** * 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 class ResourceManagementServiceImpl * 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 class ResourceManagementServiceImpl } 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); + } } diff --git a/src/net/java/sip/communicator/impl/resources/util/SkinJarBuilder.java b/src/net/java/sip/communicator/impl/resources/util/SkinJarBuilder.java new file mode 100644 index 0000000..59d1ff7 --- /dev/null +++ b/src/net/java/sip/communicator/impl/resources/util/SkinJarBuilder.java @@ -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); + } +} diff --git a/src/net/java/sip/communicator/plugin/pluginmanager/BundleComparator.java b/src/net/java/sip/communicator/plugin/pluginmanager/BundleComparator.java index a6313bc..87fce57 100644 --- a/src/net/java/sip/communicator/plugin/pluginmanager/BundleComparator.java +++ b/src/net/java/sip/communicator/plugin/pluginmanager/BundleComparator.java @@ -27,7 +27,7 @@ public class BundleComparator implements Comparator<Bundle> { 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 class BundleComparator implements Comparator<Bundle> { n2 = "unknown"; } - + return n1.compareTo(n2); } - } diff --git a/src/net/java/sip/communicator/plugin/pluginmanager/ManageButtonsPanel.java b/src/net/java/sip/communicator/plugin/pluginmanager/ManageButtonsPanel.java index 1499d09..bd36dd2 100644 --- a/src/net/java/sip/communicator/plugin/pluginmanager/ManageButtonsPanel.java +++ b/src/net/java/sip/communicator/plugin/pluginmanager/ManageButtonsPanel.java @@ -10,7 +10,6 @@ import java.awt.*; 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 class ManageButtonsPanel 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(); diff --git a/src/net/java/sip/communicator/plugin/pluginmanager/NewBundleDialog.java b/src/net/java/sip/communicator/plugin/pluginmanager/NewBundleDialog.java index f67d6f1..b2730c3 100644 --- a/src/net/java/sip/communicator/plugin/pluginmanager/NewBundleDialog.java +++ b/src/net/java/sip/communicator/plugin/pluginmanager/NewBundleDialog.java @@ -14,36 +14,73 @@ import java.net.*; 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 class 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 class NewBundleDialog } 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 @@ public class NewBundleDialog } 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(); diff --git a/src/net/java/sip/communicator/plugin/pluginmanager/PluginListCellRenderer.java b/src/net/java/sip/communicator/plugin/pluginmanager/PluginListCellRenderer.java index c917325..53d8a18 100644 --- a/src/net/java/sip/communicator/plugin/pluginmanager/PluginListCellRenderer.java +++ b/src/net/java/sip/communicator/plugin/pluginmanager/PluginListCellRenderer.java @@ -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 class 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 class PluginListCellRenderer 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 @@ public class PluginListCellRenderer /** * 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 class PluginListCellRenderer } } + /** + * 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); diff --git a/src/net/java/sip/communicator/plugin/pluginmanager/PluginTableModel.java b/src/net/java/sip/communicator/plugin/pluginmanager/PluginTableModel.java index 1569a75..7553d40 100644 --- a/src/net/java/sip/communicator/plugin/pluginmanager/PluginTableModel.java +++ b/src/net/java/sip/communicator/plugin/pluginmanager/PluginTableModel.java @@ -194,7 +194,36 @@ public class PluginTableModel */ 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); } } diff --git a/src/net/java/sip/communicator/plugin/skinmanager/BundleComparator.java b/src/net/java/sip/communicator/plugin/skinmanager/BundleComparator.java new file mode 100644 index 0000000..41e4382 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/skinmanager/BundleComparator.java @@ -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); + } +} diff --git a/src/net/java/sip/communicator/plugin/skinmanager/ManageButtonsPanel.java b/src/net/java/sip/communicator/plugin/skinmanager/ManageButtonsPanel.java new file mode 100644 index 0000000..34eaac1 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/skinmanager/ManageButtonsPanel.java @@ -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); + } +} diff --git a/src/net/java/sip/communicator/plugin/skinmanager/NewBundleDialog.java b/src/net/java/sip/communicator/plugin/skinmanager/NewBundleDialog.java new file mode 100644 index 0000000..217b15b --- /dev/null +++ b/src/net/java/sip/communicator/plugin/skinmanager/NewBundleDialog.java @@ -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(); + } +} diff --git a/src/net/java/sip/communicator/plugin/skinmanager/Resources.java b/src/net/java/sip/communicator/plugin/skinmanager/Resources.java new file mode 100644 index 0000000..2f7fcf3 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/skinmanager/Resources.java @@ -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; + } +} diff --git a/src/net/java/sip/communicator/plugin/skinmanager/SkinListCellRenderer.java b/src/net/java/sip/communicator/plugin/skinmanager/SkinListCellRenderer.java new file mode 100644 index 0000000..0a3faf2 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/skinmanager/SkinListCellRenderer.java @@ -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); + } +} diff --git a/src/net/java/sip/communicator/plugin/skinmanager/SkinManagerActivator.java b/src/net/java/sip/communicator/plugin/skinmanager/SkinManagerActivator.java new file mode 100644 index 0000000..e7f0c07 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/skinmanager/SkinManagerActivator.java @@ -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; + } +} diff --git a/src/net/java/sip/communicator/plugin/skinmanager/SkinManagerPanel.java b/src/net/java/sip/communicator/plugin/skinmanager/SkinManagerPanel.java new file mode 100644 index 0000000..f1b3efc --- /dev/null +++ b/src/net/java/sip/communicator/plugin/skinmanager/SkinManagerPanel.java @@ -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())); + } + } + } +} diff --git a/src/net/java/sip/communicator/plugin/skinmanager/SkinTableModel.java b/src/net/java/sip/communicator/plugin/skinmanager/SkinTableModel.java new file mode 100644 index 0000000..eacb2d3 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/skinmanager/SkinTableModel.java @@ -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); + } +} diff --git a/src/net/java/sip/communicator/plugin/skinmanager/TitlePanel.java b/src/net/java/sip/communicator/plugin/skinmanager/TitlePanel.java new file mode 100644 index 0000000..c2797c3 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/skinmanager/TitlePanel.java @@ -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); + } +} diff --git a/src/net/java/sip/communicator/plugin/skinmanager/skinmanager.manifest.mf b/src/net/java/sip/communicator/plugin/skinmanager/skinmanager.manifest.mf new file mode 100644 index 0000000..8919efa --- /dev/null +++ b/src/net/java/sip/communicator/plugin/skinmanager/skinmanager.manifest.mf @@ -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 diff --git a/src/net/java/sip/communicator/plugin/skinresourcepack/SkinResourcesPack.java b/src/net/java/sip/communicator/plugin/skinresourcepack/SkinResourcesPack.java new file mode 100644 index 0000000..bd47802 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/skinresourcepack/SkinResourcesPack.java @@ -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; + } +} diff --git a/src/net/java/sip/communicator/plugin/skinresourcepack/skinresourcepack.manifest.mf b/src/net/java/sip/communicator/plugin/skinresourcepack/skinresourcepack.manifest.mf new file mode 100644 index 0000000..a00e4b4 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/skinresourcepack/skinresourcepack.manifest.mf @@ -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 diff --git a/src/net/java/sip/communicator/service/resources/ResourceManagementService.java b/src/net/java/sip/communicator/service/resources/ResourceManagementService.java index 5400f9e..a89135b 100644 --- a/src/net/java/sip/communicator/service/resources/ResourceManagementService.java +++ b/src/net/java/sip/communicator/service/resources/ResourceManagementService.java @@ -18,6 +18,7 @@ import javax.swing.*; * 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; } diff --git a/src/net/java/sip/communicator/service/resources/SkinPack.java b/src/net/java/sip/communicator/service/resources/SkinPack.java new file mode 100644 index 0000000..56f033f --- /dev/null +++ b/src/net/java/sip/communicator/service/resources/SkinPack.java @@ -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(); +} |