diff --git a/build.xml b/build.xml
index afd43f372..44f2ddba5 100644
--- a/build.xml
+++ b/build.xml
@@ -777,7 +777,7 @@
bundle-fileaccess-slick,bundle-media,bundle-media-slick,
bundle-resource-manager,bundle-resources-defaultpack,
bundle-protocol,bundle-icq,bundle-icq-slick,bundle-mock,bundle-smacklib,
- bundle-jabber,bundle-jabber-slick,bundle-swing-ui,bundle-ui-service,
+ bundle-jabber,bundle-jabber-slick,bundle-swing-common,bundle-swing-ui,bundle-ui-service,
bundle-msn,bundle-msn-slick,bundle-yahoo,bundle-yahoo-slick,
bundle-contactlist,meta-contactlist,meta-contactlist-slick,
bundle-plugin-icqaccregwizz,bundle-plugin-jabberaccregwizz,
@@ -958,6 +958,8 @@
prefix="net/java/sip/communicator/service/media"/>
+
@@ -979,6 +981,8 @@
prefix="net/java/sip/communicator/service/media"/>
+
@@ -999,6 +1003,8 @@
prefix="net/java/sip/communicator/service/media"/>
+
@@ -1301,6 +1307,16 @@ javax.swing.event, javax.swing.border"/>
+
+
+
+
+
+
+
+
diff --git a/lib/felix.client.run.properties b/lib/felix.client.run.properties
index f6c5cd598..0ea932baf 100644
--- a/lib/felix.client.run.properties
+++ b/lib/felix.client.run.properties
@@ -83,7 +83,8 @@ felix.auto.start.45= \
reference:file:sc-bundles/argdelegation-service.jar \
reference:file:sc-bundles/version.jar \
reference:file:sc-bundles/version-impl.jar \
- reference:file:sc-bundles/branding.jar
+ reference:file:sc-bundles/branding.jar \
+ reference:file:sc-bundles/swing-common.jar
felix.auto.start.49= \
reference:file:sc-bundles/zrtp4j.jar \
diff --git a/resources/images/images.properties b/resources/images/images.properties
index b1c15842a..c212623f6 100644
--- a/resources/images/images.properties
+++ b/resources/images/images.properties
@@ -427,3 +427,5 @@ soundIcon=resources/images/plugin/notificationconfiguration/soundIcon.png
activatedIcon=resources/images/plugin/notificationconfiguration/activeIcon.png
desactivatedIcon=resources/images/plugin/notificationconfiguration/desactivatedIcon.png
foldericon=resources/images/plugin/notificationconfiguration/folder.png
+
+MediaConfigurationForm_icon=resources/images/impl/media/media.png
diff --git a/resources/images/impl/media/media.png b/resources/images/impl/media/media.png
new file mode 100644
index 000000000..245447821
Binary files /dev/null and b/resources/images/impl/media/media.png differ
diff --git a/resources/languages/resources.properties b/resources/languages/resources.properties
index 1be7cc13a..b9c64283d 100644
--- a/resources/languages/resources.properties
+++ b/resources/languages/resources.properties
@@ -748,3 +748,10 @@ sasUnsecuredAtPeerRequestTooltip=Call unsecured at peer request
# Profiler4J
profiler=Profiler4j
+
+MediaConfigurationForm_title=Media
+MediaConfigurationPanel_audio=&Audio:
+MediaConfigurationPanel_down=&Down
+MediaConfigurationPanel_encodings=&Encodings:
+MediaConfigurationPanel_up=&Up
+MediaConfigurationPanel_video=&Video:
diff --git a/src/net/java/sip/communicator/impl/gui/customcontrols/TransparentPanel.java b/src/net/java/sip/communicator/impl/gui/customcontrols/TransparentPanel.java
index 1c00a3e6e..d2e89fead 100644
--- a/src/net/java/sip/communicator/impl/gui/customcontrols/TransparentPanel.java
+++ b/src/net/java/sip/communicator/impl/gui/customcontrols/TransparentPanel.java
@@ -1,22 +1,29 @@
+/*
+ * 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.gui.customcontrols;
import java.awt.*;
import javax.swing.*;
+/**
+ * @author Yana Stamcheva
+ */
public class TransparentPanel
extends JPanel
{
- public TransparentPanel ()
+ public TransparentPanel()
{
- super();
-
this.setOpaque(false);
}
- public TransparentPanel (LayoutManager layoutManager)
+ public TransparentPanel(LayoutManager layout)
{
- super(layoutManager);
+ super(layout);
this.setOpaque(false);
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallParticipantPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/CallParticipantPanel.java
index ed192b8a5..ea33b3b96 100644
--- a/src/net/java/sip/communicator/impl/gui/main/call/CallParticipantPanel.java
+++ b/src/net/java/sip/communicator/impl/gui/main/call/CallParticipantPanel.java
@@ -18,6 +18,7 @@
import net.java.sip.communicator.impl.gui.utils.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
+import net.java.sip.communicator.swing.*;
import net.java.sip.communicator.util.*;
/**
@@ -227,94 +228,9 @@ public void hierarchyChanged(HierarchyEvent event)
* Component at a time and, in the absence of such a
* Component, displays noVideoComponent
*/
- private Container createVideoContainer(final Component noVideoComponent)
+ private Container createVideoContainer(Component noVideoComponent)
{
- final ContainerListener containerListener = new ContainerListener()
- {
-
- /*
- * Since the videoContainer displays either noVideoComponent or a
- * single visual Component which represents video, ensures the last
- * Component added to the Container is the only Component it
- * contains i.e. noVideoComponent goes away when the video is
- * displayed and the video goes away when noVideoComponent is
- * displayed.
- */
- public void componentAdded(ContainerEvent event)
- {
- Container container = event.getContainer();
- Component local =
- ((VideoLayout) container.getLayout()).getLocal();
- Component added = event.getChild();
-
- if ((local != null) && (added == local))
- return;
-
- Component[] components = container.getComponents();
- boolean validate = false;
-
- for (int i = 0; i < components.length; i++)
- {
- Component component = components[i];
-
- if ((component != added) && (component != local))
- {
- container.remove(component);
- validate = true;
- }
- }
- if (validate)
- container.validate();
- }
-
- /*
- * Displays noVideoComponent when there is no visual Component which
- * represents video to be displayed.
- */
- public void componentRemoved(ContainerEvent event)
- {
- Container container = event.getContainer();
-
- if ((container.getComponentCount() <= 0)
- || (((VideoLayout) container.getLayout()).getRemote() == null))
- {
- container.add(noVideoComponent, VideoLayout.REMOTE);
- container.validate();
- }
- }
- };
- Container videoContainer = new TransparentPanel(new VideoLayout())
- {
-
- /*
- * Ensures noVideoComponent is displayed even when the clients of
- * the videoContainer invoke its #removeAll() to remove their
- * previous visual Components representing video. Just adding
- * noVideoComponent upon ContainerEvent#COMPONENT_REMOVED when there
- * is no other Component left in the Container will cause an
- * infinite loop because Container#removeAll() will detect that a
- * new Component has been added while dispatching the event and will
- * then try to remove the new Component.
- */
- public void removeAll()
- {
- removeContainerListener(containerListener);
- try
- {
- super.removeAll();
- }
- finally
- {
- addContainerListener(containerListener);
- containerListener.componentRemoved(new ContainerEvent(this,
- ContainerEvent.COMPONENT_REMOVED, null));
- }
- }
- };
-
- videoContainer.addContainerListener(containerListener);
- videoContainer.add(noVideoComponent, VideoLayout.REMOTE);
- return videoContainer;
+ return new VideoContainer(noVideoComponent);
}
/**
diff --git a/src/net/java/sip/communicator/impl/gui/swing.ui.manifest.mf b/src/net/java/sip/communicator/impl/gui/swing.ui.manifest.mf
index 546a9080e..17f57605d 100644
--- a/src/net/java/sip/communicator/impl/gui/swing.ui.manifest.mf
+++ b/src/net/java/sip/communicator/impl/gui/swing.ui.manifest.mf
@@ -39,5 +39,6 @@ Import-Package: org.osgi.framework,
javax.swing.undo,
javax.swing.border,
net.java.sip.communicator.service.audionotifier,
+ net.java.sip.communicator.swing,
org.jdesktop.jdic.desktop,
say.swing
diff --git a/src/net/java/sip/communicator/impl/media/CallSessionImpl.java b/src/net/java/sip/communicator/impl/media/CallSessionImpl.java
index ffaaf17d7..71554602a 100644
--- a/src/net/java/sip/communicator/impl/media/CallSessionImpl.java
+++ b/src/net/java/sip/communicator/impl/media/CallSessionImpl.java
@@ -11,6 +11,7 @@
import java.net.*;
import java.text.*;
import java.util.*;
+
import javax.media.*;
import javax.media.control.*;
import javax.media.format.*;
diff --git a/src/net/java/sip/communicator/impl/media/DeviceConfigurationComboBoxModel.java b/src/net/java/sip/communicator/impl/media/DeviceConfigurationComboBoxModel.java
new file mode 100644
index 000000000..dd3a13355
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/media/DeviceConfigurationComboBoxModel.java
@@ -0,0 +1,209 @@
+/*
+ * 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.media;
+
+import java.util.*;
+
+import javax.media.*;
+import javax.swing.*;
+import javax.swing.event.*;
+
+import net.java.sip.communicator.impl.media.device.*;
+
+/**
+ * @author Lubomir Marinov
+ */
+public class DeviceConfigurationComboBoxModel
+ implements ComboBoxModel
+{
+ public static class CaptureDevice
+ {
+ public final CaptureDeviceInfo info;
+
+ public CaptureDevice(CaptureDeviceInfo info)
+ {
+ if (info == null)
+ throw new IllegalArgumentException("info");
+
+ this.info = info;
+ }
+
+ public String toString()
+ {
+ return info.getName();
+ }
+ }
+
+ public static final int AUDIO = 1;
+
+ private static final CaptureDevice[] NO_CAPTURE_DEVICES =
+ new CaptureDevice[0];
+
+ public static final int VIDEO = 2;
+
+ private final DeviceConfiguration deviceConfiguration;
+
+ private CaptureDevice[] devices;
+
+ private final List listeners =
+ new ArrayList();
+
+ private final int type;
+
+ public DeviceConfigurationComboBoxModel(
+ DeviceConfiguration deviceConfiguration, int type)
+ {
+ if (deviceConfiguration == null)
+ throw new IllegalArgumentException("deviceConfiguration");
+ if ((type != AUDIO) && (type != VIDEO))
+ throw new IllegalArgumentException("type");
+
+ this.deviceConfiguration = deviceConfiguration;
+ this.type = type;
+ }
+
+ public void addListDataListener(ListDataListener listener)
+ {
+ if (listener == null)
+ throw new IllegalArgumentException("listener");
+
+ if (!listeners.contains(listener))
+ listeners.add(listener);
+ }
+
+ protected void fireContentsChanged(int index0, int index1)
+ {
+ ListDataListener[] listeners =
+ this.listeners.toArray(new ListDataListener[this.listeners.size()]);
+ ListDataEvent event =
+ new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, index0,
+ index1);
+
+ for (int i = 0; i < listeners.length; i++)
+ {
+ listeners[i].contentsChanged(event);
+ }
+ }
+
+ private DeviceConfiguration getDeviceConfiguration()
+ {
+ return deviceConfiguration;
+ }
+
+ private CaptureDevice[] getDevices()
+ {
+ if (devices != null)
+ return devices;
+
+ DeviceConfiguration deviceConfiguration = getDeviceConfiguration();
+ CaptureDeviceInfo[] infos;
+ switch (type)
+ {
+ case AUDIO:
+ infos = deviceConfiguration.getAvailableAudioCaptureDevices();
+ break;
+ case VIDEO:
+ infos = deviceConfiguration.getAvailableVideoCaptureDevices();
+ break;
+ default:
+ throw new IllegalStateException("type");
+ }
+
+ final int deviceCount = infos.length;
+ if (deviceCount < 1)
+ devices = NO_CAPTURE_DEVICES;
+ else
+ {
+ devices = new CaptureDevice[deviceCount];
+ for (int i = 0; i < deviceCount; i++)
+ {
+ devices[i] = new CaptureDevice(infos[i]);
+ }
+ }
+ return devices;
+ }
+
+ public Object getElementAt(int index)
+ {
+ return getDevices()[index];
+ }
+
+ private CaptureDevice getSelectedDevice()
+ {
+ DeviceConfiguration deviceConfiguration = getDeviceConfiguration();
+ CaptureDeviceInfo info;
+ switch (type)
+ {
+ case AUDIO:
+ info = deviceConfiguration.getAudioCaptureDevice();
+ break;
+ case VIDEO:
+ info = deviceConfiguration.getVideoCaptureDevice();
+ break;
+ default:
+ throw new IllegalStateException("type");
+ }
+
+ CaptureDevice[] devices = getDevices();
+ for (int i = 0; i < devices.length; i++)
+ {
+ CaptureDevice device = devices[i];
+ if (device.info.equals(info))
+ {
+ return device;
+ }
+ }
+ return null;
+ }
+
+ public Object getSelectedItem()
+ {
+ return getSelectedDevice();
+ }
+
+ public int getSize()
+ {
+ return getDevices().length;
+ }
+
+ public void removeListDataListener(ListDataListener listener)
+ {
+ if (listener == null)
+ throw new IllegalArgumentException("listener");
+
+ listeners.remove(listener);
+ }
+
+ private void setSelectedDevice(CaptureDevice device)
+ {
+ // We cannot clear the selection of DeviceConfiguration.
+ if (device == null)
+ return;
+
+ CaptureDevice selectedDevice = getSelectedDevice();
+ if (selectedDevice != device)
+ {
+ DeviceConfiguration deviceConfiguration = getDeviceConfiguration();
+ switch (type)
+ {
+ case AUDIO:
+ deviceConfiguration.setAudioCaptureDevice(device.info);
+ break;
+ case VIDEO:
+ deviceConfiguration.setVideoCaptureDevice(device.info);
+ break;
+ }
+
+ fireContentsChanged(-1, -1);
+ }
+ }
+
+ public void setSelectedItem(Object item)
+ {
+ setSelectedDevice((CaptureDevice) item);
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/media/EncodingConfigurationTableModel.java b/src/net/java/sip/communicator/impl/media/EncodingConfigurationTableModel.java
new file mode 100644
index 000000000..eec5d0376
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/media/EncodingConfigurationTableModel.java
@@ -0,0 +1,187 @@
+/*
+ * 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.media;
+
+import java.util.*;
+
+import javax.swing.table.*;
+
+import net.java.sip.communicator.impl.media.codec.*;
+
+/**
+ * @author Lubomir Marinov
+ */
+public class EncodingConfigurationTableModel
+ extends AbstractTableModel
+{
+ public static final int AUDIO = DeviceConfigurationComboBoxModel.AUDIO;
+
+ private static final String[] NO_ENCODINGS = new String[0];
+
+ public static final int VIDEO = DeviceConfigurationComboBoxModel.VIDEO;
+
+ private final EncodingConfiguration encodingConfiguration;
+
+ private String[] encodings;
+
+ private final int type;
+
+ public EncodingConfigurationTableModel(
+ EncodingConfiguration encodingConfiguration, int type)
+ {
+ if (encodingConfiguration == null)
+ throw new IllegalArgumentException("encodingConfiguration");
+ if ((type != AUDIO) && (type != VIDEO))
+ throw new IllegalArgumentException("type");
+
+ this.encodingConfiguration = encodingConfiguration;
+ this.type = type;
+ }
+
+ public Class> getColumnClass(int columnIndex)
+ {
+ return (columnIndex == 0) ? Boolean.class : super
+ .getColumnClass(columnIndex);
+ }
+
+ public int getColumnCount()
+ {
+ return 2;
+ }
+
+ private String[] getEncodings()
+ {
+ if (encodings != null)
+ return encodings;
+
+ String[] availableEncodings;
+ switch (type)
+ {
+ case AUDIO:
+ availableEncodings =
+ encodingConfiguration.getAvailableAudioEncodings();
+ break;
+ case VIDEO:
+ availableEncodings =
+ encodingConfiguration.getAvailableVideoEncodings();
+ break;
+ default:
+ throw new IllegalStateException("type");
+ }
+
+ final int encodingCount = availableEncodings.length;
+ if (encodingCount < 1)
+ encodings = NO_ENCODINGS;
+ else
+ {
+ encodings = new String[encodingCount];
+ System
+ .arraycopy(availableEncodings, 0, encodings, 0, encodingCount);
+ Arrays.sort(encodings, 0, encodingCount, new Comparator()
+ {
+ public int compare(String encoding0, String encoding1)
+ {
+ if (encodingConfiguration.getPriority(encoding0) > encodingConfiguration
+ .getPriority(encoding1))
+ return -1;
+ return encoding0.compareTo(encoding1);
+ }
+ });
+ }
+ return encodings;
+ }
+
+ private int[] getPriorities()
+ {
+ String[] encodings = getEncodings();
+ final int count = encodings.length;
+ int[] priorities = new int[count];
+ for (int i = 0; i < count; i++)
+ {
+ int priority = encodingConfiguration.getPriority(encodings[i]);
+ priorities[i] = (priority > 0) ? (count - i) : 0;
+ }
+ return priorities;
+ }
+
+ public int getRowCount()
+ {
+ return getEncodings().length;
+ }
+
+ public Object getValueAt(int rowIndex, int columnIndex)
+ {
+ String encoding = getEncodings()[rowIndex];
+ switch (columnIndex)
+ {
+ case 0:
+ return Boolean
+ .valueOf(encodingConfiguration.getPriority(encoding) > 0);
+ case 1:
+ return MediaUtils.sdpToJmfEncoding(encoding);
+ default:
+ return null;
+ }
+ }
+
+ public boolean isCellEditable(int rowIndex, int columnIndex)
+ {
+ return (columnIndex == 0);
+ }
+
+ public void move(int rowIndex, boolean up)
+ {
+ if (up)
+ {
+ if (rowIndex <= 0)
+ throw new IllegalArgumentException("rowIndex");
+
+ move(rowIndex - 1, false);
+ return;
+ }
+
+ if (rowIndex >= (getRowCount() - 1))
+ throw new IllegalArgumentException("rowIndex");
+
+ int[] priorities = getPriorities();
+ final int nextRowIndex = rowIndex + 1;
+ if (priorities[rowIndex] > 0)
+ priorities[rowIndex] = priorities.length - nextRowIndex;
+ if (priorities[nextRowIndex] > 0)
+ priorities[nextRowIndex] = priorities.length - rowIndex;
+ setPriorities(priorities);
+
+ String swap = encodings[rowIndex];
+ encodings[rowIndex] = encodings[nextRowIndex];
+ encodings[nextRowIndex] = swap;
+
+ fireTableRowsUpdated(rowIndex, nextRowIndex);
+ }
+
+ private void setPriorities(int[] priorities)
+ {
+ final int count = encodings.length;
+ if (priorities.length != count)
+ throw new IllegalArgumentException("priorities");
+
+ for (int i = 0; i < count; i++)
+ encodingConfiguration.setPriority(encodings[i], priorities[i]);
+ }
+
+ public void setValueAt(Object value, int rowIndex, int columnIndex)
+ {
+ if ((columnIndex == 0) && (value instanceof Boolean))
+ {
+ int[] priorities = getPriorities();
+ priorities[rowIndex] =
+ ((Boolean) value) ? (priorities.length - rowIndex) : 0;
+ setPriorities(priorities);
+
+ fireTableCellUpdated(rowIndex, columnIndex);
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/media/MediaActivator.java b/src/net/java/sip/communicator/impl/media/MediaActivator.java
index f4ab42b55..3599aa37c 100644
--- a/src/net/java/sip/communicator/impl/media/MediaActivator.java
+++ b/src/net/java/sip/communicator/impl/media/MediaActivator.java
@@ -6,14 +6,15 @@
*/
package net.java.sip.communicator.impl.media;
-import org.osgi.framework.*;
-import net.java.sip.communicator.util.*;
import net.java.sip.communicator.service.configuration.*;
-import net.java.sip.communicator.service.netaddr.*;
-import java.util.*;
-import net.java.sip.communicator.service.media.*;
import net.java.sip.communicator.service.fileaccess.*;
+import net.java.sip.communicator.service.gui.ConfigurationForm;
+import net.java.sip.communicator.service.media.*;
+import net.java.sip.communicator.service.netaddr.*;
+import net.java.sip.communicator.service.resources.*;
+import net.java.sip.communicator.util.*;
+import org.osgi.framework.*;
/**
* Invoke "Service Binder" to parse the service XML and register
@@ -25,7 +26,7 @@
public class MediaActivator
implements BundleActivator
{
- private Logger logger = Logger.getLogger(MediaActivator.class.getName());
+ private final Logger logger = Logger.getLogger(MediaActivator.class.getName());
private static MediaServiceImpl mediaServiceImpl = null;
@@ -34,6 +35,7 @@ public class MediaActivator
private static NetworkAddressManagerService networkAddressManagerService
= null;
private static FileAccessService fileAccessService = null;
+ private static ResourceManagementService resources;
private ServiceRegistration mediaServiceRegistration = null;
@@ -51,22 +53,21 @@ public void start(BundleContext context)
throws Exception
{
logger.debug("Started.");
- this.bundleContext = context;
- Hashtable hashtable = new Hashtable();
- mediaServiceImpl = new MediaServiceImpl();
+ MediaActivator.bundleContext = context;
- //load all icq providers
+ // MediaService
+ mediaServiceImpl = new MediaServiceImpl();
mediaServiceImpl.start();
- //reg the icq account man.
- mediaServiceRegistration = context.registerService(
- MediaService.class.getName(),
- mediaServiceImpl,
- hashtable);
-
-
+ mediaServiceRegistration =
+ context.registerService(MediaService.class.getName(),
+ mediaServiceImpl, null);
logger.debug("Media Service ... [REGISTERED]");
+
+ // MediaConfigurationForm
+ context.registerService(ConfigurationForm.class.getName(),
+ new MediaConfigurationForm(), null);
}
/**
@@ -132,6 +133,13 @@ public static FileAccessService getFileAccessService()
return fileAccessService;
}
+ public static ResourceManagementService getResources()
+ {
+ if (resources == null)
+ resources =
+ ResourceManagementServiceUtils.getService(bundleContext);
+ return resources;
+ }
/**
* Returns a reference to the bundle context that we were started with.
diff --git a/src/net/java/sip/communicator/impl/media/MediaConfigurationForm.java b/src/net/java/sip/communicator/impl/media/MediaConfigurationForm.java
new file mode 100644
index 000000000..7990273dc
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/media/MediaConfigurationForm.java
@@ -0,0 +1,38 @@
+/*
+ * 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.media;
+
+import net.java.sip.communicator.service.gui.*;
+
+/**
+ * @author Lubomir Marinov
+ */
+public class MediaConfigurationForm
+ implements ConfigurationForm
+{
+ public Object getForm()
+ {
+ return new MediaConfigurationPanel();
+ }
+
+ public byte[] getIcon()
+ {
+ return MediaActivator.getResources().getImageInBytes(
+ "MediaConfigurationForm_icon");
+ }
+
+ public int getIndex()
+ {
+ return -1;
+ }
+
+ public String getTitle()
+ {
+ return MediaActivator.getResources().getI18NString(
+ "MediaConfigurationForm_title");
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/media/MediaConfigurationPanel.java b/src/net/java/sip/communicator/impl/media/MediaConfigurationPanel.java
new file mode 100644
index 000000000..13a94f56c
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/media/MediaConfigurationPanel.java
@@ -0,0 +1,429 @@
+/*
+ * 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.media;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+
+import javax.media.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.table.*;
+
+import net.java.sip.communicator.service.media.*;
+import net.java.sip.communicator.service.resources.*;
+import net.java.sip.communicator.swing.*;
+import net.java.sip.communicator.util.*;
+
+import org.osgi.framework.*;
+
+/**
+ * @author Lubomir Marinov
+ */
+public class MediaConfigurationPanel
+ extends JPanel
+{
+ private static final int HGAP = 5;
+
+ private static final int VGAP = 5;
+
+ private static MediaServiceImpl getMediaService()
+ {
+ BundleContext bundleContext = MediaActivator.getBundleContext();
+ ServiceReference serviceReference =
+ bundleContext.getServiceReference(MediaService.class.getName());
+
+ return (serviceReference == null) ? null
+ : (MediaServiceImpl) bundleContext.getService(serviceReference);
+ }
+
+ private final Logger logger =
+ Logger.getLogger(MediaConfigurationPanel.class);
+
+ private final MediaServiceImpl mediaService = getMediaService();
+
+ public MediaConfigurationPanel()
+ {
+ super(new GridLayout(0, 1, HGAP, VGAP));
+
+ int[] types =
+ new int[]
+ { DeviceConfigurationComboBoxModel.AUDIO,
+ DeviceConfigurationComboBoxModel.VIDEO };
+ for (int i = 0; i < types.length; i++)
+ add(createControls(types[i]));
+ }
+
+ private void controllerUpdateForPreview(ControllerEvent event,
+ Container videoContainer)
+ {
+ if (event instanceof RealizeCompleteEvent)
+ {
+ Player player = (Player) event.getSourceController();
+ Component video = player.getVisualComponent();
+
+ showPreview(videoContainer, video, player);
+ }
+ }
+
+ private Component createControls(int type)
+ {
+ final JComboBox comboBox = new JComboBox();
+ comboBox.setEditable(false);
+
+ JLabel label = new JLabel(getLabelText(type));
+ label.setDisplayedMnemonic(getDisplayedMnemonic(type));
+ label.setLabelFor(comboBox);
+
+ final JComponent preview;
+ ActionListener comboBoxListener = null;
+ if (type == DeviceConfigurationComboBoxModel.VIDEO)
+ {
+ JLabel noPreview =
+ new JLabel(MediaActivator.getResources().getI18NString(
+ "MediaConfigurationPanel_noPreview"));
+ noPreview.setHorizontalAlignment(SwingConstants.CENTER);
+ noPreview.setVerticalAlignment(SwingConstants.CENTER);
+
+ preview = createVideoContainer(noPreview);
+ Dimension previewSize = new Dimension(150, 150);
+ preview.setMaximumSize(previewSize);
+ preview.setMinimumSize(previewSize);
+ preview.setPreferredSize(previewSize);
+
+ comboBoxListener = new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ Object selection = comboBox.getSelectedItem();
+ CaptureDeviceInfo device = null;
+ if (selection instanceof DeviceConfigurationComboBoxModel.CaptureDevice)
+ {
+ device =
+ ((DeviceConfigurationComboBoxModel.CaptureDevice) selection).info;
+ }
+
+ createPreview(device, preview);
+ }
+ };
+ comboBox.addActionListener(comboBoxListener);
+ } else
+ preview = null;
+
+ Container deviceContainer = new JPanel(new GridBagLayout());
+ GridBagConstraints deviceConstraints = new GridBagConstraints();
+ deviceConstraints.anchor = GridBagConstraints.NORTHWEST;
+ deviceConstraints.gridx = 0;
+ deviceConstraints.gridy = 0;
+ deviceConstraints.weightx = 0;
+ deviceContainer.add(label, deviceConstraints);
+ deviceConstraints.gridx = 1;
+ deviceConstraints.weightx = 1;
+ deviceContainer.add(comboBox, deviceConstraints);
+ if (preview != null)
+ {
+ deviceConstraints.gridx = 2;
+ deviceConstraints.weightx = 0;
+ deviceContainer.add(preview, deviceConstraints);
+ }
+
+ comboBox.setModel(new DeviceConfigurationComboBoxModel(mediaService
+ .getDeviceConfiguration(), type));
+ if (comboBoxListener != null)
+ comboBoxListener.actionPerformed(null);
+
+ Container container = new JPanel(new GridBagLayout());
+ GridBagConstraints constraints = new GridBagConstraints();
+ constraints.fill = GridBagConstraints.HORIZONTAL;
+ constraints.gridx = 0;
+ constraints.gridy = 0;
+ constraints.weightx = 1;
+ constraints.weighty = 0;
+ container.add(deviceContainer, constraints);
+ constraints.fill = GridBagConstraints.BOTH;
+ constraints.gridy = 1;
+ constraints.weighty = 1;
+ container.add(createEncodingControls(type), constraints);
+ return container;
+ }
+
+ private Component createEncodingControls(int type)
+ {
+ ResourceManagementService resources = MediaActivator.getResources();
+ String key;
+
+ final JTable table = new JTable();
+ table.setFillsViewportHeight(true);
+ table.setShowGrid(false);
+ table.setTableHeader(null);
+
+ key = "MediaConfigurationPanel_encodings";
+ JLabel label = new JLabel(resources.getI18NString(key));
+ label.setDisplayedMnemonic(resources.getI18nMnemonic(key));
+ label.setLabelFor(table);
+
+ key = "MediaConfigurationPanel_up";
+ final JButton upButton = new JButton(resources.getI18NString(key));
+ upButton.setMnemonic(resources.getI18nMnemonic(key));
+
+ key = "MediaConfigurationPanel_down";
+ final JButton downButton = new JButton(resources.getI18NString(key));
+ downButton.setMnemonic(resources.getI18nMnemonic(key));
+
+ Container buttonBar = new JPanel(new GridLayout(0, 1));
+ buttonBar.add(upButton);
+ buttonBar.add(downButton);
+
+ Container container = new JPanel(new GridBagLayout());
+ GridBagConstraints constraints = new GridBagConstraints();
+ constraints.anchor = GridBagConstraints.NORTHWEST;
+ constraints.fill = GridBagConstraints.HORIZONTAL;
+ constraints.gridwidth = 2;
+ constraints.gridx = 0;
+ constraints.gridy = 0;
+ constraints.weightx = 0;
+ constraints.weighty = 0;
+ container.add(label, constraints);
+ constraints.anchor = GridBagConstraints.CENTER;
+ constraints.fill = GridBagConstraints.BOTH;
+ constraints.gridwidth = 1;
+ constraints.gridx = 0;
+ constraints.gridy = 1;
+ constraints.weightx = 1;
+ constraints.weighty = 1;
+ container.add(new JScrollPane(table), constraints);
+ constraints.anchor = GridBagConstraints.NORTHEAST;
+ constraints.fill = GridBagConstraints.NONE;
+ constraints.gridwidth = 1;
+ constraints.gridx = 1;
+ constraints.gridy = 1;
+ constraints.weightx = 0;
+ constraints.weighty = 0;
+ container.add(buttonBar, constraints);
+
+ table.setModel(new EncodingConfigurationTableModel(mediaService
+ .getEncodingConfiguration(), type));
+
+ /*
+ * The first column contains the check boxes which enable/disable their
+ * associated encodings and it doesn't make sense to make it wider than
+ * the check boxes.
+ */
+ TableColumnModel tableColumnModel = table.getColumnModel();
+ TableColumn tableColumn = tableColumnModel.getColumn(0);
+ tableColumn.setMaxWidth(tableColumn.getMinWidth());
+
+ ListSelectionListener tableSelectionListener =
+ new ListSelectionListener()
+ {
+ public void valueChanged(ListSelectionEvent event)
+ {
+ if (table.getSelectedRowCount() == 1)
+ {
+ int selectedRow = table.getSelectedRow();
+ if (selectedRow > -1)
+ {
+ upButton.setEnabled(selectedRow > 0);
+ downButton.setEnabled(selectedRow < (table
+ .getRowCount() - 1));
+ return;
+ }
+ }
+ upButton.setEnabled(false);
+ downButton.setEnabled(false);
+ }
+ };
+ table.getSelectionModel().addListSelectionListener(
+ tableSelectionListener);
+ tableSelectionListener.valueChanged(null);
+
+ ActionListener buttonListener = new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ Object source = event.getSource();
+ boolean up;
+ if (source == upButton)
+ up = true;
+ else if (source == downButton)
+ up = false;
+ else
+ return;
+
+ ((EncodingConfigurationTableModel) table.getModel()).move(table
+ .getSelectedRow(), up);
+ }
+ };
+ upButton.addActionListener(buttonListener);
+ downButton.addActionListener(buttonListener);
+
+ return container;
+ }
+
+ private void createPreview(CaptureDeviceInfo device,
+ final Container videoContainer)
+ {
+ videoContainer.removeAll();
+
+ if (device == null)
+ return;
+
+ Player player = null;
+ Exception exception = null;
+ try
+ {
+ player = Manager.createPlayer(device.getLocator());
+ }
+ catch (IOException ex)
+ {
+ exception = ex;
+ }
+ catch (NoPlayerException ex)
+ {
+ exception = ex;
+ }
+ if (exception != null)
+ {
+ logger.error("Failed to create preview for device " + device,
+ exception);
+ return;
+ }
+
+ player.addControllerListener(new ControllerListener()
+ {
+ public void controllerUpdate(ControllerEvent event)
+ {
+ controllerUpdateForPreview(event, videoContainer);
+ }
+ });
+ player.start();
+ }
+
+ private JComponent createVideoContainer(Component noVideoComponent)
+ {
+ return new VideoContainer(noVideoComponent);
+ }
+
+ private void disposePlayer(Player player)
+ {
+ player.stop();
+ player.deallocate();
+ player.close();
+ }
+
+ private char getDisplayedMnemonic(int type)
+ {
+ switch (type)
+ {
+ case DeviceConfigurationComboBoxModel.AUDIO:
+ return MediaActivator.getResources().getI18nMnemonic(
+ "MediaConfigurationPanel_audio");
+ case DeviceConfigurationComboBoxModel.VIDEO:
+ return MediaActivator.getResources().getI18nMnemonic(
+ "MediaConfigurationPanel_video");
+ default:
+ throw new IllegalArgumentException("type");
+ }
+ }
+
+ private String getLabelText(int type)
+ {
+ switch (type)
+ {
+ case DeviceConfigurationComboBoxModel.AUDIO:
+ return MediaActivator.getResources().getI18NString(
+ "MediaConfigurationPanel_audio");
+ case DeviceConfigurationComboBoxModel.VIDEO:
+ return MediaActivator.getResources().getI18NString(
+ "MediaConfigurationPanel_video");
+ default:
+ throw new IllegalArgumentException("type");
+ }
+ }
+
+ private void showPreview(final Container previewContainer,
+ final Component preview, final Player player)
+ {
+ if (!SwingUtilities.isEventDispatchThread())
+ {
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ showPreview(previewContainer, preview, player);
+ }
+ });
+ return;
+ }
+
+ previewContainer.removeAll();
+
+ if (preview != null)
+ {
+ HierarchyListener hierarchyListener = new HierarchyListener()
+ {
+ private Window window;
+
+ private WindowListener windowListener;
+
+ public void dispose()
+ {
+ if (windowListener != null)
+ {
+ if (window != null)
+ {
+ window.removeWindowListener(windowListener);
+ window = null;
+ }
+ windowListener = null;
+ }
+
+ preview.removeHierarchyListener(this);
+
+ disposePlayer(player);
+ }
+
+ public void hierarchyChanged(HierarchyEvent event)
+ {
+ if ((event.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0)
+ {
+ if (preview.isDisplayable())
+ {
+ if (windowListener == null)
+ {
+ window =
+ SwingUtilities.windowForComponent(preview);
+ if (window != null)
+ {
+ windowListener = new WindowAdapter()
+ {
+ public void windowClosing(
+ WindowEvent event)
+ {
+ dispose();
+ }
+ };
+ window.addWindowListener(windowListener);
+ }
+ }
+ }
+ else
+ {
+ dispose();
+ }
+ }
+ }
+ };
+ preview.addHierarchyListener(hierarchyListener);
+
+ previewContainer.add(preview);
+ }
+ else
+ disposePlayer(player);
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/media/MediaControl.java b/src/net/java/sip/communicator/impl/media/MediaControl.java
index e786ce453..6eab840a1 100644
--- a/src/net/java/sip/communicator/impl/media/MediaControl.java
+++ b/src/net/java/sip/communicator/impl/media/MediaControl.java
@@ -14,11 +14,9 @@
import javax.media.control.*;
import javax.media.format.*;
import javax.media.protocol.*;
-import javax.sdp.*;
import net.java.sip.communicator.impl.media.codec.*;
import net.java.sip.communicator.impl.media.device.*;
-import net.java.sip.communicator.service.configuration.*;
import net.java.sip.communicator.service.media.MediaException;
import net.java.sip.communicator.util.*;
diff --git a/src/net/java/sip/communicator/impl/media/codec/EncodingConfiguration.java b/src/net/java/sip/communicator/impl/media/codec/EncodingConfiguration.java
index bcb36b9ca..c2fc130fa 100644
--- a/src/net/java/sip/communicator/impl/media/codec/EncodingConfiguration.java
+++ b/src/net/java/sip/communicator/impl/media/codec/EncodingConfiguration.java
@@ -1,3 +1,9 @@
+/*
+ * 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.media.codec;
import java.io.*;
@@ -25,7 +31,7 @@ public class EncodingConfiguration
/**
* SDP Codes of all video formats that JMF supports.
*/
- private String[] availableVideoEncodings = new String[]
+ private final String[] availableVideoEncodings = new String[]
{ Integer.toString(Constants.H264_RTP_SDP),
// javax.media.format.VideoFormat.H263_RTP
Integer.toString(SdpConstants.H263),
@@ -37,7 +43,7 @@ public class EncodingConfiguration
/**
* SDP Codes of all audio formats that JMF supports.
*/
- private String[] availableAudioEncodings = new String[]
+ private final String[] availableAudioEncodings = new String[]
{
// ILBC
Integer.toString(97),
@@ -60,10 +66,10 @@ public class EncodingConfiguration
// Integer.toString(SdpConstants.G729)
};
- private TreeSet suportedVideoEncodings =
+ private final Set suportedVideoEncodings =
new TreeSet(new EncodingComparator());
- private TreeSet suportedAudioEncodings =
+ private final Set suportedAudioEncodings =
new TreeSet(new EncodingComparator());
/**
@@ -73,13 +79,10 @@ public class EncodingConfiguration
* would be decorelated and other components (such as the UI) should present
* them separately.
*/
- private final Hashtable encodingPreferences =
+ private final Map encodingPreferences =
new Hashtable();
- /**
- *
- */
- private static String[] customCodecs =
+ private static final String[] customCodecs =
new String[]
{
FMJConditionals.FMJ_CODECS ? "net.sf.fmj.media.codec.audio.alaw.Encoder"
@@ -101,7 +104,7 @@ public class EncodingConfiguration
/**
* Custom Packages provided by Sip-Communicator
*/
- private static String[] customPackages = new String[]
+ private static final String[] customPackages = new String[]
{ // datasource for low latency ALSA input
"net.java.sip.communicator.impl", "net.sf.fmj" };
@@ -144,10 +147,8 @@ private void initializeFormatPreferences()
List sdpPreferences =
confService.getPropertyNamesByPrefix(PROP_SDP_PREFERENCE, false);
- Iterator sdpPreferencesIter = sdpPreferences.iterator();
- while (sdpPreferencesIter.hasNext())
+ for (String pName : sdpPreferences)
{
- String pName = sdpPreferencesIter.next();
String prefStr = confService.getString(pName);
String fmtName =
pName.substring(pName.lastIndexOf('.') + 1).replaceAll("sdp",
@@ -206,19 +207,16 @@ private void updateSupportedEncodings()
suportedVideoEncodings.remove(ac);
}
}
-
+
/**
* Updates the codecs in the set according preferences in
* encodingPreferences. If value is "0" the codec is disabled.
*/
public String[] updateEncodings(List encs)
{
- TreeSet result = new TreeSet(new EncodingComparator());
- Iterator iter = encs.iterator();
- while (iter.hasNext())
- {
- String c = (String) iter.next();
-
+ Set result = new TreeSet(new EncodingComparator());
+ for (String c : encs)
+ {
Integer pref1 = encodingPreferences.get(c);
int pref1IntValue = (pref1 == null) ? 0 : pref1.intValue();
@@ -279,6 +277,11 @@ public void setPriority(String encoding, int priority)
updateSupportedEncodings();
}
+ public int getPriority(String encoding)
+ {
+ return encodingPreferences.get(encoding);
+ }
+
/**
* Register in JMF the custom codecs we provide
*/
@@ -360,7 +363,7 @@ private void registerCustomPackages()
// list is always short
if (!currentPackagePrefix.contains(className))
{
- currentPackagePrefix.addElement(className);
+ currentPackagePrefix.add(className);
logger.debug("Adding package : " + className);
}
}
@@ -426,6 +429,5 @@ public int compare(String s1, String s2)
{
return compareEncodingPreferences(s1, s2);
}
-
}
}
diff --git a/src/net/java/sip/communicator/impl/media/media.manifest.mf b/src/net/java/sip/communicator/impl/media/media.manifest.mf
index 7f195c9bb..69ab1b37b 100644
--- a/src/net/java/sip/communicator/impl/media/media.manifest.mf
+++ b/src/net/java/sip/communicator/impl/media/media.manifest.mf
@@ -4,35 +4,37 @@ Bundle-Description: A bundle that offers Media capture and presentation capabili
Bundle-Vendor: sip-communicator.org
Bundle-Version: 0.0.1
Import-Package: org.osgi.framework,
- net.java.sip.communicator.service.configuration,
- net.java.sip.communicator.service.configuration.event,
- net.java.sip.communicator.service.protocol,
- net.java.sip.communicator.service.protocol.event,
- net.java.sip.communicator.util,
- net.java.sip.communicator.service.netaddr,
+ org.bouncycastle.jce.provider,
+ org.xml.sax,
+ javax.crypto,
+ javax.crypto.interfaces,
+ javax.crypto.spec,
+ javax.imageio,
+ javax.sound,
+ javax.sound.sampled,
javax.swing,
- javax.swing.event,
javax.swing.border,
- javax.imageio,
+ javax.swing.event,
+ javax.swing.table,
+ net.java.sip.communicator.service.configuration,
+ net.java.sip.communicator.service.configuration.event,
net.java.sip.communicator.service.fileaccess,
net.java.sip.communicator.service.gui,
+ net.java.sip.communicator.service.netaddr,
+ net.java.sip.communicator.service.protocol,
+ net.java.sip.communicator.service.protocol.event,
net.java.sip.communicator.service.resources,
- javax.sound,
- javax.sound.sampled,
+ net.java.sip.communicator.swing,
+ net.java.sip.communicator.util,
quicktime,
quicktime.std.sg,
quicktime.qd,
quicktime.util,
quicktime.std.image,
- javax.crypto,
- javax.crypto.spec,
- javax.crypto.interfaces,
- org.xml.sax,
- org.bouncycastle.jce.provider,
gnu.java.zrtp,
- gnu.java.zrtp.zidfile,
+ gnu.java.zrtp.packets,
gnu.java.zrtp.utils,
- gnu.java.zrtp.packets
+ gnu.java.zrtp.zidfile
Export-Package: net.java.sip.communicator.service.media,
net.java.sip.communicator.service.media.event,
net.java.sip.communicator.impl.media,
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/FitLayout.java b/src/net/java/sip/communicator/swing/FitLayout.java
similarity index 96%
rename from src/net/java/sip/communicator/impl/gui/main/call/FitLayout.java
rename to src/net/java/sip/communicator/swing/FitLayout.java
index 8f2434571..e9661c665 100644
--- a/src/net/java/sip/communicator/impl/gui/main/call/FitLayout.java
+++ b/src/net/java/sip/communicator/swing/FitLayout.java
@@ -4,7 +4,7 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
-package net.java.sip.communicator.impl.gui.main.call;
+package net.java.sip.communicator.swing;
import java.awt.*;
diff --git a/src/net/java/sip/communicator/swing/VideoContainer.java b/src/net/java/sip/communicator/swing/VideoContainer.java
new file mode 100644
index 000000000..2ad47154f
--- /dev/null
+++ b/src/net/java/sip/communicator/swing/VideoContainer.java
@@ -0,0 +1,114 @@
+/*
+ * 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.swing;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+
+/**
+ * @author Lubomir Marinov
+ */
+public class VideoContainer
+ extends JPanel
+{
+ private final ContainerListener containerListener = new ContainerListener()
+ {
+
+ /*
+ * Since the videoContainer displays either noVideoComponent or a single
+ * visual Component which represents video, ensures the last Component
+ * added to the Container is the only Component it contains i.e.
+ * noVideoComponent goes away when the video is displayed and the video
+ * goes away when noVideoComponent is displayed.
+ */
+ public void componentAdded(ContainerEvent event)
+ {
+ Container container = event.getContainer();
+ Component local = ((VideoLayout) container.getLayout()).getLocal();
+ Component added = event.getChild();
+
+ if ((local != null) && (added == local))
+ return;
+
+ Component[] components = container.getComponents();
+ boolean validate = false;
+
+ for (int i = 0; i < components.length; i++)
+ {
+ Component component = components[i];
+
+ if ((component != added) && (component != local))
+ {
+ container.remove(component);
+ validate = true;
+ }
+ }
+ if (validate)
+ container.validate();
+ };
+
+ /*
+ * Displays noVideoComponent when there is no visual Component which
+ * represents video to be displayed.
+ */
+ public void componentRemoved(ContainerEvent event)
+ {
+ Container container = event.getContainer();
+
+ if ((container.getComponentCount() <= 0)
+ || (((VideoLayout) container.getLayout()).getRemote() == null))
+ {
+ container.add(noVideoComponent, VideoLayout.REMOTE);
+ container.validate();
+ }
+ }
+ };
+
+ private final Component noVideoComponent;
+
+ public VideoContainer(Component noVideoComponent)
+ {
+ super(new VideoLayout());
+
+ this.noVideoComponent = noVideoComponent;
+
+ addContainerListener(containerListener);
+ add(noVideoComponent, VideoLayout.REMOTE);
+ }
+
+ public Component add(Component comp)
+ {
+ add(comp, VideoLayout.REMOTE);
+ return comp;
+ }
+
+ /*
+ * Ensures noVideoComponent is displayed even when the clients of the
+ * videoContainer invoke its #removeAll() to remove their previous visual
+ * Components representing video. Just adding noVideoComponent upon
+ * ContainerEvent#COMPONENT_REMOVED when there is no other Component left in
+ * the Container will cause an infinite loop because Container#removeAll()
+ * will detect that a new Component has been added while dispatching the
+ * event and will then try to remove the new Component.
+ */
+ public void removeAll()
+ {
+ removeContainerListener(containerListener);
+ try
+ {
+ super.removeAll();
+ }
+ finally
+ {
+ addContainerListener(containerListener);
+ containerListener.componentRemoved(new ContainerEvent(this,
+ ContainerEvent.COMPONENT_REMOVED, null));
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/VideoLayout.java b/src/net/java/sip/communicator/swing/VideoLayout.java
similarity index 93%
rename from src/net/java/sip/communicator/impl/gui/main/call/VideoLayout.java
rename to src/net/java/sip/communicator/swing/VideoLayout.java
index 56ba39106..70d2568df 100644
--- a/src/net/java/sip/communicator/impl/gui/main/call/VideoLayout.java
+++ b/src/net/java/sip/communicator/swing/VideoLayout.java
@@ -4,7 +4,7 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
-package net.java.sip.communicator.impl.gui.main.call;
+package net.java.sip.communicator.swing;
import java.awt.*;
diff --git a/src/net/java/sip/communicator/swing/swing.common.manifest.mf b/src/net/java/sip/communicator/swing/swing.common.manifest.mf
new file mode 100644
index 000000000..f98555eb6
--- /dev/null
+++ b/src/net/java/sip/communicator/swing/swing.common.manifest.mf
@@ -0,0 +1,6 @@
+Bundle-Name: Swing Common
+Bundle-Description: Common/generic Swing additions not specific to SIP Communicator
+Bundle-Vendor: sip-communicator.org
+Bundle-Version: 0.0.1
+Import-Package: javax.swing
+Export-Package: net.java.sip.communicator.swing