/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.java.sip.communicator.impl.gui.utils;
import java.awt.*;
import java.util.*;
import javax.swing.*;
import net.java.sip.communicator.impl.gui.*;
import net.java.sip.communicator.impl.gui.event.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.gui.Container;
import net.java.sip.communicator.util.*;
import org.osgi.framework.*;
/**
* Provides capabilities to a specific JComponent
to contain
* PluginComponent
s, track when they are added and removed.
*
* @author Lyubomir Marinov
*/
public class PluginContainer
implements PluginComponentListener
{
/**
* The Logger used by the PluginContainer class and its
* instances for logging output.
*/
private static final Logger logger
= Logger.getLogger(PluginContainer.class);
/**
* The JComponent
which contains the components of the
* PluginComponent
s managed by this instance.
*/
private final JComponent container;
/**
* The container id of the PluginComponent
managed by this
* instance.
*/
private final Container containerId;
/**
* The list of PluginComponent
instances which have their
* components added to this PluginContainer
.
*/
private final java.util.List pluginComponents
= new LinkedList();
/**
* Initializes a new PluginContainer
instance which is to
* provide capabilities to a specific JComponent
container with
* a specific Container
id to contain
* PluginComponent
and track when they are added and removed.
*
* @param container
* the JComponent
container the new instance is to
* provide its capabilities to
* @param containerId
* the Container
id of the specified
* container
*/
public PluginContainer(JComponent container, Container containerId)
{
this.container = container;
this.containerId = containerId;
initPluginComponents();
}
/**
* Adds a specific Component to a specific JComponent
* container. Allows extenders to apply custom logic to the exact placement
* of the specified Component in the specified container.
*
* @param component the Component to be added to the specified
* JComponent container
* @param container the JComponent container to add the specified
* Component to
* @param preferredIndex the index at which component is to be
* added to container if possible or -1 if there is no
* preference with respect to the index in question
*/
protected void addComponentToContainer(
Component component,
JComponent container,
int preferredIndex)
{
if ((0 <= preferredIndex)
&& (preferredIndex < getComponentCount(container)))
container.add(component, preferredIndex);
else
container.add(component);
}
/**
* Adds the component of a specific PluginComponent to the
* associated Container.
*
* @param factory the PluginComponentFactory which is to have its
* component added to the Container associated with this
* PluginContainer
*/
private synchronized void addPluginComponent(PluginComponentFactory factory)
{
PluginComponent c =
factory.getPluginComponentInstance(PluginContainer.this);
if (logger.isInfoEnabled())
logger.info("Will add plugin component: " + c);
/*
* Try to respect positionIndex of PluginComponent to some extent:
* PluginComponents with positionIndex equal to 0 go at the beginning,
* these with positionIndex equal to -1 follow them and then go these
* with positionIndex greater than 0.
*/
int cIndex = factory.getPositionIndex();
int index = -1;
int i = 0;
for (PluginComponent pluginComponent : pluginComponents)
{
if (pluginComponent.equals(c))
return;
if (-1 == index)
{
int pluginComponentIndex = factory.getPositionIndex();
if ((0 == cIndex) || (-1 == cIndex))
{
if ((0 != pluginComponentIndex)
&& (cIndex != pluginComponentIndex))
index = i;
}
else if (cIndex < pluginComponentIndex)
index = i;
}
i++;
}
int pluginComponentCount = pluginComponents.size();
if (-1 == index)
index = pluginComponents.size();
/*
* The container may have added Components of its own apart from the
* ones this PluginContainer has added to it. Since the common case for
* the additional Components is to have them appear at the beginning,
* adjust the index so it gets correct in the common case.
*/
int containerComponentCount = getComponentCount(container);
addComponentToContainer(
(Component) c.getComponent(),
container,
(containerComponentCount > pluginComponentCount)
? (index + (containerComponentCount - pluginComponentCount))
: index);
pluginComponents.add(index, c);
container.revalidate();
container.repaint();
}
/**
* Runs clean-up for associated resources which need explicit disposal (e.g.
* listeners keeping this instance alive because they were added to the
* model which operationally outlives this instance).
*/
public void dispose()
{
GuiActivator.getUIService().removePluginComponentListener(this);
/*
* Explicitly remove the components of the PluginComponent instances
* because the latter are registered with OSGi and are thus global.
*/
synchronized (this)
{
for (PluginComponent pluginComponent : pluginComponents)
container.remove((Component) pluginComponent.getComponent());
pluginComponents.clear();
}
}
/**
* Gets the number of Components in a specific JComponent
* container. For example, returns the result of
* getMenuComponentCount() if container is an instance of
* JMenu.
*
* @param container the JComponent container to get the number of
* Components of
* @return the number of Components in the specified
* container
*/
protected int getComponentCount(JComponent container)
{
return
(container instanceof JMenu)
? ((JMenu) container).getMenuComponentCount()
: container.getComponentCount();
}
/**
* Gets the PluginComponents of this PluginContainer.
*
* @return an Iterable over the PluginComponents of this
* PluginContainer
*/
public Iterable getPluginComponents()
{
return pluginComponents;
}
/**
* Adds the Components of the PluginComponents registered
* in the OSGi BundleContext in the associated Container.
*/
private void initPluginComponents()
{
GuiActivator.getUIService().addPluginComponentListener(this);
// Look for PluginComponents registered in the OSGi BundleContext.
ServiceReference[] serRefs = null;
try
{
serRefs
= GuiActivator
.bundleContext
.getServiceReferences(
PluginComponentFactory.class.getName(),
"("
+ Container.CONTAINER_ID
+ "="
+ containerId.getID()
+ ")");
}
catch (InvalidSyntaxException exc)
{
logger.error("Could not obtain plugin reference.", exc);
}
if (serRefs != null)
{
for (ServiceReference serRef : serRefs)
{
PluginComponentFactory factory
= (PluginComponentFactory)
GuiActivator.bundleContext.getService(serRef);
addPluginComponent(factory);
}
}
}
/**
* Implements
* {@link PluginComponentListener#pluginComponentAdded(PluginComponentEvent)}.
*
* @param event a PluginComponentEvent which specifies the
* PluginComponent which has been added
*/
public void pluginComponentAdded(PluginComponentEvent event)
{
PluginComponentFactory factory = event.getPluginComponentFactory();
if (factory.getContainer().equals(containerId))
addPluginComponent(factory);
}
/**
* Implements
* {@link PluginComponentListener#pluginComponentRemoved(PluginComponentEvent)}.
*
* @param event a PluginComponentEvent which specifies the
* PluginComponent which has been added
*/
public void pluginComponentRemoved(PluginComponentEvent event)
{
PluginComponentFactory factory = event.getPluginComponentFactory();
if (factory.getContainer().equals(containerId))
removePluginComponent(factory);
}
/**
* Removes the component of a specific PluginComponent
from
* this PluginContainer
.
*
* @param factory
* the PluginComponent
which is to have its
* component removed from this PluginContainer
*/
private synchronized void removePluginComponent(
PluginComponentFactory factory)
{
Iterator iterator = pluginComponents.iterator();
while(iterator.hasNext())
{
PluginComponent c = iterator.next();
if(c.getParentFactory().equals(factory))
{
iterator.remove();
container.remove((Component)c.getComponent());
}
}
}
}