aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java/sip/communicator/impl/gui
diff options
context:
space:
mode:
authorWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2017-03-11 22:15:03 +0100
committerWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2017-03-11 22:15:03 +0100
commit85901329b0794b136b96bf745f4ab1572806fc89 (patch)
treef23da7e97cae727f39d825f0fef8348cffb238e4 /src/net/java/sip/communicator/impl/gui
parent3db2e44f186c59429901b2c899e139ea60117a55 (diff)
parentcf5da997da8820b4050f5b87ee9440a0ede36d1f (diff)
downloadjitsi-master.zip
jitsi-master.tar.gz
jitsi-master.tar.bz2
Merge commit 'cf5da99'HEADmaster
Signed-off-by: Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de>
Diffstat (limited to 'src/net/java/sip/communicator/impl/gui')
-rw-r--r--src/net/java/sip/communicator/impl/gui/UIServiceImpl.java83
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/MainFrame.java52
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/UINotification.java8
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/UINotificationGroup.java5
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/UINotificationListener.java7
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/UINotificationManager.java19
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/account/AccountsConfigurationPanel.java552
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/call/CallDialog.java1234
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/call/CallHistoryButton.java8
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/call/CallInfoFrame.java24
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/call/CallTransferHandler.java548
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/call/FullScreenLayout.java348
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/call/PreCallDialog.java6
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/call/SecurityPanel.java230
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/call/TransferCallDialog.java276
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceInviteDialog.java1136
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/call/conference/VideoConferenceCallPanel.java2786
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java7
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/ChatSessionChangeListener.java60
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/conference/ChatContactListModel.java466
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatManager.java2776
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/filetransfer/ReceiveFileConversationComponent.java4
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/toolBars/MainToolBar.java13
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomTableDialog.java13
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chatroomslist/ServerChatRoomsChoiceDialog.java190
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/contactlist/AddContactDialog.java109
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/contactlist/ContactInfoDialog.java131
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java2
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/contactlist/PresenceFilter.java702
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/contactlist/SearchFilter.java5
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/contactlist/TreeContactList.java4
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/SourceUIContact.java4
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/menus/MacOSXPreferencesRegistration.java56
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/menus/MacOSXQuitRegistration.java132
-rw-r--r--src/net/java/sip/communicator/impl/gui/swing.ui.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/impl/gui/utils/PluginContainer.java632
36 files changed, 6361 insertions, 6269 deletions
diff --git a/src/net/java/sip/communicator/impl/gui/UIServiceImpl.java b/src/net/java/sip/communicator/impl/gui/UIServiceImpl.java
index 2e8735f..db2eac9 100644
--- a/src/net/java/sip/communicator/impl/gui/UIServiceImpl.java
+++ b/src/net/java/sip/communicator/impl/gui/UIServiceImpl.java
@@ -74,7 +74,8 @@ public class UIServiceImpl
implements UIService,
ShutdownService,
ServiceListener,
- PropertyChangeListener
+ PropertyChangeListener,
+ UINotificationListener
{
/**
* The <tt>Logger</tt> used by the <tt>UIServiceImpl</tt> class and its
@@ -140,6 +141,7 @@ public class UIServiceImpl
*/
public UIServiceImpl()
{
+ UINotificationManager.addNotificationListener(this);
}
/**
@@ -197,8 +199,12 @@ public class UIServiceImpl
}
}
- if(ConfigurationUtils.isApplicationVisible())
+ if(ConfigurationUtils.isApplicationVisible()
+ || Boolean.getBoolean("disable-tray")
+ || ConfigurationUtils.isMinimizeInsteadOfHide())
+ {
mainFrame.setFrameVisible(true);
+ }
SwingUtilities.invokeLater(new RunLoginGui());
@@ -428,36 +434,16 @@ public class UIServiceImpl
}
/**
- * Implements {@link UIService#setExitOnMainWindowClose}. Sets the boolean
- * property which indicates whether the application should be exited when
- * the main application window is closed.
- *
- * @param exitOnMainWindowClose <tt>true</tt> if closing the main
- * application window should also be exiting the application; otherwise,
- * <tt>false</tt>
- */
- public void setExitOnMainWindowClose(boolean exitOnMainWindowClose)
- {
- mainFrame.setDefaultCloseOperation(
- exitOnMainWindowClose
- ? JFrame.DISPOSE_ON_CLOSE
- : JFrame.HIDE_ON_CLOSE);
- }
-
- /**
- * Implements {@link UIService#getExitOnMainWindowClose()}. Gets the boolean
- * property which indicates whether the application should be exited when
- * the main application window is closed.
- *
- * @return determines whether the UI impl would exit the application when
- * the main application window is closed.
+ * Called from the systray service when a tray has been initialized and
+ * hiding (instead of minimizing or exiting) is possible). If hiding is
+ * possible and the option to minimize is not selected, the application
+ * gets hidden on clicking 'X'.
+ *
+ * @param true if a tray icon was loaded.
*/
- public boolean getExitOnMainWindowClose()
+ public void setMainWindowCanHide(boolean canHide)
{
- return
- (mainFrame != null)
- && (mainFrame.getDefaultCloseOperation()
- == JFrame.DISPOSE_ON_CLOSE);
+ mainFrame.updateCloseAction(canHide);
}
/**
@@ -1642,4 +1628,41 @@ public class UIServiceImpl
ChatRoomAutoOpenConfigDialog.showChatRoomAutoOpenConfigDialog(
pps, chatRoomId);
}
+
+ /**
+ * Counts the number of unread notifications and forwards the sum to the
+ * systray service.
+ */
+ @Override
+ public void notificationReceived(UINotification notification)
+ {
+ forwardNotificationCount();
+ }
+
+ /**
+ * Counts the number of unread notifications and forwards the sum to the
+ * systray service.
+ */
+ @Override
+ public void notificationCleared(UINotification notification)
+ {
+ forwardNotificationCount();
+ }
+
+ private void forwardNotificationCount()
+ {
+ int count = 0;
+ for (UINotificationGroup g : UINotificationManager
+ .getNotificationGroups())
+ {
+ Iterator<UINotification> it =
+ UINotificationManager.getUnreadNotifications(g);
+ while (it.hasNext())
+ {
+ count += it.next().getUnreadObjects();
+ }
+ }
+
+ GuiActivator.getSystrayService().setNotificationCount(count);
+ }
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/MainFrame.java b/src/net/java/sip/communicator/impl/gui/main/MainFrame.java
index a8ee80a..b450efe 100644
--- a/src/net/java/sip/communicator/impl/gui/main/MainFrame.java
+++ b/src/net/java/sip/communicator/impl/gui/main/MainFrame.java
@@ -334,13 +334,9 @@ public class MainFrame
*/
private void init()
{
- setDefaultCloseOperation(
- GuiActivator.getUIService().getExitOnMainWindowClose()
- ? JFrame.DISPOSE_ON_CLOSE
- : JFrame.HIDE_ON_CLOSE);
-
+ // at startup, we cannot hide yet
+ updateCloseAction(false);
registerKeyActions();
-
JComponent northPanel = createTopComponent();
this.setJMenuBar(menu);
@@ -394,6 +390,30 @@ public class MainFrame
}
}
+ /**
+ * If hiding is possible and the option to minimize is not selected, the
+ * application gets hidden on clicking 'X'.
+ *
+ * @param true if hiding is possible, i.e. a tray icon is loaded
+ */
+ public void updateCloseAction(boolean canHide)
+ {
+ if (ConfigurationUtils.isMinimizeInsteadOfHide())
+ {
+ logger.info("Updating close action: DO_NOTHING_ON_CLOSE");
+ setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+ }
+ else
+ {
+ logger.info("Updating close action: " + (canHide
+ ? "HIDE_ON_CLOSE"
+ : "DISPOSE_ON_CLOSE"));
+ setDefaultCloseOperation(canHide
+ ? JFrame.HIDE_ON_CLOSE
+ : JFrame.DISPOSE_ON_CLOSE);
+ }
+ }
+
private Component createButtonPanel()
{
boolean isCallButtonEnabled = false;
@@ -1885,7 +1905,8 @@ public class MainFrame
*/
protected void windowClosed(WindowEvent event)
{
- if(GuiActivator.getUIService().getExitOnMainWindowClose())
+ if(getDefaultCloseOperation() == JFrame.EXIT_ON_CLOSE ||
+ getDefaultCloseOperation() == JFrame.DISPOSE_ON_CLOSE)
{
try
{
@@ -1919,9 +1940,17 @@ public class MainFrame
// On Mac systems the application is not quited on window close, so we
// don't need to warn the user.
- if (!GuiActivator.getUIService().getExitOnMainWindowClose()
- && !OSUtils.IS_MAC)
+ if (OSUtils.IS_MAC)
{
+ return;
+ }
+
+ switch (getDefaultCloseOperation())
+ {
+ case JFrame.EXIT_ON_CLOSE:
+ case JFrame.DISPOSE_ON_CLOSE:
+ return;
+ case JFrame.HIDE_ON_CLOSE:
SwingUtilities.invokeLater(new Runnable()
{
public void run()
@@ -1940,8 +1969,11 @@ public class MainFrame
}
}
});
-
ConfigurationUtils.setApplicationVisible(false);
+ break;
+ case JFrame.DO_NOTHING_ON_CLOSE:
+ this.minimize();
+ break;
}
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/UINotification.java b/src/net/java/sip/communicator/impl/gui/main/UINotification.java
index fbfb6da..4304907 100644
--- a/src/net/java/sip/communicator/impl/gui/main/UINotification.java
+++ b/src/net/java/sip/communicator/impl/gui/main/UINotification.java
@@ -17,6 +17,8 @@
*/
package net.java.sip.communicator.impl.gui.main;
+import java.util.Objects;
+
/**
* The <tt>UINotification</tt> class represents a notification received in the
* user interface. This could be a missed call, voicemail, email notification or
@@ -172,4 +174,10 @@ public class UINotification
return true;
}
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(notificationName, parentGroup);
+ }
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/UINotificationGroup.java b/src/net/java/sip/communicator/impl/gui/main/UINotificationGroup.java
index a2e3673..fb14645 100644
--- a/src/net/java/sip/communicator/impl/gui/main/UINotificationGroup.java
+++ b/src/net/java/sip/communicator/impl/gui/main/UINotificationGroup.java
@@ -99,7 +99,12 @@ public class UINotificationGroup
{
synchronized (unreadNotifications)
{
+ List<UINotification> copy = new ArrayList<>(unreadNotifications);
unreadNotifications.clear();
+ for (UINotification n : copy)
+ {
+ UINotificationManager.fireClearedEvent(n);
+ }
}
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/UINotificationListener.java b/src/net/java/sip/communicator/impl/gui/main/UINotificationListener.java
index fc5568d..932d96c 100644
--- a/src/net/java/sip/communicator/impl/gui/main/UINotificationListener.java
+++ b/src/net/java/sip/communicator/impl/gui/main/UINotificationListener.java
@@ -32,4 +32,11 @@ public interface UINotificationListener
* @param notification the notification that was received
*/
public void notificationReceived(UINotification notification);
+
+ /**
+ * Indicates that a notification has been cleared.
+ *
+ * @param notification the notification that was cleared.
+ */
+ public void notificationCleared(UINotification notification);
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/UINotificationManager.java b/src/net/java/sip/communicator/impl/gui/main/UINotificationManager.java
index b6001f7..2d42233 100644
--- a/src/net/java/sip/communicator/impl/gui/main/UINotificationManager.java
+++ b/src/net/java/sip/communicator/impl/gui/main/UINotificationManager.java
@@ -150,4 +150,23 @@ public class UINotificationManager
listeners.next().notificationReceived(notification);
}
}
+
+
+ /**
+ * Notifies interested <tt>UINotificationListener</tt> that a
+ * notification has been cleared.
+ *
+ * @param notification the cleared notification
+ */
+ static void fireClearedEvent(UINotification notification)
+ {
+ synchronized (notificationListeners)
+ {
+ Iterator<UINotificationListener> listeners
+ = notificationListeners.iterator();
+
+ while (listeners.hasNext())
+ listeners.next().notificationCleared(notification);
+ }
+ }
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/account/AccountsConfigurationPanel.java b/src/net/java/sip/communicator/impl/gui/main/account/AccountsConfigurationPanel.java
index 9511310..a85ffc3 100644
--- a/src/net/java/sip/communicator/impl/gui/main/account/AccountsConfigurationPanel.java
+++ b/src/net/java/sip/communicator/impl/gui/main/account/AccountsConfigurationPanel.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,278 +15,278 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.gui.main.account;
-
-import java.awt.*;
-import java.awt.event.*;
-import java.beans.*;
-import java.util.List;
-
-import javax.swing.*;
-import javax.swing.event.*;
-
-import net.java.sip.communicator.impl.gui.*;
-import net.java.sip.communicator.plugin.desktoputil.*;
-import net.java.sip.communicator.service.gui.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.account.*;
-
-import org.jitsi.service.configuration.*;
-import org.jitsi.service.resources.*;
-
-/**
- * The <tt>AccountsConfigurationPanel</tt> is the panel containing the accounts
- * list and according buttons shown in the options form.
- *
- * @author Yana Stamcheva
- * @author Lubomir Marinov
- */
-public class AccountsConfigurationPanel
- extends TransparentPanel
- implements ActionListener,
- ListSelectionListener,
- PropertyChangeListener
-{
- private final AccountList accountList;
-
- private final JButton newButton =
- new JButton(GuiActivator.getResources().getI18NString(
- "service.gui.ADD"));
-
- private final JButton editButton =
- new JButton(GuiActivator.getResources().getI18NString(
- "service.gui.EDIT"));
-
- private final JButton removeButton =
- new JButton(GuiActivator.getResources().getI18NString(
- "service.gui.DELETE"));
-
- /**
- * Creates and initializes this account configuration panel.
- */
- public AccountsConfigurationPanel()
- {
- super(new BorderLayout());
-
- accountList = new AccountList(this);
-
- /*
- * It seems that we can only delete one account at a time because our
- * confirmation dialog asks for one account.
- */
- accountList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-
- this.setPreferredSize(new Dimension(500, 400));
-
- JScrollPane accountListPane = new JScrollPane();
-
- accountListPane.getViewport().add(accountList);
- accountListPane.getVerticalScrollBar().setUnitIncrement(30);
-
- this.add(accountListPane, BorderLayout.CENTER);
-
- JPanel buttonsPanel =
- new TransparentPanel(new FlowLayout(FlowLayout.RIGHT));
-
- newButton.addActionListener(this);
- editButton.addActionListener(this);
- removeButton.addActionListener(this);
-
- this.newButton.setMnemonic(GuiActivator.getResources().getI18nMnemonic(
- "service.gui.ADD"));
- this.editButton
- .setMnemonic(GuiActivator.getResources().getI18nMnemonic(
- "service.gui.EDIT"));
- this.removeButton
- .setMnemonic(GuiActivator.getResources().getI18nMnemonic(
- "service.gui.DELETE"));
-
- buttonsPanel.add(newButton);
-
- buttonsPanel.add(editButton);
-
- buttonsPanel.add(removeButton);
-
- this.add(buttonsPanel, BorderLayout.SOUTH);
-
- accountList.addListSelectionListener(this);
- accountList.addPropertyChangeListener(
- AccountList.ACCOUNT_STATE_CHANGED, this);
- updateButtons();
- }
-
- /**
- * Handles the <tt>ActionEvent</tt> triggered when user clicks on on the
- * buttons. Shows the account registration wizard when user clicks on "New".
- *
- * @param evt the action event that has just occurred.
- */
- public void actionPerformed(ActionEvent evt)
- {
- Object sourceButton = evt.getSource();
-
- if (sourceButton.equals(newButton))
- {
- NewAccountDialog.showNewAccountDialog();
- }
- else if (sourceButton.equals(removeButton))
- {
- Account account = accountList.getSelectedAccount();
-
- if (account == null)
- return;
-
- AccountID accountID = account.getAccountID();
-
- ProtocolProviderFactory providerFactory =
- AccountUtils.getProtocolProviderFactory(
- accountID.getProtocolName());
-
- if (providerFactory != null)
- {
- int result = JOptionPane.showConfirmDialog(
- this,
- GuiActivator.getResources()
- .getI18NString("service.gui.REMOVE_ACCOUNT_MESSAGE"),
- GuiActivator.getResources().getI18NString(
- "service.gui.REMOVE_ACCOUNT"),
- JOptionPane.YES_NO_OPTION);
-
- if (result == JOptionPane.YES_OPTION)
- {
- ConfigurationService configService
- = GuiActivator.getConfigurationService();
- String prefix
- = "net.java.sip.communicator.impl.gui.accounts";
- List<String> accounts
- = configService.getPropertyNamesByPrefix(prefix, true);
-
- for (String accountRootPropName : accounts)
- {
- String accountUID
- = configService.getString(accountRootPropName);
-
- if (accountUID.equals(accountID.getAccountUniqueID()))
- {
- configService.setProperty(accountRootPropName, null);
- break;
- }
- }
- boolean isUninstalled
- = providerFactory.uninstallAccount(accountID);
-
- if (isUninstalled)
- {
- accountList.ensureAccountRemoved(accountID);
-
- // Notify the corresponding wizard that the account
- // would be removed.
- AccountRegWizardContainerImpl wizardContainer
- = (AccountRegWizardContainerImpl) GuiActivator
- .getUIService().getAccountRegWizardContainer();
-
- ProtocolProviderService protocolProvider =
- account.getProtocolProvider();
- AccountRegistrationWizard wizard =
- wizardContainer.getProtocolWizard(protocolProvider);
-
- if (wizard != null)
- wizard.accountRemoved(protocolProvider);
- }
- }
- }
- }
- else if (sourceButton.equals(editButton))
- {
- Account account = accountList.getSelectedAccount();
-
- if (account == null)
- return;
-
- AccountRegWizardContainerImpl wizard =
- (AccountRegWizardContainerImpl) GuiActivator.getUIService()
- .getAccountRegWizardContainer();
-
- AccountRegistrationWizard protocolWizard =
- wizard.getProtocolWizard(account.getProtocolProvider());
-
- ResourceManagementService resources = GuiActivator.getResources();
- if (protocolWizard != null)
- {
- wizard.setTitle(resources.getI18NString(
- "service.gui.ACCOUNT_REGISTRATION_WIZARD"));
-
- wizard.modifyAccount(account.getProtocolProvider());
- wizard.showDialog(false);
- }
- else
- {
- // There is no wizard for this account - just show an error
- // dialog:
- String title = resources.getI18NString("service.gui.ERROR");
- String message =
- resources.getI18NString("service.gui.EDIT_NOT_SUPPORTED");
- ErrorDialog dialog = new ErrorDialog(null, title, message);
- dialog.setVisible(true);
- }
- }
- }
-
- /**
- * Returns the edit button.
- *
- * @return the edit button
- */
- public JButton getEditButton()
- {
- return editButton;
- }
-
- /**
- * Updates enabled states of the buttons of this
- * <tt>AccountsConfigurationPanel</tt> to reflect their applicability to the
- * current selection in <tt>accountList</tt>.
- */
- private void updateButtons()
- {
- if(!SwingUtilities.isEventDispatchThread())
- {
- SwingUtilities.invokeLater(new Runnable()
- {
- public void run()
- {
- updateButtons();
- }
- });
- return;
- }
-
- Account account = accountList.getSelectedAccount();
- boolean enabled = (account != null);
-
- editButton.setEnabled(enabled && account.isEnabled());
- removeButton.setEnabled(enabled);
- }
-
- /**
- * Implements ListSelectionListener#valueChanged(ListSelectionEvent).
- * @param e the <tt>ListSelectionEvent</tt> that notified us
- */
- public void valueChanged(ListSelectionEvent e)
- {
- if (!e.getValueIsAdjusting())
- updateButtons();
- }
-
- /**
- * This method gets called when a property is changed.
- *
- * @param evt A PropertyChangeEvent object describing the event source
- * and the property that has changed.
- */
- public void propertyChange(PropertyChangeEvent evt)
- {
- // update buttons whenever an account changes its state
- updateButtons();
- }
-}
+package net.java.sip.communicator.impl.gui.main.account;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.beans.*;
+import java.util.List;
+
+import javax.swing.*;
+import javax.swing.event.*;
+
+import net.java.sip.communicator.impl.gui.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
+import net.java.sip.communicator.service.gui.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.util.account.*;
+
+import org.jitsi.service.configuration.*;
+import org.jitsi.service.resources.*;
+
+/**
+ * The <tt>AccountsConfigurationPanel</tt> is the panel containing the accounts
+ * list and according buttons shown in the options form.
+ *
+ * @author Yana Stamcheva
+ * @author Lubomir Marinov
+ */
+public class AccountsConfigurationPanel
+ extends TransparentPanel
+ implements ActionListener,
+ ListSelectionListener,
+ PropertyChangeListener
+{
+ private final AccountList accountList;
+
+ private final JButton newButton =
+ new JButton(GuiActivator.getResources().getI18NString(
+ "service.gui.ADD"));
+
+ private final JButton editButton =
+ new JButton(GuiActivator.getResources().getI18NString(
+ "service.gui.EDIT"));
+
+ private final JButton removeButton =
+ new JButton(GuiActivator.getResources().getI18NString(
+ "service.gui.DELETE"));
+
+ /**
+ * Creates and initializes this account configuration panel.
+ */
+ public AccountsConfigurationPanel()
+ {
+ super(new BorderLayout());
+
+ accountList = new AccountList(this);
+
+ /*
+ * It seems that we can only delete one account at a time because our
+ * confirmation dialog asks for one account.
+ */
+ accountList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+
+ this.setPreferredSize(new Dimension(500, 400));
+
+ JScrollPane accountListPane = new JScrollPane();
+
+ accountListPane.getViewport().add(accountList);
+ accountListPane.getVerticalScrollBar().setUnitIncrement(30);
+
+ this.add(accountListPane, BorderLayout.CENTER);
+
+ JPanel buttonsPanel =
+ new TransparentPanel(new FlowLayout(FlowLayout.RIGHT));
+
+ newButton.addActionListener(this);
+ editButton.addActionListener(this);
+ removeButton.addActionListener(this);
+
+ this.newButton.setMnemonic(GuiActivator.getResources().getI18nMnemonic(
+ "service.gui.ADD"));
+ this.editButton
+ .setMnemonic(GuiActivator.getResources().getI18nMnemonic(
+ "service.gui.EDIT"));
+ this.removeButton
+ .setMnemonic(GuiActivator.getResources().getI18nMnemonic(
+ "service.gui.DELETE"));
+
+ buttonsPanel.add(newButton);
+
+ buttonsPanel.add(editButton);
+
+ buttonsPanel.add(removeButton);
+
+ this.add(buttonsPanel, BorderLayout.SOUTH);
+
+ accountList.addListSelectionListener(this);
+ accountList.addPropertyChangeListener(
+ AccountList.ACCOUNT_STATE_CHANGED, this);
+ updateButtons();
+ }
+
+ /**
+ * Handles the <tt>ActionEvent</tt> triggered when user clicks on on the
+ * buttons. Shows the account registration wizard when user clicks on "New".
+ *
+ * @param evt the action event that has just occurred.
+ */
+ public void actionPerformed(ActionEvent evt)
+ {
+ Object sourceButton = evt.getSource();
+
+ if (sourceButton.equals(newButton))
+ {
+ NewAccountDialog.showNewAccountDialog();
+ }
+ else if (sourceButton.equals(removeButton))
+ {
+ Account account = accountList.getSelectedAccount();
+
+ if (account == null)
+ return;
+
+ AccountID accountID = account.getAccountID();
+
+ ProtocolProviderFactory providerFactory =
+ AccountUtils.getProtocolProviderFactory(
+ accountID.getProtocolName());
+
+ if (providerFactory != null)
+ {
+ int result = JOptionPane.showConfirmDialog(
+ this,
+ GuiActivator.getResources()
+ .getI18NString("service.gui.REMOVE_ACCOUNT_MESSAGE"),
+ GuiActivator.getResources().getI18NString(
+ "service.gui.REMOVE_ACCOUNT"),
+ JOptionPane.YES_NO_OPTION);
+
+ if (result == JOptionPane.YES_OPTION)
+ {
+ ConfigurationService configService
+ = GuiActivator.getConfigurationService();
+ String prefix
+ = "net.java.sip.communicator.impl.gui.accounts";
+ List<String> accounts
+ = configService.getPropertyNamesByPrefix(prefix, true);
+
+ for (String accountRootPropName : accounts)
+ {
+ String accountUID
+ = configService.getString(accountRootPropName);
+
+ if (accountUID.equals(accountID.getAccountUniqueID()))
+ {
+ configService.setProperty(accountRootPropName, null);
+ break;
+ }
+ }
+ boolean isUninstalled
+ = providerFactory.uninstallAccount(accountID);
+
+ if (isUninstalled)
+ {
+ accountList.ensureAccountRemoved(accountID);
+
+ // Notify the corresponding wizard that the account
+ // would be removed.
+ AccountRegWizardContainerImpl wizardContainer
+ = (AccountRegWizardContainerImpl) GuiActivator
+ .getUIService().getAccountRegWizardContainer();
+
+ ProtocolProviderService protocolProvider =
+ account.getProtocolProvider();
+ AccountRegistrationWizard wizard =
+ wizardContainer.getProtocolWizard(protocolProvider);
+
+ if (wizard != null)
+ wizard.accountRemoved(protocolProvider);
+ }
+ }
+ }
+ }
+ else if (sourceButton.equals(editButton))
+ {
+ Account account = accountList.getSelectedAccount();
+
+ if (account == null)
+ return;
+
+ AccountRegWizardContainerImpl wizard =
+ (AccountRegWizardContainerImpl) GuiActivator.getUIService()
+ .getAccountRegWizardContainer();
+
+ AccountRegistrationWizard protocolWizard =
+ wizard.getProtocolWizard(account.getProtocolProvider());
+
+ ResourceManagementService resources = GuiActivator.getResources();
+ if (protocolWizard != null)
+ {
+ wizard.setTitle(resources.getI18NString(
+ "service.gui.ACCOUNT_REGISTRATION_WIZARD"));
+
+ wizard.modifyAccount(account.getProtocolProvider());
+ wizard.showDialog(false);
+ }
+ else
+ {
+ // There is no wizard for this account - just show an error
+ // dialog:
+ String title = resources.getI18NString("service.gui.ERROR");
+ String message =
+ resources.getI18NString("service.gui.EDIT_NOT_SUPPORTED");
+ ErrorDialog dialog = new ErrorDialog(null, title, message);
+ dialog.setVisible(true);
+ }
+ }
+ }
+
+ /**
+ * Returns the edit button.
+ *
+ * @return the edit button
+ */
+ public JButton getEditButton()
+ {
+ return editButton;
+ }
+
+ /**
+ * Updates enabled states of the buttons of this
+ * <tt>AccountsConfigurationPanel</tt> to reflect their applicability to the
+ * current selection in <tt>accountList</tt>.
+ */
+ private void updateButtons()
+ {
+ if(!SwingUtilities.isEventDispatchThread())
+ {
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ updateButtons();
+ }
+ });
+ return;
+ }
+
+ Account account = accountList.getSelectedAccount();
+ boolean enabled = (account != null);
+
+ editButton.setEnabled(enabled && account.isEnabled());
+ removeButton.setEnabled(enabled);
+ }
+
+ /**
+ * Implements ListSelectionListener#valueChanged(ListSelectionEvent).
+ * @param e the <tt>ListSelectionEvent</tt> that notified us
+ */
+ public void valueChanged(ListSelectionEvent e)
+ {
+ if (!e.getValueIsAdjusting())
+ updateButtons();
+ }
+
+ /**
+ * This method gets called when a property is changed.
+ *
+ * @param evt A PropertyChangeEvent object describing the event source
+ * and the property that has changed.
+ */
+ public void propertyChange(PropertyChangeEvent evt)
+ {
+ // update buttons whenever an account changes its state
+ updateButtons();
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallDialog.java b/src/net/java/sip/communicator/impl/gui/main/call/CallDialog.java
index 697a3fc..de63f79 100644
--- a/src/net/java/sip/communicator/impl/gui/main/call/CallDialog.java
+++ b/src/net/java/sip/communicator/impl/gui/main/call/CallDialog.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,619 +15,619 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.gui.main.call;
-
-import java.awt.*;
-import java.awt.event.*;
-
-import javax.swing.*;
-
-import net.java.sip.communicator.impl.gui.*;
-import net.java.sip.communicator.plugin.desktoputil.*;
-
-/**
- * The dialog created for a given call.
- *
- * @author Yana Stamcheva
- * @author Adam Netocny
- * @author Lyubomir Marinov
- */
-public class CallDialog
- extends SIPCommFrame
- implements CallContainer,
- CallTitleListener
-{
- /**
- * Serial version UID.
- */
- private static final long serialVersionUID = 0L;
-
- /**
- * Enabling force minimized mode will always open call dialog minimized.
- * The call dialog still can be shown, but by default it will be minimized.
- */
- private static final String FORCE_MINIMIZED_MODE
- = "net.java.sip.communicator.impl.gui.main.call.FORCE_MINIMIZED_MODE";
-
- /**
- * Finds a <tt>Container</tt> which is an ancestor of a specific
- * <tt>Component</tt>, has a set <tt>preferredSize</tt> and is closest to
- * the specified <tt>Component</tt> up the ancestor hierarchy.
- *
- * @param component the <tt>Component</tt> whose ancestor hierarchy is to be
- * searched upwards
- * @return a <tt>Container</tt>, if any, which is an ancestor of the
- * specified <tt>component</tt>, has a set <tt>preferredSize</tt> and is
- * closest to the specified <tt>component</tt> up the ancestor hierarchy
- */
- private static Container findClosestAncestorWithSetPreferredSize(
- Component component)
- {
- if ((component instanceof Container) && component.isPreferredSizeSet())
- return (Container) component;
- else
- {
- Container parent;
-
- while ((parent = component.getParent()) != null)
- {
- if (parent.isPreferredSizeSet())
- return parent;
- else
- component = parent;
- }
- return null;
- }
- }
-
- /**
- * The panel, where all call components are added.
- */
- private CallPanel callPanel;
-
- private final WindowStateListener windowStateListener
- = new WindowStateListener()
- {
- public void windowStateChanged(WindowEvent ev)
- {
- switch (ev.getID())
- {
- case WindowEvent.WINDOW_DEACTIVATED:
- case WindowEvent.WINDOW_ICONIFIED:
- case WindowEvent.WINDOW_LOST_FOCUS:
- setFullScreen(false);
- break;
- }
- }
- };
-
- /**
- * Creates a <tt>CallDialog</tt> by specifying the underlying call panel.
- */
- public CallDialog()
- {
- super(true, false);
-
- setMinimumSize(new Dimension(360, 300));
- }
-
- /**
- * Adds a call panel.
- *
- * @param callPanel the call panel to add to this dialog
- */
- public void addCallPanel(CallPanel callPanel)
- {
- this.callPanel = callPanel;
-
- getContentPane().add(callPanel);
-
- callPanel.addCallTitleListener(this);
- setTitle(callPanel.getCallTitle());
-
- if (!isVisible())
- {
- pack();
-
- // checks whether we need to open the call dialog in minimized mode
- if(GuiActivator.getConfigurationService()
- .getBoolean(FORCE_MINIMIZED_MODE, false))
- {
- setState(ICONIFIED);
- }
- setVisible(true);
- }
- }
-
- /**
- * Called when the title of the given <tt>CallPanel</tt> changes.
- *
- * @param callPanel the <tt>CallPanel</tt>, which title has changed
- */
- public void callTitleChanged(CallPanel callPanel)
- {
- if (this.callPanel.equals(callPanel))
- setTitle(callPanel.getCallTitle());
- }
-
- /**
- * {@inheritDoc}
- *
- * Hang ups the call/telephony conference depicted by this
- * <tt>CallDialog</tt> on close.
- */
- @Override
- protected void close(boolean escape)
- {
- if (escape)
- {
- /*
- * In full-screen mode, ESC does not close this CallDialog but exits
- * from full-screen to windowed mode.
- */
- if (isFullScreen())
- {
- setFullScreen(false);
- return;
- }
- }
- else
- {
- /*
- * If the window has been closed by clicking the X button or
- * pressing the key combination corresponding to the same button we
- * close the window first and then perform all hang up operations.
- */
-
- callPanel.disposeCallInfoFrame();
- // We hide the window here. It will be disposed when the call has
- // been ended.
- setVisible(false);
- }
-
- // Then perform hang up operations.
- callPanel.actionPerformedOnHangupButton(escape);
- }
-
- /**
- * {@inheritDoc}
- *
- * The delay implemented by <tt>CallDialog</tt> is 5 seconds.
- */
- public void close(final CallPanel callPanel, boolean delay)
- {
- if (this.callPanel.equals(callPanel))
- {
- if (delay)
- {
- Timer timer
- = new Timer(
- 5000,
- new ActionListener()
- {
- public void actionPerformed(ActionEvent ev)
- {
- dispose();
- }
- });
-
- timer.setRepeats(false);
- timer.start();
- }
- else
- {
- dispose();
- }
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * <tt>CallDialog</tt> prepares the <tt>CallPanel</tt> it contains for
- * garbage collection.
- */
- @Override
- public void dispose()
- {
- super.dispose();
-
- /*
- * Technically, CallManager adds/removes the callPanel to/from this
- * instance. It may want to just move it to another CallContainer so it
- * does not sound right that we are disposing of it. But we do not have
- * such a case at this time so try to reduce the risk of memory leaks.
- */
- if (this.callPanel != null)
- {
- callPanel.disposeCallInfoFrame();
- callPanel.dispose();
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * Attempts to adjust the size of this <tt>Frame</tt> as requested in the
- * AWT event dispatching thread.
- * <p>
- * The method may be executed on the AWT event dispatching thread only
- * because whoever is making the decision to request an adjustment of the
- * Frame size in relation to a AWT Component should be analyzing that same
- * Component in the AWT event dispatching thread only.
- * </p>
- *
- * @throws RuntimeException if the method is not called on the AWT event
- * dispatching thread
- */
- public void ensureSize(Component component, int width, int height)
- {
- CallManager.assertIsEventDispatchingThread();
-
- Frame frame = CallPeerRendererUtils.getFrame(component);
-
- if (frame == null)
- return;
- else if ((frame.getExtendedState() & Frame.MAXIMIZED_BOTH)
- == Frame.MAXIMIZED_BOTH)
- {
- /*
- * Forcing the size of a Component which is displayed in a maximized
- * window does not sound like anything we want to do.
- */
- return;
- }
- else if (frame.equals(
- frame.getGraphicsConfiguration().getDevice()
- .getFullScreenWindow()))
- {
- /*
- * Forcing the size of a Component which is displayed in a
- * full-screen window does not sound like anything we want to do.
- */
- return;
- }
- else if (!frame.equals(this))
- {
- /* This Frame will try to adjust only its own size. */
- return;
- }
- else if ((component.getHeight() >= height)
- && (component.getWidth() >= width))
- {
- /*
- * We will only enlarge the frame size. If the component has already
- * been given at least what it is requesting, do not enlarge the
- * frame size because the whole calculation is prone to inaccuracy.
- */
- return;
- }
- else
- {
- /*
- * If there is no callPanel, it is unlikely that this CallDialog
- * will be asked to ensureSize. Anyway, support the scenario just in
- * case. In light of the absence of a callPanel to guide this
- * CallDialog about the preferred size, we do not have much of a
- * choice but to trust the method arguments.
- */
- if (callPanel != null)
- {
- /*
- * If there is a callPanel, we are likely to get a much better
- * estimation about the preferred size by asking the callPanel
- * rather than by trusting the method arguments. For example,
- * the visual Component displaying the video streaming from the
- * local user/peer to the remote peer(s) will think that its
- * preferred size is the one to base this Frame's size on but
- * that may be misleading because the local video may not be
- * displayed with its preferred size even if this Frame's size
- * will accommodate it.
- */
- /*
- * Just asking the callPanel about its preferredSize would've
- * been terrificly great. Unfortunately, that is presently
- * futile because the callPanel may have a preferredSize while
- * we are still required to display visual Components displaying
- * video in their non-scaled size. The same goes for any
- * Container which is an ancestor of the specified component.
- */
- Container ancestor
- = findClosestAncestorWithSetPreferredSize(component);
-
- if (ancestor == null)
- ancestor = callPanel;
- /*
- * If the ancestor has a forced preferredSize, its LayoutManager
- * may be able to give a good enough estimation.
- */
- if (ancestor.isPreferredSizeSet())
- {
- LayoutManager ancestorLayout = ancestor.getLayout();
-
- if (ancestorLayout != null)
- {
- Dimension preferredLayoutSize
- = ancestorLayout.preferredLayoutSize(ancestor);
-
- if (preferredLayoutSize != null)
- {
- component = ancestor;
- width = preferredLayoutSize.width;
- height = preferredLayoutSize.height;
- }
- }
- }
- else
- {
- /*
- * If the ancestor doesn't have a preferredSize forced, then
- * we may think that it will calculate an appropriate
- * preferredSize itself.
- */
- Dimension prefSize = ancestor.getPreferredSize();
-
- if (prefSize != null)
- {
- component = ancestor;
- width = prefSize.width;
- height = prefSize.height;
- }
- }
- }
-
- /*
- * If the component (which may be an ancestor of the Component
- * specified as an argument to the ensureSize method at this point)
- * has not been given a size, we will make a mistake if we try to
- * use it for the purposes of determining how much this Frame is to
- * be enlarged.
- */
- Dimension componentSize = component.getSize();
-
- if ((componentSize.width < 1) || (componentSize.height < 1))
- return;
-
- Dimension frameSize = frame.getSize();
- int newFrameWidth = frameSize.width + width - componentSize.width;
- int newFrameHeight
- = frameSize.height + height - componentSize.height;
-
- // Respect the minimum size.
- Dimension minSize = frame.getMinimumSize();
-
- if (newFrameWidth < minSize.width)
- newFrameWidth = minSize.width;
- if (newFrameHeight < minSize.height)
- newFrameHeight = minSize.height;
-
- // Don't get bigger than the screen.
- Rectangle screenBounds
- = frame.getGraphicsConfiguration().getBounds();
-
- if (newFrameWidth > screenBounds.width)
- newFrameWidth = screenBounds.width;
- if (newFrameHeight > screenBounds.height)
- newFrameHeight = screenBounds.height;
-
- /*
- * If we're going to make too small a change, don't even bother.
- * Besides, we don't want some weird recursive resizing.
- * Additionally, do not reduce the Frame size.
- */
- boolean changeWidth = ((newFrameWidth - frameSize.width) > 1);
- boolean changeHeight = ((newFrameHeight - frameSize.height) > 1);
-
- if (changeWidth || changeHeight)
- {
- if (!changeWidth)
- newFrameWidth = frameSize.width;
- else if (!changeHeight)
- newFrameHeight = frameSize.height;
-
- /*
- * The latest requirement with respect to the behavior upon
- * resizing is to center the Frame.
- */
- int newFrameX
- = screenBounds.x
- + (screenBounds.width - newFrameWidth) / 2;
- int newFrameY
- = screenBounds.y
- + (screenBounds.height - newFrameHeight) / 2;
-
- // Do not let the top left go out of the screen.
- if (newFrameX < screenBounds.x)
- newFrameX = screenBounds.x;
- if (newFrameY < screenBounds.y)
- newFrameY = screenBounds.y;
-
- frame.setBounds(
- newFrameX, newFrameY,
- newFrameWidth, newFrameHeight);
-
- /*
- * Make sure that the component which originally requested the
- * update to the size of the frame realizes the change as soon
- * as possible; otherwise, it may request yet another update.
- */
- if (frame.isDisplayable())
- {
- if (frame.isValid())
- frame.doLayout();
- else
- frame.validate();
- frame.repaint();
- }
- else
- frame.doLayout();
- }
- }
- }
-
- /**
- * Returns the frame of the call window.
- *
- * @return the frame of the call window
- */
- public JFrame getFrame()
- {
- return this;
- }
-
- /**
- * Overrides getMinimumSize and checks the minimum size that
- * is needed to display buttons and use it for minimum size if
- * needed.
- * @return minimum size.
- */
- @Override
- public Dimension getMinimumSize()
- {
- Dimension minSize = super.getMinimumSize();
-
- if(callPanel != null)
- {
- int minButtonWidth = callPanel.getMinimumButtonWidth();
-
- if(minButtonWidth > minSize.getWidth())
- minSize = new Dimension(minButtonWidth, 300);
- }
-
- return minSize;
- }
-
- /**
- * Indicates if the given <tt>callPanel</tt> is currently visible.
- *
- * @param callPanel the <tt>CallPanel</tt>, for which we verify
- * @return <tt>true</tt> if the given call container is visible in this
- * call window, otherwise - <tt>false</tt>
- */
- public boolean isCallVisible(CallPanel callPanel)
- {
- return this.callPanel.equals(callPanel) ? isVisible() : false;
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean isFullScreen()
- {
- return isFullScreen(getFrame());
- }
-
- /**
- * Determines whether a specific <tt>Window</tt> is displayed in full-screen
- * mode.
- *
- * @param window the <tt>Window</tt> to be checked whether it is displayed
- * in full-screen mode
- * @return <tt>true</tt> if the specified <tt>window</tt> is displayed in
- * full-screen mode; otherwise, <tt>false</tt>
- */
- public static boolean isFullScreen(Window window)
- {
- GraphicsConfiguration graphicsConfiguration
- = window.getGraphicsConfiguration();
-
- if (graphicsConfiguration != null)
- {
- GraphicsDevice device = graphicsConfiguration.getDevice();
-
- if (device != null)
- return window.equals(device.getFullScreenWindow());
- }
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- public void setFullScreen(boolean fullScreen)
- {
- GraphicsConfiguration graphicsConfiguration
- = getGraphicsConfiguration();
-
- if (graphicsConfiguration != null)
- {
- GraphicsDevice device = graphicsConfiguration.getDevice();
-
- if (device != null)
- {
- boolean thisIsFullScreen = equals(device.getFullScreenWindow());
- boolean firePropertyChange = false;
- boolean setVisible = isVisible();
-
- try
- {
- if (fullScreen)
- {
- if (!thisIsFullScreen)
- {
- /*
- * XXX The setUndecorated method will only work if
- * this Window is not displayable.
- */
- windowDispose();
- setUndecorated(true);
-
- device.setFullScreenWindow(this);
- firePropertyChange = true;
- }
- }
- else if (thisIsFullScreen)
- {
- /*
- * XXX The setUndecorated method will only work if this
- * Window is not displayable.
- */
- windowDispose();
- setUndecorated(false);
-
- device.setFullScreenWindow(null);
- firePropertyChange = true;
- }
-
- if (firePropertyChange)
- {
- if (fullScreen)
- {
- addWindowStateListener(windowStateListener);
-
- /*
- * If full-screen mode, a black background is the
- * most common.
- */
- getContentPane().setBackground(Color.BLACK);
- }
- else
- {
- removeWindowStateListener(windowStateListener);
-
- /*
- * In windowed mode, a system-defined background is
- * the most common.
- */
- getContentPane().setBackground(null);
- }
-
- firePropertyChange(
- PROP_FULL_SCREEN,
- thisIsFullScreen,
- fullScreen);
- }
- }
- finally
- {
- /*
- * Regardless of whether this Window successfully entered or
- * exited full-screen mode, make sure that remains visible.
- */
- if (setVisible)
- setVisible(true);
- }
- }
- }
- }
-}
+package net.java.sip.communicator.impl.gui.main.call;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.impl.gui.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
+
+/**
+ * The dialog created for a given call.
+ *
+ * @author Yana Stamcheva
+ * @author Adam Netocny
+ * @author Lyubomir Marinov
+ */
+public class CallDialog
+ extends SIPCommFrame
+ implements CallContainer,
+ CallTitleListener
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Enabling force minimized mode will always open call dialog minimized.
+ * The call dialog still can be shown, but by default it will be minimized.
+ */
+ private static final String FORCE_MINIMIZED_MODE
+ = "net.java.sip.communicator.impl.gui.main.call.FORCE_MINIMIZED_MODE";
+
+ /**
+ * Finds a <tt>Container</tt> which is an ancestor of a specific
+ * <tt>Component</tt>, has a set <tt>preferredSize</tt> and is closest to
+ * the specified <tt>Component</tt> up the ancestor hierarchy.
+ *
+ * @param component the <tt>Component</tt> whose ancestor hierarchy is to be
+ * searched upwards
+ * @return a <tt>Container</tt>, if any, which is an ancestor of the
+ * specified <tt>component</tt>, has a set <tt>preferredSize</tt> and is
+ * closest to the specified <tt>component</tt> up the ancestor hierarchy
+ */
+ private static Container findClosestAncestorWithSetPreferredSize(
+ Component component)
+ {
+ if ((component instanceof Container) && component.isPreferredSizeSet())
+ return (Container) component;
+ else
+ {
+ Container parent;
+
+ while ((parent = component.getParent()) != null)
+ {
+ if (parent.isPreferredSizeSet())
+ return parent;
+ else
+ component = parent;
+ }
+ return null;
+ }
+ }
+
+ /**
+ * The panel, where all call components are added.
+ */
+ private CallPanel callPanel;
+
+ private final WindowStateListener windowStateListener
+ = new WindowStateListener()
+ {
+ public void windowStateChanged(WindowEvent ev)
+ {
+ switch (ev.getID())
+ {
+ case WindowEvent.WINDOW_DEACTIVATED:
+ case WindowEvent.WINDOW_ICONIFIED:
+ case WindowEvent.WINDOW_LOST_FOCUS:
+ setFullScreen(false);
+ break;
+ }
+ }
+ };
+
+ /**
+ * Creates a <tt>CallDialog</tt> by specifying the underlying call panel.
+ */
+ public CallDialog()
+ {
+ super(true, false);
+
+ setMinimumSize(new Dimension(360, 300));
+ }
+
+ /**
+ * Adds a call panel.
+ *
+ * @param callPanel the call panel to add to this dialog
+ */
+ public void addCallPanel(CallPanel callPanel)
+ {
+ this.callPanel = callPanel;
+
+ getContentPane().add(callPanel);
+
+ callPanel.addCallTitleListener(this);
+ setTitle(callPanel.getCallTitle());
+
+ if (!isVisible())
+ {
+ pack();
+
+ // checks whether we need to open the call dialog in minimized mode
+ if(GuiActivator.getConfigurationService()
+ .getBoolean(FORCE_MINIMIZED_MODE, false))
+ {
+ setState(ICONIFIED);
+ }
+ setVisible(true);
+ }
+ }
+
+ /**
+ * Called when the title of the given <tt>CallPanel</tt> changes.
+ *
+ * @param callPanel the <tt>CallPanel</tt>, which title has changed
+ */
+ public void callTitleChanged(CallPanel callPanel)
+ {
+ if (this.callPanel.equals(callPanel))
+ setTitle(callPanel.getCallTitle());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Hang ups the call/telephony conference depicted by this
+ * <tt>CallDialog</tt> on close.
+ */
+ @Override
+ protected void close(boolean escape)
+ {
+ if (escape)
+ {
+ /*
+ * In full-screen mode, ESC does not close this CallDialog but exits
+ * from full-screen to windowed mode.
+ */
+ if (isFullScreen())
+ {
+ setFullScreen(false);
+ return;
+ }
+ }
+ else
+ {
+ /*
+ * If the window has been closed by clicking the X button or
+ * pressing the key combination corresponding to the same button we
+ * close the window first and then perform all hang up operations.
+ */
+
+ callPanel.disposeCallInfoFrame();
+ // We hide the window here. It will be disposed when the call has
+ // been ended.
+ setVisible(false);
+ }
+
+ // Then perform hang up operations.
+ callPanel.actionPerformedOnHangupButton(escape);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * The delay implemented by <tt>CallDialog</tt> is 5 seconds.
+ */
+ public void close(final CallPanel callPanel, boolean delay)
+ {
+ if (this.callPanel.equals(callPanel))
+ {
+ if (delay)
+ {
+ Timer timer
+ = new Timer(
+ 5000,
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent ev)
+ {
+ dispose();
+ }
+ });
+
+ timer.setRepeats(false);
+ timer.start();
+ }
+ else
+ {
+ dispose();
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <tt>CallDialog</tt> prepares the <tt>CallPanel</tt> it contains for
+ * garbage collection.
+ */
+ @Override
+ public void dispose()
+ {
+ super.dispose();
+
+ /*
+ * Technically, CallManager adds/removes the callPanel to/from this
+ * instance. It may want to just move it to another CallContainer so it
+ * does not sound right that we are disposing of it. But we do not have
+ * such a case at this time so try to reduce the risk of memory leaks.
+ */
+ if (this.callPanel != null)
+ {
+ callPanel.disposeCallInfoFrame();
+ callPanel.dispose();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Attempts to adjust the size of this <tt>Frame</tt> as requested in the
+ * AWT event dispatching thread.
+ * <p>
+ * The method may be executed on the AWT event dispatching thread only
+ * because whoever is making the decision to request an adjustment of the
+ * Frame size in relation to a AWT Component should be analyzing that same
+ * Component in the AWT event dispatching thread only.
+ * </p>
+ *
+ * @throws RuntimeException if the method is not called on the AWT event
+ * dispatching thread
+ */
+ public void ensureSize(Component component, int width, int height)
+ {
+ CallManager.assertIsEventDispatchingThread();
+
+ Frame frame = CallPeerRendererUtils.getFrame(component);
+
+ if (frame == null)
+ return;
+ else if ((frame.getExtendedState() & Frame.MAXIMIZED_BOTH)
+ == Frame.MAXIMIZED_BOTH)
+ {
+ /*
+ * Forcing the size of a Component which is displayed in a maximized
+ * window does not sound like anything we want to do.
+ */
+ return;
+ }
+ else if (frame.equals(
+ frame.getGraphicsConfiguration().getDevice()
+ .getFullScreenWindow()))
+ {
+ /*
+ * Forcing the size of a Component which is displayed in a
+ * full-screen window does not sound like anything we want to do.
+ */
+ return;
+ }
+ else if (!frame.equals(this))
+ {
+ /* This Frame will try to adjust only its own size. */
+ return;
+ }
+ else if ((component.getHeight() >= height)
+ && (component.getWidth() >= width))
+ {
+ /*
+ * We will only enlarge the frame size. If the component has already
+ * been given at least what it is requesting, do not enlarge the
+ * frame size because the whole calculation is prone to inaccuracy.
+ */
+ return;
+ }
+ else
+ {
+ /*
+ * If there is no callPanel, it is unlikely that this CallDialog
+ * will be asked to ensureSize. Anyway, support the scenario just in
+ * case. In light of the absence of a callPanel to guide this
+ * CallDialog about the preferred size, we do not have much of a
+ * choice but to trust the method arguments.
+ */
+ if (callPanel != null)
+ {
+ /*
+ * If there is a callPanel, we are likely to get a much better
+ * estimation about the preferred size by asking the callPanel
+ * rather than by trusting the method arguments. For example,
+ * the visual Component displaying the video streaming from the
+ * local user/peer to the remote peer(s) will think that its
+ * preferred size is the one to base this Frame's size on but
+ * that may be misleading because the local video may not be
+ * displayed with its preferred size even if this Frame's size
+ * will accommodate it.
+ */
+ /*
+ * Just asking the callPanel about its preferredSize would've
+ * been terrificly great. Unfortunately, that is presently
+ * futile because the callPanel may have a preferredSize while
+ * we are still required to display visual Components displaying
+ * video in their non-scaled size. The same goes for any
+ * Container which is an ancestor of the specified component.
+ */
+ Container ancestor
+ = findClosestAncestorWithSetPreferredSize(component);
+
+ if (ancestor == null)
+ ancestor = callPanel;
+ /*
+ * If the ancestor has a forced preferredSize, its LayoutManager
+ * may be able to give a good enough estimation.
+ */
+ if (ancestor.isPreferredSizeSet())
+ {
+ LayoutManager ancestorLayout = ancestor.getLayout();
+
+ if (ancestorLayout != null)
+ {
+ Dimension preferredLayoutSize
+ = ancestorLayout.preferredLayoutSize(ancestor);
+
+ if (preferredLayoutSize != null)
+ {
+ component = ancestor;
+ width = preferredLayoutSize.width;
+ height = preferredLayoutSize.height;
+ }
+ }
+ }
+ else
+ {
+ /*
+ * If the ancestor doesn't have a preferredSize forced, then
+ * we may think that it will calculate an appropriate
+ * preferredSize itself.
+ */
+ Dimension prefSize = ancestor.getPreferredSize();
+
+ if (prefSize != null)
+ {
+ component = ancestor;
+ width = prefSize.width;
+ height = prefSize.height;
+ }
+ }
+ }
+
+ /*
+ * If the component (which may be an ancestor of the Component
+ * specified as an argument to the ensureSize method at this point)
+ * has not been given a size, we will make a mistake if we try to
+ * use it for the purposes of determining how much this Frame is to
+ * be enlarged.
+ */
+ Dimension componentSize = component.getSize();
+
+ if ((componentSize.width < 1) || (componentSize.height < 1))
+ return;
+
+ Dimension frameSize = frame.getSize();
+ int newFrameWidth = frameSize.width + width - componentSize.width;
+ int newFrameHeight
+ = frameSize.height + height - componentSize.height;
+
+ // Respect the minimum size.
+ Dimension minSize = frame.getMinimumSize();
+
+ if (newFrameWidth < minSize.width)
+ newFrameWidth = minSize.width;
+ if (newFrameHeight < minSize.height)
+ newFrameHeight = minSize.height;
+
+ // Don't get bigger than the screen.
+ Rectangle screenBounds
+ = frame.getGraphicsConfiguration().getBounds();
+
+ if (newFrameWidth > screenBounds.width)
+ newFrameWidth = screenBounds.width;
+ if (newFrameHeight > screenBounds.height)
+ newFrameHeight = screenBounds.height;
+
+ /*
+ * If we're going to make too small a change, don't even bother.
+ * Besides, we don't want some weird recursive resizing.
+ * Additionally, do not reduce the Frame size.
+ */
+ boolean changeWidth = ((newFrameWidth - frameSize.width) > 1);
+ boolean changeHeight = ((newFrameHeight - frameSize.height) > 1);
+
+ if (changeWidth || changeHeight)
+ {
+ if (!changeWidth)
+ newFrameWidth = frameSize.width;
+ else if (!changeHeight)
+ newFrameHeight = frameSize.height;
+
+ /*
+ * The latest requirement with respect to the behavior upon
+ * resizing is to center the Frame.
+ */
+ int newFrameX
+ = screenBounds.x
+ + (screenBounds.width - newFrameWidth) / 2;
+ int newFrameY
+ = screenBounds.y
+ + (screenBounds.height - newFrameHeight) / 2;
+
+ // Do not let the top left go out of the screen.
+ if (newFrameX < screenBounds.x)
+ newFrameX = screenBounds.x;
+ if (newFrameY < screenBounds.y)
+ newFrameY = screenBounds.y;
+
+ frame.setBounds(
+ newFrameX, newFrameY,
+ newFrameWidth, newFrameHeight);
+
+ /*
+ * Make sure that the component which originally requested the
+ * update to the size of the frame realizes the change as soon
+ * as possible; otherwise, it may request yet another update.
+ */
+ if (frame.isDisplayable())
+ {
+ if (frame.isValid())
+ frame.doLayout();
+ else
+ frame.validate();
+ frame.repaint();
+ }
+ else
+ frame.doLayout();
+ }
+ }
+ }
+
+ /**
+ * Returns the frame of the call window.
+ *
+ * @return the frame of the call window
+ */
+ public JFrame getFrame()
+ {
+ return this;
+ }
+
+ /**
+ * Overrides getMinimumSize and checks the minimum size that
+ * is needed to display buttons and use it for minimum size if
+ * needed.
+ * @return minimum size.
+ */
+ @Override
+ public Dimension getMinimumSize()
+ {
+ Dimension minSize = super.getMinimumSize();
+
+ if(callPanel != null)
+ {
+ int minButtonWidth = callPanel.getMinimumButtonWidth();
+
+ if(minButtonWidth > minSize.getWidth())
+ minSize = new Dimension(minButtonWidth, 300);
+ }
+
+ return minSize;
+ }
+
+ /**
+ * Indicates if the given <tt>callPanel</tt> is currently visible.
+ *
+ * @param callPanel the <tt>CallPanel</tt>, for which we verify
+ * @return <tt>true</tt> if the given call container is visible in this
+ * call window, otherwise - <tt>false</tt>
+ */
+ public boolean isCallVisible(CallPanel callPanel)
+ {
+ return this.callPanel.equals(callPanel) ? isVisible() : false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isFullScreen()
+ {
+ return isFullScreen(getFrame());
+ }
+
+ /**
+ * Determines whether a specific <tt>Window</tt> is displayed in full-screen
+ * mode.
+ *
+ * @param window the <tt>Window</tt> to be checked whether it is displayed
+ * in full-screen mode
+ * @return <tt>true</tt> if the specified <tt>window</tt> is displayed in
+ * full-screen mode; otherwise, <tt>false</tt>
+ */
+ public static boolean isFullScreen(Window window)
+ {
+ GraphicsConfiguration graphicsConfiguration
+ = window.getGraphicsConfiguration();
+
+ if (graphicsConfiguration != null)
+ {
+ GraphicsDevice device = graphicsConfiguration.getDevice();
+
+ if (device != null)
+ return window.equals(device.getFullScreenWindow());
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setFullScreen(boolean fullScreen)
+ {
+ GraphicsConfiguration graphicsConfiguration
+ = getGraphicsConfiguration();
+
+ if (graphicsConfiguration != null)
+ {
+ GraphicsDevice device = graphicsConfiguration.getDevice();
+
+ if (device != null)
+ {
+ boolean thisIsFullScreen = equals(device.getFullScreenWindow());
+ boolean firePropertyChange = false;
+ boolean setVisible = isVisible();
+
+ try
+ {
+ if (fullScreen)
+ {
+ if (!thisIsFullScreen)
+ {
+ /*
+ * XXX The setUndecorated method will only work if
+ * this Window is not displayable.
+ */
+ windowDispose();
+ setUndecorated(true);
+
+ device.setFullScreenWindow(this);
+ firePropertyChange = true;
+ }
+ }
+ else if (thisIsFullScreen)
+ {
+ /*
+ * XXX The setUndecorated method will only work if this
+ * Window is not displayable.
+ */
+ windowDispose();
+ setUndecorated(false);
+
+ device.setFullScreenWindow(null);
+ firePropertyChange = true;
+ }
+
+ if (firePropertyChange)
+ {
+ if (fullScreen)
+ {
+ addWindowStateListener(windowStateListener);
+
+ /*
+ * If full-screen mode, a black background is the
+ * most common.
+ */
+ getContentPane().setBackground(Color.BLACK);
+ }
+ else
+ {
+ removeWindowStateListener(windowStateListener);
+
+ /*
+ * In windowed mode, a system-defined background is
+ * the most common.
+ */
+ getContentPane().setBackground(null);
+ }
+
+ firePropertyChange(
+ PROP_FULL_SCREEN,
+ thisIsFullScreen,
+ fullScreen);
+ }
+ }
+ finally
+ {
+ /*
+ * Regardless of whether this Window successfully entered or
+ * exited full-screen mode, make sure that remains visible.
+ */
+ if (setVisible)
+ setVisible(true);
+ }
+ }
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallHistoryButton.java b/src/net/java/sip/communicator/impl/gui/main/call/CallHistoryButton.java
index 095b3dd..d1c0a42 100644
--- a/src/net/java/sip/communicator/impl/gui/main/call/CallHistoryButton.java
+++ b/src/net/java/sip/communicator/impl/gui/main/call/CallHistoryButton.java
@@ -130,6 +130,14 @@ public class CallHistoryButton
}
/**
+ * Does nothing because this class causes the clearing.
+ */
+ @Override
+ public void notificationCleared(UINotification notification)
+ {
+ }
+
+ /**
* Sets the history view.
*/
private void setHistoryView()
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallInfoFrame.java b/src/net/java/sip/communicator/impl/gui/main/call/CallInfoFrame.java
index ad8f6fd..872e861 100644
--- a/src/net/java/sip/communicator/impl/gui/main/call/CallInfoFrame.java
+++ b/src/net/java/sip/communicator/impl/gui/main/call/CallInfoFrame.java
@@ -34,6 +34,7 @@ import net.java.sip.communicator.util.*;
import org.ice4j.ice.*;
import org.jitsi.service.neomedia.*;
+import org.jitsi.service.neomedia.stats.*;
import org.jitsi.service.resources.*;
import org.jitsi.util.*;
@@ -469,7 +470,7 @@ public class CallInfoFrame
StringBuffer stringBuffer,
MediaType mediaType)
{
- MediaStreamStats mediaStreamStats
+ MediaStreamStats2 mediaStreamStats
= mediaStream.getMediaStreamStats();
if(mediaStreamStats == null)
@@ -624,18 +625,19 @@ public class CallInfoFrame
resources.getI18NString(
"service.gui.callinfo.BANDWITH"),
"&darr; "
- + (int) mediaStreamStats.getDownloadRateKiloBitPerSec()
+ + (int) mediaStreamStats.getReceiveStats().getBitrate()/1024
+ " Kbps "
+ " &uarr; "
- + (int) mediaStreamStats.getUploadRateKiloBitPerSec()
+ + (int) mediaStreamStats.getSendStats().getBitrate()/1024
+ " Kbps"));
stringBuffer.append(
getLineString(
resources.getI18NString("service.gui.callinfo.LOSS_RATE"),
- "&darr; " + (int) mediaStreamStats.getDownloadPercentLoss()
+ "&darr;"
+ + (int) (mediaStreamStats.getReceiveStats().getLossRate() * 100)
+ "% &uarr; "
- + (int) mediaStreamStats.getUploadPercentLoss()
+ + (int) (mediaStreamStats.getSendStats().getLossRate() * 100)
+ "%"));
stringBuffer.append(
getLineString(
@@ -668,21 +670,23 @@ public class CallInfoFrame
+ mediaStreamStats.getPacketQueueCountPackets() + "/"
+ mediaStreamStats.getPacketQueueSize() + " packets"));
- long rttMs = mediaStreamStats.getRttMs();
- if(rttMs != -1)
+ long sendRttMs = mediaStreamStats.getSendStats().getRtt();
+ long recvRttMs = mediaStreamStats.getReceiveStats().getRtt();
+ if(recvRttMs != -1 || sendRttMs != -1)
{
stringBuffer.append(
getLineString(resources.getI18NString(
"service.gui.callinfo.RTT"),
- rttMs + " ms"));
+ (recvRttMs != -1 ? "&darr; " + recvRttMs + " ms" : "") +
+ (sendRttMs != -1 ? "&uarr; " + sendRttMs + " ms" : "")));
}
stringBuffer.append(
getLineString(resources.getI18NString(
"service.gui.callinfo.JITTER"),
- "&darr; " + (int) mediaStreamStats.getDownloadJitterMs()
+ "&darr; " + (int) mediaStreamStats.getReceiveStats().getJitter()
+ " ms &uarr; "
- + (int) mediaStreamStats.getUploadJitterMs() + " ms"));
+ + (int) mediaStreamStats.getSendStats().getJitter() + " ms"));
}
/**
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallTransferHandler.java b/src/net/java/sip/communicator/impl/gui/main/call/CallTransferHandler.java
index 54f48ee..6235e1c 100644
--- a/src/net/java/sip/communicator/impl/gui/main/call/CallTransferHandler.java
+++ b/src/net/java/sip/communicator/impl/gui/main/call/CallTransferHandler.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,276 +15,276 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.gui.main.call;
-
-import java.awt.datatransfer.*;
-import java.awt.im.*;
-import java.io.*;
-import java.util.*;
-
-import javax.swing.*;
-
-import org.jitsi.service.resources.*;
-
-import net.java.sip.communicator.impl.gui.*;
-import net.java.sip.communicator.impl.gui.main.contactlist.*;
-import net.java.sip.communicator.plugin.desktoputil.*;
-import net.java.sip.communicator.service.gui.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-/**
- * A <tt>TransferHandler</tt> that handles dropping of <tt>UIContact</tt>s or
- * <tt>String</tt> addresses on a <tt>CallConference</tt>. Dropping such data on
- * the <tt>CallDialog</tt> will turn a one-to-one <tt>Call</tt> into a telephony
- * conference.
- *
- * @author Yana Stamcheva
- */
-public class CallTransferHandler
- extends ExtendedTransferHandler
-{
- /**
- * Serial version UID.
- */
- private static final long serialVersionUID = 0L;
-
- /**
- * The data flavor used when transferring <tt>UIContact</tt>s.
- */
- protected static final DataFlavor uiContactDataFlavor
- = new DataFlavor(UIContact.class, "UIContact");
-
- /**
- * The logger.
- */
- private static final Logger logger
- = Logger.getLogger(CallTransferHandler.class);
-
- /**
- * The <tt>CallConference</tt> into which the dropped callees are to be
- * invited.
- */
- private final CallConference callConference;
-
- /**
- * Initializes a new <tt>CallTransferHandler</tt> instance which is to
- * invite dropped callees to a telephony conference specified by a specific
- * <tt>Call</tt> which participates in it.
- *
- * @param call the <tt>Call</tt> which specifies the telephony conference to
- * which dropped callees are to be invited
- */
- public CallTransferHandler(Call call)
- {
- this(call.getConference());
- }
-
- /**
- * Initializes a new <tt>CallTransferHandler</tt> instance which is to
- * invite dropped callees to a specific <tt>CallConference</tt>.
- *
- * @param callConference the <tt>CallConference</tt> to which dropped
- * callees are to be invited
- */
- public CallTransferHandler(CallConference callConference)
- {
- this.callConference = callConference;
- }
-
- /**
- * Indicates whether a component will accept an import of the given
- * set of data flavors prior to actually attempting to import it. We return
- * <tt>true</tt> to indicate that the transfer with at least one of the
- * given flavors would work and <tt>false</tt> to reject the transfer.
- * <p>
- * @param comp component
- * @param flavor the data formats available
- * @return true if the data can be inserted into the component, false
- * otherwise
- * @throws NullPointerException if <code>support</code> is {@code null}
- */
- @Override
- public boolean canImport(JComponent comp, DataFlavor[] flavor)
- {
- for (DataFlavor f : flavor)
- {
- if (f.equals(DataFlavor.stringFlavor)
- || f.equals(uiContactDataFlavor))
- {
- return (comp instanceof JPanel);
- }
- }
- return false;
- }
-
- /**
- * Handles transfers to the chat panel from the clip board or a
- * DND drop operation. The <tt>Transferable</tt> parameter contains the
- * data that needs to be imported.
- * <p>
- * @param comp the component to receive the transfer;
- * @param t the data to import
- * @return true if the data was inserted into the component and false
- * otherwise
- */
- @Override
- public boolean importData(JComponent comp, Transferable t)
- {
- String callee = null;
- ProtocolProviderService provider = null;
-
- if (t.isDataFlavorSupported(uiContactDataFlavor))
- {
- Object o = null;
-
- try
- {
- o = t.getTransferData(uiContactDataFlavor);
- }
- catch (UnsupportedFlavorException e)
- {
- if (logger.isDebugEnabled())
- logger.debug("Failed to drop meta contact.", e);
- }
- catch (IOException e)
- {
- if (logger.isDebugEnabled())
- logger.debug("Failed to drop meta contact.", e);
- }
-
- if (o instanceof ContactNode)
- {
- UIContact uiContact = ((ContactNode) o).getContactDescriptor();
- Iterator<UIContactDetail> contactDetails
- = uiContact
- .getContactDetailsForOperationSet(
- OperationSetBasicTelephony.class)
- .iterator();
-
- while (contactDetails.hasNext())
- {
- UIContactDetail detail = contactDetails.next();
- ProtocolProviderService detailProvider
- = detail.getPreferredProtocolProvider(
- OperationSetBasicTelephony.class);
-
- if (detailProvider != null)
- {
- /*
- * Currently for videobridge conferences we only support
- * adding contacts via the account with the videobridge
- */
- if (callConference.isJitsiVideobridge())
- {
- for (Call call : callConference.getCalls())
- {
- if (detailProvider == call.getProtocolProvider())
- {
- callee = detail.getAddress();
- provider = detailProvider;
- break;
- }
- }
- }
- else
- {
- callee = detail.getAddress();
- provider = detailProvider;
- break;
- }
- }
- }
-
- if (callee == null)
- {
- /*
- * It turns out that the error message to be reported would
- * like to display information about the account which could
- * not add the dropped callee to the telephony conference.
- * Unfortunately, a telephony conference may have multiple
- * accounts involved. Anyway, choose the first account
- * involved in the telephony conference.
- */
- ProtocolProviderService callProvider
- = callConference.getCalls().get(0)
- .getProtocolProvider();
-
- ResourceManagementService resources
- = GuiActivator.getResources();
- AccountID accountID = callProvider.getAccountID();
-
- new ErrorDialog(null,
- resources.getI18NString("service.gui.ERROR"),
- resources.getI18NString(
- "service.gui.CALL_NOT_SUPPORTING_PARTICIPANT",
- new String[]
- {
- accountID.getService(),
- accountID.getUserID(),
- uiContact.getDisplayName()
- }))
- .showDialog();
- }
- }
- }
- else if (t.isDataFlavorSupported(DataFlavor.stringFlavor))
- {
- InputContext inputContext = comp.getInputContext();
-
- if (inputContext != null)
- inputContext.endComposition();
-
- try
- {
- BufferedReader reader
- = new BufferedReader(
- DataFlavor.stringFlavor.getReaderForText(t));
-
- try
- {
- String line;
- StringBuilder calleeBuilder = new StringBuilder();
-
- while ((line = reader.readLine()) != null)
- calleeBuilder.append(line);
-
- callee = calleeBuilder.toString();
- /*
- * The value of the local variable provider will be null
- * because we have a String only and hence we have no
- * associated ProtocolProviderService.
- * CallManager.inviteToConferenceCall will accept it.
- */
- }
- finally
- {
- reader.close();
- }
- }
- catch (UnsupportedFlavorException e)
- {
- if (logger.isDebugEnabled())
- logger.debug("Failed to drop string.", e);
- }
- catch (IOException e)
- {
- if (logger.isDebugEnabled())
- logger.debug("Failed to drop string.", e);
- }
- }
-
- if (callee == null)
- return false;
- else
- {
- Map<ProtocolProviderService, List<String>> callees
- = new HashMap<ProtocolProviderService, List<String>>();
-
- callees.put(provider, Arrays.asList(callee));
- CallManager.inviteToConferenceCall(callees, callConference);
-
- return true;
- }
- }
-}
+package net.java.sip.communicator.impl.gui.main.call;
+
+import java.awt.datatransfer.*;
+import java.awt.im.*;
+import java.io.*;
+import java.util.*;
+
+import javax.swing.*;
+
+import org.jitsi.service.resources.*;
+
+import net.java.sip.communicator.impl.gui.*;
+import net.java.sip.communicator.impl.gui.main.contactlist.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
+import net.java.sip.communicator.service.gui.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.util.*;
+
+/**
+ * A <tt>TransferHandler</tt> that handles dropping of <tt>UIContact</tt>s or
+ * <tt>String</tt> addresses on a <tt>CallConference</tt>. Dropping such data on
+ * the <tt>CallDialog</tt> will turn a one-to-one <tt>Call</tt> into a telephony
+ * conference.
+ *
+ * @author Yana Stamcheva
+ */
+public class CallTransferHandler
+ extends ExtendedTransferHandler
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * The data flavor used when transferring <tt>UIContact</tt>s.
+ */
+ protected static final DataFlavor uiContactDataFlavor
+ = new DataFlavor(UIContact.class, "UIContact");
+
+ /**
+ * The logger.
+ */
+ private static final Logger logger
+ = Logger.getLogger(CallTransferHandler.class);
+
+ /**
+ * The <tt>CallConference</tt> into which the dropped callees are to be
+ * invited.
+ */
+ private final CallConference callConference;
+
+ /**
+ * Initializes a new <tt>CallTransferHandler</tt> instance which is to
+ * invite dropped callees to a telephony conference specified by a specific
+ * <tt>Call</tt> which participates in it.
+ *
+ * @param call the <tt>Call</tt> which specifies the telephony conference to
+ * which dropped callees are to be invited
+ */
+ public CallTransferHandler(Call call)
+ {
+ this(call.getConference());
+ }
+
+ /**
+ * Initializes a new <tt>CallTransferHandler</tt> instance which is to
+ * invite dropped callees to a specific <tt>CallConference</tt>.
+ *
+ * @param callConference the <tt>CallConference</tt> to which dropped
+ * callees are to be invited
+ */
+ public CallTransferHandler(CallConference callConference)
+ {
+ this.callConference = callConference;
+ }
+
+ /**
+ * Indicates whether a component will accept an import of the given
+ * set of data flavors prior to actually attempting to import it. We return
+ * <tt>true</tt> to indicate that the transfer with at least one of the
+ * given flavors would work and <tt>false</tt> to reject the transfer.
+ * <p>
+ * @param comp component
+ * @param flavor the data formats available
+ * @return true if the data can be inserted into the component, false
+ * otherwise
+ * @throws NullPointerException if <code>support</code> is {@code null}
+ */
+ @Override
+ public boolean canImport(JComponent comp, DataFlavor[] flavor)
+ {
+ for (DataFlavor f : flavor)
+ {
+ if (f.equals(DataFlavor.stringFlavor)
+ || f.equals(uiContactDataFlavor))
+ {
+ return (comp instanceof JPanel);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Handles transfers to the chat panel from the clip board or a
+ * DND drop operation. The <tt>Transferable</tt> parameter contains the
+ * data that needs to be imported.
+ * <p>
+ * @param comp the component to receive the transfer;
+ * @param t the data to import
+ * @return true if the data was inserted into the component and false
+ * otherwise
+ */
+ @Override
+ public boolean importData(JComponent comp, Transferable t)
+ {
+ String callee = null;
+ ProtocolProviderService provider = null;
+
+ if (t.isDataFlavorSupported(uiContactDataFlavor))
+ {
+ Object o = null;
+
+ try
+ {
+ o = t.getTransferData(uiContactDataFlavor);
+ }
+ catch (UnsupportedFlavorException e)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Failed to drop meta contact.", e);
+ }
+ catch (IOException e)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Failed to drop meta contact.", e);
+ }
+
+ if (o instanceof ContactNode)
+ {
+ UIContact uiContact = ((ContactNode) o).getContactDescriptor();
+ Iterator<UIContactDetail> contactDetails
+ = uiContact
+ .getContactDetailsForOperationSet(
+ OperationSetBasicTelephony.class)
+ .iterator();
+
+ while (contactDetails.hasNext())
+ {
+ UIContactDetail detail = contactDetails.next();
+ ProtocolProviderService detailProvider
+ = detail.getPreferredProtocolProvider(
+ OperationSetBasicTelephony.class);
+
+ if (detailProvider != null)
+ {
+ /*
+ * Currently for videobridge conferences we only support
+ * adding contacts via the account with the videobridge
+ */
+ if (callConference.isJitsiVideobridge())
+ {
+ for (Call call : callConference.getCalls())
+ {
+ if (detailProvider == call.getProtocolProvider())
+ {
+ callee = detail.getAddress();
+ provider = detailProvider;
+ break;
+ }
+ }
+ }
+ else
+ {
+ callee = detail.getAddress();
+ provider = detailProvider;
+ break;
+ }
+ }
+ }
+
+ if (callee == null)
+ {
+ /*
+ * It turns out that the error message to be reported would
+ * like to display information about the account which could
+ * not add the dropped callee to the telephony conference.
+ * Unfortunately, a telephony conference may have multiple
+ * accounts involved. Anyway, choose the first account
+ * involved in the telephony conference.
+ */
+ ProtocolProviderService callProvider
+ = callConference.getCalls().get(0)
+ .getProtocolProvider();
+
+ ResourceManagementService resources
+ = GuiActivator.getResources();
+ AccountID accountID = callProvider.getAccountID();
+
+ new ErrorDialog(null,
+ resources.getI18NString("service.gui.ERROR"),
+ resources.getI18NString(
+ "service.gui.CALL_NOT_SUPPORTING_PARTICIPANT",
+ new String[]
+ {
+ accountID.getService(),
+ accountID.getUserID(),
+ uiContact.getDisplayName()
+ }))
+ .showDialog();
+ }
+ }
+ }
+ else if (t.isDataFlavorSupported(DataFlavor.stringFlavor))
+ {
+ InputContext inputContext = comp.getInputContext();
+
+ if (inputContext != null)
+ inputContext.endComposition();
+
+ try
+ {
+ BufferedReader reader
+ = new BufferedReader(
+ DataFlavor.stringFlavor.getReaderForText(t));
+
+ try
+ {
+ String line;
+ StringBuilder calleeBuilder = new StringBuilder();
+
+ while ((line = reader.readLine()) != null)
+ calleeBuilder.append(line);
+
+ callee = calleeBuilder.toString();
+ /*
+ * The value of the local variable provider will be null
+ * because we have a String only and hence we have no
+ * associated ProtocolProviderService.
+ * CallManager.inviteToConferenceCall will accept it.
+ */
+ }
+ finally
+ {
+ reader.close();
+ }
+ }
+ catch (UnsupportedFlavorException e)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Failed to drop string.", e);
+ }
+ catch (IOException e)
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Failed to drop string.", e);
+ }
+ }
+
+ if (callee == null)
+ return false;
+ else
+ {
+ Map<ProtocolProviderService, List<String>> callees
+ = new HashMap<ProtocolProviderService, List<String>>();
+
+ callees.put(provider, Arrays.asList(callee));
+ CallManager.inviteToConferenceCall(callees, callConference);
+
+ return true;
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/FullScreenLayout.java b/src/net/java/sip/communicator/impl/gui/main/call/FullScreenLayout.java
index 3e823ba..c56a415 100644
--- a/src/net/java/sip/communicator/impl/gui/main/call/FullScreenLayout.java
+++ b/src/net/java/sip/communicator/impl/gui/main/call/FullScreenLayout.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,176 +15,176 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.gui.main.call;
-
-import java.awt.*;
-import java.util.*;
-import java.util.List;
-
-/**
- * Implements a <tt>LayoutManager</tt> for the full-screen <tt>Call</tt>
- * display.
- *
- * @author Lyubomir Marinov
- */
-public class FullScreenLayout
- implements LayoutManager
-{
- public static final String CENTER = "CENTER";
-
- public static final String SOUTH = "SOUTH";
-
- private Component center;
-
- /**
- * The indicator which determines whether {@link #south} is to be laid out
- * on top of {@link #center} i.e. as an overlay.
- */
- private final boolean overlay;
-
- private Component south;
-
- /**
- * The vertical gap between the center and the south components.
- */
- private int yGap = 0;
-
- /**
- * Initializes a new <tt>FullScreenLayout</tt> instance.
- *
- * @param overlay <tt>true</tt> to lay out the <tt>Component</tt> at
- * {@link #SOUTH} on top of the <tt>Component</tt> at {@link #CENTER} i.e as
- * an overlay; otherwise, <tt>false</tt>
- * @oaram yGap the gap betwen the center and the south component
- */
- public FullScreenLayout(boolean overlay, int yGap)
- {
- this.overlay = overlay;
- this.yGap = yGap;
- }
-
- /**
- * Adds the given component to this layout.
- *
- * @param name the name of the constraint (CENTER or SOUTH)
- * @param comp the component to add to this layout
- */
- public void addLayoutComponent(String name, Component comp)
- {
- if (CENTER.equals(name))
- center = comp;
- else if (SOUTH.equals(name))
- south = comp;
- }
-
- /**
- * Gets a <tt>List</tt> of the <tt>Component</tt>s to be laid out by this
- * <tt>LayoutManager</tt> i.e. the non-<tt>null</tt> of {@link #center}
- * and {@link #south}.
- *
- * @return a <tt>List</tt> of the <tt>Component</tt>s to be laid out by this
- * <tt>LayoutManager</tt>
- */
- private List<Component> getLayoutComponents()
- {
- List<Component> layoutComponents = new ArrayList<Component>(2);
-
- if (center != null)
- layoutComponents.add(center);
- if (south != null)
- layoutComponents.add(south);
- return layoutComponents;
- }
-
- /**
- * Lays out the components added in the given parent container
- *
- * @param parent the parent container to lay out
- */
- public void layoutContainer(Container parent)
- {
- int southWidth;
- int southHeight;
-
- if (south == null)
- {
- southWidth = southHeight = 0;
- }
- else
- {
- Dimension southSize = south.getPreferredSize();
-
- southWidth = southSize.width;
- southHeight = southSize.height;
- }
-
- Dimension parentSize = parent.getSize();
-
- if (center != null)
- {
- /*
- * If the Component at the SOUTH is not to be shown as an overlay,
- * make room for it bellow the Component at the CENTER.
- */
- int yOffset = overlay ? 0 : southHeight + yGap;
-
- center.setBounds(
- 0,
- 0,
- parentSize.width,
- parentSize.height - yOffset);
- }
- if (south != null)
- {
- south.setBounds(
- (parentSize.width - southWidth) / 2,
- parentSize.height - southHeight,
- southWidth,
- southHeight);
- }
- }
-
- public Dimension minimumLayoutSize(Container parent)
- {
- List<Component> components = getLayoutComponents();
- Dimension size = new Dimension(0, 0);
-
- for (Component component : components)
- {
- Dimension componentSize = component.getMinimumSize();
-
- size.width = Math.max(size.width, componentSize.width);
- if (overlay)
- size.height = Math.max(size.height, componentSize.height);
- else
- size.height += componentSize.height;
- }
- return size;
- }
-
- public Dimension preferredLayoutSize(Container parent)
- {
- List<Component> components = getLayoutComponents();
- Dimension size = new Dimension(0, 0);
-
- for (Component component : components)
- {
- Dimension componentSize = component.getPreferredSize();
-
- size.width = Math.max(size.width, componentSize.width);
- if (overlay)
- size.height = Math.max(size.height, componentSize.height);
- else
- size.height += componentSize.height;
- }
- return size;
- }
-
- public void removeLayoutComponent(Component comp)
- {
- if (comp.equals(center))
- center = null;
- else if (comp.equals(south))
- south = null;
- }
-}
+package net.java.sip.communicator.impl.gui.main.call;
+
+import java.awt.*;
+import java.util.*;
+import java.util.List;
+
+/**
+ * Implements a <tt>LayoutManager</tt> for the full-screen <tt>Call</tt>
+ * display.
+ *
+ * @author Lyubomir Marinov
+ */
+public class FullScreenLayout
+ implements LayoutManager
+{
+ public static final String CENTER = "CENTER";
+
+ public static final String SOUTH = "SOUTH";
+
+ private Component center;
+
+ /**
+ * The indicator which determines whether {@link #south} is to be laid out
+ * on top of {@link #center} i.e. as an overlay.
+ */
+ private final boolean overlay;
+
+ private Component south;
+
+ /**
+ * The vertical gap between the center and the south components.
+ */
+ private int yGap = 0;
+
+ /**
+ * Initializes a new <tt>FullScreenLayout</tt> instance.
+ *
+ * @param overlay <tt>true</tt> to lay out the <tt>Component</tt> at
+ * {@link #SOUTH} on top of the <tt>Component</tt> at {@link #CENTER} i.e as
+ * an overlay; otherwise, <tt>false</tt>
+ * @oaram yGap the gap betwen the center and the south component
+ */
+ public FullScreenLayout(boolean overlay, int yGap)
+ {
+ this.overlay = overlay;
+ this.yGap = yGap;
+ }
+
+ /**
+ * Adds the given component to this layout.
+ *
+ * @param name the name of the constraint (CENTER or SOUTH)
+ * @param comp the component to add to this layout
+ */
+ public void addLayoutComponent(String name, Component comp)
+ {
+ if (CENTER.equals(name))
+ center = comp;
+ else if (SOUTH.equals(name))
+ south = comp;
+ }
+
+ /**
+ * Gets a <tt>List</tt> of the <tt>Component</tt>s to be laid out by this
+ * <tt>LayoutManager</tt> i.e. the non-<tt>null</tt> of {@link #center}
+ * and {@link #south}.
+ *
+ * @return a <tt>List</tt> of the <tt>Component</tt>s to be laid out by this
+ * <tt>LayoutManager</tt>
+ */
+ private List<Component> getLayoutComponents()
+ {
+ List<Component> layoutComponents = new ArrayList<Component>(2);
+
+ if (center != null)
+ layoutComponents.add(center);
+ if (south != null)
+ layoutComponents.add(south);
+ return layoutComponents;
+ }
+
+ /**
+ * Lays out the components added in the given parent container
+ *
+ * @param parent the parent container to lay out
+ */
+ public void layoutContainer(Container parent)
+ {
+ int southWidth;
+ int southHeight;
+
+ if (south == null)
+ {
+ southWidth = southHeight = 0;
+ }
+ else
+ {
+ Dimension southSize = south.getPreferredSize();
+
+ southWidth = southSize.width;
+ southHeight = southSize.height;
+ }
+
+ Dimension parentSize = parent.getSize();
+
+ if (center != null)
+ {
+ /*
+ * If the Component at the SOUTH is not to be shown as an overlay,
+ * make room for it bellow the Component at the CENTER.
+ */
+ int yOffset = overlay ? 0 : southHeight + yGap;
+
+ center.setBounds(
+ 0,
+ 0,
+ parentSize.width,
+ parentSize.height - yOffset);
+ }
+ if (south != null)
+ {
+ south.setBounds(
+ (parentSize.width - southWidth) / 2,
+ parentSize.height - southHeight,
+ southWidth,
+ southHeight);
+ }
+ }
+
+ public Dimension minimumLayoutSize(Container parent)
+ {
+ List<Component> components = getLayoutComponents();
+ Dimension size = new Dimension(0, 0);
+
+ for (Component component : components)
+ {
+ Dimension componentSize = component.getMinimumSize();
+
+ size.width = Math.max(size.width, componentSize.width);
+ if (overlay)
+ size.height = Math.max(size.height, componentSize.height);
+ else
+ size.height += componentSize.height;
+ }
+ return size;
+ }
+
+ public Dimension preferredLayoutSize(Container parent)
+ {
+ List<Component> components = getLayoutComponents();
+ Dimension size = new Dimension(0, 0);
+
+ for (Component component : components)
+ {
+ Dimension componentSize = component.getPreferredSize();
+
+ size.width = Math.max(size.width, componentSize.width);
+ if (overlay)
+ size.height = Math.max(size.height, componentSize.height);
+ else
+ size.height += componentSize.height;
+ }
+ return size;
+ }
+
+ public void removeLayoutComponent(Component comp)
+ {
+ if (comp.equals(center))
+ center = null;
+ else if (comp.equals(south))
+ south = null;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/PreCallDialog.java b/src/net/java/sip/communicator/impl/gui/main/call/PreCallDialog.java
index 76c4139..0d6206a 100644
--- a/src/net/java/sip/communicator/impl/gui/main/call/PreCallDialog.java
+++ b/src/net/java/sip/communicator/impl/gui/main/call/PreCallDialog.java
@@ -256,8 +256,12 @@ public abstract class PreCallDialog
receivedCallWindow.setAlwaysOnTop(true);
+ // Register the JFrame so the dialog window is able to get dragged
+ // across the screen
+ ComponentMover.registerComponent(receivedCallWindow);
+
// prevents dialog window to get unwanted key events and when going
- // on top on linux, it steals focus and if we are accidently
+ // on top on linux, it steals focus and if we are accidentally
// writing something and pressing enter a call get answered
receivedCallWindow.setFocusableWindowState(false);
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/SecurityPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/SecurityPanel.java
index 2e2ed5b..b49e0a3 100644
--- a/src/net/java/sip/communicator/impl/gui/main/call/SecurityPanel.java
+++ b/src/net/java/sip/communicator/impl/gui/main/call/SecurityPanel.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,117 +15,117 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.gui.main.call;
-
-import net.java.sip.communicator.plugin.desktoputil.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.util.skin.*;
-
-import org.jitsi.service.neomedia.*;
-
-/**
- * Base class for security panels that show encryption specific UI controls.
- *
- * @author Ingo Bauersachs
- */
-public abstract class SecurityPanel<T extends SrtpControl>
- extends FadeInBalloonPanel
- implements Skinnable
-{
- /**
- * The currently used security control.
- */
- protected T securityControl;
-
- /**
- * Create security panel using the security control.
- * @param securityControl
- */
- public SecurityPanel(T securityControl)
- {
- this.securityControl = securityControl;
- }
-
- /**
- * The currently used security control.
- * @return
- */
- public T getSecurityControl()
- {
- return securityControl;
- }
-
- /**
- * The currently used security control.
- * @return
- */
- public void setSecurityControl(T securityControl)
- {
- this.securityControl = securityControl;
- }
-
- /**
- * Creates the security panel depending on the concrete implementation of
- * the passed security controller.
- *
- * @param srtpControl the security controller that provides the information
- * to be shown on the UI
- * @return An instance of a {@link SecurityPanel} for the security
- * controller or an {@link TransparentPanel} if the controller is
- * unknown or does not have any controls to show.
- */
- public static SecurityPanel<?> create(
- SwingCallPeerRenderer peerRenderer,
- CallPeer callPeer,
- SrtpControl srtpControl)
- {
- if(srtpControl instanceof ZrtpControl)
- {
- return
- new ZrtpSecurityPanel(
- peerRenderer,
- callPeer,
- (ZrtpControl) srtpControl);
- }
- else
- {
- return
- new SecurityPanel<SrtpControl>(srtpControl)
- {
- public void loadSkin() {}
-
- @Override
- public void securityOn(CallPeerSecurityOnEvent evt) {}
-
- @Override
- public void securityOff(CallPeerSecurityOffEvent evt) {}
-
- @Override
- public void securityTimeout(
- CallPeerSecurityTimeoutEvent evt) {}
- };
- }
- }
-
- /**
- * Indicates that the security is turned on.
- *
- * @param evt details about the event that caused this message.
- */
- public abstract void securityOn(CallPeerSecurityOnEvent evt);
-
- /**
- * Indicates that the security is turned off.
- *
- * @param evt details about the event that caused this message.
- */
- public abstract void securityOff(CallPeerSecurityOffEvent evt);
-
- /**
- * Indicates that the security is timeouted, is not supported by the
- * other end.
- * @param evt Details about the event that caused this message.
- */
- public abstract void securityTimeout(CallPeerSecurityTimeoutEvent evt);
-}
+package net.java.sip.communicator.impl.gui.main.call;
+
+import net.java.sip.communicator.plugin.desktoputil.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.event.*;
+import net.java.sip.communicator.util.skin.*;
+
+import org.jitsi.service.neomedia.*;
+
+/**
+ * Base class for security panels that show encryption specific UI controls.
+ *
+ * @author Ingo Bauersachs
+ */
+public abstract class SecurityPanel<T extends SrtpControl>
+ extends FadeInBalloonPanel
+ implements Skinnable
+{
+ /**
+ * The currently used security control.
+ */
+ protected T securityControl;
+
+ /**
+ * Create security panel using the security control.
+ * @param securityControl
+ */
+ public SecurityPanel(T securityControl)
+ {
+ this.securityControl = securityControl;
+ }
+
+ /**
+ * The currently used security control.
+ * @return
+ */
+ public T getSecurityControl()
+ {
+ return securityControl;
+ }
+
+ /**
+ * The currently used security control.
+ * @return
+ */
+ public void setSecurityControl(T securityControl)
+ {
+ this.securityControl = securityControl;
+ }
+
+ /**
+ * Creates the security panel depending on the concrete implementation of
+ * the passed security controller.
+ *
+ * @param srtpControl the security controller that provides the information
+ * to be shown on the UI
+ * @return An instance of a {@link SecurityPanel} for the security
+ * controller or an {@link TransparentPanel} if the controller is
+ * unknown or does not have any controls to show.
+ */
+ public static SecurityPanel<?> create(
+ SwingCallPeerRenderer peerRenderer,
+ CallPeer callPeer,
+ SrtpControl srtpControl)
+ {
+ if(srtpControl instanceof ZrtpControl)
+ {
+ return
+ new ZrtpSecurityPanel(
+ peerRenderer,
+ callPeer,
+ (ZrtpControl) srtpControl);
+ }
+ else
+ {
+ return
+ new SecurityPanel<SrtpControl>(srtpControl)
+ {
+ public void loadSkin() {}
+
+ @Override
+ public void securityOn(CallPeerSecurityOnEvent evt) {}
+
+ @Override
+ public void securityOff(CallPeerSecurityOffEvent evt) {}
+
+ @Override
+ public void securityTimeout(
+ CallPeerSecurityTimeoutEvent evt) {}
+ };
+ }
+ }
+
+ /**
+ * Indicates that the security is turned on.
+ *
+ * @param evt details about the event that caused this message.
+ */
+ public abstract void securityOn(CallPeerSecurityOnEvent evt);
+
+ /**
+ * Indicates that the security is turned off.
+ *
+ * @param evt details about the event that caused this message.
+ */
+ public abstract void securityOff(CallPeerSecurityOffEvent evt);
+
+ /**
+ * Indicates that the security is timeouted, is not supported by the
+ * other end.
+ * @param evt Details about the event that caused this message.
+ */
+ public abstract void securityTimeout(CallPeerSecurityTimeoutEvent evt);
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/TransferCallDialog.java b/src/net/java/sip/communicator/impl/gui/main/call/TransferCallDialog.java
index f2f2bd2..982738b 100644
--- a/src/net/java/sip/communicator/impl/gui/main/call/TransferCallDialog.java
+++ b/src/net/java/sip/communicator/impl/gui/main/call/TransferCallDialog.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,140 +15,140 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.gui.main.call;
-
-import java.awt.*;
-import java.awt.event.*;
-import java.util.*;
-
-import net.java.sip.communicator.impl.gui.*;
-import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*;
-import net.java.sip.communicator.impl.gui.utils.*;
-import net.java.sip.communicator.service.contactsource.*;
-import net.java.sip.communicator.service.gui.*;
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * Represents a <tt>Dialog</tt> which allows specifying the target contact
- * address of a transfer-call operation.
- *
- * @author Yana Stamcheva
- */
-public class TransferCallDialog
- extends OneChoiceInviteDialog
-{
- /**
- * The peer to transfer.
- */
- private final CallPeer transferPeer;
-
- /**
- * Creates a <tt>TransferCallDialog</tt> by specifying the peer to transfer
- * @param peer the peer to transfer
- */
- public TransferCallDialog(final CallPeer peer)
- {
- super(GuiActivator.getResources()
- .getI18NString("service.gui.TRANSFER_CALL_TITLE"));
-
- this.transferPeer = peer;
-
- this.initContactListData(peer.getProtocolProvider());
-
- this.setInfoText(GuiActivator.getResources()
- .getI18NString("service.gui.TRANSFER_CALL_MSG"));
- this.setOkButtonText(GuiActivator.getResources()
- .getI18NString("service.gui.TRANSFER"));
-
- this.setMinimumSize(new Dimension(300, 300));
-
- addOkButtonListener(new ActionListener()
- {
- public void actionPerformed(ActionEvent e)
- {
- UIContact uiContact = getSelectedContact();
-
- if (uiContact != null)
- {
- transferToContact(uiContact);
- }
-
- setVisible(false);
- dispose();
- }
- });
- addCancelButtonListener(new ActionListener()
- {
- public void actionPerformed(ActionEvent e)
- {
- setVisible(false);
- dispose();
- }
- });
- }
-
- /**
- * Initializes contact list sources.
- */
- private void initContactSources()
- {
- DemuxContactSourceService demuxCSService
- = GuiActivator.getDemuxContactSourceService();
-
- // If the DemuxContactSourceService isn't registered we use the default
- // contact source set.
- if (demuxCSService == null)
- return;
-
- Iterator<UIContactSource> sourcesIter
- = new ArrayList<UIContactSource>(
- contactList.getContactSources()).iterator();
-
- contactList.removeAllContactSources();
-
- while (sourcesIter.hasNext())
- {
- ContactSourceService contactSource
- = sourcesIter.next().getContactSourceService();
-
- contactList.addContactSource(
- demuxCSService.createDemuxContactSource(contactSource));
- }
- }
-
- /**
- * Initializes the left contact list with the contacts that could be added
- * to the current chat session.
- *
- * @param protocolProvider the protocol provider from which to initialize
- * the contact list data
- */
- private void initContactListData(ProtocolProviderService protocolProvider)
- {
- initContactSources();
-
- contactList.addContactSource(
- new ProtocolContactSourceServiceImpl(
- protocolProvider, OperationSetBasicTelephony.class));
- contactList.addContactSource(
- new StringContactSourceServiceImpl(
- protocolProvider, OperationSetBasicTelephony.class));
-
- contactList.applyDefaultFilter();
- }
-
- /**
- * Transfer the transfer peer to the given <tt>UIContact</tt>.
- *
- * @param uiContact the contact to transfer to
- */
- private void transferToContact(UIContact uiContact)
- {
- UIContactDetail contactDetail = uiContact
- .getDefaultContactDetail(
- OperationSetBasicTelephony.class);
-
- CallManager.transferCall( transferPeer,
- contactDetail.getAddress());
- }
-}
+package net.java.sip.communicator.impl.gui.main.call;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+
+import net.java.sip.communicator.impl.gui.*;
+import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*;
+import net.java.sip.communicator.impl.gui.utils.*;
+import net.java.sip.communicator.service.contactsource.*;
+import net.java.sip.communicator.service.gui.*;
+import net.java.sip.communicator.service.protocol.*;
+
+/**
+ * Represents a <tt>Dialog</tt> which allows specifying the target contact
+ * address of a transfer-call operation.
+ *
+ * @author Yana Stamcheva
+ */
+public class TransferCallDialog
+ extends OneChoiceInviteDialog
+{
+ /**
+ * The peer to transfer.
+ */
+ private final CallPeer transferPeer;
+
+ /**
+ * Creates a <tt>TransferCallDialog</tt> by specifying the peer to transfer
+ * @param peer the peer to transfer
+ */
+ public TransferCallDialog(final CallPeer peer)
+ {
+ super(GuiActivator.getResources()
+ .getI18NString("service.gui.TRANSFER_CALL_TITLE"));
+
+ this.transferPeer = peer;
+
+ this.initContactListData(peer.getProtocolProvider());
+
+ this.setInfoText(GuiActivator.getResources()
+ .getI18NString("service.gui.TRANSFER_CALL_MSG"));
+ this.setOkButtonText(GuiActivator.getResources()
+ .getI18NString("service.gui.TRANSFER"));
+
+ this.setMinimumSize(new Dimension(300, 300));
+
+ addOkButtonListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ UIContact uiContact = getSelectedContact();
+
+ if (uiContact != null)
+ {
+ transferToContact(uiContact);
+ }
+
+ setVisible(false);
+ dispose();
+ }
+ });
+ addCancelButtonListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ setVisible(false);
+ dispose();
+ }
+ });
+ }
+
+ /**
+ * Initializes contact list sources.
+ */
+ private void initContactSources()
+ {
+ DemuxContactSourceService demuxCSService
+ = GuiActivator.getDemuxContactSourceService();
+
+ // If the DemuxContactSourceService isn't registered we use the default
+ // contact source set.
+ if (demuxCSService == null)
+ return;
+
+ Iterator<UIContactSource> sourcesIter
+ = new ArrayList<UIContactSource>(
+ contactList.getContactSources()).iterator();
+
+ contactList.removeAllContactSources();
+
+ while (sourcesIter.hasNext())
+ {
+ ContactSourceService contactSource
+ = sourcesIter.next().getContactSourceService();
+
+ contactList.addContactSource(
+ demuxCSService.createDemuxContactSource(contactSource));
+ }
+ }
+
+ /**
+ * Initializes the left contact list with the contacts that could be added
+ * to the current chat session.
+ *
+ * @param protocolProvider the protocol provider from which to initialize
+ * the contact list data
+ */
+ private void initContactListData(ProtocolProviderService protocolProvider)
+ {
+ initContactSources();
+
+ contactList.addContactSource(
+ new ProtocolContactSourceServiceImpl(
+ protocolProvider, OperationSetBasicTelephony.class));
+ contactList.addContactSource(
+ new StringContactSourceServiceImpl(
+ protocolProvider, OperationSetBasicTelephony.class));
+
+ contactList.applyDefaultFilter();
+ }
+
+ /**
+ * Transfer the transfer peer to the given <tt>UIContact</tt>.
+ *
+ * @param uiContact the contact to transfer to
+ */
+ private void transferToContact(UIContact uiContact)
+ {
+ UIContactDetail contactDetail = uiContact
+ .getDefaultContactDetail(
+ OperationSetBasicTelephony.class);
+
+ CallManager.transferCall( transferPeer,
+ contactDetail.getAddress());
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceInviteDialog.java b/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceInviteDialog.java
index 80eedc6..bb32858 100644
--- a/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceInviteDialog.java
+++ b/src/net/java/sip/communicator/impl/gui/main/call/conference/ConferenceInviteDialog.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,570 +15,570 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.gui.main.call.conference;
-
-import java.awt.*;
-import java.awt.event.*;
-import java.util.*;
-import java.util.List;
-
-import javax.swing.*;
-
-import net.java.sip.communicator.impl.gui.*;
-import net.java.sip.communicator.impl.gui.main.call.*;
-import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*;
-import net.java.sip.communicator.impl.gui.utils.*;
-import net.java.sip.communicator.plugin.desktoputil.*;
-import net.java.sip.communicator.service.contactsource.*;
-import net.java.sip.communicator.service.gui.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-/**
- * The invite dialog is the one shown when the user clicks on the conference
- * button in the chat toolbar.
- *
- * @author Yana Stamcheva
- * @author Lyubomir Marinov
- */
-public class ConferenceInviteDialog
- extends InviteDialog
-{
- /**
- * Serial version UID.
- */
- private static final long serialVersionUID = 0L;
-
- /**
- * The account selector box.
- */
- private final JComboBox accountSelectorBox = new JComboBox();
-
- /**
- * The last selected account.
- */
- private Object lastSelectedAccount;
-
- /**
- * The telephony conference into which this instance is to invite
- * participants.
- */
- private final CallConference conference;
-
- /**
- * The current provider contact source.
- */
- private ContactSourceService currentProviderContactSource;
-
- /**
- * The current string contact source.
- */
- private ContactSourceService currentStringContactSource;
-
- /**
- * The previously selected protocol provider, with which this dialog has
- * been instantiated.
- */
- private ProtocolProviderService preselectedProtocolProvider;
-
- /**
- * Indicates whether this conference invite dialog is associated with a
- * Jitsi Videobridge invite.
- */
- private final boolean isJitsiVideobridge;
-
- /**
- * Initializes a new <tt>ConferenceInviteDialog</tt> instance which is to
- * invite contacts/participants in a specific telephony conference.
- *
- * @param conference the telephony conference in which the new instance is
- * to invite contacts/participants
- */
- public ConferenceInviteDialog(
- CallConference conference,
- ProtocolProviderService preselectedProvider,
- List<ProtocolProviderService> protocolProviders,
- final boolean isJitsiVideobridge)
- {
- // Set the correct dialog title depending if we're going to create a
- // video bridge conference call
- super((isJitsiVideobridge
- ? GuiActivator.getResources()
- .getI18NString("service.gui.INVITE_CONTACT_TO_VIDEO_BRIDGE")
- : GuiActivator.getResources()
- .getI18NString("service.gui.INVITE_CONTACT_TO_CALL")),
- false);
-
- this.conference = conference;
- this.preselectedProtocolProvider = preselectedProvider;
- this.isJitsiVideobridge = isJitsiVideobridge;
-
- if (preselectedProtocolProvider == null)
- initAccountSelectorPanel(protocolProviders);
-
- // init the list, as we check whether features are supported
- // it may take some time if we have too much contacts
- SwingUtilities.invokeLater(new Runnable()
- {
- public void run()
- {
- initContactSources();
-
- // Initialize the list of contacts to select from.
- if (preselectedProtocolProvider != null)
- initContactListData(preselectedProtocolProvider);
- else
- initContactListData(
- (ProtocolProviderService) accountSelectorBox
- .getSelectedItem());
- }
- });
-
- this.addInviteButtonListener(new ActionListener()
- {
- public void actionPerformed(ActionEvent e)
- {
- Collection<UIContact> selectedContacts
- = destContactList.getContacts(null);
-
- if (selectedContacts != null && selectedContacts.size() > 0)
- {
- if (preselectedProtocolProvider == null)
- preselectedProtocolProvider
- = (ProtocolProviderService) accountSelectorBox
- .getSelectedItem();
-
- if (isJitsiVideobridge)
- inviteJitsiVideobridgeContacts( preselectedProtocolProvider,
- selectedContacts);
- else
- inviteContacts(selectedContacts);
-
- // Store the last used account in order to pre-select it
- // next time.
- ConfigurationUtils.setLastCallConferenceProvider(
- preselectedProtocolProvider);
-
- dispose();
- }
- else
- {
- // TODO: The underlying invite dialog should show a message
- // to the user that she should select at least two contacts
- // in order to create a conference.
- }
- }
- });
-
- this.addCancelButtonListener(new ActionListener()
- {
- public void actionPerformed(ActionEvent e)
- {
- dispose();
- }
- });
- }
-
- /**
- * Constructs the <tt>ConferenceInviteDialog</tt>.
- */
- public ConferenceInviteDialog()
- {
- this(null, null, null, false);
- }
-
- /**
- * Creates an instance of <tt>ConferenceInviteDialog</tt> by specifying an
- * already created conference. To use when inviting contacts to an existing
- * conference is needed.
- *
- * @param conference the existing <tt>CallConference</tt>
- */
- public ConferenceInviteDialog(CallConference conference)
- {
- this(conference, null, null, false);
- }
-
- /**
- * Creates an instance of <tt>ConferenceInviteDialog</tt> by specifying an
- * already created conference. To use when inviting contacts to an existing
- * conference is needed.
- *
- * @param conference the existing <tt>CallConference</tt>
- */
- public ConferenceInviteDialog(
- CallConference conference,
- ProtocolProviderService preselectedProtocolProvider,
- boolean isJitsiVideobridge)
- {
- this(conference, preselectedProtocolProvider, null, isJitsiVideobridge);
- }
-
- /**
- * Creates an instance of <tt>ConferenceInviteDialog</tt> by specifying a
- * preselected protocol provider to be used and if this is an invite for
- * a video bridge conference.
- *
- * @param protocolProviders the protocol providers list
- * @param isJitsiVideobridge <tt>true</tt> if this dialog should create a
- * conference through a Jitsi Videobridge; otherwise, <tt>false</tt>
- */
- public ConferenceInviteDialog(
- List<ProtocolProviderService> protocolProviders,
- boolean isJitsiVideobridge)
- {
- this(null, null, protocolProviders, isJitsiVideobridge);
- }
-
- /**
- * Creates an instance of <tt>ConferenceInviteDialog</tt> by specifying a
- * preselected protocol provider to be used and if this is an invite for
- * a video bridge conference.
- *
- * @param selectedConfProvider the preselected protocol provider
- * @param isJitsiVideobridge <tt>true</tt> if this dialog should create a
- * conference through a Jitsi Videobridge; otherwise, <tt>false</tt>
- */
- public ConferenceInviteDialog(
- ProtocolProviderService selectedConfProvider,
- boolean isJitsiVideobridge)
- {
- this(null, selectedConfProvider, null, isJitsiVideobridge);
- }
-
- /**
- * Initializes the account selector panel.
- *
- * @param protocolProviders the list of protocol providers we'd like to
- * show in the account selector box
- */
- private void initAccountSelectorPanel(
- List<ProtocolProviderService> protocolProviders)
- {
- JLabel accountSelectorLabel = new JLabel(
- GuiActivator.getResources().getI18NString("service.gui.CALL_VIA"));
-
- TransparentPanel accountSelectorPanel
- = new TransparentPanel(new BorderLayout());
-
- accountSelectorPanel.setBorder(
- BorderFactory.createEmptyBorder(5, 5, 5, 5));
- accountSelectorPanel.add(accountSelectorLabel, BorderLayout.WEST);
- accountSelectorPanel.add(accountSelectorBox, BorderLayout.CENTER);
-
- // Initialize the account selector box.
- if (protocolProviders != null && protocolProviders.size() > 0)
- this.initAccountListData(protocolProviders);
- else
- this.initAccountListData();
-
- this.accountSelectorBox.setRenderer(new DefaultListCellRenderer()
- {
- private static final long serialVersionUID = 0L;
-
- @Override
- public Component getListCellRendererComponent(JList list,
- Object value, int index, boolean isSelected,
- boolean cellHasFocus)
- {
- ProtocolProviderService protocolProvider
- = (ProtocolProviderService) value;
-
- if (protocolProvider != null)
- {
- this.setText(
- protocolProvider.getAccountID().getDisplayName());
- this.setIcon(
- ImageLoader.getAccountStatusImage(protocolProvider));
- }
-
- return this;
- }
- });
-
- this.accountSelectorBox.addActionListener(new ActionListener()
- {
- public void actionPerformed(ActionEvent e)
- {
- Object accountSelectorBoxSelectedItem
- = accountSelectorBox.getSelectedItem();
-
- if (lastSelectedAccount == null
- || !lastSelectedAccount
- .equals(accountSelectorBoxSelectedItem))
- {
- lastSelectedAccount = accountSelectorBoxSelectedItem;
-
- initContactListData(
- (ProtocolProviderService) accountSelectorBox
- .getSelectedItem());
-
- if (isJitsiVideobridge)
- destContactList.removeAll();
- }
- }
- });
-
- this.getContentPane().add(accountSelectorPanel, BorderLayout.NORTH);
- }
-
- /**
- * Initializes the account selector box with the given list of
- * <tt>ProtocolProviderService</tt>-s.
- *
- * @param protocolProviders the list of <tt>ProtocolProviderService</tt>-s
- * we'd like to show in the account selector box
- */
- private void initAccountListData(
- List<ProtocolProviderService> protocolProviders)
- {
- Iterator<ProtocolProviderService> providersIter
- = protocolProviders.iterator();
-
- while (providersIter.hasNext())
- {
- ProtocolProviderService protocolProvider
- = providersIter.next();
-
- accountSelectorBox.addItem(protocolProvider);
- }
-
- if (accountSelectorBox.getItemCount() > 0)
- accountSelectorBox.setSelectedIndex(0);
- }
-
- /**
- * Initializes the account list.
- */
- private void initAccountListData()
- {
- Iterator<ProtocolProviderService> protocolProviders
- = GuiActivator.getUIService().getMainFrame().getProtocolProviders();
-
- while(protocolProviders.hasNext())
- {
- ProtocolProviderService protocolProvider
- = protocolProviders.next();
- OperationSet opSet
- = protocolProvider.getOperationSet(
- OperationSetTelephonyConferencing.class);
-
- if ((opSet != null) && protocolProvider.isRegistered())
- accountSelectorBox.addItem(protocolProvider);
- }
-
- // Try to select the last used account if available.
- ProtocolProviderService pps
- = ConfigurationUtils.getLastCallConferenceProvider();
-
- if (pps == null && conference != null)
- {
- /*
- * Pick up the first account from the ones participating in the
- * associated telephony conference which supports
- * OperationSetTelephonyConferencing.
- */
- for (Call call : conference.getCalls())
- {
- ProtocolProviderService callPps = call.getProtocolProvider();
-
- if (callPps.getOperationSet(
- OperationSetTelephonyConferencing.class)
- != null)
- {
- pps = callPps;
- break;
- }
- }
- }
-
- if (pps != null)
- accountSelectorBox.setSelectedItem(pps);
- else if (accountSelectorBox.getItemCount() > 0)
- accountSelectorBox.setSelectedIndex(0);
- }
-
- /**
- * Initializes contact list sources.
- */
- private void initContactSources()
- {
- DemuxContactSourceService demuxCSService
- = GuiActivator.getDemuxContactSourceService();
-
- // If the DemuxContactSourceService isn't registered we use the default
- // contact source set.
- if (demuxCSService == null)
- return;
-
- Iterator<UIContactSource> sourcesIter
- = new ArrayList<UIContactSource>(
- srcContactList.getContactSources()).iterator();
-
- srcContactList.removeAllContactSources();
-
- while (sourcesIter.hasNext())
- {
- ContactSourceService contactSource
- = sourcesIter.next().getContactSourceService();
-
- srcContactList.addContactSource(
- demuxCSService.createDemuxContactSource(contactSource));
- }
- }
-
- /**
- * Initializes the left contact list with the contacts that could be added
- * to the current chat session.
- * @param protocolProvider the protocol provider from which to initialize
- * the contact list data
- */
- private void initContactListData(ProtocolProviderService protocolProvider)
- {
- this.setCurrentProvider(protocolProvider);
-
- Iterator<UIContactSource> sourcesIter
- = new ArrayList<UIContactSource>(
- srcContactList.getContactSources()).iterator();
-
- while (sourcesIter.hasNext())
- {
- ContactSourceService contactSource
- = sourcesIter.next().getContactSourceService();
-
- if (contactSource instanceof ProtocolAwareContactSourceService)
- {
- ((ProtocolAwareContactSourceService) contactSource)
- .setPreferredProtocolProvider(
- OperationSetBasicTelephony.class, protocolProvider);
- }
- }
-
- srcContactList.removeContactSource(currentProviderContactSource);
- srcContactList.removeContactSource(currentStringContactSource);
-
- currentProviderContactSource
- = new ProtocolContactSourceServiceImpl(
- protocolProvider,
- OperationSetBasicTelephony.class);
- currentStringContactSource
- = new StringContactSourceServiceImpl(
- protocolProvider,
- OperationSetBasicTelephony.class);
-
- srcContactList.addContactSource(currentProviderContactSource);
- srcContactList.addContactSource(currentStringContactSource);
-
- srcContactList.applyDefaultFilter();
- }
-
- /**
- * Invites the contacts to the chat conference.
- *
- * @param contacts the list of contacts to invite
- */
- private void inviteContacts(Collection<UIContact> contacts)
- {
- ProtocolProviderService selectedProvider;
- Map<ProtocolProviderService, List<String>> selectedProviderCallees
- = new HashMap<ProtocolProviderService, List<String>>();
- List<String> callees;
-
- Iterator<UIContact> contactsIter = contacts.iterator();
-
- while (contactsIter.hasNext())
- {
- UIContact uiContact = contactsIter.next();
-
- Iterator<UIContactDetail> contactDetailsIter = uiContact
- .getContactDetailsForOperationSet(
- OperationSetBasicTelephony.class).iterator();
-
- // We invite the first protocol contact that corresponds to the
- // invite provider.
- if (contactDetailsIter.hasNext())
- {
- UIContactDetail inviteDetail = contactDetailsIter.next();
- selectedProvider = inviteDetail
- .getPreferredProtocolProvider(
- OperationSetBasicTelephony.class);
-
- if (selectedProvider == null)
- {
- selectedProvider
- = (ProtocolProviderService)
- accountSelectorBox.getSelectedItem();
- }
-
- if(selectedProvider != null
- && selectedProviderCallees.get(selectedProvider) != null)
- {
- callees = selectedProviderCallees.get(selectedProvider);
- }
- else
- {
- callees = new ArrayList<String>();
- }
-
- callees.add(inviteDetail.getAddress());
- selectedProviderCallees.put(selectedProvider, callees);
- }
- }
-
- if(conference != null)
- {
- CallManager.inviteToConferenceCall(
- selectedProviderCallees,
- conference);
- }
- else
- {
- CallManager.createConferenceCall(selectedProviderCallees);
- }
- }
-
- /**
- * Invites the contacts to the chat conference.
- *
- * @param contacts the list of contacts to invite
- */
- private void inviteJitsiVideobridgeContacts(
- ProtocolProviderService preselectedProvider,
- Collection<UIContact> contacts)
- {
- List<String> callees = new ArrayList<String>();
-
- Iterator<UIContact> contactsIter = contacts.iterator();
-
- while (contactsIter.hasNext())
- {
- UIContact uiContact = contactsIter.next();
-
- Iterator<UIContactDetail> contactDetailsIter = uiContact
- .getContactDetailsForOperationSet(
- OperationSetBasicTelephony.class).iterator();
-
- // We invite the first protocol contact that corresponds to the
- // invite provider.
- if (contactDetailsIter.hasNext())
- {
- UIContactDetail inviteDetail = contactDetailsIter.next();
-
- callees.add(inviteDetail.getAddress());
- }
- }
-
- if(conference != null)
- {
- CallManager.inviteToJitsiVideobridgeConfCall(
- callees.toArray(new String[callees.size()]),
- conference.getCalls().get(0));
- }
- else
- {
- CallManager.createJitsiVideobridgeConfCall(
- preselectedProvider,
- callees.toArray(new String[callees.size()]));
- }
- }
-}
+package net.java.sip.communicator.impl.gui.main.call.conference;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import java.util.List;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.impl.gui.*;
+import net.java.sip.communicator.impl.gui.main.call.*;
+import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*;
+import net.java.sip.communicator.impl.gui.utils.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
+import net.java.sip.communicator.service.contactsource.*;
+import net.java.sip.communicator.service.gui.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.util.*;
+
+/**
+ * The invite dialog is the one shown when the user clicks on the conference
+ * button in the chat toolbar.
+ *
+ * @author Yana Stamcheva
+ * @author Lyubomir Marinov
+ */
+public class ConferenceInviteDialog
+ extends InviteDialog
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * The account selector box.
+ */
+ private final JComboBox accountSelectorBox = new JComboBox();
+
+ /**
+ * The last selected account.
+ */
+ private Object lastSelectedAccount;
+
+ /**
+ * The telephony conference into which this instance is to invite
+ * participants.
+ */
+ private final CallConference conference;
+
+ /**
+ * The current provider contact source.
+ */
+ private ContactSourceService currentProviderContactSource;
+
+ /**
+ * The current string contact source.
+ */
+ private ContactSourceService currentStringContactSource;
+
+ /**
+ * The previously selected protocol provider, with which this dialog has
+ * been instantiated.
+ */
+ private ProtocolProviderService preselectedProtocolProvider;
+
+ /**
+ * Indicates whether this conference invite dialog is associated with a
+ * Jitsi Videobridge invite.
+ */
+ private final boolean isJitsiVideobridge;
+
+ /**
+ * Initializes a new <tt>ConferenceInviteDialog</tt> instance which is to
+ * invite contacts/participants in a specific telephony conference.
+ *
+ * @param conference the telephony conference in which the new instance is
+ * to invite contacts/participants
+ */
+ public ConferenceInviteDialog(
+ CallConference conference,
+ ProtocolProviderService preselectedProvider,
+ List<ProtocolProviderService> protocolProviders,
+ final boolean isJitsiVideobridge)
+ {
+ // Set the correct dialog title depending if we're going to create a
+ // video bridge conference call
+ super((isJitsiVideobridge
+ ? GuiActivator.getResources()
+ .getI18NString("service.gui.INVITE_CONTACT_TO_VIDEO_BRIDGE")
+ : GuiActivator.getResources()
+ .getI18NString("service.gui.INVITE_CONTACT_TO_CALL")),
+ false);
+
+ this.conference = conference;
+ this.preselectedProtocolProvider = preselectedProvider;
+ this.isJitsiVideobridge = isJitsiVideobridge;
+
+ if (preselectedProtocolProvider == null)
+ initAccountSelectorPanel(protocolProviders);
+
+ // init the list, as we check whether features are supported
+ // it may take some time if we have too much contacts
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ initContactSources();
+
+ // Initialize the list of contacts to select from.
+ if (preselectedProtocolProvider != null)
+ initContactListData(preselectedProtocolProvider);
+ else
+ initContactListData(
+ (ProtocolProviderService) accountSelectorBox
+ .getSelectedItem());
+ }
+ });
+
+ this.addInviteButtonListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ Collection<UIContact> selectedContacts
+ = destContactList.getContacts(null);
+
+ if (selectedContacts != null && selectedContacts.size() > 0)
+ {
+ if (preselectedProtocolProvider == null)
+ preselectedProtocolProvider
+ = (ProtocolProviderService) accountSelectorBox
+ .getSelectedItem();
+
+ if (isJitsiVideobridge)
+ inviteJitsiVideobridgeContacts( preselectedProtocolProvider,
+ selectedContacts);
+ else
+ inviteContacts(selectedContacts);
+
+ // Store the last used account in order to pre-select it
+ // next time.
+ ConfigurationUtils.setLastCallConferenceProvider(
+ preselectedProtocolProvider);
+
+ dispose();
+ }
+ else
+ {
+ // TODO: The underlying invite dialog should show a message
+ // to the user that she should select at least two contacts
+ // in order to create a conference.
+ }
+ }
+ });
+
+ this.addCancelButtonListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ dispose();
+ }
+ });
+ }
+
+ /**
+ * Constructs the <tt>ConferenceInviteDialog</tt>.
+ */
+ public ConferenceInviteDialog()
+ {
+ this(null, null, null, false);
+ }
+
+ /**
+ * Creates an instance of <tt>ConferenceInviteDialog</tt> by specifying an
+ * already created conference. To use when inviting contacts to an existing
+ * conference is needed.
+ *
+ * @param conference the existing <tt>CallConference</tt>
+ */
+ public ConferenceInviteDialog(CallConference conference)
+ {
+ this(conference, null, null, false);
+ }
+
+ /**
+ * Creates an instance of <tt>ConferenceInviteDialog</tt> by specifying an
+ * already created conference. To use when inviting contacts to an existing
+ * conference is needed.
+ *
+ * @param conference the existing <tt>CallConference</tt>
+ */
+ public ConferenceInviteDialog(
+ CallConference conference,
+ ProtocolProviderService preselectedProtocolProvider,
+ boolean isJitsiVideobridge)
+ {
+ this(conference, preselectedProtocolProvider, null, isJitsiVideobridge);
+ }
+
+ /**
+ * Creates an instance of <tt>ConferenceInviteDialog</tt> by specifying a
+ * preselected protocol provider to be used and if this is an invite for
+ * a video bridge conference.
+ *
+ * @param protocolProviders the protocol providers list
+ * @param isJitsiVideobridge <tt>true</tt> if this dialog should create a
+ * conference through a Jitsi Videobridge; otherwise, <tt>false</tt>
+ */
+ public ConferenceInviteDialog(
+ List<ProtocolProviderService> protocolProviders,
+ boolean isJitsiVideobridge)
+ {
+ this(null, null, protocolProviders, isJitsiVideobridge);
+ }
+
+ /**
+ * Creates an instance of <tt>ConferenceInviteDialog</tt> by specifying a
+ * preselected protocol provider to be used and if this is an invite for
+ * a video bridge conference.
+ *
+ * @param selectedConfProvider the preselected protocol provider
+ * @param isJitsiVideobridge <tt>true</tt> if this dialog should create a
+ * conference through a Jitsi Videobridge; otherwise, <tt>false</tt>
+ */
+ public ConferenceInviteDialog(
+ ProtocolProviderService selectedConfProvider,
+ boolean isJitsiVideobridge)
+ {
+ this(null, selectedConfProvider, null, isJitsiVideobridge);
+ }
+
+ /**
+ * Initializes the account selector panel.
+ *
+ * @param protocolProviders the list of protocol providers we'd like to
+ * show in the account selector box
+ */
+ private void initAccountSelectorPanel(
+ List<ProtocolProviderService> protocolProviders)
+ {
+ JLabel accountSelectorLabel = new JLabel(
+ GuiActivator.getResources().getI18NString("service.gui.CALL_VIA"));
+
+ TransparentPanel accountSelectorPanel
+ = new TransparentPanel(new BorderLayout());
+
+ accountSelectorPanel.setBorder(
+ BorderFactory.createEmptyBorder(5, 5, 5, 5));
+ accountSelectorPanel.add(accountSelectorLabel, BorderLayout.WEST);
+ accountSelectorPanel.add(accountSelectorBox, BorderLayout.CENTER);
+
+ // Initialize the account selector box.
+ if (protocolProviders != null && protocolProviders.size() > 0)
+ this.initAccountListData(protocolProviders);
+ else
+ this.initAccountListData();
+
+ this.accountSelectorBox.setRenderer(new DefaultListCellRenderer()
+ {
+ private static final long serialVersionUID = 0L;
+
+ @Override
+ public Component getListCellRendererComponent(JList list,
+ Object value, int index, boolean isSelected,
+ boolean cellHasFocus)
+ {
+ ProtocolProviderService protocolProvider
+ = (ProtocolProviderService) value;
+
+ if (protocolProvider != null)
+ {
+ this.setText(
+ protocolProvider.getAccountID().getDisplayName());
+ this.setIcon(
+ ImageLoader.getAccountStatusImage(protocolProvider));
+ }
+
+ return this;
+ }
+ });
+
+ this.accountSelectorBox.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ Object accountSelectorBoxSelectedItem
+ = accountSelectorBox.getSelectedItem();
+
+ if (lastSelectedAccount == null
+ || !lastSelectedAccount
+ .equals(accountSelectorBoxSelectedItem))
+ {
+ lastSelectedAccount = accountSelectorBoxSelectedItem;
+
+ initContactListData(
+ (ProtocolProviderService) accountSelectorBox
+ .getSelectedItem());
+
+ if (isJitsiVideobridge)
+ destContactList.removeAll();
+ }
+ }
+ });
+
+ this.getContentPane().add(accountSelectorPanel, BorderLayout.NORTH);
+ }
+
+ /**
+ * Initializes the account selector box with the given list of
+ * <tt>ProtocolProviderService</tt>-s.
+ *
+ * @param protocolProviders the list of <tt>ProtocolProviderService</tt>-s
+ * we'd like to show in the account selector box
+ */
+ private void initAccountListData(
+ List<ProtocolProviderService> protocolProviders)
+ {
+ Iterator<ProtocolProviderService> providersIter
+ = protocolProviders.iterator();
+
+ while (providersIter.hasNext())
+ {
+ ProtocolProviderService protocolProvider
+ = providersIter.next();
+
+ accountSelectorBox.addItem(protocolProvider);
+ }
+
+ if (accountSelectorBox.getItemCount() > 0)
+ accountSelectorBox.setSelectedIndex(0);
+ }
+
+ /**
+ * Initializes the account list.
+ */
+ private void initAccountListData()
+ {
+ Iterator<ProtocolProviderService> protocolProviders
+ = GuiActivator.getUIService().getMainFrame().getProtocolProviders();
+
+ while(protocolProviders.hasNext())
+ {
+ ProtocolProviderService protocolProvider
+ = protocolProviders.next();
+ OperationSet opSet
+ = protocolProvider.getOperationSet(
+ OperationSetTelephonyConferencing.class);
+
+ if ((opSet != null) && protocolProvider.isRegistered())
+ accountSelectorBox.addItem(protocolProvider);
+ }
+
+ // Try to select the last used account if available.
+ ProtocolProviderService pps
+ = ConfigurationUtils.getLastCallConferenceProvider();
+
+ if (pps == null && conference != null)
+ {
+ /*
+ * Pick up the first account from the ones participating in the
+ * associated telephony conference which supports
+ * OperationSetTelephonyConferencing.
+ */
+ for (Call call : conference.getCalls())
+ {
+ ProtocolProviderService callPps = call.getProtocolProvider();
+
+ if (callPps.getOperationSet(
+ OperationSetTelephonyConferencing.class)
+ != null)
+ {
+ pps = callPps;
+ break;
+ }
+ }
+ }
+
+ if (pps != null)
+ accountSelectorBox.setSelectedItem(pps);
+ else if (accountSelectorBox.getItemCount() > 0)
+ accountSelectorBox.setSelectedIndex(0);
+ }
+
+ /**
+ * Initializes contact list sources.
+ */
+ private void initContactSources()
+ {
+ DemuxContactSourceService demuxCSService
+ = GuiActivator.getDemuxContactSourceService();
+
+ // If the DemuxContactSourceService isn't registered we use the default
+ // contact source set.
+ if (demuxCSService == null)
+ return;
+
+ Iterator<UIContactSource> sourcesIter
+ = new ArrayList<UIContactSource>(
+ srcContactList.getContactSources()).iterator();
+
+ srcContactList.removeAllContactSources();
+
+ while (sourcesIter.hasNext())
+ {
+ ContactSourceService contactSource
+ = sourcesIter.next().getContactSourceService();
+
+ srcContactList.addContactSource(
+ demuxCSService.createDemuxContactSource(contactSource));
+ }
+ }
+
+ /**
+ * Initializes the left contact list with the contacts that could be added
+ * to the current chat session.
+ * @param protocolProvider the protocol provider from which to initialize
+ * the contact list data
+ */
+ private void initContactListData(ProtocolProviderService protocolProvider)
+ {
+ this.setCurrentProvider(protocolProvider);
+
+ Iterator<UIContactSource> sourcesIter
+ = new ArrayList<UIContactSource>(
+ srcContactList.getContactSources()).iterator();
+
+ while (sourcesIter.hasNext())
+ {
+ ContactSourceService contactSource
+ = sourcesIter.next().getContactSourceService();
+
+ if (contactSource instanceof ProtocolAwareContactSourceService)
+ {
+ ((ProtocolAwareContactSourceService) contactSource)
+ .setPreferredProtocolProvider(
+ OperationSetBasicTelephony.class, protocolProvider);
+ }
+ }
+
+ srcContactList.removeContactSource(currentProviderContactSource);
+ srcContactList.removeContactSource(currentStringContactSource);
+
+ currentProviderContactSource
+ = new ProtocolContactSourceServiceImpl(
+ protocolProvider,
+ OperationSetBasicTelephony.class);
+ currentStringContactSource
+ = new StringContactSourceServiceImpl(
+ protocolProvider,
+ OperationSetBasicTelephony.class);
+
+ srcContactList.addContactSource(currentProviderContactSource);
+ srcContactList.addContactSource(currentStringContactSource);
+
+ srcContactList.applyDefaultFilter();
+ }
+
+ /**
+ * Invites the contacts to the chat conference.
+ *
+ * @param contacts the list of contacts to invite
+ */
+ private void inviteContacts(Collection<UIContact> contacts)
+ {
+ ProtocolProviderService selectedProvider;
+ Map<ProtocolProviderService, List<String>> selectedProviderCallees
+ = new HashMap<ProtocolProviderService, List<String>>();
+ List<String> callees;
+
+ Iterator<UIContact> contactsIter = contacts.iterator();
+
+ while (contactsIter.hasNext())
+ {
+ UIContact uiContact = contactsIter.next();
+
+ Iterator<UIContactDetail> contactDetailsIter = uiContact
+ .getContactDetailsForOperationSet(
+ OperationSetBasicTelephony.class).iterator();
+
+ // We invite the first protocol contact that corresponds to the
+ // invite provider.
+ if (contactDetailsIter.hasNext())
+ {
+ UIContactDetail inviteDetail = contactDetailsIter.next();
+ selectedProvider = inviteDetail
+ .getPreferredProtocolProvider(
+ OperationSetBasicTelephony.class);
+
+ if (selectedProvider == null)
+ {
+ selectedProvider
+ = (ProtocolProviderService)
+ accountSelectorBox.getSelectedItem();
+ }
+
+ if(selectedProvider != null
+ && selectedProviderCallees.get(selectedProvider) != null)
+ {
+ callees = selectedProviderCallees.get(selectedProvider);
+ }
+ else
+ {
+ callees = new ArrayList<String>();
+ }
+
+ callees.add(inviteDetail.getAddress());
+ selectedProviderCallees.put(selectedProvider, callees);
+ }
+ }
+
+ if(conference != null)
+ {
+ CallManager.inviteToConferenceCall(
+ selectedProviderCallees,
+ conference);
+ }
+ else
+ {
+ CallManager.createConferenceCall(selectedProviderCallees);
+ }
+ }
+
+ /**
+ * Invites the contacts to the chat conference.
+ *
+ * @param contacts the list of contacts to invite
+ */
+ private void inviteJitsiVideobridgeContacts(
+ ProtocolProviderService preselectedProvider,
+ Collection<UIContact> contacts)
+ {
+ List<String> callees = new ArrayList<String>();
+
+ Iterator<UIContact> contactsIter = contacts.iterator();
+
+ while (contactsIter.hasNext())
+ {
+ UIContact uiContact = contactsIter.next();
+
+ Iterator<UIContactDetail> contactDetailsIter = uiContact
+ .getContactDetailsForOperationSet(
+ OperationSetBasicTelephony.class).iterator();
+
+ // We invite the first protocol contact that corresponds to the
+ // invite provider.
+ if (contactDetailsIter.hasNext())
+ {
+ UIContactDetail inviteDetail = contactDetailsIter.next();
+
+ callees.add(inviteDetail.getAddress());
+ }
+ }
+
+ if(conference != null)
+ {
+ CallManager.inviteToJitsiVideobridgeConfCall(
+ callees.toArray(new String[callees.size()]),
+ conference.getCalls().get(0));
+ }
+ else
+ {
+ CallManager.createJitsiVideobridgeConfCall(
+ preselectedProvider,
+ callees.toArray(new String[callees.size()]));
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/conference/VideoConferenceCallPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/conference/VideoConferenceCallPanel.java
index 0dd6ef5..07c653d 100644
--- a/src/net/java/sip/communicator/impl/gui/main/call/conference/VideoConferenceCallPanel.java
+++ b/src/net/java/sip/communicator/impl/gui/main/call/conference/VideoConferenceCallPanel.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,1395 +15,1395 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.gui.main.call.conference;
-
-import java.awt.*;
-import java.util.*;
-import java.util.List;
-
-import javax.swing.*;
-
-import net.java.sip.communicator.impl.gui.main.call.*;
-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.util.*;
-import net.java.sip.communicator.plugin.desktoputil.*;
-import net.java.sip.communicator.plugin.desktoputil.TransparentPanel;
-
-import org.jitsi.util.swing.*;
-
-/**
- * Extends <tt>BasicConferenceCallPanel</tt> to implement a user interface
- * <tt>Component</tt> which depicts a <tt>CallConference</tt> with audio and
- * video and is contained in a <tt>CallPanel</tt>.
- *
- * @author Yana Stamcheva
- * @author Lyubomir Marinov
- */
-public class VideoConferenceCallPanel
- extends BasicConferenceCallPanel
-{
- /**
- * The <tt>Logger</tt> used by the <tt>VideoConferenceCallPanel</tt> class
- * and its instances for logging output.
- */
- private static final Logger logger
- = Logger.getLogger(VideoConferenceCallPanel.class);
-
- /**
- * The compile-time flag which indicates whether each video displayed by
- * <tt>VideoConferenceCallPanel</tt> is to be depicted with an associated
- * tool bar showing information and controls related to the (local or
- * remote) peer sending the respective video.
- */
- private static final boolean SHOW_TOOLBARS = true;
-
- /**
- * The facility which aids this instance with the video-related information.
- */
- private final UIVideoHandler2 uiVideoHandler;
-
- /**
- * The <tt>Observer</tt> which listens to {@link #uiVideoHandler} about
- * changes in the video-related information.
- */
- private final Observer uiVideoHandlerObserver
- = new Observer()
- {
- public void update(Observable o, Object arg)
- {
- updateViewFromModel();
- }
- };
-
- /**
- * The <tt>VideoContainer</tt> which occupies this whole <tt>Component</tt>
- * and arranges the visual <tt>Component</tt>s displaying the video
- * streaming between the local peer/user and the remote peer(s).
- */
- private final VideoContainer videoContainer;
-
- /**
- * The set of visual <tt>Component</tt>s displaying video streaming between
- * the local peer/user and the remote peers which are depicted by this
- * instance.
- */
- private final Set<Component> videos = new HashSet<Component>();
-
- /**
- * The thumbnail container.
- */
- private final ThumbnailConferenceCallPanel thumbnailContainer;
-
- private final JPanel thumbnailPanel;
-
- /**
- * Initializes a new <tt>VideoConferenceCallPanel</tt> instance which is to
- * be used by a specific <tt>CallPanel</tt> to depict a specific
- * <tt>CallConference</tt>. The new instance will depict both the
- * audio-related and the video-related information.
- *
- * @param callPanel the <tt>CallPanel</tt> which will use the new instance
- * to depict the specified <tt>CallConference</tt>.
- * @param callConference the <tt>CallConference</tt> to be depicted by the
- * new instance
- * @param uiVideoHandler the utility which is to aid the new instance in
- * dealing with the video-related information
- */
- public VideoConferenceCallPanel(
- CallPanel callPanel,
- CallConference callConference,
- UIVideoHandler2 uiVideoHandler)
- {
- super(callPanel, callConference);
-
- this.uiVideoHandler = uiVideoHandler;
-
- thumbnailPanel = new JPanel(new BorderLayout());
- thumbnailContainer
- = new ThumbnailConferenceCallPanel( callPanel,
- callConference,
- uiVideoHandler);
-
- videoContainer = createVideoContainer();
-
- /*
- * Our user interface hierarchy has been initialized so we are ready to
- * begin receiving events warranting updates of this view from its
- * model.
- */
- uiVideoHandler.addObserver(uiVideoHandlerObserver);
-
- /*
- * Notify the super that this instance has completed its initialization
- * and the view that it implements is ready to be updated from the
- * model.
- */
- initializeComplete();
- }
-
- private void addConferenceMemberContainers(
- ConferenceParticipantContainer cpc)
- {
- List<ConferenceParticipantContainer> cmcs
- = cpc.conferenceMemberContainers;
-
- if ((cmcs != null) && !cmcs.isEmpty())
- {
- for (ConferenceParticipantContainer cmc : cmcs)
- {
- if (!cmc.toBeRemoved)
- {
- videoContainer.add(
- cmc.getComponent(),
- VideoLayout.CENTER_REMOTE);
- }
- }
- }
- }
-
- private Component createDefaultPhotoPanel(Call call)
- {
- OperationSetServerStoredAccountInfo accountInfo
- = call.getProtocolProvider().getOperationSet(
- OperationSetServerStoredAccountInfo.class);
- ImageIcon photoLabelIcon = null;
-
- if (accountInfo != null)
- {
- byte[] accountImage = AccountInfoUtils.getImage(accountInfo);
-
- // do not set empty images
- if ((accountImage != null) && (accountImage.length > 0))
- photoLabelIcon = new ImageIcon(accountImage);
- }
- if (photoLabelIcon == null)
- {
- photoLabelIcon
- = new ImageIcon(
- ImageLoader.getImage(ImageLoader.DEFAULT_USER_PHOTO));
- }
-
- return createDefaultPhotoPanel(photoLabelIcon);
- }
-
- private Component createDefaultPhotoPanel(CallPeer callPeer)
- {
- byte[] peerImage = CallManager.getPeerImage(callPeer);
- ImageIcon photoLabelIcon
- = (peerImage == null)
- ? new ImageIcon(
- ImageLoader.getImage(ImageLoader.DEFAULT_USER_PHOTO))
- : new ImageIcon(peerImage);
-
- return createDefaultPhotoPanel(photoLabelIcon);
- }
-
- private Component createDefaultPhotoPanel(ConferenceMember conferenceMember)
- {
- return
- createDefaultPhotoPanel(
- new ImageIcon(
- ImageLoader.getImage(
- ImageLoader.DEFAULT_USER_PHOTO)));
- }
-
- /**
- * Creates a new <tt>Component</tt> which is to display a specific
- * <tt>ImageIcon</tt> representing the photo of a participant in a call.
- *
- * @param photoLabelIcon the <tt>ImageIcon</tt> which represents the photo
- * of a participant in a call and which is to be displayed by the new
- * <tt>Component</tt>
- * @return a new <tt>Component</tt> which displays the specified
- * <tt>photoLabelIcon</tt>
- */
- private Component createDefaultPhotoPanel(ImageIcon photoLabelIcon)
- {
- JLabel photoLabel = new JLabel();
-
- photoLabel.setIcon(photoLabelIcon);
-
- @SuppressWarnings("serial")
- JPanel photoPanel
- = new TransparentPanel(new GridBagLayout())
- {
- /**
- * @{inheritDoc}
- */
- @Override
- public void paintComponent(Graphics g)
- {
- super.paintComponent(g);
-
- g = g.create();
- try
- {
- AntialiasingManager.activateAntialiasing(g);
-
- g.setColor(Color.GRAY);
- g.fillRoundRect(
- 0, 0, this.getWidth(), this.getHeight(),
- 6, 6);
- }
- finally
- {
- g.dispose();
- }
- }
- };
-
- photoPanel.setPreferredSize(new Dimension(320, 240));
-
- GridBagConstraints photoPanelConstraints = new GridBagConstraints();
-
- photoPanelConstraints.anchor = GridBagConstraints.CENTER;
- photoPanelConstraints.fill = GridBagConstraints.NONE;
- photoPanel.add(photoLabel, photoPanelConstraints);
-
- return photoPanel;
- }
-
- /**
- * Initializes a new <tt>VideoContainer</tt> instance which is to contain
- * the visual/video <tt>Component</tt>s of the telephony conference depicted
- * by this instance.
- */
- private VideoContainer createVideoContainer()
- {
- VideoContainer videoContainer = new VideoContainer(null, true);
-
- thumbnailPanel.setBackground(Color.DARK_GRAY);
- thumbnailPanel.add(thumbnailContainer, BorderLayout.NORTH);
-
- add(thumbnailPanel, BorderLayout.EAST);
- add(videoContainer, BorderLayout.CENTER);
-
- return videoContainer;
- }
-
- /**
- * Shows/hides the participants thumbnails list.
- *
- * @param show <tt>true</tt> to show the participants list, <tt>false</tt>
- * to hide it
- */
- public void showThumbnailsList(boolean show)
- {
- thumbnailPanel.setVisible(show);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void dispose()
- {
- try
- {
- uiVideoHandler.deleteObserver(uiVideoHandlerObserver);
- }
- finally
- {
- super.dispose();
- }
- }
-
- /**
- * Determines whether a specific <tt>ConferenceMember</tt> represents the
- * same conference participant as a specific <tt>CallPeer</tt>. If the
- * specified <tt>conferenceMember</tt> is <tt>null</tt>, returns
- * <tt>true</tt>. Otherwise, determines whether the addresses of the
- * specified <tt>conferenceMember</tt> and the specified <tt>callPeer</tt>
- * identify one and the same entity.
- *
- * @param conferenceMember the <tt>ConferenceMember</tt> to be checked
- * whether is represents the same conference participant as the specified
- * <tt>callPeer</tt>. If it is <tt>null</tt>, <tt>true</tt> is returned.
- * @param callPeer the <tt>CallPeer</tt> to be checked whether it represents
- * the same conference participant as the specified
- * <tt>conferenceMember</tt>
- * @return <tt>true</tt> if the specified <tt>conferenceMember</tt> and the
- * specified <tt>callPeer</tt> represent the same conference participant or
- * the specified <tt>conferenceMember</tt> is <tt>null</tt>; otherwise,
- * <tt>false</tt>
- */
- private boolean isConferenceMemberCallPeer(
- ConferenceMember conferenceMember,
- CallPeer callPeer)
- {
- return
- (conferenceMember == null)
- ? true
- : CallManager.addressesAreEqual(
- conferenceMember.getAddress(),
- callPeer.getAddress());
- }
-
- /**
- * Determines whether a specific <tt>ConferenceMember</tt> represents the
- * local peer/user. Since this instance depicts a whole telephony
- * conference, the local peer/user may be participating with multiple
- * <tt>Call</tt>s in it. The <tt>Call</tt>s may be through different
- * (local) accounts. That's why the implementation determines whether the
- * address of the specified <tt>conferenceMember</tt> identifies the address
- * of a (local) accounts involved in the telephony conference depicted by
- * this instance.
- *
- * @param conferenceMember the <tt>ConferenceMember</tt> to be checked
- * whether it represents the local peer/user
- * @return <tt>true</tt> if the specified <tt>conferenceMember</tt>
- * represents the local peer/user; otherwise, <tt>false</tt>
- */
- private boolean isConferenceMemberLocalUser(
- ConferenceMember conferenceMember)
- {
- String address = conferenceMember.getAddress();
-
- for (Call call : callConference.getCalls())
- {
- if (CallManager.addressesAreEqual(
- address,
- call.getProtocolProvider().getAccountID()
- .getAccountAddress()))
- {
- return true;
- }
- }
- return false;
- }
-
- private void removeConferenceMemberContainers(
- ConferenceParticipantContainer cpc,
- boolean all)
- {
- List<ConferenceParticipantContainer> cmcs
- = cpc.conferenceMemberContainers;
-
- if ((cmcs != null) && !cmcs.isEmpty())
- {
- Iterator<ConferenceParticipantContainer> i = cmcs.iterator();
-
- while (i.hasNext())
- {
- ConferenceParticipantContainer cmc = i.next();
-
- if (all || cmc.toBeRemoved)
- {
- i.remove();
-
- videoContainer.remove(cmc.getComponent());
- cmc.dispose();
- }
- }
- }
- }
-
- /**
- * Updates the <tt>ConferenceParticipantContainer</tt>s which depict the
- * <tt>ConferenceMember</tt>s of the <tt>CallPeer</tt> depicted by a
- * specific <tt>ConferenceParticipantContainer</tt>.
- *
- * @param cpc the <tt>ConferenceParticipantContainer</tt> which depicts the
- * <tt>CallPeer</tt> whose <tt>ConferenceMember</tt>s are to be depicted
- * @param videos the visual <tt>Component</tt>s displaying video streaming
- * from the remote peer (represented by <tt>cpc</tt>) to the local peer/user
- * @param videoTelephony the <tt>OperationSetVideoTelephony</tt> which
- * retrieved the specified <tt>videos</tt> from the <tt>CallPeer</tt>
- * depicted by <tt>cpc</tt>. While the <tt>CallPeer</tt> could be queried
- * for it, such a query would waste more resources at run time given that
- * the invoker has it already.
- */
- private void updateConferenceMemberContainers(
- ConferenceParticipantContainer cpc,
- List<Component> videos,
- OperationSetVideoTelephony videoTelephony)
- {
- CallPeer callPeer = (CallPeer) cpc.getParticipant();
- List<ConferenceParticipantContainer> cmcs
- = cpc.conferenceMemberContainers;
-
- /*
- * Invalidate all conferenceMemberContainers. Then validate which of
- * them are to remain and which of them are to really be removed
- * later on.
- */
- if (cmcs != null)
- {
- for (ConferenceParticipantContainer cmc : cmcs)
- cmc.toBeRemoved = true;
- }
-
- /*
- * Depict the remote videos. They may or may not be associated with
- * ConferenceMembers so the ConferenceMembers which have no
- * associated videos will be depicted afterwards.
- */
- if (videos != null)
- {
- Component video = cpc.getVideo();
-
- for (Component conferenceMemberVideo : videos)
- {
- /*
- * One of the remote videos is already used to depict the
- * callPeer.
- */
- if (conferenceMemberVideo == video)
- continue;
-
- boolean addNewConferenceParticipantContainer = true;
- ConferenceMember conferenceMember
- = videoTelephony.getConferenceMember(
- callPeer,
- conferenceMemberVideo);
-
- if (cmcs == null)
- {
- cmcs = new LinkedList<ConferenceParticipantContainer>();
- cpc.conferenceMemberContainers = cmcs;
- }
- else
- {
- for (ConferenceParticipantContainer cmc : cmcs)
- {
- Object cmcParticipant = cmc.getParticipant();
-
- if (conferenceMember == null)
- {
- if (cmcParticipant == callPeer)
- {
- Component cmcVideo = cmc.getVideo();
-
- if (cmcVideo == null)
- {
- cmc.setVideo(conferenceMemberVideo);
- cmc.toBeRemoved = false;
- addNewConferenceParticipantContainer
- = false;
- break;
- }
- else if (cmcVideo == conferenceMemberVideo)
- {
- cmc.toBeRemoved = false;
- addNewConferenceParticipantContainer
- = false;
- break;
- }
- }
- }
- else if (cmcParticipant == conferenceMember)
- {
- cmc.setVideo(conferenceMemberVideo);
- cmc.toBeRemoved = false;
- addNewConferenceParticipantContainer = false;
- break;
- }
- }
- }
-
- if (addNewConferenceParticipantContainer)
- {
- ConferenceParticipantContainer cmc
- = (conferenceMember == null)
- ? new ConferenceParticipantContainer(
- callPeer,
- conferenceMemberVideo)
- : new ConferenceParticipantContainer(
- conferenceMember,
- conferenceMemberVideo);
-
- cmcs.add(cmc);
- }
- }
- }
-
- /*
- * Depict the ConferenceMembers which have not been depicted yet.
- * They have no associated videos.
- */
- List<ConferenceMember> conferenceMembers
- = callPeer.getConferenceMembers();
-
- if (!conferenceMembers.isEmpty())
- {
- if (cmcs == null)
- {
- cmcs = new LinkedList<ConferenceParticipantContainer>();
- cpc.conferenceMemberContainers = cmcs;
- }
- for (ConferenceMember conferenceMember : conferenceMembers)
- {
- /*
- * If the callPeer reports itself as a ConferenceMember, then
- * we've already depicted it with cpc.
- */
- if (isConferenceMemberCallPeer(conferenceMember, callPeer))
- continue;
- /*
- * If the callPeer reports the local peer/user as a
- * ConferenceMember, then we've already depicted it.
- */
- if (isConferenceMemberLocalUser(conferenceMember))
- continue;
-
- boolean addNewConferenceParticipantContainer = true;
-
- for (ConferenceParticipantContainer cmc : cmcs)
- {
- if (cmc.getParticipant() == conferenceMember)
- {
- /*
- * It is possible to have a ConferenceMember who is
- * sending video but we just do not have the SSRC of
- * that video to associate the video with the
- * ConferenceMember. In such a case, we may be depicting
- * the ConferenceMember twice: once with video without a
- * ConferenceMember and once with a ConferenceMember
- * without video. This will surely be the case at the
- * time of this writing with non-focus participants in a
- * telephony conference hosted on a Jitsi Videobridge.
- * Such a display is undesirable. If the
- * conferenceMember is known to send video, we will not
- * display it until we associated it with a video. This
- * way, if a ConferenceMember is not sending video, we
- * will depict it and we can be sure that no video
- * without a ConferenceMember association will be
- * depicting it a second time.
- */
- if (cmc.toBeRemoved
- && !conferenceMember
- .getVideoStatus()
- .allowsSending())
- {
- cmc.setVideo(null);
- cmc.toBeRemoved = false;
- }
- addNewConferenceParticipantContainer = false;
- break;
- }
- }
-
- if (addNewConferenceParticipantContainer)
- {
- ConferenceParticipantContainer cmc
- = new ConferenceParticipantContainer(
- conferenceMember,
- null);
-
- cmcs.add(cmc);
- }
- }
- }
-
- if ((cmcs != null) && !cmcs.isEmpty())
- {
- removeConferenceMemberContainers(cpc, false);
- /*
- * If cpc is already added to the user interface hierarchy of this
- * instance, then it was there before the update procedure and it
- * was determined to be appropriate to continue to depict its model.
- * Consequently, its Component will be neither added to (because it
- * was already added) nor removed from the user interface hierarchy
- * of this instance. That's why we have make sure that the
- * Components of its conferenceMemberContainers are also added to
- * the user interface.
- */
- if (UIVideoHandler2.isAncestor(this, cpc.getComponent()))
- addConferenceMemberContainers(cpc);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected ConferenceCallPeerRenderer updateViewFromModel(
- ConferenceCallPeerRenderer callPeerPanel,
- CallPeer callPeer)
- {
- if (callPeer == null)
- {
- /*
- * The local peer/user will be represented by a Call which has a
- * CallPeer who provides local video. However, if the user has
- * selected to hide the local video, the local peer/user will not be
- * represented at all.
- */
- Component video = null;
-
- if (uiVideoHandler.isLocalVideoVisible())
- {
- for (Call aCall : callConference.getCalls())
- {
- Iterator<? extends CallPeer> callPeerIter
- = aCall.getCallPeers();
- OperationSetVideoTelephony videoTelephony
- = aCall.getProtocolProvider().getOperationSet(
- OperationSetVideoTelephony.class);
-
- while (callPeerIter.hasNext())
- {
- callPeer = callPeerIter.next();
-
- if (videoTelephony != null)
- {
- try
- {
- video
- = videoTelephony.getLocalVisualComponent(
- callPeer);
- }
- catch (OperationFailedException ofe)
- {
- logger.error(
- "Failed to retrieve the local video"
- + " for display",
- ofe);
- }
- if (video != null)
- break;
- }
- }
- if (video != null)
- break;
- }
- }
-
- if (callPeer == null)
- callPeerPanel = null;
- else
- {
- Call call = callPeer.getCall();
-
- if (callPeerPanel instanceof ConferenceParticipantContainer)
- {
- ConferenceParticipantContainer cpc
- = (ConferenceParticipantContainer) callPeerPanel;
-
- if (cpc.getParticipant() == call)
- cpc.setVideo(video);
- else
- callPeerPanel = null;
- }
- else
- callPeerPanel = null;
- if (callPeerPanel == null)
- {
- callPeerPanel
- = new ConferenceParticipantContainer(call, video);
- }
- }
- }
- else
- {
- /*
- * The specified callPeer will be represented by one of its remote
- * videos which is not associated with a ConferenceMember or is
- * associated with a ConferenceMember representing the callPeer
- * itself.
- */
- OperationSetVideoTelephony videoTelephony
- = callPeer.getProtocolProvider().getOperationSet(
- OperationSetVideoTelephony.class);
- List<Component> videos = null;
- Component video = null;
-
- if (videoTelephony != null)
- {
- videos = videoTelephony.getVisualComponents(callPeer);
- if ((videos != null) && !videos.isEmpty())
- {
- for (Component aVideo : videos)
- {
- ConferenceMember conferenceMember
- = videoTelephony.getConferenceMember(
- callPeer,
- aVideo);
-
- if (isConferenceMemberCallPeer(
- conferenceMember,
- callPeer))
- {
- video = aVideo;
- break;
- }
- }
- }
- }
-
- ConferenceParticipantContainer cpc = null;
-
- if (callPeerPanel instanceof ConferenceParticipantContainer)
- {
- cpc = (ConferenceParticipantContainer) callPeerPanel;
- if (cpc.getParticipant() == callPeer)
- cpc.setVideo(video);
- else
- cpc = null;
- }
- if (cpc == null)
- cpc = new ConferenceParticipantContainer(callPeer, video);
- callPeerPanel = cpc;
-
- // Update the conferenceMemberContainers of the cpc.
- updateConferenceMemberContainers(cpc, videos, videoTelephony);
- }
- return callPeerPanel;
- }
-
- /**
- * {@inheritDoc}
- *
- * If {@link #SHOW_TOOLBARS} is <tt>false</tt>, disables the use of
- * <tt>ConferenceParticipantContainer</tt>. A reason for such a value of
- * <tt>SHOW_TOOLBARS</tt> may be that the functionality implemented in the
- * model may not fully support mapping of visual <tt>Component</tt>s
- * displaying video to telephony conference participants (e.g. in telephony
- * conferences utilizing the Jitsi Videobridge server-side technology). In
- * such a case displays the videos only, does not map videos to participants
- * and does not display participants who do not have videos.
- */
- @Override
- protected void updateViewFromModelInEventDispatchThread()
- {
- if (SHOW_TOOLBARS)
- {
- super.updateViewFromModelInEventDispatchThread();
- return;
- }
-
- /*
- * Determine the set of visual Components displaying video streaming
- * between the local peer/user and the remote peers which are to be
- * depicted by this instance.
- */
- Component localVideo = null;
- Set<Component> videos = new HashSet<Component>();
-
- for (Call call : callConference.getCalls())
- {
- OperationSetVideoTelephony videoTelephony
- = call.getProtocolProvider().getOperationSet(
- OperationSetVideoTelephony.class);
-
- if (videoTelephony == null)
- continue;
-
- Iterator<? extends CallPeer> callPeerIter = call.getCallPeers();
-
- while (callPeerIter.hasNext())
- {
- CallPeer callPeer = callPeerIter.next();
-
- /*
- * TODO VideoConferenceCallPanel respects
- * UIVideoHandler2.isLocalVideoVisible() in order to react to
- * the associated button at the bottom of the CallPanel.
- * However, it does not add a close button on top of the local
- * video in contrast to OneToOneCallPeerPanel. Overall, the
- * result is questionable.
- */
- if (uiVideoHandler.isLocalVideoVisible()
- && (localVideo == null))
- {
- try
- {
- localVideo
- = videoTelephony.getLocalVisualComponent(callPeer);
- }
- catch (OperationFailedException ofe)
- {
- /*
- * We'll just try to get the local video through another
- * CallPeer then.
- */
- }
- if (localVideo != null)
- videos.add(localVideo);
- }
-
- List<Component> callPeerRemoteVideos
- = videoTelephony.getVisualComponents(callPeer);
-
- videos.addAll(callPeerRemoteVideos);
- }
- }
-
- /*
- * Remove the Components of this view which are no longer present in the
- * model.
- */
- Iterator<Component> thisVideoIter = this.videos.iterator();
-
- while (thisVideoIter.hasNext())
- {
- Component thisVideo = thisVideoIter.next();
-
- if (!videos.contains(thisVideo))
- {
- thisVideoIter.remove();
- videoContainer.remove(thisVideo);
- }
-
- /*
- * If a video is known to be depicted by this view and is still
- * present in the model, then we could remove it from the set of
- * videos present in the model in order to prevent going through the
- * procedure of adding it to this view. However, we choose to play
- * on the safe side.
- */
- }
-
- /*
- * Add the Components of the model which are not depicted by this view.
- */
- for (Component video : videos)
- {
- if (!UIVideoHandler2.isAncestor(videoContainer, video))
- {
- this.videos.add(video);
- videoContainer.add(
- video,
- (video == localVideo)
- ? VideoLayout.LOCAL
- : VideoLayout.CENTER_REMOTE);
- }
- }
- }
-
- @Override
- protected void viewForModelAdded(
- ConferenceCallPeerRenderer callPeerPanel,
- CallPeer callPeer)
- {
- videoContainer.add(
- callPeerPanel.getComponent(),
- VideoLayout.CENTER_REMOTE);
- if ((callPeer != null)
- && (callPeerPanel instanceof ConferenceParticipantContainer))
- {
- addConferenceMemberContainers(
- (ConferenceParticipantContainer) callPeerPanel);
- }
- }
-
- @Override
- protected void viewForModelRemoved(
- ConferenceCallPeerRenderer callPeerPanel,
- CallPeer callPeer)
- {
- videoContainer.remove(callPeerPanel.getComponent());
- if ((callPeer != null)
- && (callPeerPanel instanceof ConferenceParticipantContainer))
- {
- removeConferenceMemberContainers(
- (ConferenceParticipantContainer) callPeerPanel,
- true);
- }
- }
-
- /**
- * Implements an AWT <tt>Component</tt> which contains the user interface
- * elements depicting a specific participant in the telephony conference
- * depicted by a <tt>VideoConferenceCallPanel</tt>.
- */
- private class ConferenceParticipantContainer
- extends TransparentPanel
- implements ConferenceCallPeerRenderer
- {
- /**
- * The list of <tt>ConferenceParticipantContainer</tt>s which represent
- * the <tt>ConferenceMember</tt>s of the participant represented by this
- * instance. Since a <tt>CallPeer</tt> may send the local peer/user
- * multiple videos without providing a way to associate a
- * ConferenceMember with each one of them, the list may contain
- * <tt>ConferenceParticipantContainer</tt>s which do not represent a
- * specific <tt>ConferenceMember</tt> instance but rather a video sent
- * by a <tt>CallPeer</tt> to the local peer/user which looks like (in
- * the terms of <tt>VideoConferenceCallPanel) a member of a conference
- * organized by the <tt>CallPeer</tt> in question.
- * <p>
- * Implements a state which is private to
- * <tt>VideoConferenceCallPanel</tt> and is of no concern to
- * <tt>ConferenceParticipantContainer</tt>.
- * </p>
- */
- List<ConferenceParticipantContainer> conferenceMemberContainers;
-
- /**
- * The indicator which determines whether this instance is to be removed
- * because it has become out-of-date, obsolete, unnecessary.
- * <p>
- * Implements a state which is private to
- * <tt>VideoConferenceCallPanel</tt> and is of no concern to
- * <tt>ConferenceParticipantContainer</tt>.
- * </p>
- */
- boolean toBeRemoved;
-
- /**
- * The <tt>BasicConferenceParticipantPanel</tt> which is displayed at
- * the bottom of this instance, bellow the {@link #video} (i.e.
- * {@link #videoContainer}) and is referred to as the tool bar.
- */
- private final BasicConferenceParticipantPanel<?> toolBar;
-
- /**
- * The visual <tt>Component</tt>, if any, displaying video which is
- * depicted by this instance.
- */
- private Component video;
-
- /**
- * The <tt>VideoContainer</tt> which lays out the video depicted by this
- * instance i.e. {@link #video}.
- */
- private final VideoContainer videoContainer;
-
- /**
- * The <tt>CallPeer</tt> associated with this container, if it has been
- * created to represent a <tt>CallPeer</tt>.
- */
- private CallPeer callPeer;
-
- /**
- * The <tt>conferenceMember</tt> associated with this container, if it
- * has been created to represent a <tt>conferenceMember</tt>.
- */
- private ConferenceMember conferenceMember;
-
- /**
- * Indicates that this container contains information for the local
- * user.
- */
- private boolean isLocalUser;
-
- /**
- * Initializes a new <tt>ConferenceParticipantContainer</tt> instance
- * which is to depict the local peer/user.
- *
- * @param call a <tt>Call</tt> which is to provide information about the
- * local peer/user
- * @param video the visual <tt>Component</tt>, if any, displaying the
- * video streaming from the local peer/user to the remote peer(s)
- */
- public ConferenceParticipantContainer(Call call, Component video)
- {
- this(
- createDefaultPhotoPanel(call),
- video,
- new ConferencePeerPanel(
- VideoConferenceCallPanel.this,
- call,
- true),
- null, null, true);
- }
-
- public ConferenceParticipantContainer(
- CallPeer callPeer,
- Component video)
- {
- this( createDefaultPhotoPanel(callPeer),
- video,
- new ConferencePeerPanel(
- VideoConferenceCallPanel.this,
- callPeer,
- true),
- callPeer, null, false);
- }
-
- private ConferenceParticipantContainer(
- Component noVideo,
- Component video,
- BasicConferenceParticipantPanel<?> toolBar,
- CallPeer callPeer,
- ConferenceMember conferenceMember,
- boolean isLocalUser)
- {
- super(new BorderLayout());
-
- this.callPeer = callPeer;
- this.conferenceMember = conferenceMember;
- this.isLocalUser = isLocalUser;
-
- videoContainer = new VideoContainer(noVideo, false);
- add(videoContainer, BorderLayout.CENTER);
-
- this.toolBar = toolBar;
- if (this.toolBar != null)
- add(this.toolBar, BorderLayout.SOUTH);
-
- if (video != null)
- {
- setVideo(video);
- }
- else
- setVisible(false);
- }
-
- public ConferenceParticipantContainer(
- ConferenceMember conferenceMember,
- Component video)
- {
- this(
- createDefaultPhotoPanel(conferenceMember),
- video,
- new ConferenceMemberPanel(
- VideoConferenceCallPanel.this,
- conferenceMember,
- true),
- null, conferenceMember, false);
- }
-
- public void dispose()
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.dispose();
-
- // Dispose of the conferenceMemberContainers if any.
- /*
- * XXX The field conferenceMemberContainers implements a state
- * private to VideoConferenceCallPanel which the latter makes sure
- * to access on the AWT event dispatching thread only. Since we are
- * going out of our way here to help VideoConferenceCallPanel,
- * ensure that the mentioned synchronization rule is not violated.
- */
- CallManager.assertIsEventDispatchingThread();
- if (conferenceMemberContainers != null)
- {
- for (ConferenceParticipantContainer cmc
- : conferenceMemberContainers)
- {
- cmc.dispose();
- }
- }
- }
-
- public CallPanel getCallPanel()
- {
- return getCallRenderer().getCallContainer();
- }
-
- public SwingCallRenderer getCallRenderer()
- {
- return VideoConferenceCallPanel.this;
- }
-
- public Component getComponent()
- {
- return this;
- }
-
- private ConferenceCallPeerRenderer
- getConferenceCallPeerRendererDelegate()
- {
- return
- (toolBar instanceof ConferenceCallPeerRenderer)
- ? (ConferenceCallPeerRenderer) toolBar
- : null;
- }
-
- /**
- * Gets the conference participant depicted by this instance.
- *
- * @return the conference participant depicted by this instance
- */
- public Object getParticipant()
- {
- return (toolBar == null) ? null : toolBar.getParticipant();
- }
-
- public Component getVideo()
- {
- return video;
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only. Otherwise, returns <tt>false</tt>.
- */
- public boolean isLocalVideoVisible()
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- return (delegate == null) ? false : delegate.isLocalVideoVisible();
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void printDTMFTone(char dtmfChar)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.printDTMFTone(dtmfChar);
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void securityNegotiationStarted(
- CallPeerSecurityNegotiationStartedEvent ev)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.securityNegotiationStarted(ev);
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void securityOff(CallPeerSecurityOffEvent ev)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.securityOff(ev);
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void securityOn(CallPeerSecurityOnEvent ev)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.securityOn(ev);
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void securityPending()
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.securityPending();
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void securityTimeout(CallPeerSecurityTimeoutEvent ev)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.securityTimeout(ev);
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void setErrorReason(String reason)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.setErrorReason(reason);
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void setLocalVideoVisible(boolean visible)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.setLocalVideoVisible(visible);
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void setMute(boolean mute)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.setMute(mute);
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void setOnHold(boolean onHold)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.setOnHold(onHold);
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void setPeerImage(byte[] image)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.setPeerImage(image);
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void setPeerName(String name)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.setPeerName(name);
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void setPeerState(
- CallPeerState oldState,
- CallPeerState newState,
- String stateString)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.setPeerState(oldState, newState, stateString);
- }
-
- /**
- * {@inheritDoc}
- *
- * Delegates to the <tt>toolBar</tt>, if the latter implements
- * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
- * container only.
- */
- public void setSecurityPanelVisible(boolean visible)
- {
- ConferenceCallPeerRenderer delegate
- = getConferenceCallPeerRendererDelegate();
-
- if (delegate != null)
- delegate.setSecurityPanelVisible(visible);
- }
-
- /**
- * Sets the visual <tt>Component</tt> displaying the video associated
- * with the participant depicted by this instance.
- *
- * @param video the visual <tt>Component</tt> displaying video which is
- * to be associated with the participant depicted by this instance
- */
- void setVideo(Component video)
- {
- if (this.video != video)
- {
- if (this.video != null)
- videoContainer.remove(this.video);
-
- this.video = video;
-
- if (this.video != null)
- {
- setVisible(true);
- videoContainer.add(this.video, VideoLayout.CENTER_REMOTE);
- }
- else
- setVisible(false);
-
- // Update thumbnails container according to video status.
- if (thumbnailContainer != null)
- {
- if (conferenceMember != null)
- thumbnailContainer
- .updateThumbnail(conferenceMember, (video != null));
- else if (callPeer != null)
- thumbnailContainer
- .updateThumbnail(callPeer, (video != null));
- else if (isLocalUser)
- thumbnailContainer
- .updateThumbnail((video != null));
- }
- }
- }
- }
-}
+package net.java.sip.communicator.impl.gui.main.call.conference;
+
+import java.awt.*;
+import java.util.*;
+import java.util.List;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.impl.gui.main.call.*;
+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.util.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
+import net.java.sip.communicator.plugin.desktoputil.TransparentPanel;
+
+import org.jitsi.util.swing.*;
+
+/**
+ * Extends <tt>BasicConferenceCallPanel</tt> to implement a user interface
+ * <tt>Component</tt> which depicts a <tt>CallConference</tt> with audio and
+ * video and is contained in a <tt>CallPanel</tt>.
+ *
+ * @author Yana Stamcheva
+ * @author Lyubomir Marinov
+ */
+public class VideoConferenceCallPanel
+ extends BasicConferenceCallPanel
+{
+ /**
+ * The <tt>Logger</tt> used by the <tt>VideoConferenceCallPanel</tt> class
+ * and its instances for logging output.
+ */
+ private static final Logger logger
+ = Logger.getLogger(VideoConferenceCallPanel.class);
+
+ /**
+ * The compile-time flag which indicates whether each video displayed by
+ * <tt>VideoConferenceCallPanel</tt> is to be depicted with an associated
+ * tool bar showing information and controls related to the (local or
+ * remote) peer sending the respective video.
+ */
+ private static final boolean SHOW_TOOLBARS = true;
+
+ /**
+ * The facility which aids this instance with the video-related information.
+ */
+ private final UIVideoHandler2 uiVideoHandler;
+
+ /**
+ * The <tt>Observer</tt> which listens to {@link #uiVideoHandler} about
+ * changes in the video-related information.
+ */
+ private final Observer uiVideoHandlerObserver
+ = new Observer()
+ {
+ public void update(Observable o, Object arg)
+ {
+ updateViewFromModel();
+ }
+ };
+
+ /**
+ * The <tt>VideoContainer</tt> which occupies this whole <tt>Component</tt>
+ * and arranges the visual <tt>Component</tt>s displaying the video
+ * streaming between the local peer/user and the remote peer(s).
+ */
+ private final VideoContainer videoContainer;
+
+ /**
+ * The set of visual <tt>Component</tt>s displaying video streaming between
+ * the local peer/user and the remote peers which are depicted by this
+ * instance.
+ */
+ private final Set<Component> videos = new HashSet<Component>();
+
+ /**
+ * The thumbnail container.
+ */
+ private final ThumbnailConferenceCallPanel thumbnailContainer;
+
+ private final JPanel thumbnailPanel;
+
+ /**
+ * Initializes a new <tt>VideoConferenceCallPanel</tt> instance which is to
+ * be used by a specific <tt>CallPanel</tt> to depict a specific
+ * <tt>CallConference</tt>. The new instance will depict both the
+ * audio-related and the video-related information.
+ *
+ * @param callPanel the <tt>CallPanel</tt> which will use the new instance
+ * to depict the specified <tt>CallConference</tt>.
+ * @param callConference the <tt>CallConference</tt> to be depicted by the
+ * new instance
+ * @param uiVideoHandler the utility which is to aid the new instance in
+ * dealing with the video-related information
+ */
+ public VideoConferenceCallPanel(
+ CallPanel callPanel,
+ CallConference callConference,
+ UIVideoHandler2 uiVideoHandler)
+ {
+ super(callPanel, callConference);
+
+ this.uiVideoHandler = uiVideoHandler;
+
+ thumbnailPanel = new JPanel(new BorderLayout());
+ thumbnailContainer
+ = new ThumbnailConferenceCallPanel( callPanel,
+ callConference,
+ uiVideoHandler);
+
+ videoContainer = createVideoContainer();
+
+ /*
+ * Our user interface hierarchy has been initialized so we are ready to
+ * begin receiving events warranting updates of this view from its
+ * model.
+ */
+ uiVideoHandler.addObserver(uiVideoHandlerObserver);
+
+ /*
+ * Notify the super that this instance has completed its initialization
+ * and the view that it implements is ready to be updated from the
+ * model.
+ */
+ initializeComplete();
+ }
+
+ private void addConferenceMemberContainers(
+ ConferenceParticipantContainer cpc)
+ {
+ List<ConferenceParticipantContainer> cmcs
+ = cpc.conferenceMemberContainers;
+
+ if ((cmcs != null) && !cmcs.isEmpty())
+ {
+ for (ConferenceParticipantContainer cmc : cmcs)
+ {
+ if (!cmc.toBeRemoved)
+ {
+ videoContainer.add(
+ cmc.getComponent(),
+ VideoLayout.CENTER_REMOTE);
+ }
+ }
+ }
+ }
+
+ private Component createDefaultPhotoPanel(Call call)
+ {
+ OperationSetServerStoredAccountInfo accountInfo
+ = call.getProtocolProvider().getOperationSet(
+ OperationSetServerStoredAccountInfo.class);
+ ImageIcon photoLabelIcon = null;
+
+ if (accountInfo != null)
+ {
+ byte[] accountImage = AccountInfoUtils.getImage(accountInfo);
+
+ // do not set empty images
+ if ((accountImage != null) && (accountImage.length > 0))
+ photoLabelIcon = new ImageIcon(accountImage);
+ }
+ if (photoLabelIcon == null)
+ {
+ photoLabelIcon
+ = new ImageIcon(
+ ImageLoader.getImage(ImageLoader.DEFAULT_USER_PHOTO));
+ }
+
+ return createDefaultPhotoPanel(photoLabelIcon);
+ }
+
+ private Component createDefaultPhotoPanel(CallPeer callPeer)
+ {
+ byte[] peerImage = CallManager.getPeerImage(callPeer);
+ ImageIcon photoLabelIcon
+ = (peerImage == null)
+ ? new ImageIcon(
+ ImageLoader.getImage(ImageLoader.DEFAULT_USER_PHOTO))
+ : new ImageIcon(peerImage);
+
+ return createDefaultPhotoPanel(photoLabelIcon);
+ }
+
+ private Component createDefaultPhotoPanel(ConferenceMember conferenceMember)
+ {
+ return
+ createDefaultPhotoPanel(
+ new ImageIcon(
+ ImageLoader.getImage(
+ ImageLoader.DEFAULT_USER_PHOTO)));
+ }
+
+ /**
+ * Creates a new <tt>Component</tt> which is to display a specific
+ * <tt>ImageIcon</tt> representing the photo of a participant in a call.
+ *
+ * @param photoLabelIcon the <tt>ImageIcon</tt> which represents the photo
+ * of a participant in a call and which is to be displayed by the new
+ * <tt>Component</tt>
+ * @return a new <tt>Component</tt> which displays the specified
+ * <tt>photoLabelIcon</tt>
+ */
+ private Component createDefaultPhotoPanel(ImageIcon photoLabelIcon)
+ {
+ JLabel photoLabel = new JLabel();
+
+ photoLabel.setIcon(photoLabelIcon);
+
+ @SuppressWarnings("serial")
+ JPanel photoPanel
+ = new TransparentPanel(new GridBagLayout())
+ {
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public void paintComponent(Graphics g)
+ {
+ super.paintComponent(g);
+
+ g = g.create();
+ try
+ {
+ AntialiasingManager.activateAntialiasing(g);
+
+ g.setColor(Color.GRAY);
+ g.fillRoundRect(
+ 0, 0, this.getWidth(), this.getHeight(),
+ 6, 6);
+ }
+ finally
+ {
+ g.dispose();
+ }
+ }
+ };
+
+ photoPanel.setPreferredSize(new Dimension(320, 240));
+
+ GridBagConstraints photoPanelConstraints = new GridBagConstraints();
+
+ photoPanelConstraints.anchor = GridBagConstraints.CENTER;
+ photoPanelConstraints.fill = GridBagConstraints.NONE;
+ photoPanel.add(photoLabel, photoPanelConstraints);
+
+ return photoPanel;
+ }
+
+ /**
+ * Initializes a new <tt>VideoContainer</tt> instance which is to contain
+ * the visual/video <tt>Component</tt>s of the telephony conference depicted
+ * by this instance.
+ */
+ private VideoContainer createVideoContainer()
+ {
+ VideoContainer videoContainer = new VideoContainer(null, true);
+
+ thumbnailPanel.setBackground(Color.DARK_GRAY);
+ thumbnailPanel.add(thumbnailContainer, BorderLayout.NORTH);
+
+ add(thumbnailPanel, BorderLayout.EAST);
+ add(videoContainer, BorderLayout.CENTER);
+
+ return videoContainer;
+ }
+
+ /**
+ * Shows/hides the participants thumbnails list.
+ *
+ * @param show <tt>true</tt> to show the participants list, <tt>false</tt>
+ * to hide it
+ */
+ public void showThumbnailsList(boolean show)
+ {
+ thumbnailPanel.setVisible(show);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void dispose()
+ {
+ try
+ {
+ uiVideoHandler.deleteObserver(uiVideoHandlerObserver);
+ }
+ finally
+ {
+ super.dispose();
+ }
+ }
+
+ /**
+ * Determines whether a specific <tt>ConferenceMember</tt> represents the
+ * same conference participant as a specific <tt>CallPeer</tt>. If the
+ * specified <tt>conferenceMember</tt> is <tt>null</tt>, returns
+ * <tt>true</tt>. Otherwise, determines whether the addresses of the
+ * specified <tt>conferenceMember</tt> and the specified <tt>callPeer</tt>
+ * identify one and the same entity.
+ *
+ * @param conferenceMember the <tt>ConferenceMember</tt> to be checked
+ * whether is represents the same conference participant as the specified
+ * <tt>callPeer</tt>. If it is <tt>null</tt>, <tt>true</tt> is returned.
+ * @param callPeer the <tt>CallPeer</tt> to be checked whether it represents
+ * the same conference participant as the specified
+ * <tt>conferenceMember</tt>
+ * @return <tt>true</tt> if the specified <tt>conferenceMember</tt> and the
+ * specified <tt>callPeer</tt> represent the same conference participant or
+ * the specified <tt>conferenceMember</tt> is <tt>null</tt>; otherwise,
+ * <tt>false</tt>
+ */
+ private boolean isConferenceMemberCallPeer(
+ ConferenceMember conferenceMember,
+ CallPeer callPeer)
+ {
+ return
+ (conferenceMember == null)
+ ? true
+ : CallManager.addressesAreEqual(
+ conferenceMember.getAddress(),
+ callPeer.getAddress());
+ }
+
+ /**
+ * Determines whether a specific <tt>ConferenceMember</tt> represents the
+ * local peer/user. Since this instance depicts a whole telephony
+ * conference, the local peer/user may be participating with multiple
+ * <tt>Call</tt>s in it. The <tt>Call</tt>s may be through different
+ * (local) accounts. That's why the implementation determines whether the
+ * address of the specified <tt>conferenceMember</tt> identifies the address
+ * of a (local) accounts involved in the telephony conference depicted by
+ * this instance.
+ *
+ * @param conferenceMember the <tt>ConferenceMember</tt> to be checked
+ * whether it represents the local peer/user
+ * @return <tt>true</tt> if the specified <tt>conferenceMember</tt>
+ * represents the local peer/user; otherwise, <tt>false</tt>
+ */
+ private boolean isConferenceMemberLocalUser(
+ ConferenceMember conferenceMember)
+ {
+ String address = conferenceMember.getAddress();
+
+ for (Call call : callConference.getCalls())
+ {
+ if (CallManager.addressesAreEqual(
+ address,
+ call.getProtocolProvider().getAccountID()
+ .getAccountAddress()))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void removeConferenceMemberContainers(
+ ConferenceParticipantContainer cpc,
+ boolean all)
+ {
+ List<ConferenceParticipantContainer> cmcs
+ = cpc.conferenceMemberContainers;
+
+ if ((cmcs != null) && !cmcs.isEmpty())
+ {
+ Iterator<ConferenceParticipantContainer> i = cmcs.iterator();
+
+ while (i.hasNext())
+ {
+ ConferenceParticipantContainer cmc = i.next();
+
+ if (all || cmc.toBeRemoved)
+ {
+ i.remove();
+
+ videoContainer.remove(cmc.getComponent());
+ cmc.dispose();
+ }
+ }
+ }
+ }
+
+ /**
+ * Updates the <tt>ConferenceParticipantContainer</tt>s which depict the
+ * <tt>ConferenceMember</tt>s of the <tt>CallPeer</tt> depicted by a
+ * specific <tt>ConferenceParticipantContainer</tt>.
+ *
+ * @param cpc the <tt>ConferenceParticipantContainer</tt> which depicts the
+ * <tt>CallPeer</tt> whose <tt>ConferenceMember</tt>s are to be depicted
+ * @param videos the visual <tt>Component</tt>s displaying video streaming
+ * from the remote peer (represented by <tt>cpc</tt>) to the local peer/user
+ * @param videoTelephony the <tt>OperationSetVideoTelephony</tt> which
+ * retrieved the specified <tt>videos</tt> from the <tt>CallPeer</tt>
+ * depicted by <tt>cpc</tt>. While the <tt>CallPeer</tt> could be queried
+ * for it, such a query would waste more resources at run time given that
+ * the invoker has it already.
+ */
+ private void updateConferenceMemberContainers(
+ ConferenceParticipantContainer cpc,
+ List<Component> videos,
+ OperationSetVideoTelephony videoTelephony)
+ {
+ CallPeer callPeer = (CallPeer) cpc.getParticipant();
+ List<ConferenceParticipantContainer> cmcs
+ = cpc.conferenceMemberContainers;
+
+ /*
+ * Invalidate all conferenceMemberContainers. Then validate which of
+ * them are to remain and which of them are to really be removed
+ * later on.
+ */
+ if (cmcs != null)
+ {
+ for (ConferenceParticipantContainer cmc : cmcs)
+ cmc.toBeRemoved = true;
+ }
+
+ /*
+ * Depict the remote videos. They may or may not be associated with
+ * ConferenceMembers so the ConferenceMembers which have no
+ * associated videos will be depicted afterwards.
+ */
+ if (videos != null)
+ {
+ Component video = cpc.getVideo();
+
+ for (Component conferenceMemberVideo : videos)
+ {
+ /*
+ * One of the remote videos is already used to depict the
+ * callPeer.
+ */
+ if (conferenceMemberVideo == video)
+ continue;
+
+ boolean addNewConferenceParticipantContainer = true;
+ ConferenceMember conferenceMember
+ = videoTelephony.getConferenceMember(
+ callPeer,
+ conferenceMemberVideo);
+
+ if (cmcs == null)
+ {
+ cmcs = new LinkedList<ConferenceParticipantContainer>();
+ cpc.conferenceMemberContainers = cmcs;
+ }
+ else
+ {
+ for (ConferenceParticipantContainer cmc : cmcs)
+ {
+ Object cmcParticipant = cmc.getParticipant();
+
+ if (conferenceMember == null)
+ {
+ if (cmcParticipant == callPeer)
+ {
+ Component cmcVideo = cmc.getVideo();
+
+ if (cmcVideo == null)
+ {
+ cmc.setVideo(conferenceMemberVideo);
+ cmc.toBeRemoved = false;
+ addNewConferenceParticipantContainer
+ = false;
+ break;
+ }
+ else if (cmcVideo == conferenceMemberVideo)
+ {
+ cmc.toBeRemoved = false;
+ addNewConferenceParticipantContainer
+ = false;
+ break;
+ }
+ }
+ }
+ else if (cmcParticipant == conferenceMember)
+ {
+ cmc.setVideo(conferenceMemberVideo);
+ cmc.toBeRemoved = false;
+ addNewConferenceParticipantContainer = false;
+ break;
+ }
+ }
+ }
+
+ if (addNewConferenceParticipantContainer)
+ {
+ ConferenceParticipantContainer cmc
+ = (conferenceMember == null)
+ ? new ConferenceParticipantContainer(
+ callPeer,
+ conferenceMemberVideo)
+ : new ConferenceParticipantContainer(
+ conferenceMember,
+ conferenceMemberVideo);
+
+ cmcs.add(cmc);
+ }
+ }
+ }
+
+ /*
+ * Depict the ConferenceMembers which have not been depicted yet.
+ * They have no associated videos.
+ */
+ List<ConferenceMember> conferenceMembers
+ = callPeer.getConferenceMembers();
+
+ if (!conferenceMembers.isEmpty())
+ {
+ if (cmcs == null)
+ {
+ cmcs = new LinkedList<ConferenceParticipantContainer>();
+ cpc.conferenceMemberContainers = cmcs;
+ }
+ for (ConferenceMember conferenceMember : conferenceMembers)
+ {
+ /*
+ * If the callPeer reports itself as a ConferenceMember, then
+ * we've already depicted it with cpc.
+ */
+ if (isConferenceMemberCallPeer(conferenceMember, callPeer))
+ continue;
+ /*
+ * If the callPeer reports the local peer/user as a
+ * ConferenceMember, then we've already depicted it.
+ */
+ if (isConferenceMemberLocalUser(conferenceMember))
+ continue;
+
+ boolean addNewConferenceParticipantContainer = true;
+
+ for (ConferenceParticipantContainer cmc : cmcs)
+ {
+ if (cmc.getParticipant() == conferenceMember)
+ {
+ /*
+ * It is possible to have a ConferenceMember who is
+ * sending video but we just do not have the SSRC of
+ * that video to associate the video with the
+ * ConferenceMember. In such a case, we may be depicting
+ * the ConferenceMember twice: once with video without a
+ * ConferenceMember and once with a ConferenceMember
+ * without video. This will surely be the case at the
+ * time of this writing with non-focus participants in a
+ * telephony conference hosted on a Jitsi Videobridge.
+ * Such a display is undesirable. If the
+ * conferenceMember is known to send video, we will not
+ * display it until we associated it with a video. This
+ * way, if a ConferenceMember is not sending video, we
+ * will depict it and we can be sure that no video
+ * without a ConferenceMember association will be
+ * depicting it a second time.
+ */
+ if (cmc.toBeRemoved
+ && !conferenceMember
+ .getVideoStatus()
+ .allowsSending())
+ {
+ cmc.setVideo(null);
+ cmc.toBeRemoved = false;
+ }
+ addNewConferenceParticipantContainer = false;
+ break;
+ }
+ }
+
+ if (addNewConferenceParticipantContainer)
+ {
+ ConferenceParticipantContainer cmc
+ = new ConferenceParticipantContainer(
+ conferenceMember,
+ null);
+
+ cmcs.add(cmc);
+ }
+ }
+ }
+
+ if ((cmcs != null) && !cmcs.isEmpty())
+ {
+ removeConferenceMemberContainers(cpc, false);
+ /*
+ * If cpc is already added to the user interface hierarchy of this
+ * instance, then it was there before the update procedure and it
+ * was determined to be appropriate to continue to depict its model.
+ * Consequently, its Component will be neither added to (because it
+ * was already added) nor removed from the user interface hierarchy
+ * of this instance. That's why we have make sure that the
+ * Components of its conferenceMemberContainers are also added to
+ * the user interface.
+ */
+ if (UIVideoHandler2.isAncestor(this, cpc.getComponent()))
+ addConferenceMemberContainers(cpc);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected ConferenceCallPeerRenderer updateViewFromModel(
+ ConferenceCallPeerRenderer callPeerPanel,
+ CallPeer callPeer)
+ {
+ if (callPeer == null)
+ {
+ /*
+ * The local peer/user will be represented by a Call which has a
+ * CallPeer who provides local video. However, if the user has
+ * selected to hide the local video, the local peer/user will not be
+ * represented at all.
+ */
+ Component video = null;
+
+ if (uiVideoHandler.isLocalVideoVisible())
+ {
+ for (Call aCall : callConference.getCalls())
+ {
+ Iterator<? extends CallPeer> callPeerIter
+ = aCall.getCallPeers();
+ OperationSetVideoTelephony videoTelephony
+ = aCall.getProtocolProvider().getOperationSet(
+ OperationSetVideoTelephony.class);
+
+ while (callPeerIter.hasNext())
+ {
+ callPeer = callPeerIter.next();
+
+ if (videoTelephony != null)
+ {
+ try
+ {
+ video
+ = videoTelephony.getLocalVisualComponent(
+ callPeer);
+ }
+ catch (OperationFailedException ofe)
+ {
+ logger.error(
+ "Failed to retrieve the local video"
+ + " for display",
+ ofe);
+ }
+ if (video != null)
+ break;
+ }
+ }
+ if (video != null)
+ break;
+ }
+ }
+
+ if (callPeer == null)
+ callPeerPanel = null;
+ else
+ {
+ Call call = callPeer.getCall();
+
+ if (callPeerPanel instanceof ConferenceParticipantContainer)
+ {
+ ConferenceParticipantContainer cpc
+ = (ConferenceParticipantContainer) callPeerPanel;
+
+ if (cpc.getParticipant() == call)
+ cpc.setVideo(video);
+ else
+ callPeerPanel = null;
+ }
+ else
+ callPeerPanel = null;
+ if (callPeerPanel == null)
+ {
+ callPeerPanel
+ = new ConferenceParticipantContainer(call, video);
+ }
+ }
+ }
+ else
+ {
+ /*
+ * The specified callPeer will be represented by one of its remote
+ * videos which is not associated with a ConferenceMember or is
+ * associated with a ConferenceMember representing the callPeer
+ * itself.
+ */
+ OperationSetVideoTelephony videoTelephony
+ = callPeer.getProtocolProvider().getOperationSet(
+ OperationSetVideoTelephony.class);
+ List<Component> videos = null;
+ Component video = null;
+
+ if (videoTelephony != null)
+ {
+ videos = videoTelephony.getVisualComponents(callPeer);
+ if ((videos != null) && !videos.isEmpty())
+ {
+ for (Component aVideo : videos)
+ {
+ ConferenceMember conferenceMember
+ = videoTelephony.getConferenceMember(
+ callPeer,
+ aVideo);
+
+ if (isConferenceMemberCallPeer(
+ conferenceMember,
+ callPeer))
+ {
+ video = aVideo;
+ break;
+ }
+ }
+ }
+ }
+
+ ConferenceParticipantContainer cpc = null;
+
+ if (callPeerPanel instanceof ConferenceParticipantContainer)
+ {
+ cpc = (ConferenceParticipantContainer) callPeerPanel;
+ if (cpc.getParticipant() == callPeer)
+ cpc.setVideo(video);
+ else
+ cpc = null;
+ }
+ if (cpc == null)
+ cpc = new ConferenceParticipantContainer(callPeer, video);
+ callPeerPanel = cpc;
+
+ // Update the conferenceMemberContainers of the cpc.
+ updateConferenceMemberContainers(cpc, videos, videoTelephony);
+ }
+ return callPeerPanel;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * If {@link #SHOW_TOOLBARS} is <tt>false</tt>, disables the use of
+ * <tt>ConferenceParticipantContainer</tt>. A reason for such a value of
+ * <tt>SHOW_TOOLBARS</tt> may be that the functionality implemented in the
+ * model may not fully support mapping of visual <tt>Component</tt>s
+ * displaying video to telephony conference participants (e.g. in telephony
+ * conferences utilizing the Jitsi Videobridge server-side technology). In
+ * such a case displays the videos only, does not map videos to participants
+ * and does not display participants who do not have videos.
+ */
+ @Override
+ protected void updateViewFromModelInEventDispatchThread()
+ {
+ if (SHOW_TOOLBARS)
+ {
+ super.updateViewFromModelInEventDispatchThread();
+ return;
+ }
+
+ /*
+ * Determine the set of visual Components displaying video streaming
+ * between the local peer/user and the remote peers which are to be
+ * depicted by this instance.
+ */
+ Component localVideo = null;
+ Set<Component> videos = new HashSet<Component>();
+
+ for (Call call : callConference.getCalls())
+ {
+ OperationSetVideoTelephony videoTelephony
+ = call.getProtocolProvider().getOperationSet(
+ OperationSetVideoTelephony.class);
+
+ if (videoTelephony == null)
+ continue;
+
+ Iterator<? extends CallPeer> callPeerIter = call.getCallPeers();
+
+ while (callPeerIter.hasNext())
+ {
+ CallPeer callPeer = callPeerIter.next();
+
+ /*
+ * TODO VideoConferenceCallPanel respects
+ * UIVideoHandler2.isLocalVideoVisible() in order to react to
+ * the associated button at the bottom of the CallPanel.
+ * However, it does not add a close button on top of the local
+ * video in contrast to OneToOneCallPeerPanel. Overall, the
+ * result is questionable.
+ */
+ if (uiVideoHandler.isLocalVideoVisible()
+ && (localVideo == null))
+ {
+ try
+ {
+ localVideo
+ = videoTelephony.getLocalVisualComponent(callPeer);
+ }
+ catch (OperationFailedException ofe)
+ {
+ /*
+ * We'll just try to get the local video through another
+ * CallPeer then.
+ */
+ }
+ if (localVideo != null)
+ videos.add(localVideo);
+ }
+
+ List<Component> callPeerRemoteVideos
+ = videoTelephony.getVisualComponents(callPeer);
+
+ videos.addAll(callPeerRemoteVideos);
+ }
+ }
+
+ /*
+ * Remove the Components of this view which are no longer present in the
+ * model.
+ */
+ Iterator<Component> thisVideoIter = this.videos.iterator();
+
+ while (thisVideoIter.hasNext())
+ {
+ Component thisVideo = thisVideoIter.next();
+
+ if (!videos.contains(thisVideo))
+ {
+ thisVideoIter.remove();
+ videoContainer.remove(thisVideo);
+ }
+
+ /*
+ * If a video is known to be depicted by this view and is still
+ * present in the model, then we could remove it from the set of
+ * videos present in the model in order to prevent going through the
+ * procedure of adding it to this view. However, we choose to play
+ * on the safe side.
+ */
+ }
+
+ /*
+ * Add the Components of the model which are not depicted by this view.
+ */
+ for (Component video : videos)
+ {
+ if (!UIVideoHandler2.isAncestor(videoContainer, video))
+ {
+ this.videos.add(video);
+ videoContainer.add(
+ video,
+ (video == localVideo)
+ ? VideoLayout.LOCAL
+ : VideoLayout.CENTER_REMOTE);
+ }
+ }
+ }
+
+ @Override
+ protected void viewForModelAdded(
+ ConferenceCallPeerRenderer callPeerPanel,
+ CallPeer callPeer)
+ {
+ videoContainer.add(
+ callPeerPanel.getComponent(),
+ VideoLayout.CENTER_REMOTE);
+ if ((callPeer != null)
+ && (callPeerPanel instanceof ConferenceParticipantContainer))
+ {
+ addConferenceMemberContainers(
+ (ConferenceParticipantContainer) callPeerPanel);
+ }
+ }
+
+ @Override
+ protected void viewForModelRemoved(
+ ConferenceCallPeerRenderer callPeerPanel,
+ CallPeer callPeer)
+ {
+ videoContainer.remove(callPeerPanel.getComponent());
+ if ((callPeer != null)
+ && (callPeerPanel instanceof ConferenceParticipantContainer))
+ {
+ removeConferenceMemberContainers(
+ (ConferenceParticipantContainer) callPeerPanel,
+ true);
+ }
+ }
+
+ /**
+ * Implements an AWT <tt>Component</tt> which contains the user interface
+ * elements depicting a specific participant in the telephony conference
+ * depicted by a <tt>VideoConferenceCallPanel</tt>.
+ */
+ private class ConferenceParticipantContainer
+ extends TransparentPanel
+ implements ConferenceCallPeerRenderer
+ {
+ /**
+ * The list of <tt>ConferenceParticipantContainer</tt>s which represent
+ * the <tt>ConferenceMember</tt>s of the participant represented by this
+ * instance. Since a <tt>CallPeer</tt> may send the local peer/user
+ * multiple videos without providing a way to associate a
+ * ConferenceMember with each one of them, the list may contain
+ * <tt>ConferenceParticipantContainer</tt>s which do not represent a
+ * specific <tt>ConferenceMember</tt> instance but rather a video sent
+ * by a <tt>CallPeer</tt> to the local peer/user which looks like (in
+ * the terms of <tt>VideoConferenceCallPanel) a member of a conference
+ * organized by the <tt>CallPeer</tt> in question.
+ * <p>
+ * Implements a state which is private to
+ * <tt>VideoConferenceCallPanel</tt> and is of no concern to
+ * <tt>ConferenceParticipantContainer</tt>.
+ * </p>
+ */
+ List<ConferenceParticipantContainer> conferenceMemberContainers;
+
+ /**
+ * The indicator which determines whether this instance is to be removed
+ * because it has become out-of-date, obsolete, unnecessary.
+ * <p>
+ * Implements a state which is private to
+ * <tt>VideoConferenceCallPanel</tt> and is of no concern to
+ * <tt>ConferenceParticipantContainer</tt>.
+ * </p>
+ */
+ boolean toBeRemoved;
+
+ /**
+ * The <tt>BasicConferenceParticipantPanel</tt> which is displayed at
+ * the bottom of this instance, bellow the {@link #video} (i.e.
+ * {@link #videoContainer}) and is referred to as the tool bar.
+ */
+ private final BasicConferenceParticipantPanel<?> toolBar;
+
+ /**
+ * The visual <tt>Component</tt>, if any, displaying video which is
+ * depicted by this instance.
+ */
+ private Component video;
+
+ /**
+ * The <tt>VideoContainer</tt> which lays out the video depicted by this
+ * instance i.e. {@link #video}.
+ */
+ private final VideoContainer videoContainer;
+
+ /**
+ * The <tt>CallPeer</tt> associated with this container, if it has been
+ * created to represent a <tt>CallPeer</tt>.
+ */
+ private CallPeer callPeer;
+
+ /**
+ * The <tt>conferenceMember</tt> associated with this container, if it
+ * has been created to represent a <tt>conferenceMember</tt>.
+ */
+ private ConferenceMember conferenceMember;
+
+ /**
+ * Indicates that this container contains information for the local
+ * user.
+ */
+ private boolean isLocalUser;
+
+ /**
+ * Initializes a new <tt>ConferenceParticipantContainer</tt> instance
+ * which is to depict the local peer/user.
+ *
+ * @param call a <tt>Call</tt> which is to provide information about the
+ * local peer/user
+ * @param video the visual <tt>Component</tt>, if any, displaying the
+ * video streaming from the local peer/user to the remote peer(s)
+ */
+ public ConferenceParticipantContainer(Call call, Component video)
+ {
+ this(
+ createDefaultPhotoPanel(call),
+ video,
+ new ConferencePeerPanel(
+ VideoConferenceCallPanel.this,
+ call,
+ true),
+ null, null, true);
+ }
+
+ public ConferenceParticipantContainer(
+ CallPeer callPeer,
+ Component video)
+ {
+ this( createDefaultPhotoPanel(callPeer),
+ video,
+ new ConferencePeerPanel(
+ VideoConferenceCallPanel.this,
+ callPeer,
+ true),
+ callPeer, null, false);
+ }
+
+ private ConferenceParticipantContainer(
+ Component noVideo,
+ Component video,
+ BasicConferenceParticipantPanel<?> toolBar,
+ CallPeer callPeer,
+ ConferenceMember conferenceMember,
+ boolean isLocalUser)
+ {
+ super(new BorderLayout());
+
+ this.callPeer = callPeer;
+ this.conferenceMember = conferenceMember;
+ this.isLocalUser = isLocalUser;
+
+ videoContainer = new VideoContainer(noVideo, false);
+ add(videoContainer, BorderLayout.CENTER);
+
+ this.toolBar = toolBar;
+ if (this.toolBar != null)
+ add(this.toolBar, BorderLayout.SOUTH);
+
+ if (video != null)
+ {
+ setVideo(video);
+ }
+ else
+ setVisible(false);
+ }
+
+ public ConferenceParticipantContainer(
+ ConferenceMember conferenceMember,
+ Component video)
+ {
+ this(
+ createDefaultPhotoPanel(conferenceMember),
+ video,
+ new ConferenceMemberPanel(
+ VideoConferenceCallPanel.this,
+ conferenceMember,
+ true),
+ null, conferenceMember, false);
+ }
+
+ public void dispose()
+ {
+ ConferenceCallPeerRenderer delegate
+ = getConferenceCallPeerRendererDelegate();
+
+ if (delegate != null)
+ delegate.dispose();
+
+ // Dispose of the conferenceMemberContainers if any.
+ /*
+ * XXX The field conferenceMemberContainers implements a state
+ * private to VideoConferenceCallPanel which the latter makes sure
+ * to access on the AWT event dispatching thread only. Since we are
+ * going out of our way here to help VideoConferenceCallPanel,
+ * ensure that the mentioned synchronization rule is not violated.
+ */
+ CallManager.assertIsEventDispatchingThread();
+ if (conferenceMemberContainers != null)
+ {
+ for (ConferenceParticipantContainer cmc
+ : conferenceMemberContainers)
+ {
+ cmc.dispose();
+ }
+ }
+ }
+
+ public CallPanel getCallPanel()
+ {
+ return getCallRenderer().getCallContainer();
+ }
+
+ public SwingCallRenderer getCallRenderer()
+ {
+ return VideoConferenceCallPanel.this;
+ }
+
+ public Component getComponent()
+ {
+ return this;
+ }
+
+ private ConferenceCallPeerRenderer
+ getConferenceCallPeerRendererDelegate()
+ {
+ return
+ (toolBar instanceof ConferenceCallPeerRenderer)
+ ? (ConferenceCallPeerRenderer) toolBar
+ : null;
+ }
+
+ /**
+ * Gets the conference participant depicted by this instance.
+ *
+ * @return the conference participant depicted by this instance
+ */
+ public Object getParticipant()
+ {
+ return (toolBar == null) ? null : toolBar.getParticipant();
+ }
+
+ public Component getVideo()
+ {
+ return video;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Delegates to the <tt>toolBar</tt>, if the latter implements
+ * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
+ * container only. Otherwise, returns <tt>false</tt>.
+ */
+ public boolean isLocalVideoVisible()
+ {
+ ConferenceCallPeerRenderer delegate
+ = getConferenceCallPeerRendererDelegate();
+
+ return (delegate == null) ? false : delegate.isLocalVideoVisible();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Delegates to the <tt>toolBar</tt>, if the latter implements
+ * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
+ * container only.
+ */
+ public void printDTMFTone(char dtmfChar)
+ {
+ ConferenceCallPeerRenderer delegate
+ = getConferenceCallPeerRendererDelegate();
+
+ if (delegate != null)
+ delegate.printDTMFTone(dtmfChar);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Delegates to the <tt>toolBar</tt>, if the latter implements
+ * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
+ * container only.
+ */
+ public void securityNegotiationStarted(
+ CallPeerSecurityNegotiationStartedEvent ev)
+ {
+ ConferenceCallPeerRenderer delegate
+ = getConferenceCallPeerRendererDelegate();
+
+ if (delegate != null)
+ delegate.securityNegotiationStarted(ev);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Delegates to the <tt>toolBar</tt>, if the latter implements
+ * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
+ * container only.
+ */
+ public void securityOff(CallPeerSecurityOffEvent ev)
+ {
+ ConferenceCallPeerRenderer delegate
+ = getConferenceCallPeerRendererDelegate();
+
+ if (delegate != null)
+ delegate.securityOff(ev);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Delegates to the <tt>toolBar</tt>, if the latter implements
+ * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
+ * container only.
+ */
+ public void securityOn(CallPeerSecurityOnEvent ev)
+ {
+ ConferenceCallPeerRenderer delegate
+ = getConferenceCallPeerRendererDelegate();
+
+ if (delegate != null)
+ delegate.securityOn(ev);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Delegates to the <tt>toolBar</tt>, if the latter implements
+ * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
+ * container only.
+ */
+ public void securityPending()
+ {
+ ConferenceCallPeerRenderer delegate
+ = getConferenceCallPeerRendererDelegate();
+
+ if (delegate != null)
+ delegate.securityPending();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Delegates to the <tt>toolBar</tt>, if the latter implements
+ * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
+ * container only.
+ */
+ public void securityTimeout(CallPeerSecurityTimeoutEvent ev)
+ {
+ ConferenceCallPeerRenderer delegate
+ = getConferenceCallPeerRendererDelegate();
+
+ if (delegate != null)
+ delegate.securityTimeout(ev);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Delegates to the <tt>toolBar</tt>, if the latter implements
+ * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
+ * container only.
+ */
+ public void setErrorReason(String reason)
+ {
+ ConferenceCallPeerRenderer delegate
+ = getConferenceCallPeerRendererDelegate();
+
+ if (delegate != null)
+ delegate.setErrorReason(reason);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Delegates to the <tt>toolBar</tt>, if the latter implements
+ * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
+ * container only.
+ */
+ public void setLocalVideoVisible(boolean visible)
+ {
+ ConferenceCallPeerRenderer delegate
+ = getConferenceCallPeerRendererDelegate();
+
+ if (delegate != null)
+ delegate.setLocalVideoVisible(visible);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Delegates to the <tt>toolBar</tt>, if the latter implements
+ * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
+ * container only.
+ */
+ public void setMute(boolean mute)
+ {
+ ConferenceCallPeerRenderer delegate
+ = getConferenceCallPeerRendererDelegate();
+
+ if (delegate != null)
+ delegate.setMute(mute);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Delegates to the <tt>toolBar</tt>, if the latter implements
+ * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
+ * container only.
+ */
+ public void setOnHold(boolean onHold)
+ {
+ ConferenceCallPeerRenderer delegate
+ = getConferenceCallPeerRendererDelegate();
+
+ if (delegate != null)
+ delegate.setOnHold(onHold);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Delegates to the <tt>toolBar</tt>, if the latter implements
+ * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
+ * container only.
+ */
+ public void setPeerImage(byte[] image)
+ {
+ ConferenceCallPeerRenderer delegate
+ = getConferenceCallPeerRendererDelegate();
+
+ if (delegate != null)
+ delegate.setPeerImage(image);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Delegates to the <tt>toolBar</tt>, if the latter implements
+ * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
+ * container only.
+ */
+ public void setPeerName(String name)
+ {
+ ConferenceCallPeerRenderer delegate
+ = getConferenceCallPeerRendererDelegate();
+
+ if (delegate != null)
+ delegate.setPeerName(name);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Delegates to the <tt>toolBar</tt>, if the latter implements
+ * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
+ * container only.
+ */
+ public void setPeerState(
+ CallPeerState oldState,
+ CallPeerState newState,
+ String stateString)
+ {
+ ConferenceCallPeerRenderer delegate
+ = getConferenceCallPeerRendererDelegate();
+
+ if (delegate != null)
+ delegate.setPeerState(oldState, newState, stateString);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Delegates to the <tt>toolBar</tt>, if the latter implements
+ * <tt>ConferenceCallPeerRenderer</tt>, because this instance is a
+ * container only.
+ */
+ public void setSecurityPanelVisible(boolean visible)
+ {
+ ConferenceCallPeerRenderer delegate
+ = getConferenceCallPeerRendererDelegate();
+
+ if (delegate != null)
+ delegate.setSecurityPanelVisible(visible);
+ }
+
+ /**
+ * Sets the visual <tt>Component</tt> displaying the video associated
+ * with the participant depicted by this instance.
+ *
+ * @param video the visual <tt>Component</tt> displaying video which is
+ * to be associated with the participant depicted by this instance
+ */
+ void setVideo(Component video)
+ {
+ if (this.video != video)
+ {
+ if (this.video != null)
+ videoContainer.remove(this.video);
+
+ this.video = video;
+
+ if (this.video != null)
+ {
+ setVisible(true);
+ videoContainer.add(this.video, VideoLayout.CENTER_REMOTE);
+ }
+ else
+ setVisible(false);
+
+ // Update thumbnails container according to video status.
+ if (thumbnailContainer != null)
+ {
+ if (conferenceMember != null)
+ thumbnailContainer
+ .updateThumbnail(conferenceMember, (video != null));
+ else if (callPeer != null)
+ thumbnailContainer
+ .updateThumbnail(callPeer, (video != null));
+ else if (isLocalUser)
+ thumbnailContainer
+ .updateThumbnail((video != null));
+ }
+ }
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java
index 127e28b..0283e25 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java
@@ -790,8 +790,6 @@ public class ChatConversationPanel
*/
public void correctMessage(final ChatMessage chatMessage)
{
- lastMessageUID = chatMessage.getMessageUID();
-
if (!SwingUtilities.isEventDispatchThread())
{
SwingUtilities.invokeLater(new Runnable()
@@ -805,6 +803,11 @@ public class ChatConversationPanel
}
String correctedUID = chatMessage.getCorrectedMessageUID();
+ if (correctedUID != null && correctedUID.equals(lastMessageUID))
+ {
+ lastMessageUID = chatMessage.getMessageUID();
+ }
+
Element root = document.getDefaultRootElement();
Element correctedMsgElement
= document.getElement(root,
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatSessionChangeListener.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatSessionChangeListener.java
index 0b96069..1e6127e 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatSessionChangeListener.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatSessionChangeListener.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,32 +15,32 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.gui.main.chat;
-
-/**
- * Listens for changes in {@link ChatSession}.
- * @author George Politis
- */
-public interface ChatSessionChangeListener
-{
- /**
- * The icon representing the ChatTransport has changed.
- */
- public static final int ICON_UPDATED = 1;
-
- /**
- * Called when the current {@link ChatTransport} has
- * changed.
- *
- * @param chatSession the {@link ChatSession} it's current
- * {@link ChatTransport} has changed
- */
- public void currentChatTransportChanged(ChatSession chatSession);
-
- /**
- * When a property of the chatTransport has changed.
- * @param eventID the event id representing the property of the transport
- * that has changed.
- */
- public void currentChatTransportUpdated(int eventID);
-}
+package net.java.sip.communicator.impl.gui.main.chat;
+
+/**
+ * Listens for changes in {@link ChatSession}.
+ * @author George Politis
+ */
+public interface ChatSessionChangeListener
+{
+ /**
+ * The icon representing the ChatTransport has changed.
+ */
+ public static final int ICON_UPDATED = 1;
+
+ /**
+ * Called when the current {@link ChatTransport} has
+ * changed.
+ *
+ * @param chatSession the {@link ChatSession} it's current
+ * {@link ChatTransport} has changed
+ */
+ public void currentChatTransportChanged(ChatSession chatSession);
+
+ /**
+ * When a property of the chatTransport has changed.
+ * @param eventID the event id representing the property of the transport
+ * that has changed.
+ */
+ public void currentChatTransportUpdated(int eventID);
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/conference/ChatContactListModel.java b/src/net/java/sip/communicator/impl/gui/main/chat/conference/ChatContactListModel.java
index d42ecfb..acf36bf 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/conference/ChatContactListModel.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/conference/ChatContactListModel.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,235 +15,235 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.gui.main.chat.conference;
-
-import java.util.*;
-
-import javax.swing.*;
-
-import net.java.sip.communicator.impl.gui.main.chat.*;
-import net.java.sip.communicator.service.muc.*;
-import net.java.sip.communicator.service.protocol.event.*;
-
-/**
- * Implements an <tt>AbstractListModel</tt> which represents a member list of
- * <tt>ChatContact</tt>s. The primary purpose of the implementation is to sort
- * the <tt>ChatContact</tt>s according to their member roles and in alphabetical
- * order according to their names.
- *
- * @author Lyubomir Marinov
- */
-public class ChatContactListModel
- extends AbstractListModel
- implements ChatRoomMemberPropertyChangeListener
-{
-
- /**
- * The backing store of this <tt>AbstractListModel</tt> listing the
- * <tt>ChatContact</tt>s.
- */
- private final List<ChatContact<?>> chatContacts
- = new ArrayList<ChatContact<?>>();
-
- /**
- * Current chat session.
- */
- private ChatSession chatSession;
-
- /**
- * The implementation of the sorting rules - the <tt>ChatContact</tt>s are
- * first sorted according to their roles in decreasing order of their
- * privileges and then they are sorted according to their names in
- * alphabetical order.
- */
- private final Comparator<ChatContact<?>> sorter
- = new Comparator<ChatContact<?>>()
- {
- public int compare(ChatContact<?> chatContact0, ChatContact<?> chatContact1)
- {
- /*
- * Place ChatMembers with more privileges at the beginning of
- * the list.
- */
- if (chatContact0 instanceof ConferenceChatContact)
- {
- if (chatContact1 instanceof ConferenceChatContact)
- {
- int role0
- = ((ConferenceChatContact) chatContact0).getRole()
- .getRoleIndex();
- int role1
- = ((ConferenceChatContact) chatContact1).getRole()
- .getRoleIndex();
-
- if (role0 > role1)
- return -1;
- else if (role0 < role1)
- return 1;
- }
- else
- return -1;
- }
- else if (chatContact1 instanceof ConferenceChatContact)
- return 1;
-
- /* By default, sort the ChatContacts in alphabetical order. */
- return
- chatContact0.getName().compareToIgnoreCase(
- chatContact1.getName());
- }
- };
-
- /**
- * Creates the model.
- * @param chatSession The current model chat session.
- */
- public ChatContactListModel(ChatSession chatSession)
- {
- this.chatSession = chatSession;
-
- // when something like rename on a member change update the UI to
- // reflect it
- Object descriptor = chatSession.getDescriptor();
-
- if(descriptor instanceof ChatRoomWrapper)
- {
- ((ChatRoomWrapper) descriptor)
- .getChatRoom().addMemberPropertyChangeListener(this);
- }
- }
-
- /**
- * Listens for property change in chat room members.
- * @param ev the event
- */
- public void chatRoomPropertyChanged(ChatRoomMemberPropertyChangeEvent ev)
- {
- // Translate into
- // ListDataListener.contentsChanged.
- int chatContactCount = chatContacts.size();
-
- for (int i = 0; i < chatContactCount; i++)
- {
- ChatContact<?> chatContact = chatContacts.get(i);
-
- if(chatContact.getDescriptor().equals(ev.getSourceChatRoomMember()))
- {
- fireContentsChanged(chatContact, i, i);
- /*
- * TODO Can ev.sourceChatRoomMember
- * equal more than one chatContacts
- * element? If it cannot, it will be
- * more efficient to break here.
- */
- }
- }
- }
-
- /**
- * Adds a specific <tt>ChatContact</tt> to this <tt>AbstractListModel</tt>
- * implementation and preserves the sorting it applies.
- *
- * @param chatContact a <tt>ChatContact</tt> to be added to this
- * <tt>AbstractListModel</tt>
- */
- public void addElement(ChatContact<?> chatContact)
- {
- if (chatContact == null)
- throw new IllegalArgumentException("chatContact");
-
- int index = -1;
-
- synchronized(chatContacts)
- {
- int chatContactCount = chatContacts.size();
-
- for (int i = 0; i < chatContactCount; i++)
- {
- ChatContact<?> containedChatContact = chatContacts.get(i);
-
- // We don't want duplicates.
- if (chatContact.equals(containedChatContact))
- return;
- if ((index == -1)
- && (sorter.compare(containedChatContact, chatContact) > 0))
- {
- index = i;
- // Continue in order to prevent duplicates.
- }
- }
- if (index == -1)
- index = chatContactCount;
-
- chatContacts.add(index, chatContact);
- }
- fireIntervalAdded(this, index, index);
- }
-
- /* Implements ListModel#getElementAt(int). */
- public ChatContact<?> getElementAt(int index)
- {
- synchronized(chatContacts)
- {
- return chatContacts.get(index);
- }
- }
-
- /* Implements ListModel#getSize(). */
- public int getSize()
- {
- synchronized(chatContacts)
- {
- return chatContacts.size();
- }
- }
-
- /**
- * Removes a specific <tt>ChatContact</tt> from this
- * <tt>AbstractListModel</tt> implementation.
- *
- * @param chatContact a <tt>ChatContact</tt> to be removed from this
- * <tt>AbstractListModel</tt> if it's already contained
- */
- public void removeElement(ChatContact<?> chatContact)
- {
- synchronized(chatContacts)
- {
- int index = chatContacts.indexOf(chatContact);
-
- if ((index >= 0) && chatContacts.remove(chatContact))
- fireIntervalRemoved(this, index, index);
- }
- }
-
- /**
- * Removes all the elements from this model.
- */
- public void removeAllElements()
- {
- if (chatContacts == null || chatContacts.size() <= 0)
- return;
-
- synchronized(chatContacts)
- {
- int contactsSize = chatContacts.size();
- chatContacts.clear();
-
- fireIntervalRemoved(this, 0, contactsSize - 1);
- }
- }
-
- /**
- * Runs clean-up.
- */
- public void dispose()
- {
- Object descriptor = chatSession.getDescriptor();
-
- if(descriptor instanceof ChatRoomWrapper)
- {
- ((ChatRoomWrapper) descriptor)
- .getChatRoom().removeMemberPropertyChangeListener(this);
- }
- }
-}
+package net.java.sip.communicator.impl.gui.main.chat.conference;
+
+import java.util.*;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.impl.gui.main.chat.*;
+import net.java.sip.communicator.service.muc.*;
+import net.java.sip.communicator.service.protocol.event.*;
+
+/**
+ * Implements an <tt>AbstractListModel</tt> which represents a member list of
+ * <tt>ChatContact</tt>s. The primary purpose of the implementation is to sort
+ * the <tt>ChatContact</tt>s according to their member roles and in alphabetical
+ * order according to their names.
+ *
+ * @author Lyubomir Marinov
+ */
+public class ChatContactListModel
+ extends AbstractListModel
+ implements ChatRoomMemberPropertyChangeListener
+{
+
+ /**
+ * The backing store of this <tt>AbstractListModel</tt> listing the
+ * <tt>ChatContact</tt>s.
+ */
+ private final List<ChatContact<?>> chatContacts
+ = new ArrayList<ChatContact<?>>();
+
+ /**
+ * Current chat session.
+ */
+ private ChatSession chatSession;
+
+ /**
+ * The implementation of the sorting rules - the <tt>ChatContact</tt>s are
+ * first sorted according to their roles in decreasing order of their
+ * privileges and then they are sorted according to their names in
+ * alphabetical order.
+ */
+ private final Comparator<ChatContact<?>> sorter
+ = new Comparator<ChatContact<?>>()
+ {
+ public int compare(ChatContact<?> chatContact0, ChatContact<?> chatContact1)
+ {
+ /*
+ * Place ChatMembers with more privileges at the beginning of
+ * the list.
+ */
+ if (chatContact0 instanceof ConferenceChatContact)
+ {
+ if (chatContact1 instanceof ConferenceChatContact)
+ {
+ int role0
+ = ((ConferenceChatContact) chatContact0).getRole()
+ .getRoleIndex();
+ int role1
+ = ((ConferenceChatContact) chatContact1).getRole()
+ .getRoleIndex();
+
+ if (role0 > role1)
+ return -1;
+ else if (role0 < role1)
+ return 1;
+ }
+ else
+ return -1;
+ }
+ else if (chatContact1 instanceof ConferenceChatContact)
+ return 1;
+
+ /* By default, sort the ChatContacts in alphabetical order. */
+ return
+ chatContact0.getName().compareToIgnoreCase(
+ chatContact1.getName());
+ }
+ };
+
+ /**
+ * Creates the model.
+ * @param chatSession The current model chat session.
+ */
+ public ChatContactListModel(ChatSession chatSession)
+ {
+ this.chatSession = chatSession;
+
+ // when something like rename on a member change update the UI to
+ // reflect it
+ Object descriptor = chatSession.getDescriptor();
+
+ if(descriptor instanceof ChatRoomWrapper)
+ {
+ ((ChatRoomWrapper) descriptor)
+ .getChatRoom().addMemberPropertyChangeListener(this);
+ }
+ }
+
+ /**
+ * Listens for property change in chat room members.
+ * @param ev the event
+ */
+ public void chatRoomPropertyChanged(ChatRoomMemberPropertyChangeEvent ev)
+ {
+ // Translate into
+ // ListDataListener.contentsChanged.
+ int chatContactCount = chatContacts.size();
+
+ for (int i = 0; i < chatContactCount; i++)
+ {
+ ChatContact<?> chatContact = chatContacts.get(i);
+
+ if(chatContact.getDescriptor().equals(ev.getSourceChatRoomMember()))
+ {
+ fireContentsChanged(chatContact, i, i);
+ /*
+ * TODO Can ev.sourceChatRoomMember
+ * equal more than one chatContacts
+ * element? If it cannot, it will be
+ * more efficient to break here.
+ */
+ }
+ }
+ }
+
+ /**
+ * Adds a specific <tt>ChatContact</tt> to this <tt>AbstractListModel</tt>
+ * implementation and preserves the sorting it applies.
+ *
+ * @param chatContact a <tt>ChatContact</tt> to be added to this
+ * <tt>AbstractListModel</tt>
+ */
+ public void addElement(ChatContact<?> chatContact)
+ {
+ if (chatContact == null)
+ throw new IllegalArgumentException("chatContact");
+
+ int index = -1;
+
+ synchronized(chatContacts)
+ {
+ int chatContactCount = chatContacts.size();
+
+ for (int i = 0; i < chatContactCount; i++)
+ {
+ ChatContact<?> containedChatContact = chatContacts.get(i);
+
+ // We don't want duplicates.
+ if (chatContact.equals(containedChatContact))
+ return;
+ if ((index == -1)
+ && (sorter.compare(containedChatContact, chatContact) > 0))
+ {
+ index = i;
+ // Continue in order to prevent duplicates.
+ }
+ }
+ if (index == -1)
+ index = chatContactCount;
+
+ chatContacts.add(index, chatContact);
+ }
+ fireIntervalAdded(this, index, index);
+ }
+
+ /* Implements ListModel#getElementAt(int). */
+ public ChatContact<?> getElementAt(int index)
+ {
+ synchronized(chatContacts)
+ {
+ return chatContacts.get(index);
+ }
+ }
+
+ /* Implements ListModel#getSize(). */
+ public int getSize()
+ {
+ synchronized(chatContacts)
+ {
+ return chatContacts.size();
+ }
+ }
+
+ /**
+ * Removes a specific <tt>ChatContact</tt> from this
+ * <tt>AbstractListModel</tt> implementation.
+ *
+ * @param chatContact a <tt>ChatContact</tt> to be removed from this
+ * <tt>AbstractListModel</tt> if it's already contained
+ */
+ public void removeElement(ChatContact<?> chatContact)
+ {
+ synchronized(chatContacts)
+ {
+ int index = chatContacts.indexOf(chatContact);
+
+ if ((index >= 0) && chatContacts.remove(chatContact))
+ fireIntervalRemoved(this, index, index);
+ }
+ }
+
+ /**
+ * Removes all the elements from this model.
+ */
+ public void removeAllElements()
+ {
+ if (chatContacts == null || chatContacts.size() <= 0)
+ return;
+
+ synchronized(chatContacts)
+ {
+ int contactsSize = chatContacts.size();
+ chatContacts.clear();
+
+ fireIntervalRemoved(this, 0, contactsSize - 1);
+ }
+ }
+
+ /**
+ * Runs clean-up.
+ */
+ public void dispose()
+ {
+ Object descriptor = chatSession.getDescriptor();
+
+ if(descriptor instanceof ChatRoomWrapper)
+ {
+ ((ChatRoomWrapper) descriptor)
+ .getChatRoom().removeMemberPropertyChangeListener(this);
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatManager.java b/src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatManager.java
index 58a1db4..89ceb48 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatManager.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatManager.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,1390 +15,1390 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.gui.main.chat.conference;
-
-import java.util.*;
-import java.util.concurrent.*;
-
-import javax.swing.*;
-
-import net.java.sip.communicator.impl.gui.*;
-import net.java.sip.communicator.impl.gui.main.chat.*;
-import net.java.sip.communicator.impl.gui.main.chat.history.*;
-import net.java.sip.communicator.impl.gui.main.chatroomslist.*;
-import net.java.sip.communicator.plugin.desktoputil.*;
-import net.java.sip.communicator.service.gui.*;
-import net.java.sip.communicator.service.muc.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.service.protocol.globalstatus.*;
-import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.Logger;
-
-import org.jdesktop.swingworker.SwingWorker;
-import org.jitsi.util.*;
-import org.osgi.framework.*;
-
-/**
- * The <tt>ConferenceChatManager</tt> is the one that manages both chat room and
- * ad-hoc chat rooms invitations.
- *
- * @author Yana Stamcheva
- * @author Lubomir Marinov
- * @author Valentin Martinet
- * @author Hristo Terezov
- */
-public class ConferenceChatManager
- implements ChatRoomMessageListener,
- ChatRoomInvitationListener,
- ChatRoomInvitationRejectionListener,
- AdHocChatRoomMessageListener,
- AdHocChatRoomInvitationListener,
- AdHocChatRoomInvitationRejectionListener,
- LocalUserChatRoomPresenceListener,
- LocalUserAdHocChatRoomPresenceListener,
- ServiceListener, ChatRoomLocalUserRoleListener
-{
- /**
- * The object used for logging.
- */
- private static final Logger logger
- = Logger.getLogger(ConferenceChatManager.class);
-
- /**
- * Maps each history window to a <tt>ChatRoomWrapper</tt>.
- */
- private final Hashtable<ChatRoomWrapper, HistoryWindow> chatRoomHistory =
- new Hashtable<ChatRoomWrapper, HistoryWindow>();
-
- /**
- * The list of ad-hoc chat rooms.
- */
- private final AdHocChatRoomList adHocChatRoomList = new AdHocChatRoomList();
-
- /**
- * A list of all <tt>AdHocChatRoomListChangeListener</tt>-s.
- */
- private final Vector<AdHocChatRoomListChangeListener>
- adHoclistChangeListeners = new Vector<AdHocChatRoomListChangeListener>();
-
- /**
- * Creates an instance of <tt>ConferenceChatManager</tt>.
- */
- public ConferenceChatManager()
- {
- // Loads the chat rooms list in a separate thread.
- new Thread()
- {
- @Override
- public void run()
- {
- adHocChatRoomList.loadList();
- }
- }.start();
-
- GuiActivator.bundleContext.addServiceListener(this);
-
- }
-
- /**
- * Returns all chat room providers currently contained in the ad-hoc chat
- * room list.
- *
- * @return all chat room providers currently contained in the ad-hoc chat
- * room list.
- */
- public AdHocChatRoomList getAdHocChatRoomList()
- {
- return adHocChatRoomList;
- }
-
- /**
- * Handles <tt>ChatRoomInvitationReceivedEvent</tt>-s.
- */
- public void invitationReceived(ChatRoomInvitationReceivedEvent evt)
- {
- InvitationReceivedDialog dialog
- = new InvitationReceivedDialog(
- this,
- evt.getSourceOperationSet(),
- evt.getInvitation());
-
- dialog.setVisible(true);
- }
-
- public void invitationRejected(ChatRoomInvitationRejectedEvent evt) {}
-
- /**
- * Implements the <tt>ChatRoomMessageListener.messageDelivered</tt> method.
- * <br>
- * Shows the message in the conversation area and clears the write message
- * area.
- * @param evt the <tt>ChatRoomMessageDeliveredEvent</tt> that notified us
- * that the message was delivered to its destination
- */
- public void messageDelivered(ChatRoomMessageDeliveredEvent evt)
- {
- ChatRoom sourceChatRoom = (ChatRoom) evt.getSource();
-
- if (logger.isTraceEnabled())
- logger.trace(
- "MESSAGE DELIVERED to chat room: " + sourceChatRoom.getName());
-
- ChatPanel chatPanel = GuiActivator.getUIService().getChatWindowManager()
- .getMultiChat(sourceChatRoom, false);
-
- if(chatPanel != null)
- {
- String messageType;
-
- switch (evt.getEventType())
- {
- case ChatRoomMessageDeliveredEvent.CONVERSATION_MESSAGE_DELIVERED:
- messageType = Chat.OUTGOING_MESSAGE;
- break;
- case ChatRoomMessageDeliveredEvent.ACTION_MESSAGE_DELIVERED:
- messageType = Chat.ACTION_MESSAGE;
- break;
- default:
- messageType = null;
- break;
- }
-
- Message msg = evt.getMessage();
-
- chatPanel.addMessage(
- sourceChatRoom.getUserNickname(),
- null,
- evt.getTimestamp(),
- messageType,
- msg.getContent(),
- msg.getContentType(),
- msg.getMessageUID(),
- null);
- }
- }
-
- /**
- * Implements the <tt>ChatRoomMessageListener.messageReceived</tt> method.
- * <br>
- * Obtains the corresponding <tt>ChatPanel</tt> and process the message
- * there.
- * @param evt the <tt>ChatRoomMessageReceivedEvent</tt> that notified us
- * that a message has been received
- */
- public void messageReceived(ChatRoomMessageReceivedEvent evt)
- {
- ChatRoom sourceChatRoom = evt.getSourceChatRoom();
- ChatRoomMember sourceMember = evt.getSourceChatRoomMember();
-
- String messageType = null;
-
- switch (evt.getEventType())
- {
- case ChatRoomMessageReceivedEvent.CONVERSATION_MESSAGE_RECEIVED:
- messageType = Chat.INCOMING_MESSAGE;
- break;
- case ChatRoomMessageReceivedEvent.SYSTEM_MESSAGE_RECEIVED:
- messageType = Chat.SYSTEM_MESSAGE;
- break;
- case ChatRoomMessageReceivedEvent.ACTION_MESSAGE_RECEIVED:
- messageType = Chat.ACTION_MESSAGE;
- break;
- }
-
- if (logger.isTraceEnabled())
- logger.trace("MESSAGE RECEIVED from contact: "
- + sourceMember.getContactAddress());
-
- Message message = evt.getMessage();
-
- ChatPanel chatPanel = null;
-
- ChatWindowManager chatWindowManager
- = GuiActivator.getUIService().getChatWindowManager();
-
- boolean createWindow = false;
- String autoOpenConfig
- = MUCService.getChatRoomAutoOpenOption(
- sourceChatRoom.getParentProvider(),
- sourceChatRoom.getIdentifier());
- if(autoOpenConfig == null)
- autoOpenConfig = MUCService.DEFAULT_AUTO_OPEN_BEHAVIOUR;
-
- if(autoOpenConfig.equals(MUCService.OPEN_ON_ACTIVITY)
- || (autoOpenConfig.equals(MUCService.OPEN_ON_MESSAGE)
- && !evt.isHistoryMessage())
- || evt.isImportantMessage())
- createWindow = true;
-
- if(sourceChatRoom.isSystem())
- {
- ChatRoomProviderWrapper serverWrapper
- = GuiActivator.getMUCService().findServerWrapperFromProvider(
- sourceChatRoom.getParentProvider());
-
- chatPanel = chatWindowManager.getMultiChat(
- serverWrapper.getSystemRoomWrapper(), createWindow);
- }
- else
- {
- chatPanel = chatWindowManager.getMultiChat(
- sourceChatRoom, createWindow, message.getMessageUID());
- }
-
- if(chatPanel == null)
- return;
-
- String messageContent = message.getContent();
-
- if (evt.isHistoryMessage())
- {
- Date timeStamp = chatPanel.getChatConversationPanel()
- .getLastIncomingMsgTimestamp();
- Collection<Object> c =
- chatPanel.getChatSession().getHistoryBeforeDate(
- new Date(
- timeStamp.equals(new Date(0))
- ? System.currentTimeMillis() - 10000
- : timeStamp.getTime()
- ), 20);
- if (c.size() > 0)
- {
- boolean isPresent = false;
- for (Object o : c)
- {
- if (o instanceof ChatRoomMessageDeliveredEvent)
- {
- ChatRoomMessageDeliveredEvent ev =
- (ChatRoomMessageDeliveredEvent) o;
- if (evt.getTimestamp() != null
- && evt.getTimestamp().equals(ev.getTimestamp()))
- {
- isPresent = true;
- break;
- }
- }
- else if(o instanceof ChatRoomMessageReceivedEvent)
- {
- ChatRoomMessageReceivedEvent ev =
- (ChatRoomMessageReceivedEvent) o;
- if (evt.getTimestamp() != null
- && evt.getTimestamp().equals(ev.getTimestamp()))
- {
- isPresent = true;
- break;
- }
- }
-
- Message m2 = evt.getMessage();
-
- if(m2 != null
- && m2.getContent().equals(messageContent))
- {
- isPresent = true;
- break;
- }
- }
-
- if (isPresent)
- return;
- }
- }
-
- chatPanel.addMessage(
- sourceMember.getName(),
- null,
- evt.getTimestamp(),
- messageType,
- messageContent,
- message.getContentType(),
- message.getMessageUID(),
- null);
-
- if(createWindow)
- chatWindowManager.openChat(chatPanel, false);
- }
-
- /**
- * Implements the <tt>ChatRoomMessageListener.messageDeliveryFailed</tt>
- * method.
- * <br>
- * In the conversation area shows an error message, explaining the problem.
- * @param evt the <tt>ChatRoomMessageDeliveryFailedEvent</tt> that notified
- * us of a delivery failure
- */
- public void messageDeliveryFailed(ChatRoomMessageDeliveryFailedEvent evt)
- {
- ChatRoom sourceChatRoom = evt.getSourceChatRoom();
-
- String errorMsg = null;
-
- /*
- * FIXME ChatRoomMessageDeliveryFailedEvent#getSource() is not a Message
- * instance at the time of this writing and the attempt "(Message)
- * evt.getSource()" seems to be to get the message which failed to be
- * delivered. I'm not sure it's
- * ChatRoomMessageDeliveryFailedEvent#getMessage() but since it's the
- * only message I can get out of ChatRoomMessageDeliveryFailedEvent, I'm
- * using it.
- */
- Message sourceMessage = evt.getMessage();
-
- ChatRoomMember destMember = evt.getDestinationChatRoomMember();
-
- if (evt.getErrorCode()
- == MessageDeliveryFailedEvent.OFFLINE_MESSAGES_NOT_SUPPORTED)
- {
- errorMsg = GuiActivator.getResources().getI18NString(
- "service.gui.MSG_DELIVERY_NOT_SUPPORTED",
- new String[]{destMember.getName()});
- }
- else if (evt.getErrorCode()
- == MessageDeliveryFailedEvent.NETWORK_FAILURE)
- {
- errorMsg = GuiActivator.getResources()
- .getI18NString("service.gui.MSG_NOT_DELIVERED");
- }
- else if (evt.getErrorCode()
- == MessageDeliveryFailedEvent.PROVIDER_NOT_REGISTERED)
- {
- errorMsg = GuiActivator.getResources().getI18NString(
- "service.gui.MSG_SEND_CONNECTION_PROBLEM");
- }
- else if (evt.getErrorCode()
- == MessageDeliveryFailedEvent.INTERNAL_ERROR)
- {
- errorMsg = GuiActivator.getResources().getI18NString(
- "service.gui.MSG_DELIVERY_INTERNAL_ERROR");
- }
- else if (evt.getErrorCode()
- == ChatRoomMessageDeliveryFailedEvent.FORBIDDEN)
- {
- errorMsg = GuiActivator.getResources().getI18NString(
- "service.gui.CHAT_ROOM_SEND_MSG_FORBIDDEN");
- }
- else if (evt.getErrorCode()
- == ChatRoomMessageDeliveryFailedEvent.UNSUPPORTED_OPERATION)
- {
- errorMsg =
- GuiActivator.getResources().getI18NString(
- "service.gui.MSG_DELIVERY_UNSUPPORTED_OPERATION");
- }
- else
- {
- errorMsg = GuiActivator.getResources().getI18NString(
- "service.gui.MSG_DELIVERY_UNKNOWN_ERROR");
- }
-
- String reason = evt.getReason();
- if (reason != null)
- errorMsg += " " + GuiActivator.getResources().getI18NString(
- "service.gui.ERROR_WAS",
- new String[]{reason});
-
- ChatWindowManager chatWindowManager
- = GuiActivator.getUIService().getChatWindowManager();
- ChatPanel chatPanel
- = chatWindowManager.getMultiChat(sourceChatRoom, true);
-
- chatPanel.addMessage(
- destMember != null ? destMember.getName()
- : sourceChatRoom.getName(),
- new Date(),
- Chat.OUTGOING_MESSAGE,
- sourceMessage.getContent(),
- sourceMessage.getContentType());
-
- chatPanel.addErrorMessage(
- destMember != null ? destMember.getName()
- : sourceChatRoom.getName(),
- errorMsg);
-
- chatWindowManager.openChat(chatPanel, false);
- }
-
- /**
- * Implements the
- * <tt>LocalUserAdHocChatRoomPresenceListener.localUserPresenceChanged</tt>
- * method
- *
- * @param evt the <tt>LocalUserAdHocChatRoomPresenceChangeEvent</tt> that
- * notified us of a presence change
- */
- public void localUserAdHocPresenceChanged(
- LocalUserAdHocChatRoomPresenceChangeEvent evt)
- {
- AdHocChatRoom sourceAdHocChatRoom = evt.getAdHocChatRoom();
- AdHocChatRoomWrapper adHocChatRoomWrapper
- = adHocChatRoomList
- .findChatRoomWrapperFromAdHocChatRoom(sourceAdHocChatRoom);
-
- String eventType = evt.getEventType();
-
- if (LocalUserAdHocChatRoomPresenceChangeEvent
- .LOCAL_USER_JOINED.equals(eventType))
- {
- if(adHocChatRoomWrapper != null)
- {
- this.fireAdHocChatRoomListChangedEvent(
- adHocChatRoomWrapper,
- AdHocChatRoomListChangeEvent.AD_HOC_CHAT_ROOM_CHANGED);
-
- ChatWindowManager chatWindowManager
- = GuiActivator.getUIService().getChatWindowManager();
- ChatPanel chatPanel
- = chatWindowManager
- .getMultiChat(adHocChatRoomWrapper, true);
-
- // Check if we have already opened a chat window for this chat
- // wrapper and load the real chat room corresponding to the
- // wrapper.
- if(chatPanel.isShown())
- ((AdHocConferenceChatSession) chatPanel.getChatSession())
- .loadChatRoom(sourceAdHocChatRoom);
- else
- chatWindowManager.openChat(chatPanel, true);
- }
-
- sourceAdHocChatRoom.addMessageListener(this);
- }
- else if (evt.getEventType().equals(
- LocalUserAdHocChatRoomPresenceChangeEvent.LOCAL_USER_JOIN_FAILED))
- {
- GuiActivator.getAlertUIService().showAlertPopup(
- GuiActivator.getResources().getI18NString("service.gui.ERROR"),
- GuiActivator.getResources().getI18NString(
- "service.gui.FAILED_TO_JOIN_CHAT_ROOM",
- new String[]{sourceAdHocChatRoom.getName()})
- + evt.getReason());
- }
- else if (LocalUserAdHocChatRoomPresenceChangeEvent
- .LOCAL_USER_LEFT.equals(eventType)
- || LocalUserAdHocChatRoomPresenceChangeEvent
- .LOCAL_USER_DROPPED.equals(eventType))
- {
- this.closeAdHocChatRoom(adHocChatRoomWrapper);
-
- // Need to refresh the chat room's list in order to change
- // the state of the chat room to offline.
- fireAdHocChatRoomListChangedEvent(
- adHocChatRoomWrapper,
- AdHocChatRoomListChangeEvent.AD_HOC_CHAT_ROOM_CHANGED);
-
- sourceAdHocChatRoom.removeMessageListener(this);
- }
- }
-
- /**
- * Implements the
- * <tt>LocalUserChatRoomPresenceListener.localUserPresenceChanged</tt>
- * method.
- * @param evt the <tt>LocalUserChatRoomPresenceChangeEvent</tt> that
- * notified us
- */
- public void localUserPresenceChanged(
- final LocalUserChatRoomPresenceChangeEvent evt)
- {
- if(!SwingUtilities.isEventDispatchThread())
- {
- SwingUtilities.invokeLater(new Runnable()
- {
- @Override
- public void run()
- {
- localUserPresenceChanged(evt);
- }
- });
- return;
- }
-
- ChatRoom sourceChatRoom = evt.getChatRoom();
- ChatRoomWrapper chatRoomWrapper
- = GuiActivator.getMUCService().findChatRoomWrapperFromChatRoom(
- sourceChatRoom);
-
- String eventType = evt.getEventType();
-
- if (LocalUserChatRoomPresenceChangeEvent
- .LOCAL_USER_JOINED.equals(eventType))
- {
- if(chatRoomWrapper != null)
- {
- GuiActivator.getMUCService().fireChatRoomListChangedEvent(
- chatRoomWrapper,
- ChatRoomListChangeEvent.CHAT_ROOM_CHANGED);
-
- boolean createWindow = false;
-
- String autoOpenConfig
- = MUCService.getChatRoomAutoOpenOption(
- sourceChatRoom.getParentProvider(),
- sourceChatRoom.getIdentifier());
-
- if(autoOpenConfig != null
- && autoOpenConfig.equals(MUCService.OPEN_ON_ACTIVITY))
- createWindow = true;
-
- ChatWindowManager chatWindowManager
- = GuiActivator.getUIService().getChatWindowManager();
- ChatPanel chatPanel
- = chatWindowManager.getMultiChat(
- chatRoomWrapper, createWindow);
-
- if(chatPanel != null)
- {
- chatPanel.setChatIcon(
- chatPanel.getChatSession().getChatStatusIcon());
-
- // Check if we have already opened a chat window for this chat
- // wrapper and load the real chat room corresponding to the
- // wrapper.
- if(chatPanel.isShown())
- {
- ((ConferenceChatSession) chatPanel.getChatSession())
- .loadChatRoom(sourceChatRoom);
- }
- else
- {
- chatWindowManager.openChat(chatPanel, true);
- }
- }
- }
-
- if (sourceChatRoom.isSystem())
- {
- ChatRoomProviderWrapper serverWrapper
- = GuiActivator.getMUCService()
- .findServerWrapperFromProvider(
- sourceChatRoom.getParentProvider());
-
- serverWrapper.setSystemRoom(sourceChatRoom);
- }
-
- sourceChatRoom.addMessageListener(this);
- sourceChatRoom.addLocalUserRoleListener(this);
- }
- else if (LocalUserChatRoomPresenceChangeEvent
- .LOCAL_USER_JOIN_FAILED.equals(eventType))
- {
- GuiActivator.getAlertUIService().showAlertPopup(
- GuiActivator.getResources().getI18NString("service.gui.ERROR"),
- GuiActivator.getResources().getI18NString(
- "service.gui.FAILED_TO_JOIN_CHAT_ROOM",
- new String[]{sourceChatRoom.getName()})
- + evt.getReason());
- }
- else if (LocalUserChatRoomPresenceChangeEvent
- .LOCAL_USER_LEFT.equals(eventType)
- || LocalUserChatRoomPresenceChangeEvent
- .LOCAL_USER_KICKED.equals(eventType)
- || LocalUserChatRoomPresenceChangeEvent
- .LOCAL_USER_DROPPED.equals(eventType))
- {
- if(chatRoomWrapper != null)
- {
- if(StringUtils.isNullOrEmpty(evt.getReason()))
- {
- GuiActivator.getUIService()
- .closeChatRoomWindow(chatRoomWrapper);
- }
- else
- {
- // send some system messages informing for the
- // reason of leaving
- ChatWindowManager chatWindowManager
- = GuiActivator.getUIService().getChatWindowManager();
-
- ChatPanel chatPanel = chatWindowManager.getMultiChat(
- sourceChatRoom, false);
-
- if(chatPanel != null)
- {
- chatPanel.addMessage(
- sourceChatRoom.getName(),
- null,
- new Date(),
- Chat.SYSTEM_MESSAGE,
- evt.getReason(),
- OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE,
- null,
- null);
-
- // print and the alternate address
- if(!StringUtils.isNullOrEmpty(
- evt.getAlternateAddress()))
- {
- chatPanel.addMessage(
- sourceChatRoom.getName(),
- null,
- new Date(),
- Chat.SYSTEM_MESSAGE,
- GuiActivator.getResources().getI18NString(
- "service.gui.CHAT_ROOM_ALTERNATE_ADDRESS",
- new String[]{evt.getAlternateAddress()}),
- OperationSetBasicInstantMessaging
- .DEFAULT_MIME_TYPE,
- null,
- null);
- }
- }
- }
-
- // Need to refresh the chat room's list in order to change
- // the state of the chat room to offline.
-
- GuiActivator.getMUCService().fireChatRoomListChangedEvent(
- chatRoomWrapper,
- ChatRoomListChangeEvent.CHAT_ROOM_CHANGED);
- }
-
- sourceChatRoom.removeMessageListener(this);
- sourceChatRoom.removelocalUserRoleListener(this);
- }
- }
-
-
- /**
- * Called to accept an incoming invitation. Adds the invitation chat room
- * to the list of chat rooms and joins it.
- *
- * @param invitation the invitation to accept
- * @param multiUserChatOpSet the operation set for chat conferencing
- * @throws OperationFailedException if the accept fails
- */
- public void acceptInvitation(
- AdHocChatRoomInvitation invitation,
- OperationSetAdHocMultiUserChat multiUserChatOpSet)
- throws OperationFailedException
- {
- AdHocChatRoom chatRoom = invitation.getTargetAdHocChatRoom();
-
- chatRoom.join();
- }
-
- /**
- * Rejects the given invitation with the specified reason.
- *
- * @param multiUserChatAdHocOpSet the operation set to use for rejecting the
- * invitation
- * @param invitation the invitation to reject
- * @param reason the reason for the rejection
- */
- public void rejectInvitation(
- OperationSetAdHocMultiUserChat multiUserChatAdHocOpSet,
- AdHocChatRoomInvitation invitation,
- String reason)
- {
- multiUserChatAdHocOpSet.rejectInvitation(invitation, reason);
- }
-
- /**
- * Creates an ad-hoc chat room, by specifying the ad-hoc chat room name, the
- * parent protocol provider and eventually, the contacts invited to
- * participate in this ad-hoc chat room.
- *
- * @param protocolProvider the parent protocol provider.
- * @param contacts the contacts invited when creating the chat room.
- * @param reason the reason for this invitation
- * @return the <tt>AdHocChatRoomWrapper</tt> corresponding to the created
- * ad hoc chat room
- */
- public AdHocChatRoomWrapper createAdHocChatRoom(
- ProtocolProviderService protocolProvider,
- Collection<String> contacts,
- String reason)
- {
- AdHocChatRoomWrapper chatRoomWrapper = null;
-
- OperationSetAdHocMultiUserChat groupChatOpSet
- = protocolProvider
- .getOperationSet(OperationSetAdHocMultiUserChat.class);
-
- // If there's no group chat operation set we have nothing to do here.
- if (groupChatOpSet == null)
- return null;
-
- AdHocChatRoom chatRoom = null;
-
- try
- {
- java.util.List<String> members = new LinkedList<String>();
-
- for(String address : contacts)
- members.add(address);
-
- chatRoom = groupChatOpSet.createAdHocChatRoom(
- "chatroom-" + new Date().getTime(), members, reason);
- }
- catch (OperationFailedException ex)
- {
- new ErrorDialog(
- GuiActivator.getUIService().getMainFrame(),
- GuiActivator.getResources().getI18NString("service.gui.ERROR"),
- GuiActivator.getResources().getI18NString(
- "service.gui.CREATE_CHAT_ROOM_ERROR",
- new String[]{protocolProvider.getProtocolDisplayName()}),
- ex)
- .showDialog();
- }
- catch (OperationNotSupportedException ex)
- {
- new ErrorDialog(
- GuiActivator.getUIService().getMainFrame(),
- GuiActivator.getResources().getI18NString("service.gui.ERROR"),
- GuiActivator.getResources().getI18NString(
- "service.gui.CREATE_CHAT_ROOM_ERROR",
- new String[]{protocolProvider.getProtocolDisplayName()}),
- ex)
- .showDialog();
- }
-
- if(chatRoom != null)
- {
- AdHocChatRoomProviderWrapper parentProvider
- = adHocChatRoomList.findServerWrapperFromProvider(
- protocolProvider);
-
- chatRoomWrapper = new AdHocChatRoomWrapper(
- parentProvider, chatRoom);
- parentProvider.addAdHocChatRoom(chatRoomWrapper);
- adHocChatRoomList.addAdHocChatRoom(chatRoomWrapper);
-
- fireAdHocChatRoomListChangedEvent(
- chatRoomWrapper,
- AdHocChatRoomListChangeEvent.AD_HOC_CHAT_ROOM_ADDED);
- }
-
- return chatRoomWrapper;
- }
-
- /**
- * Joins the given ad-hoc chat room
- *
- * @param chatRoomWrapper
- */
- public void joinChatRoom(AdHocChatRoomWrapper chatRoomWrapper)
- {
- AdHocChatRoom chatRoom = chatRoomWrapper.getAdHocChatRoom();
-
- if(chatRoom == null)
- {
- new ErrorDialog(
- GuiActivator.getUIService().getMainFrame(),
- GuiActivator.getResources().getI18NString("service.gui.WARNING"),
- GuiActivator.getResources().getI18NString(
- "service.gui.CHAT_ROOM_NOT_CONNECTED",
- new String[]{chatRoomWrapper.getAdHocChatRoomName()}))
- .showDialog();
-
- return;
- }
-
- new JoinAdHocChatRoomTask(chatRoomWrapper).execute();
- }
-
- /**
- * Removes the given chat room from the UI.
- *
- * @param chatRoomWrapper the chat room to remove.
- */
- public void removeChatRoom(ChatRoomWrapper chatRoomWrapper)
- {
- ChatRoom chatRoom = chatRoomWrapper.getChatRoom();
-
- if (chatRoom != null)
- leaveChatRoom(chatRoomWrapper);
-
- GuiActivator.getUIService().closeChatRoomWindow(chatRoomWrapper);
-
- GuiActivator.getMUCService().removeChatRoom(chatRoomWrapper);
-
- }
-
- /**
- * Joins the given chat room and manages all the exceptions that could
- * occur during the join process.
- *
- * @param chatRoom the chat room to join
- */
- public void joinChatRoom(AdHocChatRoom chatRoom)
- {
- AdHocChatRoomWrapper chatRoomWrapper
- = adHocChatRoomList.findChatRoomWrapperFromAdHocChatRoom(chatRoom);
-
- if(chatRoomWrapper == null)
- {
- AdHocChatRoomProviderWrapper parentProvider
- = adHocChatRoomList.findServerWrapperFromProvider(
- chatRoom.getParentProvider());
-
- chatRoomWrapper =
- new AdHocChatRoomWrapper(parentProvider, chatRoom);
-
- adHocChatRoomList.addAdHocChatRoom(chatRoomWrapper);
-
- fireAdHocChatRoomListChangedEvent(
- chatRoomWrapper,
- AdHocChatRoomListChangeEvent.AD_HOC_CHAT_ROOM_ADDED);
- }
-
- this.joinChatRoom(chatRoomWrapper);
-
- ChatWindowManager chatWindowManager
- = GuiActivator.getUIService().getChatWindowManager();
-
- chatWindowManager
- .openChat(
- chatWindowManager.getMultiChat(chatRoomWrapper, true),
- true);
- }
-
- /**
- * Leaves the given <tt>ChatRoom</tt>.
- *
- * @param chatRoomWrapper the <tt>ChatRoom</tt> to leave.
- */
- public void leaveChatRoom(ChatRoomWrapper chatRoomWrapper)
- {
- ChatRoomWrapper leavedRoomWrapped
- = GuiActivator.getMUCService().leaveChatRoom(chatRoomWrapper);
- if(leavedRoomWrapped != null)
- GuiActivator.getUIService().closeChatRoomWindow(leavedRoomWrapped);
- }
-
- /**
- * Leaves the given <tt>ChatRoom</tt>.
- *
- * @param chatRoomWrapper the <tt>ChatRoom</tt> to leave.
- */
- public void leaveChatRoom(AdHocChatRoomWrapper chatRoomWrapper)
- {
- AdHocChatRoom chatRoom = chatRoomWrapper.getAdHocChatRoom();
-
- if (chatRoom != null)
- {
- chatRoom.leave();
- }
- else
- {
- new ErrorDialog(
- GuiActivator.getUIService().getMainFrame(),
- GuiActivator.getResources().getI18NString("service.gui.WARNING"),
- GuiActivator.getResources().getI18NString(
- "service.gui.CHAT_ROOM_LEAVE_NOT_CONNECTED"))
- .showDialog();
- }
- }
-
- /**
- * Checks if there's an open history window for the given chat room.
- *
- * @param chatRoomWrapper the chat room wrapper to check for
- * @return TRUE if there's an opened history window for the given chat room,
- * FALSE otherwise.
- */
- public boolean containsHistoryWindowForChatRoom(
- ChatRoomWrapper chatRoomWrapper)
- {
- return chatRoomHistory.containsKey(chatRoomWrapper);
- }
-
- /**
- * Returns the history window for the given chat room.
- *
- * @param chatRoomWrapper the chat room wrapper to search for
- * @return the history window for the given chat room
- */
- public HistoryWindow getHistoryWindowForChatRoom(
- ChatRoomWrapper chatRoomWrapper)
- {
- return chatRoomHistory.get(chatRoomWrapper);
- }
-
- /**
- * Adds a history window for a given chat room in the table of opened
- * history windows.
- *
- * @param chatRoomWrapper the chat room wrapper to add
- * @param historyWindow the history window to add
- */
- public void addHistoryWindowForChatRoom(ChatRoomWrapper chatRoomWrapper,
- HistoryWindow historyWindow)
- {
- chatRoomHistory.put(chatRoomWrapper, historyWindow);
- }
-
- /**
- * Removes the history window for the given chat room.
- *
- * @param chatRoomWrapper the chat room wrapper to remove the history window
- */
- public void removeHistoryWindowForChatRoom(ChatRoomWrapper chatRoomWrapper)
- {
- chatRoomHistory.remove(chatRoomWrapper);
- }
-
- /**
- * Adds the given <tt>AdHocChatRoomListChangeListener</tt> that will listen
- * for all changes of the chat room list data model.
- *
- * @param l the listener to add.
- */
- public void addAdHocChatRoomListChangeListener(
- AdHocChatRoomListChangeListener l)
- {
- synchronized (adHoclistChangeListeners)
- {
- adHoclistChangeListeners.add(l);
- }
- }
-
- /**
- * Removes the given <tt>AdHocChatRoomListChangeListener</tt>.
- *
- * @param l the listener to remove.
- */
- public void removeAdHocChatRoomListChangeListener(
- AdHocChatRoomListChangeListener l)
- {
- synchronized (adHoclistChangeListeners)
- {
- adHoclistChangeListeners.remove(l);
- }
- }
-
- /**
- * Notifies all interested listeners that a change in the chat room list
- * model has occurred.
- * @param adHocChatRoomWrapper the chat room wrapper that identifies the
- * chat room
- * @param eventID the identifier of the event
- */
- private void fireAdHocChatRoomListChangedEvent(
- AdHocChatRoomWrapper adHocChatRoomWrapper,
- int eventID)
- {
- AdHocChatRoomListChangeEvent evt
- = new AdHocChatRoomListChangeEvent(adHocChatRoomWrapper, eventID);
-
- for (AdHocChatRoomListChangeListener l : adHoclistChangeListeners)
- {
- l.contentChanged(evt);
- }
- }
-
-
- /**
- * Closes the chat corresponding to the given ad-hoc chat room wrapper, if
- * such exists.
- *
- * @param chatRoomWrapper the ad-hoc chat room wrapper for which we search a
- * chat to close.
- */
- private void closeAdHocChatRoom(AdHocChatRoomWrapper chatRoomWrapper)
- {
- ChatWindowManager chatWindowManager
- = GuiActivator.getUIService().getChatWindowManager();
- ChatPanel chatPanel
- = chatWindowManager.getMultiChat(chatRoomWrapper, false);
-
- if (chatPanel != null)
- chatWindowManager.closeChat(chatPanel);
- }
-
- /**
- * Handles <tt>ServiceEvent</tt>s triggered by adding or removing a
- * ProtocolProviderService. Updates the list of available chat rooms and
- * chat room servers.
- *
- * @param event The event to handle.
- */
- public void serviceChanged(ServiceEvent event)
- {
- // if the event is caused by a bundle being stopped, we don't want to
- // know
- if (event.getServiceReference().getBundle().getState()
- == Bundle.STOPPING)
- return;
-
- Object service = GuiActivator.bundleContext.getService(event
- .getServiceReference());
-
- // we don't care if the source service is not a protocol provider
- if (!(service instanceof ProtocolProviderService))
- return;
-
- ProtocolProviderService protocolProvider
- = (ProtocolProviderService) service;
-
-
- Object multiUserChatAdHocOpSet
- = protocolProvider
- .getOperationSet(OperationSetAdHocMultiUserChat.class);
-
- if (multiUserChatAdHocOpSet != null)
- {
- if (event.getType() == ServiceEvent.REGISTERED)
- {
- adHocChatRoomList.addChatProvider(protocolProvider);
- }
- else if (event.getType() == ServiceEvent.UNREGISTERING)
- {
- adHocChatRoomList.removeChatProvider(protocolProvider);
- }
- }
- }
-
- /**
- * Joins an ad-hoc chat room in an asynchronous way.
- */
- private static class JoinAdHocChatRoomTask
- extends SwingWorker<String, Object>
- {
- private static final String SUCCESS = "Success";
-
- private static final String AUTHENTICATION_FAILED
- = "AuthenticationFailed";
-
- private static final String REGISTRATION_REQUIRED
- = "RegistrationRequired";
-
- private static final String PROVIDER_NOT_REGISTERED
- = "ProviderNotRegistered";
-
- private static final String SUBSCRIPTION_ALREADY_EXISTS
- = "SubscriptionAlreadyExists";
-
- private static final String UNKNOWN_ERROR
- = "UnknownError";
-
- private final AdHocChatRoomWrapper adHocChatRoomWrapper;
-
- JoinAdHocChatRoomTask(AdHocChatRoomWrapper chatRoomWrapper)
- {
- this.adHocChatRoomWrapper = chatRoomWrapper;
- }
-
- /**
- * @override {@link SwingWorker}{@link #doInBackground()} to perform
- * all asynchronous tasks.
- * @return SUCCESS if success, otherwise the error code
- */
- @Override
- public String doInBackground()
- {
- AdHocChatRoom chatRoom = adHocChatRoomWrapper.getAdHocChatRoom();
-
- try
- {
- chatRoom.join();
-
- return SUCCESS;
- }
- catch (OperationFailedException e)
- {
- if (logger.isTraceEnabled())
- logger.trace("Failed to join ad-hoc chat room: "
- + chatRoom.getName(), e);
-
- switch (e.getErrorCode())
- {
- case OperationFailedException.AUTHENTICATION_FAILED:
- return AUTHENTICATION_FAILED;
- case OperationFailedException.REGISTRATION_REQUIRED:
- return REGISTRATION_REQUIRED;
- case OperationFailedException.PROVIDER_NOT_REGISTERED:
- return PROVIDER_NOT_REGISTERED;
- case OperationFailedException.SUBSCRIPTION_ALREADY_EXISTS:
- return SUBSCRIPTION_ALREADY_EXISTS;
- default:
- return UNKNOWN_ERROR;
- }
- }
- }
-
- /**
- * @override {@link SwingWorker}{@link #done()} to perform UI changes
- * after the ad-hoc chat room join task has finished.
- */
- @Override
- protected void done()
- {
- String returnCode = null;
- try
- {
- returnCode = get();
- }
- catch (InterruptedException ignore)
- {}
- catch (ExecutionException ignore)
- {}
-
- ConfigurationUtils.updateChatRoomStatus(
- adHocChatRoomWrapper.getParentProvider().getProtocolProvider(),
- adHocChatRoomWrapper.getAdHocChatRoomID(),
- GlobalStatusEnum.ONLINE_STATUS);
-
- String errorMessage = null;
- if(PROVIDER_NOT_REGISTERED.equals(returnCode))
- {
- errorMessage
- = GuiActivator.getResources()
- .getI18NString("service.gui.CHAT_ROOM_NOT_CONNECTED",
- new String[]{
- adHocChatRoomWrapper.getAdHocChatRoomName()});
- }
- else if(SUBSCRIPTION_ALREADY_EXISTS.equals(returnCode))
- {
- errorMessage
- = GuiActivator.getResources()
- .getI18NString("service.gui.CHAT_ROOM_ALREADY_JOINED",
- new String[]{
- adHocChatRoomWrapper.getAdHocChatRoomName()});
- }
- else
- {
- errorMessage
- = GuiActivator.getResources()
- .getI18NString("service.gui.FAILED_TO_JOIN_CHAT_ROOM",
- new String[]{
- adHocChatRoomWrapper.getAdHocChatRoomName()});
- }
-
- if (!SUCCESS.equals(returnCode)
- && !AUTHENTICATION_FAILED.equals(returnCode))
- {
- GuiActivator.getAlertUIService().showAlertPopup(
- GuiActivator.getResources().getI18NString(
- "service.gui.ERROR"), errorMessage);
- }
- }
- }
-
-
- /**
- * Indicates that an invitation has been received and opens the invitation
- * dialog to notify the user.
- * @param evt the <tt>AdHocChatRoomInvitationReceivedEvent</tt> that
- * notified us
- */
- public void invitationReceived(AdHocChatRoomInvitationReceivedEvent evt)
- {
- if (logger.isInfoEnabled())
- logger.info("Invitation received: "+evt.toString());
- OperationSetAdHocMultiUserChat multiUserChatOpSet
- = evt.getSourceOperationSet();
-
- InvitationReceivedDialog dialog = new InvitationReceivedDialog(
- this, multiUserChatOpSet, evt.getInvitation());
-
- dialog.setVisible(true);
- }
-
- /**
- * Implements the <tt>AdHocChatRoomMessageListener.messageDelivered</tt>
- * method.
- * <br>
- * Shows the message in the conversation area and clears the write message
- * area.
- * @param evt the <tt>AdHocChatRoomMessageDeliveredEvent</tt> that notified
- * us
- */
- public void messageDelivered(AdHocChatRoomMessageDeliveredEvent evt)
- {
- AdHocChatRoom sourceChatRoom = (AdHocChatRoom) evt.getSource();
-
- if (logger.isInfoEnabled())
- logger.info("MESSAGE DELIVERED to ad-hoc chat room: "
- + sourceChatRoom.getName());
-
- ChatPanel chatPanel
- = GuiActivator
- .getUIService()
- .getChatWindowManager()
- .getMultiChat(sourceChatRoom, false);
-
- if(chatPanel != null)
- {
- String messageType;
- switch (evt.getEventType())
- {
- case AdHocChatRoomMessageDeliveredEvent
- .CONVERSATION_MESSAGE_DELIVERED:
- messageType = Chat.OUTGOING_MESSAGE;
- break;
- case AdHocChatRoomMessageDeliveredEvent.ACTION_MESSAGE_DELIVERED:
- messageType = Chat.ACTION_MESSAGE;
- break;
- default:
- messageType = null;
- }
-
- Message msg = evt.getMessage();
-
- chatPanel
- .addMessage(
- sourceChatRoom
- .getParentProvider().getAccountID().getUserID(),
- null,
- evt.getTimestamp(),
- messageType,
- msg.getContent(),
- msg.getContentType(),
- msg.getMessageUID(),
- null);
- }
- else
- {
- logger.error("chat panel is null, message NOT DELIVERED !");
- }
- }
-
- /**
- * Implements <tt>AdHocChatRoomMessageListener.messageDeliveryFailed</tt>
- * method.
- * <br>
- * In the conversation area shows an error message, explaining the problem.
- * @param evt the <tt>AdHocChatRoomMessageDeliveryFailedEvent</tt> that
- * notified us
- */
- public void messageDeliveryFailed(
- AdHocChatRoomMessageDeliveryFailedEvent evt)
- {
- AdHocChatRoom sourceChatRoom = evt.getSourceChatRoom();
- Message sourceMessage = evt.getMessage();
- Contact destParticipant = evt.getDestinationParticipant();
-
- String errorMsg = null;
- if (evt.getErrorCode()
- == MessageDeliveryFailedEvent.OFFLINE_MESSAGES_NOT_SUPPORTED)
- {
- errorMsg = GuiActivator.getResources().getI18NString(
- "service.gui.MSG_DELIVERY_NOT_SUPPORTED",
- new String[]{destParticipant.getDisplayName()});
- }
- else if (evt.getErrorCode()
- == MessageDeliveryFailedEvent.NETWORK_FAILURE)
- {
- errorMsg = GuiActivator.getResources()
- .getI18NString("service.gui.MSG_NOT_DELIVERED");
- }
- else if (evt.getErrorCode()
- == MessageDeliveryFailedEvent.PROVIDER_NOT_REGISTERED)
- {
- errorMsg = GuiActivator.getResources().getI18NString(
- "service.gui.MSG_SEND_CONNECTION_PROBLEM");
- }
- else if (evt.getErrorCode()
- == MessageDeliveryFailedEvent.INTERNAL_ERROR)
- {
- errorMsg = GuiActivator.getResources().getI18NString(
- "service.gui.MSG_DELIVERY_INTERNAL_ERROR");
- }
- else if (evt.getErrorCode()
- == MessageDeliveryFailedEvent.UNSUPPORTED_OPERATION)
- {
- errorMsg = GuiActivator.getResources().getI18NString(
- "service.gui.MSG_DELIVERY_UNSUPPORTED_OPERATION");
- }
- else
- {
- errorMsg = GuiActivator.getResources().getI18NString(
- "service.gui.MSG_DELIVERY_UNKNOWN_ERROR");
- }
-
- ChatWindowManager chatWindowManager
- = GuiActivator.getUIService().getChatWindowManager();
- ChatPanel chatPanel
- = chatWindowManager.getMultiChat(sourceChatRoom, true);
-
- chatPanel.addMessage(
- destParticipant.getDisplayName(),
- new Date(),
- Chat.OUTGOING_MESSAGE,
- sourceMessage.getContent(),
- sourceMessage.getContentType());
-
- chatPanel.addErrorMessage(
- destParticipant.getDisplayName(),
- errorMsg);
-
- chatWindowManager.openChat(chatPanel, false);
- }
-
- /**
- * Implements the <tt>AdHocChatRoomMessageListener.messageReceived</tt>
- * method.
- * <br>
- * Obtains the corresponding <tt>ChatPanel</tt> and process the message
- * there.
- * @param evt the <tt>AdHocChatRoomMessageReceivedEvent</tt> that notified
- * us
- */
- public void messageReceived(AdHocChatRoomMessageReceivedEvent evt)
- {
- AdHocChatRoom sourceChatRoom = evt.getSourceChatRoom();
- Contact sourceParticipant = evt.getSourceChatRoomParticipant();
-
- String messageType = null;
-
- switch (evt.getEventType())
- {
- case AdHocChatRoomMessageReceivedEvent.CONVERSATION_MESSAGE_RECEIVED:
- messageType = Chat.INCOMING_MESSAGE;
- break;
- case AdHocChatRoomMessageReceivedEvent.SYSTEM_MESSAGE_RECEIVED:
- messageType = Chat.SYSTEM_MESSAGE;
- break;
- case AdHocChatRoomMessageReceivedEvent.ACTION_MESSAGE_RECEIVED:
- messageType = Chat.ACTION_MESSAGE;
- break;
- }
-
- if (logger.isInfoEnabled())
- logger.info("MESSAGE RECEIVED from contact: "
- + sourceParticipant.getAddress());
-
- Message message = evt.getMessage();
-
- ChatWindowManager chatWindowManager
- = GuiActivator.getUIService().getChatWindowManager();
- ChatPanel chatPanel
- = chatWindowManager
- .getMultiChat(sourceChatRoom, true, message.getMessageUID());
-
- String messageContent = message.getContent();
-
- chatPanel.addMessage(
- sourceParticipant.getDisplayName(),
- null,
- evt.getTimestamp(),
- messageType,
- messageContent,
- message.getContentType(),
- message.getMessageUID(),
- null);
-
- chatWindowManager.openChat(chatPanel, false);
- }
-
- public void invitationRejected(AdHocChatRoomInvitationRejectedEvent evt) {}
-
- @Override
- public void localUserRoleChanged(ChatRoomLocalUserRoleChangeEvent evt)
- {
- if(evt.isInitial())
- return;
- ChatRoom sourceChatRoom = evt.getSourceChatRoom();
- ChatRoomWrapper chatRoomWrapper
- = GuiActivator.getMUCService().findChatRoomWrapperFromChatRoom(
- sourceChatRoom);
- ChatWindowManager chatWindowManager
- = GuiActivator.getUIService().getChatWindowManager();
- ChatPanel chatPanel
- = chatWindowManager.getMultiChat(chatRoomWrapper, true);
- chatWindowManager.openChat(chatPanel, true);
- }
-
-}
+package net.java.sip.communicator.impl.gui.main.chat.conference;
+
+import java.util.*;
+import java.util.concurrent.*;
+
+import javax.swing.*;
+import javax.swing.SwingWorker;
+
+import net.java.sip.communicator.impl.gui.*;
+import net.java.sip.communicator.impl.gui.main.chat.*;
+import net.java.sip.communicator.impl.gui.main.chat.history.*;
+import net.java.sip.communicator.impl.gui.main.chatroomslist.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
+import net.java.sip.communicator.service.gui.*;
+import net.java.sip.communicator.service.muc.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.event.*;
+import net.java.sip.communicator.service.protocol.globalstatus.*;
+import net.java.sip.communicator.util.*;
+import net.java.sip.communicator.util.Logger;
+
+import org.jitsi.util.*;
+import org.osgi.framework.*;
+
+/**
+ * The <tt>ConferenceChatManager</tt> is the one that manages both chat room and
+ * ad-hoc chat rooms invitations.
+ *
+ * @author Yana Stamcheva
+ * @author Lubomir Marinov
+ * @author Valentin Martinet
+ * @author Hristo Terezov
+ */
+public class ConferenceChatManager
+ implements ChatRoomMessageListener,
+ ChatRoomInvitationListener,
+ ChatRoomInvitationRejectionListener,
+ AdHocChatRoomMessageListener,
+ AdHocChatRoomInvitationListener,
+ AdHocChatRoomInvitationRejectionListener,
+ LocalUserChatRoomPresenceListener,
+ LocalUserAdHocChatRoomPresenceListener,
+ ServiceListener, ChatRoomLocalUserRoleListener
+{
+ /**
+ * The object used for logging.
+ */
+ private static final Logger logger
+ = Logger.getLogger(ConferenceChatManager.class);
+
+ /**
+ * Maps each history window to a <tt>ChatRoomWrapper</tt>.
+ */
+ private final Hashtable<ChatRoomWrapper, HistoryWindow> chatRoomHistory =
+ new Hashtable<ChatRoomWrapper, HistoryWindow>();
+
+ /**
+ * The list of ad-hoc chat rooms.
+ */
+ private final AdHocChatRoomList adHocChatRoomList = new AdHocChatRoomList();
+
+ /**
+ * A list of all <tt>AdHocChatRoomListChangeListener</tt>-s.
+ */
+ private final Vector<AdHocChatRoomListChangeListener>
+ adHoclistChangeListeners = new Vector<AdHocChatRoomListChangeListener>();
+
+ /**
+ * Creates an instance of <tt>ConferenceChatManager</tt>.
+ */
+ public ConferenceChatManager()
+ {
+ // Loads the chat rooms list in a separate thread.
+ new Thread()
+ {
+ @Override
+ public void run()
+ {
+ adHocChatRoomList.loadList();
+ }
+ }.start();
+
+ GuiActivator.bundleContext.addServiceListener(this);
+
+ }
+
+ /**
+ * Returns all chat room providers currently contained in the ad-hoc chat
+ * room list.
+ *
+ * @return all chat room providers currently contained in the ad-hoc chat
+ * room list.
+ */
+ public AdHocChatRoomList getAdHocChatRoomList()
+ {
+ return adHocChatRoomList;
+ }
+
+ /**
+ * Handles <tt>ChatRoomInvitationReceivedEvent</tt>-s.
+ */
+ public void invitationReceived(ChatRoomInvitationReceivedEvent evt)
+ {
+ InvitationReceivedDialog dialog
+ = new InvitationReceivedDialog(
+ this,
+ evt.getSourceOperationSet(),
+ evt.getInvitation());
+
+ dialog.setVisible(true);
+ }
+
+ public void invitationRejected(ChatRoomInvitationRejectedEvent evt) {}
+
+ /**
+ * Implements the <tt>ChatRoomMessageListener.messageDelivered</tt> method.
+ * <br>
+ * Shows the message in the conversation area and clears the write message
+ * area.
+ * @param evt the <tt>ChatRoomMessageDeliveredEvent</tt> that notified us
+ * that the message was delivered to its destination
+ */
+ public void messageDelivered(ChatRoomMessageDeliveredEvent evt)
+ {
+ ChatRoom sourceChatRoom = (ChatRoom) evt.getSource();
+
+ if (logger.isTraceEnabled())
+ logger.trace(
+ "MESSAGE DELIVERED to chat room: " + sourceChatRoom.getName());
+
+ ChatPanel chatPanel = GuiActivator.getUIService().getChatWindowManager()
+ .getMultiChat(sourceChatRoom, false);
+
+ if(chatPanel != null)
+ {
+ String messageType;
+
+ switch (evt.getEventType())
+ {
+ case ChatRoomMessageDeliveredEvent.CONVERSATION_MESSAGE_DELIVERED:
+ messageType = Chat.OUTGOING_MESSAGE;
+ break;
+ case ChatRoomMessageDeliveredEvent.ACTION_MESSAGE_DELIVERED:
+ messageType = Chat.ACTION_MESSAGE;
+ break;
+ default:
+ messageType = null;
+ break;
+ }
+
+ Message msg = evt.getMessage();
+
+ chatPanel.addMessage(
+ sourceChatRoom.getUserNickname(),
+ null,
+ evt.getTimestamp(),
+ messageType,
+ msg.getContent(),
+ msg.getContentType(),
+ msg.getMessageUID(),
+ null);
+ }
+ }
+
+ /**
+ * Implements the <tt>ChatRoomMessageListener.messageReceived</tt> method.
+ * <br>
+ * Obtains the corresponding <tt>ChatPanel</tt> and process the message
+ * there.
+ * @param evt the <tt>ChatRoomMessageReceivedEvent</tt> that notified us
+ * that a message has been received
+ */
+ public void messageReceived(ChatRoomMessageReceivedEvent evt)
+ {
+ ChatRoom sourceChatRoom = evt.getSourceChatRoom();
+ ChatRoomMember sourceMember = evt.getSourceChatRoomMember();
+
+ String messageType = null;
+
+ switch (evt.getEventType())
+ {
+ case ChatRoomMessageReceivedEvent.CONVERSATION_MESSAGE_RECEIVED:
+ messageType = Chat.INCOMING_MESSAGE;
+ break;
+ case ChatRoomMessageReceivedEvent.SYSTEM_MESSAGE_RECEIVED:
+ messageType = Chat.SYSTEM_MESSAGE;
+ break;
+ case ChatRoomMessageReceivedEvent.ACTION_MESSAGE_RECEIVED:
+ messageType = Chat.ACTION_MESSAGE;
+ break;
+ }
+
+ if (logger.isTraceEnabled())
+ logger.trace("MESSAGE RECEIVED from contact: "
+ + sourceMember.getContactAddress());
+
+ Message message = evt.getMessage();
+
+ ChatPanel chatPanel = null;
+
+ ChatWindowManager chatWindowManager
+ = GuiActivator.getUIService().getChatWindowManager();
+
+ boolean createWindow = false;
+ String autoOpenConfig
+ = MUCService.getChatRoomAutoOpenOption(
+ sourceChatRoom.getParentProvider(),
+ sourceChatRoom.getIdentifier());
+ if(autoOpenConfig == null)
+ autoOpenConfig = MUCService.DEFAULT_AUTO_OPEN_BEHAVIOUR;
+
+ if(autoOpenConfig.equals(MUCService.OPEN_ON_ACTIVITY)
+ || (autoOpenConfig.equals(MUCService.OPEN_ON_MESSAGE)
+ && !evt.isHistoryMessage())
+ || evt.isImportantMessage())
+ createWindow = true;
+
+ if(sourceChatRoom.isSystem())
+ {
+ ChatRoomProviderWrapper serverWrapper
+ = GuiActivator.getMUCService().findServerWrapperFromProvider(
+ sourceChatRoom.getParentProvider());
+
+ chatPanel = chatWindowManager.getMultiChat(
+ serverWrapper.getSystemRoomWrapper(), createWindow);
+ }
+ else
+ {
+ chatPanel = chatWindowManager.getMultiChat(
+ sourceChatRoom, createWindow, message.getMessageUID());
+ }
+
+ if(chatPanel == null)
+ return;
+
+ String messageContent = message.getContent();
+
+ if (evt.isHistoryMessage())
+ {
+ Date timeStamp = chatPanel.getChatConversationPanel()
+ .getLastIncomingMsgTimestamp();
+ Collection<Object> c =
+ chatPanel.getChatSession().getHistoryBeforeDate(
+ new Date(
+ timeStamp.equals(new Date(0))
+ ? System.currentTimeMillis() - 10000
+ : timeStamp.getTime()
+ ), 20);
+ if (c.size() > 0)
+ {
+ boolean isPresent = false;
+ for (Object o : c)
+ {
+ if (o instanceof ChatRoomMessageDeliveredEvent)
+ {
+ ChatRoomMessageDeliveredEvent ev =
+ (ChatRoomMessageDeliveredEvent) o;
+ if (evt.getTimestamp() != null
+ && evt.getTimestamp().equals(ev.getTimestamp()))
+ {
+ isPresent = true;
+ break;
+ }
+ }
+ else if(o instanceof ChatRoomMessageReceivedEvent)
+ {
+ ChatRoomMessageReceivedEvent ev =
+ (ChatRoomMessageReceivedEvent) o;
+ if (evt.getTimestamp() != null
+ && evt.getTimestamp().equals(ev.getTimestamp()))
+ {
+ isPresent = true;
+ break;
+ }
+ }
+
+ Message m2 = evt.getMessage();
+
+ if(m2 != null
+ && m2.getContent().equals(messageContent))
+ {
+ isPresent = true;
+ break;
+ }
+ }
+
+ if (isPresent)
+ return;
+ }
+ }
+
+ chatPanel.addMessage(
+ sourceMember.getName(),
+ null,
+ evt.getTimestamp(),
+ messageType,
+ messageContent,
+ message.getContentType(),
+ message.getMessageUID(),
+ null);
+
+ if(createWindow)
+ chatWindowManager.openChat(chatPanel, false);
+ }
+
+ /**
+ * Implements the <tt>ChatRoomMessageListener.messageDeliveryFailed</tt>
+ * method.
+ * <br>
+ * In the conversation area shows an error message, explaining the problem.
+ * @param evt the <tt>ChatRoomMessageDeliveryFailedEvent</tt> that notified
+ * us of a delivery failure
+ */
+ public void messageDeliveryFailed(ChatRoomMessageDeliveryFailedEvent evt)
+ {
+ ChatRoom sourceChatRoom = evt.getSourceChatRoom();
+
+ String errorMsg = null;
+
+ /*
+ * FIXME ChatRoomMessageDeliveryFailedEvent#getSource() is not a Message
+ * instance at the time of this writing and the attempt "(Message)
+ * evt.getSource()" seems to be to get the message which failed to be
+ * delivered. I'm not sure it's
+ * ChatRoomMessageDeliveryFailedEvent#getMessage() but since it's the
+ * only message I can get out of ChatRoomMessageDeliveryFailedEvent, I'm
+ * using it.
+ */
+ Message sourceMessage = evt.getMessage();
+
+ ChatRoomMember destMember = evt.getDestinationChatRoomMember();
+
+ if (evt.getErrorCode()
+ == MessageDeliveryFailedEvent.OFFLINE_MESSAGES_NOT_SUPPORTED)
+ {
+ errorMsg = GuiActivator.getResources().getI18NString(
+ "service.gui.MSG_DELIVERY_NOT_SUPPORTED",
+ new String[]{destMember.getName()});
+ }
+ else if (evt.getErrorCode()
+ == MessageDeliveryFailedEvent.NETWORK_FAILURE)
+ {
+ errorMsg = GuiActivator.getResources()
+ .getI18NString("service.gui.MSG_NOT_DELIVERED");
+ }
+ else if (evt.getErrorCode()
+ == MessageDeliveryFailedEvent.PROVIDER_NOT_REGISTERED)
+ {
+ errorMsg = GuiActivator.getResources().getI18NString(
+ "service.gui.MSG_SEND_CONNECTION_PROBLEM");
+ }
+ else if (evt.getErrorCode()
+ == MessageDeliveryFailedEvent.INTERNAL_ERROR)
+ {
+ errorMsg = GuiActivator.getResources().getI18NString(
+ "service.gui.MSG_DELIVERY_INTERNAL_ERROR");
+ }
+ else if (evt.getErrorCode()
+ == ChatRoomMessageDeliveryFailedEvent.FORBIDDEN)
+ {
+ errorMsg = GuiActivator.getResources().getI18NString(
+ "service.gui.CHAT_ROOM_SEND_MSG_FORBIDDEN");
+ }
+ else if (evt.getErrorCode()
+ == ChatRoomMessageDeliveryFailedEvent.UNSUPPORTED_OPERATION)
+ {
+ errorMsg =
+ GuiActivator.getResources().getI18NString(
+ "service.gui.MSG_DELIVERY_UNSUPPORTED_OPERATION");
+ }
+ else
+ {
+ errorMsg = GuiActivator.getResources().getI18NString(
+ "service.gui.MSG_DELIVERY_UNKNOWN_ERROR");
+ }
+
+ String reason = evt.getReason();
+ if (reason != null)
+ errorMsg += " " + GuiActivator.getResources().getI18NString(
+ "service.gui.ERROR_WAS",
+ new String[]{reason});
+
+ ChatWindowManager chatWindowManager
+ = GuiActivator.getUIService().getChatWindowManager();
+ ChatPanel chatPanel
+ = chatWindowManager.getMultiChat(sourceChatRoom, true);
+
+ chatPanel.addMessage(
+ destMember != null ? destMember.getName()
+ : sourceChatRoom.getName(),
+ new Date(),
+ Chat.OUTGOING_MESSAGE,
+ sourceMessage.getContent(),
+ sourceMessage.getContentType());
+
+ chatPanel.addErrorMessage(
+ destMember != null ? destMember.getName()
+ : sourceChatRoom.getName(),
+ errorMsg);
+
+ chatWindowManager.openChat(chatPanel, false);
+ }
+
+ /**
+ * Implements the
+ * <tt>LocalUserAdHocChatRoomPresenceListener.localUserPresenceChanged</tt>
+ * method
+ *
+ * @param evt the <tt>LocalUserAdHocChatRoomPresenceChangeEvent</tt> that
+ * notified us of a presence change
+ */
+ public void localUserAdHocPresenceChanged(
+ LocalUserAdHocChatRoomPresenceChangeEvent evt)
+ {
+ AdHocChatRoom sourceAdHocChatRoom = evt.getAdHocChatRoom();
+ AdHocChatRoomWrapper adHocChatRoomWrapper
+ = adHocChatRoomList
+ .findChatRoomWrapperFromAdHocChatRoom(sourceAdHocChatRoom);
+
+ String eventType = evt.getEventType();
+
+ if (LocalUserAdHocChatRoomPresenceChangeEvent
+ .LOCAL_USER_JOINED.equals(eventType))
+ {
+ if(adHocChatRoomWrapper != null)
+ {
+ this.fireAdHocChatRoomListChangedEvent(
+ adHocChatRoomWrapper,
+ AdHocChatRoomListChangeEvent.AD_HOC_CHAT_ROOM_CHANGED);
+
+ ChatWindowManager chatWindowManager
+ = GuiActivator.getUIService().getChatWindowManager();
+ ChatPanel chatPanel
+ = chatWindowManager
+ .getMultiChat(adHocChatRoomWrapper, true);
+
+ // Check if we have already opened a chat window for this chat
+ // wrapper and load the real chat room corresponding to the
+ // wrapper.
+ if(chatPanel.isShown())
+ ((AdHocConferenceChatSession) chatPanel.getChatSession())
+ .loadChatRoom(sourceAdHocChatRoom);
+ else
+ chatWindowManager.openChat(chatPanel, true);
+ }
+
+ sourceAdHocChatRoom.addMessageListener(this);
+ }
+ else if (evt.getEventType().equals(
+ LocalUserAdHocChatRoomPresenceChangeEvent.LOCAL_USER_JOIN_FAILED))
+ {
+ GuiActivator.getAlertUIService().showAlertPopup(
+ GuiActivator.getResources().getI18NString("service.gui.ERROR"),
+ GuiActivator.getResources().getI18NString(
+ "service.gui.FAILED_TO_JOIN_CHAT_ROOM",
+ new String[]{sourceAdHocChatRoom.getName()})
+ + evt.getReason());
+ }
+ else if (LocalUserAdHocChatRoomPresenceChangeEvent
+ .LOCAL_USER_LEFT.equals(eventType)
+ || LocalUserAdHocChatRoomPresenceChangeEvent
+ .LOCAL_USER_DROPPED.equals(eventType))
+ {
+ this.closeAdHocChatRoom(adHocChatRoomWrapper);
+
+ // Need to refresh the chat room's list in order to change
+ // the state of the chat room to offline.
+ fireAdHocChatRoomListChangedEvent(
+ adHocChatRoomWrapper,
+ AdHocChatRoomListChangeEvent.AD_HOC_CHAT_ROOM_CHANGED);
+
+ sourceAdHocChatRoom.removeMessageListener(this);
+ }
+ }
+
+ /**
+ * Implements the
+ * <tt>LocalUserChatRoomPresenceListener.localUserPresenceChanged</tt>
+ * method.
+ * @param evt the <tt>LocalUserChatRoomPresenceChangeEvent</tt> that
+ * notified us
+ */
+ public void localUserPresenceChanged(
+ final LocalUserChatRoomPresenceChangeEvent evt)
+ {
+ if(!SwingUtilities.isEventDispatchThread())
+ {
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ localUserPresenceChanged(evt);
+ }
+ });
+ return;
+ }
+
+ ChatRoom sourceChatRoom = evt.getChatRoom();
+ ChatRoomWrapper chatRoomWrapper
+ = GuiActivator.getMUCService().findChatRoomWrapperFromChatRoom(
+ sourceChatRoom);
+
+ String eventType = evt.getEventType();
+
+ if (LocalUserChatRoomPresenceChangeEvent
+ .LOCAL_USER_JOINED.equals(eventType))
+ {
+ if(chatRoomWrapper != null)
+ {
+ GuiActivator.getMUCService().fireChatRoomListChangedEvent(
+ chatRoomWrapper,
+ ChatRoomListChangeEvent.CHAT_ROOM_CHANGED);
+
+ boolean createWindow = false;
+
+ String autoOpenConfig
+ = MUCService.getChatRoomAutoOpenOption(
+ sourceChatRoom.getParentProvider(),
+ sourceChatRoom.getIdentifier());
+
+ if(autoOpenConfig != null
+ && autoOpenConfig.equals(MUCService.OPEN_ON_ACTIVITY))
+ createWindow = true;
+
+ ChatWindowManager chatWindowManager
+ = GuiActivator.getUIService().getChatWindowManager();
+ ChatPanel chatPanel
+ = chatWindowManager.getMultiChat(
+ chatRoomWrapper, createWindow);
+
+ if(chatPanel != null)
+ {
+ chatPanel.setChatIcon(
+ chatPanel.getChatSession().getChatStatusIcon());
+
+ // Check if we have already opened a chat window for this chat
+ // wrapper and load the real chat room corresponding to the
+ // wrapper.
+ if(chatPanel.isShown())
+ {
+ ((ConferenceChatSession) chatPanel.getChatSession())
+ .loadChatRoom(sourceChatRoom);
+ }
+ else
+ {
+ chatWindowManager.openChat(chatPanel, true);
+ }
+ }
+ }
+
+ if (sourceChatRoom.isSystem())
+ {
+ ChatRoomProviderWrapper serverWrapper
+ = GuiActivator.getMUCService()
+ .findServerWrapperFromProvider(
+ sourceChatRoom.getParentProvider());
+
+ serverWrapper.setSystemRoom(sourceChatRoom);
+ }
+
+ sourceChatRoom.addMessageListener(this);
+ sourceChatRoom.addLocalUserRoleListener(this);
+ }
+ else if (LocalUserChatRoomPresenceChangeEvent
+ .LOCAL_USER_JOIN_FAILED.equals(eventType))
+ {
+ GuiActivator.getAlertUIService().showAlertPopup(
+ GuiActivator.getResources().getI18NString("service.gui.ERROR"),
+ GuiActivator.getResources().getI18NString(
+ "service.gui.FAILED_TO_JOIN_CHAT_ROOM",
+ new String[]{sourceChatRoom.getName()})
+ + evt.getReason());
+ }
+ else if (LocalUserChatRoomPresenceChangeEvent
+ .LOCAL_USER_LEFT.equals(eventType)
+ || LocalUserChatRoomPresenceChangeEvent
+ .LOCAL_USER_KICKED.equals(eventType)
+ || LocalUserChatRoomPresenceChangeEvent
+ .LOCAL_USER_DROPPED.equals(eventType))
+ {
+ if(chatRoomWrapper != null)
+ {
+ if(StringUtils.isNullOrEmpty(evt.getReason()))
+ {
+ GuiActivator.getUIService()
+ .closeChatRoomWindow(chatRoomWrapper);
+ }
+ else
+ {
+ // send some system messages informing for the
+ // reason of leaving
+ ChatWindowManager chatWindowManager
+ = GuiActivator.getUIService().getChatWindowManager();
+
+ ChatPanel chatPanel = chatWindowManager.getMultiChat(
+ sourceChatRoom, false);
+
+ if(chatPanel != null)
+ {
+ chatPanel.addMessage(
+ sourceChatRoom.getName(),
+ null,
+ new Date(),
+ Chat.SYSTEM_MESSAGE,
+ evt.getReason(),
+ OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE,
+ null,
+ null);
+
+ // print and the alternate address
+ if(!StringUtils.isNullOrEmpty(
+ evt.getAlternateAddress()))
+ {
+ chatPanel.addMessage(
+ sourceChatRoom.getName(),
+ null,
+ new Date(),
+ Chat.SYSTEM_MESSAGE,
+ GuiActivator.getResources().getI18NString(
+ "service.gui.CHAT_ROOM_ALTERNATE_ADDRESS",
+ new String[]{evt.getAlternateAddress()}),
+ OperationSetBasicInstantMessaging
+ .DEFAULT_MIME_TYPE,
+ null,
+ null);
+ }
+ }
+ }
+
+ // Need to refresh the chat room's list in order to change
+ // the state of the chat room to offline.
+
+ GuiActivator.getMUCService().fireChatRoomListChangedEvent(
+ chatRoomWrapper,
+ ChatRoomListChangeEvent.CHAT_ROOM_CHANGED);
+ }
+
+ sourceChatRoom.removeMessageListener(this);
+ sourceChatRoom.removelocalUserRoleListener(this);
+ }
+ }
+
+
+ /**
+ * Called to accept an incoming invitation. Adds the invitation chat room
+ * to the list of chat rooms and joins it.
+ *
+ * @param invitation the invitation to accept
+ * @param multiUserChatOpSet the operation set for chat conferencing
+ * @throws OperationFailedException if the accept fails
+ */
+ public void acceptInvitation(
+ AdHocChatRoomInvitation invitation,
+ OperationSetAdHocMultiUserChat multiUserChatOpSet)
+ throws OperationFailedException
+ {
+ AdHocChatRoom chatRoom = invitation.getTargetAdHocChatRoom();
+
+ chatRoom.join();
+ }
+
+ /**
+ * Rejects the given invitation with the specified reason.
+ *
+ * @param multiUserChatAdHocOpSet the operation set to use for rejecting the
+ * invitation
+ * @param invitation the invitation to reject
+ * @param reason the reason for the rejection
+ */
+ public void rejectInvitation(
+ OperationSetAdHocMultiUserChat multiUserChatAdHocOpSet,
+ AdHocChatRoomInvitation invitation,
+ String reason)
+ {
+ multiUserChatAdHocOpSet.rejectInvitation(invitation, reason);
+ }
+
+ /**
+ * Creates an ad-hoc chat room, by specifying the ad-hoc chat room name, the
+ * parent protocol provider and eventually, the contacts invited to
+ * participate in this ad-hoc chat room.
+ *
+ * @param protocolProvider the parent protocol provider.
+ * @param contacts the contacts invited when creating the chat room.
+ * @param reason the reason for this invitation
+ * @return the <tt>AdHocChatRoomWrapper</tt> corresponding to the created
+ * ad hoc chat room
+ */
+ public AdHocChatRoomWrapper createAdHocChatRoom(
+ ProtocolProviderService protocolProvider,
+ Collection<String> contacts,
+ String reason)
+ {
+ AdHocChatRoomWrapper chatRoomWrapper = null;
+
+ OperationSetAdHocMultiUserChat groupChatOpSet
+ = protocolProvider
+ .getOperationSet(OperationSetAdHocMultiUserChat.class);
+
+ // If there's no group chat operation set we have nothing to do here.
+ if (groupChatOpSet == null)
+ return null;
+
+ AdHocChatRoom chatRoom = null;
+
+ try
+ {
+ java.util.List<String> members = new LinkedList<String>();
+
+ for(String address : contacts)
+ members.add(address);
+
+ chatRoom = groupChatOpSet.createAdHocChatRoom(
+ "chatroom-" + new Date().getTime(), members, reason);
+ }
+ catch (OperationFailedException ex)
+ {
+ new ErrorDialog(
+ GuiActivator.getUIService().getMainFrame(),
+ GuiActivator.getResources().getI18NString("service.gui.ERROR"),
+ GuiActivator.getResources().getI18NString(
+ "service.gui.CREATE_CHAT_ROOM_ERROR",
+ new String[]{protocolProvider.getProtocolDisplayName()}),
+ ex)
+ .showDialog();
+ }
+ catch (OperationNotSupportedException ex)
+ {
+ new ErrorDialog(
+ GuiActivator.getUIService().getMainFrame(),
+ GuiActivator.getResources().getI18NString("service.gui.ERROR"),
+ GuiActivator.getResources().getI18NString(
+ "service.gui.CREATE_CHAT_ROOM_ERROR",
+ new String[]{protocolProvider.getProtocolDisplayName()}),
+ ex)
+ .showDialog();
+ }
+
+ if(chatRoom != null)
+ {
+ AdHocChatRoomProviderWrapper parentProvider
+ = adHocChatRoomList.findServerWrapperFromProvider(
+ protocolProvider);
+
+ chatRoomWrapper = new AdHocChatRoomWrapper(
+ parentProvider, chatRoom);
+ parentProvider.addAdHocChatRoom(chatRoomWrapper);
+ adHocChatRoomList.addAdHocChatRoom(chatRoomWrapper);
+
+ fireAdHocChatRoomListChangedEvent(
+ chatRoomWrapper,
+ AdHocChatRoomListChangeEvent.AD_HOC_CHAT_ROOM_ADDED);
+ }
+
+ return chatRoomWrapper;
+ }
+
+ /**
+ * Joins the given ad-hoc chat room
+ *
+ * @param chatRoomWrapper
+ */
+ public void joinChatRoom(AdHocChatRoomWrapper chatRoomWrapper)
+ {
+ AdHocChatRoom chatRoom = chatRoomWrapper.getAdHocChatRoom();
+
+ if(chatRoom == null)
+ {
+ new ErrorDialog(
+ GuiActivator.getUIService().getMainFrame(),
+ GuiActivator.getResources().getI18NString("service.gui.WARNING"),
+ GuiActivator.getResources().getI18NString(
+ "service.gui.CHAT_ROOM_NOT_CONNECTED",
+ new String[]{chatRoomWrapper.getAdHocChatRoomName()}))
+ .showDialog();
+
+ return;
+ }
+
+ new JoinAdHocChatRoomTask(chatRoomWrapper).execute();
+ }
+
+ /**
+ * Removes the given chat room from the UI.
+ *
+ * @param chatRoomWrapper the chat room to remove.
+ */
+ public void removeChatRoom(ChatRoomWrapper chatRoomWrapper)
+ {
+ ChatRoom chatRoom = chatRoomWrapper.getChatRoom();
+
+ if (chatRoom != null)
+ leaveChatRoom(chatRoomWrapper);
+
+ GuiActivator.getUIService().closeChatRoomWindow(chatRoomWrapper);
+
+ GuiActivator.getMUCService().removeChatRoom(chatRoomWrapper);
+
+ }
+
+ /**
+ * Joins the given chat room and manages all the exceptions that could
+ * occur during the join process.
+ *
+ * @param chatRoom the chat room to join
+ */
+ public void joinChatRoom(AdHocChatRoom chatRoom)
+ {
+ AdHocChatRoomWrapper chatRoomWrapper
+ = adHocChatRoomList.findChatRoomWrapperFromAdHocChatRoom(chatRoom);
+
+ if(chatRoomWrapper == null)
+ {
+ AdHocChatRoomProviderWrapper parentProvider
+ = adHocChatRoomList.findServerWrapperFromProvider(
+ chatRoom.getParentProvider());
+
+ chatRoomWrapper =
+ new AdHocChatRoomWrapper(parentProvider, chatRoom);
+
+ adHocChatRoomList.addAdHocChatRoom(chatRoomWrapper);
+
+ fireAdHocChatRoomListChangedEvent(
+ chatRoomWrapper,
+ AdHocChatRoomListChangeEvent.AD_HOC_CHAT_ROOM_ADDED);
+ }
+
+ this.joinChatRoom(chatRoomWrapper);
+
+ ChatWindowManager chatWindowManager
+ = GuiActivator.getUIService().getChatWindowManager();
+
+ chatWindowManager
+ .openChat(
+ chatWindowManager.getMultiChat(chatRoomWrapper, true),
+ true);
+ }
+
+ /**
+ * Leaves the given <tt>ChatRoom</tt>.
+ *
+ * @param chatRoomWrapper the <tt>ChatRoom</tt> to leave.
+ */
+ public void leaveChatRoom(ChatRoomWrapper chatRoomWrapper)
+ {
+ ChatRoomWrapper leavedRoomWrapped
+ = GuiActivator.getMUCService().leaveChatRoom(chatRoomWrapper);
+ if(leavedRoomWrapped != null)
+ GuiActivator.getUIService().closeChatRoomWindow(leavedRoomWrapped);
+ }
+
+ /**
+ * Leaves the given <tt>ChatRoom</tt>.
+ *
+ * @param chatRoomWrapper the <tt>ChatRoom</tt> to leave.
+ */
+ public void leaveChatRoom(AdHocChatRoomWrapper chatRoomWrapper)
+ {
+ AdHocChatRoom chatRoom = chatRoomWrapper.getAdHocChatRoom();
+
+ if (chatRoom != null)
+ {
+ chatRoom.leave();
+ }
+ else
+ {
+ new ErrorDialog(
+ GuiActivator.getUIService().getMainFrame(),
+ GuiActivator.getResources().getI18NString("service.gui.WARNING"),
+ GuiActivator.getResources().getI18NString(
+ "service.gui.CHAT_ROOM_LEAVE_NOT_CONNECTED"))
+ .showDialog();
+ }
+ }
+
+ /**
+ * Checks if there's an open history window for the given chat room.
+ *
+ * @param chatRoomWrapper the chat room wrapper to check for
+ * @return TRUE if there's an opened history window for the given chat room,
+ * FALSE otherwise.
+ */
+ public boolean containsHistoryWindowForChatRoom(
+ ChatRoomWrapper chatRoomWrapper)
+ {
+ return chatRoomHistory.containsKey(chatRoomWrapper);
+ }
+
+ /**
+ * Returns the history window for the given chat room.
+ *
+ * @param chatRoomWrapper the chat room wrapper to search for
+ * @return the history window for the given chat room
+ */
+ public HistoryWindow getHistoryWindowForChatRoom(
+ ChatRoomWrapper chatRoomWrapper)
+ {
+ return chatRoomHistory.get(chatRoomWrapper);
+ }
+
+ /**
+ * Adds a history window for a given chat room in the table of opened
+ * history windows.
+ *
+ * @param chatRoomWrapper the chat room wrapper to add
+ * @param historyWindow the history window to add
+ */
+ public void addHistoryWindowForChatRoom(ChatRoomWrapper chatRoomWrapper,
+ HistoryWindow historyWindow)
+ {
+ chatRoomHistory.put(chatRoomWrapper, historyWindow);
+ }
+
+ /**
+ * Removes the history window for the given chat room.
+ *
+ * @param chatRoomWrapper the chat room wrapper to remove the history window
+ */
+ public void removeHistoryWindowForChatRoom(ChatRoomWrapper chatRoomWrapper)
+ {
+ chatRoomHistory.remove(chatRoomWrapper);
+ }
+
+ /**
+ * Adds the given <tt>AdHocChatRoomListChangeListener</tt> that will listen
+ * for all changes of the chat room list data model.
+ *
+ * @param l the listener to add.
+ */
+ public void addAdHocChatRoomListChangeListener(
+ AdHocChatRoomListChangeListener l)
+ {
+ synchronized (adHoclistChangeListeners)
+ {
+ adHoclistChangeListeners.add(l);
+ }
+ }
+
+ /**
+ * Removes the given <tt>AdHocChatRoomListChangeListener</tt>.
+ *
+ * @param l the listener to remove.
+ */
+ public void removeAdHocChatRoomListChangeListener(
+ AdHocChatRoomListChangeListener l)
+ {
+ synchronized (adHoclistChangeListeners)
+ {
+ adHoclistChangeListeners.remove(l);
+ }
+ }
+
+ /**
+ * Notifies all interested listeners that a change in the chat room list
+ * model has occurred.
+ * @param adHocChatRoomWrapper the chat room wrapper that identifies the
+ * chat room
+ * @param eventID the identifier of the event
+ */
+ private void fireAdHocChatRoomListChangedEvent(
+ AdHocChatRoomWrapper adHocChatRoomWrapper,
+ int eventID)
+ {
+ AdHocChatRoomListChangeEvent evt
+ = new AdHocChatRoomListChangeEvent(adHocChatRoomWrapper, eventID);
+
+ for (AdHocChatRoomListChangeListener l : adHoclistChangeListeners)
+ {
+ l.contentChanged(evt);
+ }
+ }
+
+
+ /**
+ * Closes the chat corresponding to the given ad-hoc chat room wrapper, if
+ * such exists.
+ *
+ * @param chatRoomWrapper the ad-hoc chat room wrapper for which we search a
+ * chat to close.
+ */
+ private void closeAdHocChatRoom(AdHocChatRoomWrapper chatRoomWrapper)
+ {
+ ChatWindowManager chatWindowManager
+ = GuiActivator.getUIService().getChatWindowManager();
+ ChatPanel chatPanel
+ = chatWindowManager.getMultiChat(chatRoomWrapper, false);
+
+ if (chatPanel != null)
+ chatWindowManager.closeChat(chatPanel);
+ }
+
+ /**
+ * Handles <tt>ServiceEvent</tt>s triggered by adding or removing a
+ * ProtocolProviderService. Updates the list of available chat rooms and
+ * chat room servers.
+ *
+ * @param event The event to handle.
+ */
+ public void serviceChanged(ServiceEvent event)
+ {
+ // if the event is caused by a bundle being stopped, we don't want to
+ // know
+ if (event.getServiceReference().getBundle().getState()
+ == Bundle.STOPPING)
+ return;
+
+ Object service = GuiActivator.bundleContext.getService(event
+ .getServiceReference());
+
+ // we don't care if the source service is not a protocol provider
+ if (!(service instanceof ProtocolProviderService))
+ return;
+
+ ProtocolProviderService protocolProvider
+ = (ProtocolProviderService) service;
+
+
+ Object multiUserChatAdHocOpSet
+ = protocolProvider
+ .getOperationSet(OperationSetAdHocMultiUserChat.class);
+
+ if (multiUserChatAdHocOpSet != null)
+ {
+ if (event.getType() == ServiceEvent.REGISTERED)
+ {
+ adHocChatRoomList.addChatProvider(protocolProvider);
+ }
+ else if (event.getType() == ServiceEvent.UNREGISTERING)
+ {
+ adHocChatRoomList.removeChatProvider(protocolProvider);
+ }
+ }
+ }
+
+ /**
+ * Joins an ad-hoc chat room in an asynchronous way.
+ */
+ private static class JoinAdHocChatRoomTask
+ extends SwingWorker<String, Object>
+ {
+ private static final String SUCCESS = "Success";
+
+ private static final String AUTHENTICATION_FAILED
+ = "AuthenticationFailed";
+
+ private static final String REGISTRATION_REQUIRED
+ = "RegistrationRequired";
+
+ private static final String PROVIDER_NOT_REGISTERED
+ = "ProviderNotRegistered";
+
+ private static final String SUBSCRIPTION_ALREADY_EXISTS
+ = "SubscriptionAlreadyExists";
+
+ private static final String UNKNOWN_ERROR
+ = "UnknownError";
+
+ private final AdHocChatRoomWrapper adHocChatRoomWrapper;
+
+ JoinAdHocChatRoomTask(AdHocChatRoomWrapper chatRoomWrapper)
+ {
+ this.adHocChatRoomWrapper = chatRoomWrapper;
+ }
+
+ /**
+ * @override {@link SwingWorker}{@link #doInBackground()} to perform
+ * all asynchronous tasks.
+ * @return SUCCESS if success, otherwise the error code
+ */
+ @Override
+ public String doInBackground()
+ {
+ AdHocChatRoom chatRoom = adHocChatRoomWrapper.getAdHocChatRoom();
+
+ try
+ {
+ chatRoom.join();
+
+ return SUCCESS;
+ }
+ catch (OperationFailedException e)
+ {
+ if (logger.isTraceEnabled())
+ logger.trace("Failed to join ad-hoc chat room: "
+ + chatRoom.getName(), e);
+
+ switch (e.getErrorCode())
+ {
+ case OperationFailedException.AUTHENTICATION_FAILED:
+ return AUTHENTICATION_FAILED;
+ case OperationFailedException.REGISTRATION_REQUIRED:
+ return REGISTRATION_REQUIRED;
+ case OperationFailedException.PROVIDER_NOT_REGISTERED:
+ return PROVIDER_NOT_REGISTERED;
+ case OperationFailedException.SUBSCRIPTION_ALREADY_EXISTS:
+ return SUBSCRIPTION_ALREADY_EXISTS;
+ default:
+ return UNKNOWN_ERROR;
+ }
+ }
+ }
+
+ /**
+ * @override {@link SwingWorker}{@link #done()} to perform UI changes
+ * after the ad-hoc chat room join task has finished.
+ */
+ @Override
+ protected void done()
+ {
+ String returnCode = null;
+ try
+ {
+ returnCode = get();
+ }
+ catch (InterruptedException ignore)
+ {}
+ catch (ExecutionException ignore)
+ {}
+
+ ConfigurationUtils.updateChatRoomStatus(
+ adHocChatRoomWrapper.getParentProvider().getProtocolProvider(),
+ adHocChatRoomWrapper.getAdHocChatRoomID(),
+ GlobalStatusEnum.ONLINE_STATUS);
+
+ String errorMessage = null;
+ if(PROVIDER_NOT_REGISTERED.equals(returnCode))
+ {
+ errorMessage
+ = GuiActivator.getResources()
+ .getI18NString("service.gui.CHAT_ROOM_NOT_CONNECTED",
+ new String[]{
+ adHocChatRoomWrapper.getAdHocChatRoomName()});
+ }
+ else if(SUBSCRIPTION_ALREADY_EXISTS.equals(returnCode))
+ {
+ errorMessage
+ = GuiActivator.getResources()
+ .getI18NString("service.gui.CHAT_ROOM_ALREADY_JOINED",
+ new String[]{
+ adHocChatRoomWrapper.getAdHocChatRoomName()});
+ }
+ else
+ {
+ errorMessage
+ = GuiActivator.getResources()
+ .getI18NString("service.gui.FAILED_TO_JOIN_CHAT_ROOM",
+ new String[]{
+ adHocChatRoomWrapper.getAdHocChatRoomName()});
+ }
+
+ if (!SUCCESS.equals(returnCode)
+ && !AUTHENTICATION_FAILED.equals(returnCode))
+ {
+ GuiActivator.getAlertUIService().showAlertPopup(
+ GuiActivator.getResources().getI18NString(
+ "service.gui.ERROR"), errorMessage);
+ }
+ }
+ }
+
+
+ /**
+ * Indicates that an invitation has been received and opens the invitation
+ * dialog to notify the user.
+ * @param evt the <tt>AdHocChatRoomInvitationReceivedEvent</tt> that
+ * notified us
+ */
+ public void invitationReceived(AdHocChatRoomInvitationReceivedEvent evt)
+ {
+ if (logger.isInfoEnabled())
+ logger.info("Invitation received: "+evt.toString());
+ OperationSetAdHocMultiUserChat multiUserChatOpSet
+ = evt.getSourceOperationSet();
+
+ InvitationReceivedDialog dialog = new InvitationReceivedDialog(
+ this, multiUserChatOpSet, evt.getInvitation());
+
+ dialog.setVisible(true);
+ }
+
+ /**
+ * Implements the <tt>AdHocChatRoomMessageListener.messageDelivered</tt>
+ * method.
+ * <br>
+ * Shows the message in the conversation area and clears the write message
+ * area.
+ * @param evt the <tt>AdHocChatRoomMessageDeliveredEvent</tt> that notified
+ * us
+ */
+ public void messageDelivered(AdHocChatRoomMessageDeliveredEvent evt)
+ {
+ AdHocChatRoom sourceChatRoom = (AdHocChatRoom) evt.getSource();
+
+ if (logger.isInfoEnabled())
+ logger.info("MESSAGE DELIVERED to ad-hoc chat room: "
+ + sourceChatRoom.getName());
+
+ ChatPanel chatPanel
+ = GuiActivator
+ .getUIService()
+ .getChatWindowManager()
+ .getMultiChat(sourceChatRoom, false);
+
+ if(chatPanel != null)
+ {
+ String messageType;
+ switch (evt.getEventType())
+ {
+ case AdHocChatRoomMessageDeliveredEvent
+ .CONVERSATION_MESSAGE_DELIVERED:
+ messageType = Chat.OUTGOING_MESSAGE;
+ break;
+ case AdHocChatRoomMessageDeliveredEvent.ACTION_MESSAGE_DELIVERED:
+ messageType = Chat.ACTION_MESSAGE;
+ break;
+ default:
+ messageType = null;
+ }
+
+ Message msg = evt.getMessage();
+
+ chatPanel
+ .addMessage(
+ sourceChatRoom
+ .getParentProvider().getAccountID().getUserID(),
+ null,
+ evt.getTimestamp(),
+ messageType,
+ msg.getContent(),
+ msg.getContentType(),
+ msg.getMessageUID(),
+ null);
+ }
+ else
+ {
+ logger.error("chat panel is null, message NOT DELIVERED !");
+ }
+ }
+
+ /**
+ * Implements <tt>AdHocChatRoomMessageListener.messageDeliveryFailed</tt>
+ * method.
+ * <br>
+ * In the conversation area shows an error message, explaining the problem.
+ * @param evt the <tt>AdHocChatRoomMessageDeliveryFailedEvent</tt> that
+ * notified us
+ */
+ public void messageDeliveryFailed(
+ AdHocChatRoomMessageDeliveryFailedEvent evt)
+ {
+ AdHocChatRoom sourceChatRoom = evt.getSourceChatRoom();
+ Message sourceMessage = evt.getMessage();
+ Contact destParticipant = evt.getDestinationParticipant();
+
+ String errorMsg = null;
+ if (evt.getErrorCode()
+ == MessageDeliveryFailedEvent.OFFLINE_MESSAGES_NOT_SUPPORTED)
+ {
+ errorMsg = GuiActivator.getResources().getI18NString(
+ "service.gui.MSG_DELIVERY_NOT_SUPPORTED",
+ new String[]{destParticipant.getDisplayName()});
+ }
+ else if (evt.getErrorCode()
+ == MessageDeliveryFailedEvent.NETWORK_FAILURE)
+ {
+ errorMsg = GuiActivator.getResources()
+ .getI18NString("service.gui.MSG_NOT_DELIVERED");
+ }
+ else if (evt.getErrorCode()
+ == MessageDeliveryFailedEvent.PROVIDER_NOT_REGISTERED)
+ {
+ errorMsg = GuiActivator.getResources().getI18NString(
+ "service.gui.MSG_SEND_CONNECTION_PROBLEM");
+ }
+ else if (evt.getErrorCode()
+ == MessageDeliveryFailedEvent.INTERNAL_ERROR)
+ {
+ errorMsg = GuiActivator.getResources().getI18NString(
+ "service.gui.MSG_DELIVERY_INTERNAL_ERROR");
+ }
+ else if (evt.getErrorCode()
+ == MessageDeliveryFailedEvent.UNSUPPORTED_OPERATION)
+ {
+ errorMsg = GuiActivator.getResources().getI18NString(
+ "service.gui.MSG_DELIVERY_UNSUPPORTED_OPERATION");
+ }
+ else
+ {
+ errorMsg = GuiActivator.getResources().getI18NString(
+ "service.gui.MSG_DELIVERY_UNKNOWN_ERROR");
+ }
+
+ ChatWindowManager chatWindowManager
+ = GuiActivator.getUIService().getChatWindowManager();
+ ChatPanel chatPanel
+ = chatWindowManager.getMultiChat(sourceChatRoom, true);
+
+ chatPanel.addMessage(
+ destParticipant.getDisplayName(),
+ new Date(),
+ Chat.OUTGOING_MESSAGE,
+ sourceMessage.getContent(),
+ sourceMessage.getContentType());
+
+ chatPanel.addErrorMessage(
+ destParticipant.getDisplayName(),
+ errorMsg);
+
+ chatWindowManager.openChat(chatPanel, false);
+ }
+
+ /**
+ * Implements the <tt>AdHocChatRoomMessageListener.messageReceived</tt>
+ * method.
+ * <br>
+ * Obtains the corresponding <tt>ChatPanel</tt> and process the message
+ * there.
+ * @param evt the <tt>AdHocChatRoomMessageReceivedEvent</tt> that notified
+ * us
+ */
+ public void messageReceived(AdHocChatRoomMessageReceivedEvent evt)
+ {
+ AdHocChatRoom sourceChatRoom = evt.getSourceChatRoom();
+ Contact sourceParticipant = evt.getSourceChatRoomParticipant();
+
+ String messageType = null;
+
+ switch (evt.getEventType())
+ {
+ case AdHocChatRoomMessageReceivedEvent.CONVERSATION_MESSAGE_RECEIVED:
+ messageType = Chat.INCOMING_MESSAGE;
+ break;
+ case AdHocChatRoomMessageReceivedEvent.SYSTEM_MESSAGE_RECEIVED:
+ messageType = Chat.SYSTEM_MESSAGE;
+ break;
+ case AdHocChatRoomMessageReceivedEvent.ACTION_MESSAGE_RECEIVED:
+ messageType = Chat.ACTION_MESSAGE;
+ break;
+ }
+
+ if (logger.isInfoEnabled())
+ logger.info("MESSAGE RECEIVED from contact: "
+ + sourceParticipant.getAddress());
+
+ Message message = evt.getMessage();
+
+ ChatWindowManager chatWindowManager
+ = GuiActivator.getUIService().getChatWindowManager();
+ ChatPanel chatPanel
+ = chatWindowManager
+ .getMultiChat(sourceChatRoom, true, message.getMessageUID());
+
+ String messageContent = message.getContent();
+
+ chatPanel.addMessage(
+ sourceParticipant.getDisplayName(),
+ null,
+ evt.getTimestamp(),
+ messageType,
+ messageContent,
+ message.getContentType(),
+ message.getMessageUID(),
+ null);
+
+ chatWindowManager.openChat(chatPanel, false);
+ }
+
+ public void invitationRejected(AdHocChatRoomInvitationRejectedEvent evt) {}
+
+ @Override
+ public void localUserRoleChanged(ChatRoomLocalUserRoleChangeEvent evt)
+ {
+ if(evt.isInitial())
+ return;
+ ChatRoom sourceChatRoom = evt.getSourceChatRoom();
+ ChatRoomWrapper chatRoomWrapper
+ = GuiActivator.getMUCService().findChatRoomWrapperFromChatRoom(
+ sourceChatRoom);
+ ChatWindowManager chatWindowManager
+ = GuiActivator.getUIService().getChatWindowManager();
+ ChatPanel chatPanel
+ = chatWindowManager.getMultiChat(chatRoomWrapper, true);
+ chatWindowManager.openChat(chatPanel, true);
+ }
+
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/filetransfer/ReceiveFileConversationComponent.java b/src/net/java/sip/communicator/impl/gui/main/chat/filetransfer/ReceiveFileConversationComponent.java
index ef72a89..f5a698b 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/filetransfer/ReceiveFileConversationComponent.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/filetransfer/ReceiveFileConversationComponent.java
@@ -164,6 +164,10 @@ public class ReceiveFileConversationComponent
File downloadDir = null;
String incomingFileName = fileTransferRequest.getFileName();
+ // strip characters that are invalid on Windows and maybe other
+ // platforms too
+ incomingFileName = incomingFileName
+ .replaceAll("[\\\\/:*?\"<>|]", "_");
try
{
downloadDir = GuiActivator.getFileAccessService()
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/toolBars/MainToolBar.java b/src/net/java/sip/communicator/impl/gui/main/chat/toolBars/MainToolBar.java
index 6905df9..7080d13 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/toolBars/MainToolBar.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/toolBars/MainToolBar.java
@@ -715,14 +715,19 @@ public class MainToolBar
m.put(opSetClass, ct.getProtocolProvider());
UIContactDetailImpl d = new UIContactDetailImpl(
- ct.getName(),
+ ct.getName() + (ct.getResourceName() == null
+ ? ""
+ : "/" + ct.getResourceName()),
ct.getDisplayName(),
null,
- null,
+ (ct.getResourceName() == null
+ ? Arrays.asList(GuiActivator.getResources().getI18NString("service.gui.VIA") + ": "
+ + ct.getProtocolProvider().getAccountID().getAccountAddress())
+ : null),
null,
m,
null,
- ct.getName());
+ ct);
PresenceStatus status = ct.getStatus();
byte[] statusIconBytes = status.getStatusIcon();
@@ -736,7 +741,7 @@ public class MainToolBar
res.add(d);
}
-
+
Point location = new Point(callButton.getX(),
callButton.getY() + callButton.getHeight());
diff --git a/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomTableDialog.java b/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomTableDialog.java
index 0efb860..28f3e08 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomTableDialog.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ChatRoomTableDialog.java
@@ -55,6 +55,13 @@ public class ChatRoomTableDialog
"REMOVE_ROOM_ON_FIRST_JOIN_FAILED";
/**
+ * Whether we should make rooms autojoin by default.
+ */
+ private static final String ENABLE_ROOM_AUTO_JOIN_ON_CREATION
+ = "net.java.sip.communicator.impl.gui.main.chatroomslist." +
+ "ENABLE_ROOM_AUTO_JOIN_ON_CREATION";
+
+ /**
* The global/shared <code>ChatRoomTableDialog</code> currently showing.
*/
private static ChatRoomTableDialog chatRoomTableDialog;
@@ -425,6 +432,12 @@ public class ChatRoomTableDialog
chatRoomWrapper.getChatRoomID(),
chatRoomWrapper.getChatRoomID(),
chatRoomWrapper.getChatRoomName());
+
+ if(GuiActivator.getConfigurationService()
+ .getBoolean(ENABLE_ROOM_AUTO_JOIN_ON_CREATION, false))
+ {
+ chatRoomWrapper.setAutoJoin(true);
+ }
}
String nickName = nicknameField.getText().trim();
diff --git a/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ServerChatRoomsChoiceDialog.java b/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ServerChatRoomsChoiceDialog.java
index 3eeb783..4725a08 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ServerChatRoomsChoiceDialog.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chatroomslist/ServerChatRoomsChoiceDialog.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,97 +15,97 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.gui.main.chatroomslist;
-
-import java.awt.*;
-import java.awt.event.*;
-
-import net.java.sip.communicator.impl.gui.*;
-import net.java.sip.communicator.impl.gui.main.contactlist.*;
-import net.java.sip.communicator.impl.gui.utils.*;
-import net.java.sip.communicator.service.contactsource.*;
-import net.java.sip.communicator.service.gui.*;
-import net.java.sip.communicator.service.muc.*;
-
-/**
- * A dialog that lists the existing chat rooms on the server.
- *
- * @author Hristo Terezov
- */
-public class ServerChatRoomsChoiceDialog
- extends OneChoiceInviteDialog
-{
-
- /**
- * Generated serial id.
- */
- private static final long serialVersionUID = 428358553225114162L;
-
- /**
- * The contact source that generates the list of chat rooms.
- */
- private ContactSourceService contactSource;
-
- /**
- * Creates new instance of <tt>ServerChatRoomsChoiceDialog</tt>.
- *
- * @param title the title of the window.
- * @param pps the protocol provider service associated with the list of chat
- * rooms.
- */
- public ServerChatRoomsChoiceDialog(String title,
- ChatRoomProviderWrapper pps)
- {
- super(title);
- contactList.setDefaultFilter(new SearchFilter(contactList));
- contactList.removeAllContactSources();
- contactSource = GuiActivator.getMUCService()
- .getServerChatRoomsContactSourceForProvider(pps);
- contactList.addContactSource(
- contactSource);
-
- setInfoText(GuiActivator.getResources().getI18NString(
- "service.gui.SERVER_CHAT_ROOMS_DIALOG_TEXT"));
-
- contactList.applyDefaultFilter();
- this.setMinimumSize(new Dimension(300, 300));
- addOkButtonListener(new ActionListener()
- {
- public void actionPerformed(ActionEvent e)
- {
- UIContact uiContact = getSelectedContact();
-
- if (uiContact != null)
- {
- ChatRoomTableDialog.setChatRoomField(
- uiContact.getDisplayName());
- }
-
- setVisible(false);
- dispose();
- }
- });
- addCancelButtonListener(new ActionListener()
- {
- public void actionPerformed(ActionEvent e)
- {
- setVisible(false);
- dispose();
- }
- });
- }
-
- /**
- * Handles provider change.
- *
- * @param provider the provider.
- */
- public void changeProtocolProvider(ChatRoomProviderWrapper provider)
- {
- contactList.removeContactSource(contactSource);
- contactSource = GuiActivator.getMUCService()
- .getServerChatRoomsContactSourceForProvider(provider);
- contactList.addContactSource(contactSource);
- contactList.applyDefaultFilter();
- }
-}
+package net.java.sip.communicator.impl.gui.main.chatroomslist;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import net.java.sip.communicator.impl.gui.*;
+import net.java.sip.communicator.impl.gui.main.contactlist.*;
+import net.java.sip.communicator.impl.gui.utils.*;
+import net.java.sip.communicator.service.contactsource.*;
+import net.java.sip.communicator.service.gui.*;
+import net.java.sip.communicator.service.muc.*;
+
+/**
+ * A dialog that lists the existing chat rooms on the server.
+ *
+ * @author Hristo Terezov
+ */
+public class ServerChatRoomsChoiceDialog
+ extends OneChoiceInviteDialog
+{
+
+ /**
+ * Generated serial id.
+ */
+ private static final long serialVersionUID = 428358553225114162L;
+
+ /**
+ * The contact source that generates the list of chat rooms.
+ */
+ private ContactSourceService contactSource;
+
+ /**
+ * Creates new instance of <tt>ServerChatRoomsChoiceDialog</tt>.
+ *
+ * @param title the title of the window.
+ * @param pps the protocol provider service associated with the list of chat
+ * rooms.
+ */
+ public ServerChatRoomsChoiceDialog(String title,
+ ChatRoomProviderWrapper pps)
+ {
+ super(title);
+ contactList.setDefaultFilter(new SearchFilter(contactList));
+ contactList.removeAllContactSources();
+ contactSource = GuiActivator.getMUCService()
+ .getServerChatRoomsContactSourceForProvider(pps);
+ contactList.addContactSource(
+ contactSource);
+
+ setInfoText(GuiActivator.getResources().getI18NString(
+ "service.gui.SERVER_CHAT_ROOMS_DIALOG_TEXT"));
+
+ contactList.applyDefaultFilter();
+ this.setMinimumSize(new Dimension(300, 300));
+ addOkButtonListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ UIContact uiContact = getSelectedContact();
+
+ if (uiContact != null)
+ {
+ ChatRoomTableDialog.setChatRoomField(
+ uiContact.getDisplayName());
+ }
+
+ setVisible(false);
+ dispose();
+ }
+ });
+ addCancelButtonListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ setVisible(false);
+ dispose();
+ }
+ });
+ }
+
+ /**
+ * Handles provider change.
+ *
+ * @param provider the provider.
+ */
+ public void changeProtocolProvider(ChatRoomProviderWrapper provider)
+ {
+ contactList.removeContactSource(contactSource);
+ contactSource = GuiActivator.getMUCService()
+ .getServerChatRoomsContactSourceForProvider(provider);
+ contactList.addContactSource(contactSource);
+ contactList.applyDefaultFilter();
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/AddContactDialog.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/AddContactDialog.java
index 856ae5b..8d43c7f 100644
--- a/src/net/java/sip/communicator/impl/gui/main/contactlist/AddContactDialog.java
+++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/AddContactDialog.java
@@ -21,9 +21,14 @@ import java.awt.*;
import java.awt.Container;
import java.awt.event.*;
import java.util.*;
+import java.util.List;
import javax.swing.*;
+import javax.swing.border.*;
import javax.swing.event.*;
+import javax.swing.text.*;
+
+import org.jitsi.util.*;
import net.java.sip.communicator.impl.gui.*;
import net.java.sip.communicator.impl.gui.main.contactlist.addgroup.*;
@@ -163,31 +168,100 @@ public class AddContactDialog
}
/**
+ * Adds a faint gray prompt to the provided text field that
+ * will vanish as soon as text is entered into the field.
+ */
+ private void addPrompt(JTextField field, String text)
+ {
+ final JLabel prompt = new JLabel(text);
+
+ // Give prompt a foreground color like the original
+ // text field, but with half transparency.
+ final Color fg = field.getForeground();
+ final Color color = new Color(
+ fg.getRed(), fg.getGreen(), fg.getBlue(), 128);
+
+ // Mimic properties of given text field
+ prompt.setFont(field.getFont());
+ prompt.setForeground(color);
+ prompt.setBorder(new EmptyBorder(field.getInsets()));
+ prompt.setHorizontalAlignment(JLabel.LEADING);
+
+ // Add handler to hide prompt when text is entered
+ final Document doc = field.getDocument();
+ doc.addDocumentListener( new DocumentListener() {
+ public void insertUpdate(DocumentEvent e)
+ {
+ prompt.setVisible(doc.getLength() == 0);
+ }
+
+ public void removeUpdate(DocumentEvent e)
+ {
+ prompt.setVisible(doc.getLength() == 0);
+ }
+
+ public void changedUpdate(DocumentEvent e) {}
+ });
+
+ // Add prompt to text field
+ field.setLayout( new BorderLayout() );
+ field.add(prompt);
+ }
+
+ /**
* Initializes the dialog.
*/
private void init()
{
+ // Get tool tip text for primary controls
+ final String displayNameInfo =
+ GuiActivator.getResources().getI18NString(
+ "service.gui.DISPLAY_NAME_INFO");
+ final String contactInfo =
+ GuiActivator.getResources().getI18NString(
+ "service.gui.CONTACT_NAME_INFO");
+ final String accountInfo =
+ GuiActivator.getResources().getI18NString(
+ "service.gui.SELECT_ACCOUNT_INFO");
+ final String groupInfo =
+ GuiActivator.getResources().getI18NString(
+ "service.gui.SELECT_GROUP_INFO");
+
+ // Initialize controls
this.accountLabel = new JLabel(
GuiActivator.getResources().getI18NString(
"service.gui.SELECT_ACCOUNT") + ": ");
+ this.accountLabel.setToolTipText(accountInfo);
this.accountCombo = new JComboBox();
-
- this.groupLabel = new JLabel(
- GuiActivator.getResources().getI18NString(
- "service.gui.SELECT_GROUP") + ": ");
+ this.accountCombo.setToolTipText(accountInfo);
this.contactAddressLabel = new JLabel(
GuiActivator.getResources().getI18NString(
"service.gui.CONTACT_NAME") + ": ");
+ this.contactAddressLabel.setToolTipText(contactInfo);
this.displayNameLabel = new JLabel(
GuiActivator.getResources().getI18NString(
"service.gui.DISPLAY_NAME") + ": ");
+ this.displayNameLabel.setToolTipText(displayNameInfo);
this.contactAddressField = new JTextField();
+ this.contactAddressField.setToolTipText(contactInfo);
+ addPrompt(this.contactAddressField,
+ GuiActivator.getResources().getI18NString(
+ "service.gui.CONTACT_NAME_PROMPT"));
this.displayNameField = new JTextField();
+ this.displayNameField.setToolTipText(displayNameInfo);
+ addPrompt(this.displayNameField,
+ GuiActivator.getResources().getI18NString(
+ "service.gui.DISPLAY_NAME_PROMPT"));
+
+ this.groupLabel = new JLabel(
+ GuiActivator.getResources().getI18NString(
+ "service.gui.SELECT_GROUP") + ": ");
+ this.groupLabel.setToolTipText(groupInfo);
this.addButton = new JButton(
GuiActivator.getResources().getI18NString("service.gui.ADD"));
@@ -198,6 +272,7 @@ public class AddContactDialog
this.imageLabel = new JLabel();
this.groupCombo = createGroupCombo(this);
+ this.groupCombo.setToolTipText(groupInfo);
if(metaContact != null)
{
@@ -225,15 +300,15 @@ public class AddContactDialog
fieldsPanel.add(accountCombo);
}
- labelsPanel.add(groupLabel);
- fieldsPanel.add(groupCombo);
-
labelsPanel.add(contactAddressLabel);
fieldsPanel.add(contactAddressField);
labelsPanel.add(displayNameLabel);
fieldsPanel.add(displayNameField);
+ labelsPanel.add(groupLabel);
+ fieldsPanel.add(groupCombo);
+
contactAddressField.getDocument().addDocumentListener(
new DocumentListener()
{
@@ -499,6 +574,26 @@ public class AddContactDialog
final String contactAddress = contactAddressField.getText().trim();
final String displayName = displayNameField.getText();
+ List<String> validationResult = new ArrayList<>(2);
+ if (!protocolProvider.validateContactAddress(contactAddress,
+ validationResult))
+ {
+ new ErrorDialog(GuiActivator.getUIService().getMainFrame(),
+ GuiActivator.getResources()
+ .getI18NString("service.gui.ADD_CONTACT_ERROR_TITLE"),
+ validationResult.get(0), ErrorDialog.WARNING).showDialog();
+ if (validationResult.size() >= 2)
+ {
+ contactAddressField.setText(validationResult.get(1));
+ if (StringUtils.isNullOrEmpty(displayName, true))
+ {
+ displayNameField.setText(contactAddress);
+ }
+ }
+
+ return;
+ }
+
if (!protocolProvider.isRegistered())
{
new ErrorDialog(
diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactInfoDialog.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactInfoDialog.java
deleted file mode 100644
index 325be90..0000000
--- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactInfoDialog.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * 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.main.contactlist;
-
-import java.awt.*;
-import java.awt.event.*;
-
-import javax.swing.*;
-
-import net.java.sip.communicator.impl.gui.customcontrols.*;
-import net.java.sip.communicator.plugin.desktoputil.*;
-import net.java.sip.communicator.service.contactlist.*;
-
-/**
- * The <tt>ContactInfoPanel</tt> is a popup dialog containing the contact
- * detailed info.
- *
- * @author Yana Stamcheva
- */
-public class ContactInfoDialog
- extends SIPCommDialog
- implements WindowFocusListener
-{
-
- private JPanel protocolsPanel = new TransparentPanel(new GridLayout(0, 1));
-
- private TransparentBackground bg;
-
- /**
- * Creates an instance of the <tt>ContactInfoPanel</tt>.
- *
- * @param owner The frame owner of this dialog.
- * @param contactItem The <tt>MetaContact</tt> for the info.
- */
- public ContactInfoDialog(Frame owner, MetaContact contactItem)
- {
- super(owner);
-
- this.setUndecorated(true);
-
- this.setModal(true);
-
- // Create the transparent background component
- this.bg = new TransparentBackground(this);
-
- this.bg.setLayout(new BorderLayout());
-
- this.bg.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
-
- this.getContentPane().setLayout(new BorderLayout());
-
- this.init();
-
- this.getContentPane().add(bg, BorderLayout.CENTER);
-
- this.pack();
-
- this.setSize(140, 50);
-
- this.addWindowFocusListener(this);
- }
-
- /**
- * Initializes the <tt>ContactInfoPanel</tt>.
- */
- private void init()
- {
- /*
- * String[] protocolList = this.contactItem.getC();
- *
- * if(protocolsPanel.getComponentCount() == 0){ for(int i = 0; i <
- * protocolList.length; i ++){
- *
- * JLabel protocolLabel = new JLabel(protocolList[i], new
- * ImageIcon(Constants.getProtocolIcon(protocolList[i])), JLabel.LEFT);
- *
- * this.protocolsPanel.add(protocolLabel); } }
- *
- * this.bg.add(protocolsPanel, BorderLayout.CENTER);
- */
- }
-
- /**
- * Returns the panel containing all contact protocols' information.
- *
- * @return the panel containing all contact protocols' information.
- */
- public JPanel getProtocolsPanel()
- {
- return protocolsPanel;
- }
-
- public void windowGainedFocus(WindowEvent e)
- {
-
- }
-
- public void windowLostFocus(WindowEvent e)
- {
- close(false);
- }
-
- public void setPopupLocation(int x, int y)
- {
- this.setLocation(x, y);
-
- this.bg.updateBackground(x, y);
- }
-
- @Override
- protected void close(boolean isEscaped)
- {
- this.setVisible(false);
- this.dispose();
- }
-}
diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java
index bfe2fd3..ae0e3b0 100644
--- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java
+++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java
@@ -1078,7 +1078,7 @@ public class ContactListTreeCellRenderer
UIContactDetail desktopContact
= uiContact.getDefaultContactDetail(
- OperationSetDesktopStreaming.class);
+ OperationSetDesktopSharingServer.class);
if (desktopContact != null
|| (contactPhoneUtil != null
diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/PresenceFilter.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/PresenceFilter.java
index cf7108f..011b00a 100644
--- a/src/net/java/sip/communicator/impl/gui/main/contactlist/PresenceFilter.java
+++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/PresenceFilter.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,353 +15,353 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.gui.main.contactlist;
-
-import java.util.*;
-
-import net.java.sip.communicator.impl.gui.*;
-import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*;
-import net.java.sip.communicator.service.contactlist.*;
-import net.java.sip.communicator.service.contactsource.*;
-import net.java.sip.communicator.service.gui.*;
-import net.java.sip.communicator.service.gui.event.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-/**
- * The <tt>PresenceFilter</tt> is used to filter offline contacts from the
- * contact list.
- *
- * @author Yana Stamcheva
- */
-public class PresenceFilter
- implements ContactListFilter
-{
- /**
- * The <tt>Logger</tt> used by the <tt>PresenceFilter</tt> class and its
- * instances to print debugging information.
- */
- private static final Logger logger = Logger.getLogger(PresenceFilter.class);
-
- /**
- * Indicates if this presence filter shows or hides the offline contacts.
- */
- private boolean isShowOffline;
-
- /**
- * The initial result count below which we insert all filter results
- * directly to the contact list without firing events.
- */
- private static final int INITIAL_CONTACT_COUNT = 30;
-
- /**
- * Creates an instance of <tt>PresenceFilter</tt>.
- */
- public PresenceFilter()
- {
- isShowOffline = ConfigurationUtils.isShowOffline();
- }
-
- /**
- * Applies this filter. This filter is applied over the
- * <tt>MetaContactListService</tt>.
- *
- * @param filterQuery the query which keeps track of the filtering results
- */
- public void applyFilter(FilterQuery filterQuery)
- {
- // Create the query that will track filtering.
- MetaContactQuery query = new MetaContactQuery();
-
- // Add this query to the filterQuery.
- filterQuery.addContactQuery(query);
-
- TreeContactList contactList = GuiActivator.getContactList();
-
- Collection<UIContactSource> uiContactSourceCollection
- = contactList.getContactSources(
- ContactSourceService.CONTACT_LIST_TYPE);
-
- Iterator<UIContactSource> filterSources
- = uiContactSourceCollection.iterator();
- int maxIndex = 0;
- while (filterSources.hasNext())
- {
- UIContactSource filterSource = filterSources.next();
- int currIx = filterSource.getContactSourceService().getIndex();
- if(maxIndex < currIx)
- maxIndex = currIx;
- }
-
- contactList.getMetaContactListSource().setIndex(maxIndex + 1);
-
- filterSources = uiContactSourceCollection.iterator();
- while (filterSources.hasNext())
- {
- UIContactSource filterSource = filterSources.next();
-
- filterSource.setContactSourceIndex(
- filterSource.getContactSourceService().getIndex());
-
- ContactSourceService sourceService
- = filterSource.getContactSourceService();
-
- ContactQuery contactQuery
- = sourceService.createContactQuery(null);
-
- if(contactQuery == null)
- continue;
-
- // Add this query to the filterQuery.
- filterQuery.addContactQuery(contactQuery);
-
- contactQuery.addContactQueryListener(contactList);
-
- contactQuery.start();
- }
-
- // Closes this filter to indicate that we finished adding queries to it.
- filterQuery.close();
-
- query.addContactQueryListener(GuiActivator.getContactList());
- int resultCount = 0;
-
- addMatching(GuiActivator.getContactListService().getRoot(),
- query,
- resultCount);
-
- query.fireQueryEvent(
- query.isCanceled()
- ? MetaContactQueryStatusEvent.QUERY_CANCELED
- : MetaContactQueryStatusEvent.QUERY_COMPLETED);
- }
-
- /**
- * Indicates if the given <tt>uiContact</tt> is matching this filter.
- *
- * @param uiContact the <tt>UIContact</tt> to check
- * @return <tt>true</tt> if the given <tt>uiContact</tt> is matching
- * this filter, otherwise returns <tt>false</tt>
- */
- public boolean isMatching(UIContact uiContact)
- {
- Object descriptor = uiContact.getDescriptor();
-
- if (descriptor instanceof MetaContact)
- return isMatching((MetaContact) descriptor);
- else if (descriptor instanceof SourceContact)
- return isMatching((SourceContact)descriptor);
- else
- return false;
- }
-
- /**
- * Indicates if the given <tt>uiGroup</tt> is matching this filter.
- *
- * @param uiGroup the <tt>UIGroup</tt> to check
- * @return <tt>true</tt> if the given <tt>uiGroup</tt> is matching
- * this filter, otherwise returns <tt>false</tt>
- */
- public boolean isMatching(UIGroup uiGroup)
- {
- Object descriptor = uiGroup.getDescriptor();
-
- if (descriptor instanceof MetaContactGroup)
- return isMatching((MetaContactGroup) descriptor);
- else
- return false;
- }
-
- /**
- * Sets the show offline property.
- *
- * @param isShowOffline indicates if offline contacts are shown
- */
- public void setShowOffline(boolean isShowOffline)
- {
- this.isShowOffline = isShowOffline;
-
- ConfigurationUtils.setShowOffline(isShowOffline);
- }
-
- /**
- * Returns <tt>true</tt> if offline contacts are shown, otherwise returns
- * <tt>false</tt>.
- *
- * @return <tt>true</tt> if offline contacts are shown, otherwise returns
- * <tt>false</tt>
- */
- public boolean isShowOffline()
- {
- return isShowOffline;
- }
-
- /**
- * Returns <tt>true</tt> if offline contacts are shown or if the given
- * <tt>MetaContact</tt> is online, otherwise returns false.
- *
- * @param metaContact the <tt>MetaContact</tt> to check
- * @return <tt>true</tt> if the given <tt>MetaContact</tt> is matching this
- * filter
- */
- public boolean isMatching(MetaContact metaContact)
- {
- return isShowOffline || isContactOnline(metaContact);
- }
-
- /**
- * Returns <tt>true</tt> if offline contacts are shown or if the given
- * <tt>MetaContact</tt> is online, otherwise returns false.
- *
- * @param contact the <tt>MetaContact</tt> to check
- * @return <tt>true</tt> if the given <tt>MetaContact</tt> is matching this
- * filter
- */
- public boolean isMatching(SourceContact contact)
- {
- // make sure we always show chat rooms and recent messages
- return
- isShowOffline
- || contact.getPresenceStatus().isOnline()
- || contact.getContactSource().getType()
- == ContactSourceService.CONTACT_LIST_TYPE;
- }
-
- /**
- * Returns <tt>true</tt> if offline contacts are shown or if the given
- * <tt>MetaContactGroup</tt> contains online contacts.
- *
- * @param metaGroup the <tt>MetaContactGroup</tt> to check
- * @return <tt>true</tt> if the given <tt>MetaContactGroup</tt> is matching
- * this filter
- */
- private boolean isMatching(MetaContactGroup metaGroup)
- {
- return
- isShowOffline
- || (metaGroup.countOnlineChildContacts() > 0)
- || MetaContactListSource.isNewGroup(metaGroup);
- }
-
- /**
- * Returns <tt>true</tt> if the given meta contact is online, <tt>false</tt>
- * otherwise.
- *
- * @param contact the meta contact
- * @return <tt>true</tt> if the given meta contact is online, <tt>false</tt>
- * otherwise
- */
- private boolean isContactOnline(MetaContact contact)
- {
- // If for some reason the default contact is null we return false.
- Contact defaultContact = contact.getDefaultContact();
- if(defaultContact == null)
- return false;
-
- // Lays on the fact that the default contact is the most connected.
- return defaultContact.getPresenceStatus().getStatus()
- >= PresenceStatus.ONLINE_THRESHOLD;
- }
-
- /**
- * Adds all contacts contained in the given <tt>MetaContactGroup</tt>
- * matching the current filter and not contained in the contact list.
- *
- * @param metaGroup the <tt>MetaContactGroup</tt>, which matching contacts
- * to add
- * @param query the <tt>MetaContactQuery</tt> that notifies interested
- * listeners of the results of this matching
- * @param resultCount the initial result count we would insert directly to
- * the contact list without firing events
- */
- private void addMatching( MetaContactGroup metaGroup,
- MetaContactQuery query,
- int resultCount)
- {
- Iterator<MetaContact> childContacts = metaGroup.getChildContacts();
-
- while (childContacts.hasNext() && !query.isCanceled())
- {
- MetaContact metaContact = childContacts.next();
-
- if(isMatching(metaContact))
- {
-
- resultCount++;
- if (resultCount <= INITIAL_CONTACT_COUNT)
- {
- UIGroup uiGroup = null;
-
- if (!MetaContactListSource.isRootGroup(metaGroup))
- {
- synchronized (metaGroup)
- {
- uiGroup = MetaContactListSource
- .getUIGroup(metaGroup);
- if (uiGroup == null)
- uiGroup = MetaContactListSource
- .createUIGroup(metaGroup);
- }
- }
-
- if (logger.isDebugEnabled())
- logger.debug("Presence filter contact added: "
- + metaContact.getDisplayName());
-
- UIContactImpl newUIContact;
- synchronized (metaContact)
- {
- newUIContact
- = MetaContactListSource.getUIContact(metaContact);
-
- if (newUIContact == null)
- {
- newUIContact = MetaContactListSource
- .createUIContact(metaContact);
- }
- }
-
- GuiActivator.getContactList().addContact(
- newUIContact,
- uiGroup,
- true,
- true);
-
- query.setInitialResultCount(resultCount);
- }
- else
- {
- query.fireQueryEvent(metaContact);
- }
- }
- }
-
- // If in the meantime the filtering has been stopped we return here.
- if (query.isCanceled())
- return;
-
- Iterator<MetaContactGroup> subgroups = metaGroup.getSubgroups();
- while(subgroups.hasNext() && !query.isCanceled())
- {
- MetaContactGroup subgroup = subgroups.next();
-
- if (isMatching(subgroup))
- {
- UIGroup uiGroup;
- synchronized(subgroup)
- {
- uiGroup = MetaContactListSource
- .getUIGroup(subgroup);
-
- if (uiGroup == null)
- uiGroup = MetaContactListSource
- .createUIGroup(subgroup);
- }
-
- GuiActivator.getContactList().addGroup(uiGroup, true);
-
- addMatching(subgroup, query, resultCount);
- }
- }
- }
-}
+package net.java.sip.communicator.impl.gui.main.contactlist;
+
+import java.util.*;
+
+import net.java.sip.communicator.impl.gui.*;
+import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*;
+import net.java.sip.communicator.service.contactlist.*;
+import net.java.sip.communicator.service.contactsource.*;
+import net.java.sip.communicator.service.gui.*;
+import net.java.sip.communicator.service.gui.event.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.util.*;
+
+/**
+ * The <tt>PresenceFilter</tt> is used to filter offline contacts from the
+ * contact list.
+ *
+ * @author Yana Stamcheva
+ */
+public class PresenceFilter
+ implements ContactListFilter
+{
+ /**
+ * The <tt>Logger</tt> used by the <tt>PresenceFilter</tt> class and its
+ * instances to print debugging information.
+ */
+ private static final Logger logger = Logger.getLogger(PresenceFilter.class);
+
+ /**
+ * Indicates if this presence filter shows or hides the offline contacts.
+ */
+ private boolean isShowOffline;
+
+ /**
+ * The initial result count below which we insert all filter results
+ * directly to the contact list without firing events.
+ */
+ private static final int INITIAL_CONTACT_COUNT = 30;
+
+ /**
+ * Creates an instance of <tt>PresenceFilter</tt>.
+ */
+ public PresenceFilter()
+ {
+ isShowOffline = ConfigurationUtils.isShowOffline();
+ }
+
+ /**
+ * Applies this filter. This filter is applied over the
+ * <tt>MetaContactListService</tt>.
+ *
+ * @param filterQuery the query which keeps track of the filtering results
+ */
+ public void applyFilter(FilterQuery filterQuery)
+ {
+ // Create the query that will track filtering.
+ MetaContactQuery query = new MetaContactQuery();
+
+ // Add this query to the filterQuery.
+ filterQuery.addContactQuery(query);
+
+ TreeContactList contactList = GuiActivator.getContactList();
+
+ Collection<UIContactSource> uiContactSourceCollection
+ = contactList.getContactSources(
+ ContactSourceService.CONTACT_LIST_TYPE);
+
+ Iterator<UIContactSource> filterSources
+ = uiContactSourceCollection.iterator();
+ int maxIndex = 0;
+ while (filterSources.hasNext())
+ {
+ UIContactSource filterSource = filterSources.next();
+ int currIx = filterSource.getContactSourceService().getIndex();
+ if(maxIndex < currIx)
+ maxIndex = currIx;
+ }
+
+ contactList.getMetaContactListSource().setIndex(maxIndex + 1);
+
+ filterSources = uiContactSourceCollection.iterator();
+ while (filterSources.hasNext())
+ {
+ UIContactSource filterSource = filterSources.next();
+
+ filterSource.setContactSourceIndex(
+ filterSource.getContactSourceService().getIndex());
+
+ ContactSourceService sourceService
+ = filterSource.getContactSourceService();
+
+ ContactQuery contactQuery
+ = sourceService.createContactQuery(null);
+
+ if(contactQuery == null)
+ continue;
+
+ // Add this query to the filterQuery.
+ filterQuery.addContactQuery(contactQuery);
+
+ contactQuery.addContactQueryListener(contactList);
+
+ contactQuery.start();
+ }
+
+ // Closes this filter to indicate that we finished adding queries to it.
+ filterQuery.close();
+
+ query.addContactQueryListener(GuiActivator.getContactList());
+ int resultCount = 0;
+
+ addMatching(GuiActivator.getContactListService().getRoot(),
+ query,
+ resultCount);
+
+ query.fireQueryEvent(
+ query.isCanceled()
+ ? MetaContactQueryStatusEvent.QUERY_CANCELED
+ : MetaContactQueryStatusEvent.QUERY_COMPLETED);
+ }
+
+ /**
+ * Indicates if the given <tt>uiContact</tt> is matching this filter.
+ *
+ * @param uiContact the <tt>UIContact</tt> to check
+ * @return <tt>true</tt> if the given <tt>uiContact</tt> is matching
+ * this filter, otherwise returns <tt>false</tt>
+ */
+ public boolean isMatching(UIContact uiContact)
+ {
+ Object descriptor = uiContact.getDescriptor();
+
+ if (descriptor instanceof MetaContact)
+ return isMatching((MetaContact) descriptor);
+ else if (descriptor instanceof SourceContact)
+ return isMatching((SourceContact)descriptor);
+ else
+ return false;
+ }
+
+ /**
+ * Indicates if the given <tt>uiGroup</tt> is matching this filter.
+ *
+ * @param uiGroup the <tt>UIGroup</tt> to check
+ * @return <tt>true</tt> if the given <tt>uiGroup</tt> is matching
+ * this filter, otherwise returns <tt>false</tt>
+ */
+ public boolean isMatching(UIGroup uiGroup)
+ {
+ Object descriptor = uiGroup.getDescriptor();
+
+ if (descriptor instanceof MetaContactGroup)
+ return isMatching((MetaContactGroup) descriptor);
+ else
+ return false;
+ }
+
+ /**
+ * Sets the show offline property.
+ *
+ * @param isShowOffline indicates if offline contacts are shown
+ */
+ public void setShowOffline(boolean isShowOffline)
+ {
+ this.isShowOffline = isShowOffline;
+
+ ConfigurationUtils.setShowOffline(isShowOffline);
+ }
+
+ /**
+ * Returns <tt>true</tt> if offline contacts are shown, otherwise returns
+ * <tt>false</tt>.
+ *
+ * @return <tt>true</tt> if offline contacts are shown, otherwise returns
+ * <tt>false</tt>
+ */
+ public boolean isShowOffline()
+ {
+ return isShowOffline;
+ }
+
+ /**
+ * Returns <tt>true</tt> if offline contacts are shown or if the given
+ * <tt>MetaContact</tt> is online, otherwise returns false.
+ *
+ * @param metaContact the <tt>MetaContact</tt> to check
+ * @return <tt>true</tt> if the given <tt>MetaContact</tt> is matching this
+ * filter
+ */
+ public boolean isMatching(MetaContact metaContact)
+ {
+ return isShowOffline || isContactOnline(metaContact);
+ }
+
+ /**
+ * Returns <tt>true</tt> if offline contacts are shown or if the given
+ * <tt>MetaContact</tt> is online, otherwise returns false.
+ *
+ * @param contact the <tt>MetaContact</tt> to check
+ * @return <tt>true</tt> if the given <tt>MetaContact</tt> is matching this
+ * filter
+ */
+ public boolean isMatching(SourceContact contact)
+ {
+ // make sure we always show chat rooms and recent messages
+ return
+ isShowOffline
+ || contact.getPresenceStatus().isOnline()
+ || contact.getContactSource().getType()
+ == ContactSourceService.CONTACT_LIST_TYPE;
+ }
+
+ /**
+ * Returns <tt>true</tt> if offline contacts are shown or if the given
+ * <tt>MetaContactGroup</tt> contains online contacts.
+ *
+ * @param metaGroup the <tt>MetaContactGroup</tt> to check
+ * @return <tt>true</tt> if the given <tt>MetaContactGroup</tt> is matching
+ * this filter
+ */
+ private boolean isMatching(MetaContactGroup metaGroup)
+ {
+ return
+ isShowOffline
+ || (metaGroup.countOnlineChildContacts() > 0)
+ || MetaContactListSource.isNewGroup(metaGroup);
+ }
+
+ /**
+ * Returns <tt>true</tt> if the given meta contact is online, <tt>false</tt>
+ * otherwise.
+ *
+ * @param contact the meta contact
+ * @return <tt>true</tt> if the given meta contact is online, <tt>false</tt>
+ * otherwise
+ */
+ private boolean isContactOnline(MetaContact contact)
+ {
+ // If for some reason the default contact is null we return false.
+ Contact defaultContact = contact.getDefaultContact();
+ if(defaultContact == null)
+ return false;
+
+ // Lays on the fact that the default contact is the most connected.
+ return defaultContact.getPresenceStatus().getStatus()
+ >= PresenceStatus.ONLINE_THRESHOLD;
+ }
+
+ /**
+ * Adds all contacts contained in the given <tt>MetaContactGroup</tt>
+ * matching the current filter and not contained in the contact list.
+ *
+ * @param metaGroup the <tt>MetaContactGroup</tt>, which matching contacts
+ * to add
+ * @param query the <tt>MetaContactQuery</tt> that notifies interested
+ * listeners of the results of this matching
+ * @param resultCount the initial result count we would insert directly to
+ * the contact list without firing events
+ */
+ private void addMatching( MetaContactGroup metaGroup,
+ MetaContactQuery query,
+ int resultCount)
+ {
+ Iterator<MetaContact> childContacts = metaGroup.getChildContacts();
+
+ while (childContacts.hasNext() && !query.isCanceled())
+ {
+ MetaContact metaContact = childContacts.next();
+
+ if(isMatching(metaContact))
+ {
+
+ resultCount++;
+ if (resultCount <= INITIAL_CONTACT_COUNT)
+ {
+ UIGroup uiGroup = null;
+
+ if (!MetaContactListSource.isRootGroup(metaGroup))
+ {
+ synchronized (metaGroup)
+ {
+ uiGroup = MetaContactListSource
+ .getUIGroup(metaGroup);
+ if (uiGroup == null)
+ uiGroup = MetaContactListSource
+ .createUIGroup(metaGroup);
+ }
+ }
+
+ if (logger.isDebugEnabled())
+ logger.debug("Presence filter contact added: "
+ + metaContact.getDisplayName());
+
+ UIContactImpl newUIContact;
+ synchronized (metaContact)
+ {
+ newUIContact
+ = MetaContactListSource.getUIContact(metaContact);
+
+ if (newUIContact == null)
+ {
+ newUIContact = MetaContactListSource
+ .createUIContact(metaContact);
+ }
+ }
+
+ GuiActivator.getContactList().addContact(
+ newUIContact,
+ uiGroup,
+ true,
+ true);
+
+ query.setInitialResultCount(resultCount);
+ }
+ else
+ {
+ query.fireQueryEvent(metaContact);
+ }
+ }
+ }
+
+ // If in the meantime the filtering has been stopped we return here.
+ if (query.isCanceled())
+ return;
+
+ Iterator<MetaContactGroup> subgroups = metaGroup.getSubgroups();
+ while(subgroups.hasNext() && !query.isCanceled())
+ {
+ MetaContactGroup subgroup = subgroups.next();
+
+ if (isMatching(subgroup))
+ {
+ UIGroup uiGroup;
+ synchronized(subgroup)
+ {
+ uiGroup = MetaContactListSource
+ .getUIGroup(subgroup);
+
+ if (uiGroup == null)
+ uiGroup = MetaContactListSource
+ .createUIGroup(subgroup);
+ }
+
+ GuiActivator.getContactList().addGroup(uiGroup, true);
+
+ addMatching(subgroup, query, resultCount);
+ }
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/SearchFilter.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/SearchFilter.java
index 837d369..4735892 100644
--- a/src/net/java/sip/communicator/impl/gui/main/contactlist/SearchFilter.java
+++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/SearchFilter.java
@@ -270,14 +270,13 @@ public class SearchFilter
*/
private boolean isMatching(String text)
{
- if (filterPattern != null)
- return filterPattern.matcher(text).find();
+ if (filterPattern != null && filterPattern.matcher(text).find())
+ return true;
if(isSearchingPhoneNumber && this.filterString != null)
return GuiActivator.getPhoneNumberI18nService()
.phoneNumbersMatch(this.filterString, text);
return true;
-
}
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/TreeContactList.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/TreeContactList.java
index a916b2b..119e000 100644
--- a/src/net/java/sip/communicator/impl/gui/main/contactlist/TreeContactList.java
+++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/TreeContactList.java
@@ -565,10 +565,6 @@ public class TreeContactList
if (isActive)
{
activeContacts.add(contactNode);
-// SystrayService stray = GuiActivator.getSystrayService();
-//
-// if (stray != null)
-// stray.setSystrayIcon(SystrayService.ENVELOPE_IMG_TYPE);
}
else
activeContacts.remove(contactNode);
diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/SourceUIContact.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/SourceUIContact.java
index 72bec25..1419416 100644
--- a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/SourceUIContact.java
+++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/SourceUIContact.java
@@ -573,7 +573,7 @@ public class SourceUIContact
}
else
{
- labelText = contactDetail.getDetail();
+ labelText = contactDetail.getDisplayName();
}
jLabels[i] = new JLabel(filterAddressDisplay(labelText));
@@ -709,11 +709,9 @@ public class SourceUIContact
case AIM:
case ICQ:
case Jabber:
- case MSN:
case Yahoo:
case Skype:
case GoogleTalk:
- case Facebook:
label = subCategory.value();
break;
default:
diff --git a/src/net/java/sip/communicator/impl/gui/main/menus/MacOSXPreferencesRegistration.java b/src/net/java/sip/communicator/impl/gui/main/menus/MacOSXPreferencesRegistration.java
index cfb5420..5a75ff1 100644
--- a/src/net/java/sip/communicator/impl/gui/main/menus/MacOSXPreferencesRegistration.java
+++ b/src/net/java/sip/communicator/impl/gui/main/menus/MacOSXPreferencesRegistration.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,30 +15,30 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.gui.main.menus;
-
-import com.apple.eawt.*;
-
-/**
- * @author Lubomir Marinov
- */
-public final class MacOSXPreferencesRegistration
-{
- public static boolean run(final Object userData)
- {
- Application application = Application.getApplication();
- if (application != null)
- {
- application.setPreferencesHandler(new PreferencesHandler()
- {
- public void handlePreferences(
- AppEvent.PreferencesEvent preferencesEvent)
- {
- ((ToolsMenu) userData).configActionPerformed();
- }
- });
- return true;
- }
- return false;
- }
-}
+package net.java.sip.communicator.impl.gui.main.menus;
+
+import com.apple.eawt.*;
+
+/**
+ * @author Lubomir Marinov
+ */
+public final class MacOSXPreferencesRegistration
+{
+ public static boolean run(final Object userData)
+ {
+ Application application = Application.getApplication();
+ if (application != null)
+ {
+ application.setPreferencesHandler(new PreferencesHandler()
+ {
+ public void handlePreferences(
+ AppEvent.PreferencesEvent preferencesEvent)
+ {
+ ((ToolsMenu) userData).configActionPerformed();
+ }
+ });
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/menus/MacOSXQuitRegistration.java b/src/net/java/sip/communicator/impl/gui/main/menus/MacOSXQuitRegistration.java
index 594623b..4b786b2 100644
--- a/src/net/java/sip/communicator/impl/gui/main/menus/MacOSXQuitRegistration.java
+++ b/src/net/java/sip/communicator/impl/gui/main/menus/MacOSXQuitRegistration.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,68 +15,68 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.impl.gui.main.menus;
-
-import com.apple.eawt.*;
-
-/**
- * @author Lubomir Marinov
- */
-public final class MacOSXQuitRegistration
-{
- public static boolean run(final Object userData)
- {
- Application application = Application.getApplication();
- if (application != null)
- {
- application.setQuitHandler(new QuitHandler()
- {
- public void handleQuitRequestWith(AppEvent.QuitEvent quitEvent,
- final QuitResponse quitResponse)
- {
- ((FileMenu) userData).closeActionPerformed();
-
- /*
- * Tell Mac OS X that it shouldn't terminate the
- * application. We've already initiated the quit and we'll
- * eventually complete it i.e. we'll honor the request of
- * Mac OS X to quit.
- *
- * (2011-06-10) Changed to true, we tell that quit is handled
- * as otherwise will stop OS from logout or shutdown and
- * a notification will be shown to user to inform about it.
- *
- * (2011-07-12) Wait before answering to the OS or we will
- * end too quickly. 15sec is the time our shutdown timer
- * waits before force the shutdown.
- */
-
- synchronized(this)
- {
- try
- {
- wait(15000);
- }catch (InterruptedException ex){}
- }
-
- /**
- * Free the event dispatch thread before performing the
- * quit (System.exit), shutdown timer may also has started
- * the quit and is waiting to free the threads which
- * we may be blocking.
- */
- new Thread(new Runnable()
- {
- public void run()
- {
- quitResponse.performQuit();
- }
- }).start();
- }
- });
-
- return true;
- }
- return false;
- }
-}
+package net.java.sip.communicator.impl.gui.main.menus;
+
+import com.apple.eawt.*;
+
+/**
+ * @author Lubomir Marinov
+ */
+public final class MacOSXQuitRegistration
+{
+ public static boolean run(final Object userData)
+ {
+ Application application = Application.getApplication();
+ if (application != null)
+ {
+ application.setQuitHandler(new QuitHandler()
+ {
+ public void handleQuitRequestWith(AppEvent.QuitEvent quitEvent,
+ final QuitResponse quitResponse)
+ {
+ ((FileMenu) userData).closeActionPerformed();
+
+ /*
+ * Tell Mac OS X that it shouldn't terminate the
+ * application. We've already initiated the quit and we'll
+ * eventually complete it i.e. we'll honor the request of
+ * Mac OS X to quit.
+ *
+ * (2011-06-10) Changed to true, we tell that quit is handled
+ * as otherwise will stop OS from logout or shutdown and
+ * a notification will be shown to user to inform about it.
+ *
+ * (2011-07-12) Wait before answering to the OS or we will
+ * end too quickly. 15sec is the time our shutdown timer
+ * waits before force the shutdown.
+ */
+
+ synchronized(this)
+ {
+ try
+ {
+ wait(15000);
+ }catch (InterruptedException ex){}
+ }
+
+ /**
+ * Free the event dispatch thread before performing the
+ * quit (System.exit), shutdown timer may also has started
+ * the quit and is waiting to free the threads which
+ * we may be blocking.
+ */
+ new Thread(new Runnable()
+ {
+ public void run()
+ {
+ quitResponse.performQuit();
+ }
+ }).start();
+ }
+ });
+
+ return true;
+ }
+ return false;
+ }
+}
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 1861c4a..2795ef9 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
@@ -72,12 +72,12 @@ Import-Package: com.apple.eawt,
org.jitsi.service.neomedia.event,
org.jitsi.service.neomedia.format,
org.jitsi.service.neomedia.recording,
+ org.jitsi.service.neomedia.stats,
org.jitsi.service.resources,
org.jitsi.util,
org.jitsi.util.event,
org.jitsi.util.swing,
org.osgi.framework,
- say.swing,
net.java.sip.communicator.service.credentialsstorage,
net.java.sip.communicator.service.muc,
net.java.sip.communicator.plugin.desktoputil.chat,
diff --git a/src/net/java/sip/communicator/impl/gui/utils/PluginContainer.java b/src/net/java/sip/communicator/impl/gui/utils/PluginContainer.java
index e85c51c..d24855f 100644
--- a/src/net/java/sip/communicator/impl/gui/utils/PluginContainer.java
+++ b/src/net/java/sip/communicator/impl/gui/utils/PluginContainer.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,318 +15,318 @@
* 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 <code>JComponent</code> to contain
- * <code>PluginComponent</code>s, track when they are added and removed.
- *
- * @author Lyubomir Marinov
- */
-public class PluginContainer
- implements PluginComponentListener
-{
- /**
- * The <tt>Logger</tt> used by the <tt>PluginContainer</tt> class and its
- * instances for logging output.
- */
- private static final Logger logger
- = Logger.getLogger(PluginContainer.class);
-
- /**
- * The <code>JComponent</code> which contains the components of the
- * <code>PluginComponent</code>s managed by this instance.
- */
- private final JComponent container;
-
- /**
- * The container id of the <code>PluginComponent</code> managed by this
- * instance.
- */
- private final Container containerId;
-
- /**
- * The list of <code>PluginComponent</code> instances which have their
- * components added to this <code>PluginContainer</code>.
- */
- private final java.util.List<PluginComponent> pluginComponents
- = new LinkedList<PluginComponent>();
-
- /**
- * Initializes a new <code>PluginContainer</code> instance which is to
- * provide capabilities to a specific <code>JComponent</code> container with
- * a specific <code>Container</code> id to contain
- * <code>PluginComponent</code> and track when they are added and removed.
- *
- * @param container
- * the <code>JComponent</code> container the new instance is to
- * provide its capabilities to
- * @param containerId
- * the <code>Container</code> id of the specified
- * <code>container</code>
- */
- public PluginContainer(JComponent container, Container containerId)
- {
- this.container = container;
- this.containerId = containerId;
-
- initPluginComponents();
- }
-
- /**
- * Adds a specific <tt>Component</tt> to a specific <tt>JComponent</tt>
- * container. Allows extenders to apply custom logic to the exact placement
- * of the specified <tt>Component</tt> in the specified container.
- *
- * @param component the <tt>Component</tt> to be added to the specified
- * <tt>JComponent</tt> container
- * @param container the <tt>JComponent</tt> container to add the specified
- * <tt>Component</tt> to
- * @param preferredIndex the index at which <tt>component</tt> is to be
- * added to <tt>container</tt> if possible or <tt>-1</tt> 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 <tt>PluginComponent</tt> to the
- * associated <tt>Container</tt>.
- *
- * @param factory the <tt>PluginComponentFactory</tt> which is to have its
- * component added to the <tt>Container</tt> associated with this
- * <tt>PluginContainer</tt>
- */
- 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 <tt>Component</tt>s in a specific <tt>JComponent</tt>
- * container. For example, returns the result of
- * <tt>getMenuComponentCount()</tt> if <tt>container</tt> is an instance of
- * <tt>JMenu</tt>.
- *
- * @param container the <tt>JComponent</tt> container to get the number of
- * <tt>Component</tt>s of
- * @return the number of <tt>Component</tt>s in the specified
- * <tt>container</tt>
- */
- protected int getComponentCount(JComponent container)
- {
- return
- (container instanceof JMenu)
- ? ((JMenu) container).getMenuComponentCount()
- : container.getComponentCount();
- }
-
- /**
- * Gets the <tt>PluginComponent</tt>s of this <tt>PluginContainer</tt>.
- *
- * @return an <tt>Iterable</tt> over the <tt>PluginComponent</tt>s of this
- * <tt>PluginContainer</tt>
- */
- public Iterable<PluginComponent> getPluginComponents()
- {
- return pluginComponents;
- }
-
- /**
- * Adds the <tt>Component</tt>s of the <tt>PluginComponent</tt>s registered
- * in the OSGi <tt>BundleContext</tt> in the associated <tt>Container</tt>.
- */
- 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 <tt>PluginComponentEvent</tt> which specifies the
- * <tt>PluginComponent</tt> 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 <tt>PluginComponentEvent</tt> which specifies the
- * <tt>PluginComponent</tt> 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 <code>PluginComponent</code> from
- * this <code>PluginContainer</code>.
- *
- * @param factory
- * the <code>PluginComponent</code> which is to have its
- * component removed from this <code>PluginContainer</code>
- */
- private synchronized void removePluginComponent(
- PluginComponentFactory factory)
- {
- Iterator<PluginComponent> iterator = pluginComponents.iterator();
- while(iterator.hasNext())
- {
- PluginComponent c = iterator.next();
- if(c.getParentFactory().equals(factory))
- {
- iterator.remove();
- container.remove((Component)c.getComponent());
- }
- }
- }
-}
+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 <code>JComponent</code> to contain
+ * <code>PluginComponent</code>s, track when they are added and removed.
+ *
+ * @author Lyubomir Marinov
+ */
+public class PluginContainer
+ implements PluginComponentListener
+{
+ /**
+ * The <tt>Logger</tt> used by the <tt>PluginContainer</tt> class and its
+ * instances for logging output.
+ */
+ private static final Logger logger
+ = Logger.getLogger(PluginContainer.class);
+
+ /**
+ * The <code>JComponent</code> which contains the components of the
+ * <code>PluginComponent</code>s managed by this instance.
+ */
+ private final JComponent container;
+
+ /**
+ * The container id of the <code>PluginComponent</code> managed by this
+ * instance.
+ */
+ private final Container containerId;
+
+ /**
+ * The list of <code>PluginComponent</code> instances which have their
+ * components added to this <code>PluginContainer</code>.
+ */
+ private final java.util.List<PluginComponent> pluginComponents
+ = new LinkedList<PluginComponent>();
+
+ /**
+ * Initializes a new <code>PluginContainer</code> instance which is to
+ * provide capabilities to a specific <code>JComponent</code> container with
+ * a specific <code>Container</code> id to contain
+ * <code>PluginComponent</code> and track when they are added and removed.
+ *
+ * @param container
+ * the <code>JComponent</code> container the new instance is to
+ * provide its capabilities to
+ * @param containerId
+ * the <code>Container</code> id of the specified
+ * <code>container</code>
+ */
+ public PluginContainer(JComponent container, Container containerId)
+ {
+ this.container = container;
+ this.containerId = containerId;
+
+ initPluginComponents();
+ }
+
+ /**
+ * Adds a specific <tt>Component</tt> to a specific <tt>JComponent</tt>
+ * container. Allows extenders to apply custom logic to the exact placement
+ * of the specified <tt>Component</tt> in the specified container.
+ *
+ * @param component the <tt>Component</tt> to be added to the specified
+ * <tt>JComponent</tt> container
+ * @param container the <tt>JComponent</tt> container to add the specified
+ * <tt>Component</tt> to
+ * @param preferredIndex the index at which <tt>component</tt> is to be
+ * added to <tt>container</tt> if possible or <tt>-1</tt> 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 <tt>PluginComponent</tt> to the
+ * associated <tt>Container</tt>.
+ *
+ * @param factory the <tt>PluginComponentFactory</tt> which is to have its
+ * component added to the <tt>Container</tt> associated with this
+ * <tt>PluginContainer</tt>
+ */
+ 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 <tt>Component</tt>s in a specific <tt>JComponent</tt>
+ * container. For example, returns the result of
+ * <tt>getMenuComponentCount()</tt> if <tt>container</tt> is an instance of
+ * <tt>JMenu</tt>.
+ *
+ * @param container the <tt>JComponent</tt> container to get the number of
+ * <tt>Component</tt>s of
+ * @return the number of <tt>Component</tt>s in the specified
+ * <tt>container</tt>
+ */
+ protected int getComponentCount(JComponent container)
+ {
+ return
+ (container instanceof JMenu)
+ ? ((JMenu) container).getMenuComponentCount()
+ : container.getComponentCount();
+ }
+
+ /**
+ * Gets the <tt>PluginComponent</tt>s of this <tt>PluginContainer</tt>.
+ *
+ * @return an <tt>Iterable</tt> over the <tt>PluginComponent</tt>s of this
+ * <tt>PluginContainer</tt>
+ */
+ public Iterable<PluginComponent> getPluginComponents()
+ {
+ return pluginComponents;
+ }
+
+ /**
+ * Adds the <tt>Component</tt>s of the <tt>PluginComponent</tt>s registered
+ * in the OSGi <tt>BundleContext</tt> in the associated <tt>Container</tt>.
+ */
+ 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 <tt>PluginComponentEvent</tt> which specifies the
+ * <tt>PluginComponent</tt> 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 <tt>PluginComponentEvent</tt> which specifies the
+ * <tt>PluginComponent</tt> 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 <code>PluginComponent</code> from
+ * this <code>PluginContainer</code>.
+ *
+ * @param factory
+ * the <code>PluginComponent</code> which is to have its
+ * component removed from this <code>PluginContainer</code>
+ */
+ private synchronized void removePluginComponent(
+ PluginComponentFactory factory)
+ {
+ Iterator<PluginComponent> iterator = pluginComponents.iterator();
+ while(iterator.hasNext())
+ {
+ PluginComponent c = iterator.next();
+ if(c.getParentFactory().equals(factory))
+ {
+ iterator.remove();
+ container.remove((Component)c.getComponent());
+ }
+ }
+ }
+}