diff options
author | Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de> | 2017-03-11 22:15:03 +0100 |
---|---|---|
committer | Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de> | 2017-03-11 22:15:03 +0100 |
commit | 85901329b0794b136b96bf745f4ab1572806fc89 (patch) | |
tree | f23da7e97cae727f39d825f0fef8348cffb238e4 /src/net/java/sip/communicator/impl/gui/main | |
parent | 3db2e44f186c59429901b2c899e139ea60117a55 (diff) | |
parent | cf5da997da8820b4050f5b87ee9440a0ede36d1f (diff) | |
download | jitsi-master.zip jitsi-master.tar.gz jitsi-master.tar.bz2 |
Signed-off-by: Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de>
Diffstat (limited to 'src/net/java/sip/communicator/impl/gui/main')
33 files changed, 5991 insertions, 5922 deletions
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"), "↓ " - + (int) mediaStreamStats.getDownloadRateKiloBitPerSec() + + (int) mediaStreamStats.getReceiveStats().getBitrate()/1024 + " Kbps " + " ↑ " - + (int) mediaStreamStats.getUploadRateKiloBitPerSec() + + (int) mediaStreamStats.getSendStats().getBitrate()/1024 + " Kbps")); stringBuffer.append( getLineString( resources.getI18NString("service.gui.callinfo.LOSS_RATE"), - "↓ " + (int) mediaStreamStats.getDownloadPercentLoss() + "↓" + + (int) (mediaStreamStats.getReceiveStats().getLossRate() * 100) + "% ↑ " - + (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 ? "↓ " + recvRttMs + " ms" : "") + + (sendRttMs != -1 ? "↑ " + sendRttMs + " ms" : ""))); } stringBuffer.append( getLineString(resources.getI18NString( "service.gui.callinfo.JITTER"), - "↓ " + (int) mediaStreamStats.getDownloadJitterMs() + "↓ " + (int) mediaStreamStats.getReceiveStats().getJitter() + " ms ↑ " - + (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; + } +} |