/** * $RCSfile: ,v $ * $Revision: $ * $Date: $ * * Copyright (C) 2004-2011 Jive Software. All rights reserved. * * 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 org.jivesoftware.sparkplugin.ui.call; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.text.SimpleDateFormat; import java.util.Date; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSeparator; import net.java.sipmack.sip.InterlocutorUI; import net.java.sipmack.softphone.SoftPhoneManager; import net.java.sipmack.softphone.SoftPhoneManager.CallRoomState; import org.jivesoftware.spark.ChatManager; import org.jivesoftware.spark.SparkManager; import org.jivesoftware.spark.component.RolloverButton; import org.jivesoftware.spark.plugin.phone.resource.PhoneRes; import org.jivesoftware.spark.ui.ChatRoom; import org.jivesoftware.spark.util.ModelUtil; import org.jivesoftware.spark.util.SwingWorker; import org.jivesoftware.spark.util.log.Log; import org.jivesoftware.sparkplugin.components.RosterMemberCallButton; import org.jivesoftware.sparkplugin.ui.PhonePad; import org.jivesoftware.sparkplugin.ui.components.ControlPanel; import org.jivesoftware.sparkplugin.ui.components.JavaMixer; import org.jivesoftware.sparkplugin.ui.transfer.TransferManager; /** * The UI for calls with Roster members. * * @author Derek DeMoro */ public class RosterMemberPanel extends PhonePanel { private static final long serialVersionUID = -327742794852188962L; private JLabel connectedLabel; private String phoneNumber; private JLabel phoneLabel; private PreviousConversationPanel historyPanel; private boolean onHold; private boolean muted; private RosterMemberCallButton muteButton; private RosterMemberCallButton holdButton; private RosterMemberCallButton transferButton; private RolloverButton hangUpButton; private SoftPhoneManager softPhone; private static String CONNECTED = PhoneRes.getIString("phone.connected"); private InterlocutorUI activeCall; private CallManager callManager; private final Color greenColor = new Color(91, 175, 41); private final Color orangeColor = new Color(229, 139, 11); private boolean callWasTransferred; private JavaMixer javaMixer = new JavaMixer(); public RosterMemberPanel() { setLayout(new GridBagLayout()); setBorder(BorderFactory.createLineBorder(Color.lightGray)); callManager = CallManager.getInstance(); // Initilize mixer. softPhone = SoftPhoneManager.getInstance(); // Build Top Layer final JPanel topPanel = buildTopPanel(); add(topPanel, new GridBagConstraints(1, 5, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(2, 2, 2, 2), 0, 0)); // Build Control Panel final JPanel controlPanel = buildControlPanel(); add(controlPanel, new GridBagConstraints(1, 6, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(2, 2, 2, 2), 0, 0)); // Add Previous Conversation historyPanel = new PreviousConversationPanel(); add(historyPanel, new GridBagConstraints(1, 8, 1, 1, 0.0, 1.0, GridBagConstraints.SOUTH, GridBagConstraints.BOTH, new Insets(2, 2, 2, 2), 0, 100)); // Setup default settings setupDefaults(); } /** * Builds the information block. * * @return the UI representing the Information Block. */ private JPanel buildTopPanel() { final JPanel panel = new JPanel(new GridBagLayout()); panel.setOpaque(false); // Add phone label phoneLabel = new JLabel(); phoneLabel.setFont(new Font("Arial", Font.BOLD, 13)); phoneLabel.setForeground(new Color(64, 103, 162)); panel.add(phoneLabel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 2, 2, 2), 0, 0)); // Add Dial Pad final RolloverButton dialPadButton = new RolloverButton(PhoneRes.getImageIcon("ICON_NUMBERPAD_IMAGE")); panel.add(dialPadButton, new GridBagConstraints(1, 0, 1, 3, 1.0, 0.0, GridBagConstraints.NORTHEAST, GridBagConstraints.NONE, new Insets(0, 2, 2, 2), 0, 0)); final PhonePad pad = new PhonePad(); dialPadButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent actionEvent) { pad.showDialpad(dialPadButton, true); } }); // Add Connected Label connectedLabel = new JLabel(CONNECTED); connectedLabel.setFont(new Font("Arial", Font.BOLD, 13)); connectedLabel.setHorizontalTextPosition(JLabel.CENTER); connectedLabel.setHorizontalAlignment(JLabel.CENTER); panel.add(connectedLabel, new GridBagConstraints(0, 1, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(2, 2, 2, 2), 0, 0)); return panel; } /** * Builds the Control Panel. * * @return the control panel. */ private JPanel buildControlPanel() { // Add Control Panel final JPanel mainPanel = new JPanel(new GridBagLayout()); mainPanel.setOpaque(false); // Initialize Mixer. // Add Input Volume To Control Panel try { final ControlPanel inputPanel = new ControlPanel(new GridBagLayout()); final JLabel inputIcon = new JLabel(PhoneRes.getImageIcon("SPEAKER_IMAGE")); inputPanel.add(javaMixer.getPrefferedMasterVolume(), new GridBagConstraints(0, 0, 1, 1, 0.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.VERTICAL, new Insets(2, 2, 2, 2), 0, 0)); inputPanel.add(inputIcon, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(2, 2, 2, 2), 0, 0)); mainPanel.add(inputPanel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.2, GridBagConstraints.NORTHWEST, GridBagConstraints.VERTICAL, new Insets(2, 1, 2, 1), 0, 0)); } catch (Exception e) { Log.error(e); } // Add Output Volume To Control Panel try { final ControlPanel outputPanel = new ControlPanel(new GridBagLayout()); final JLabel outputIcon = new JLabel(PhoneRes.getImageIcon("MICROPHONE_IMAGE")); outputPanel.add(javaMixer.getPrefferedInputVolume(), new GridBagConstraints(0, 0, 1, 1, 0.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.VERTICAL, new Insets(2, 2, 2, 2), 0, 0)); outputPanel.add(outputIcon, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(2, 2, 2, 2), 0, 0)); mainPanel.add(outputPanel, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.2, GridBagConstraints.NORTHWEST, GridBagConstraints.VERTICAL, new Insets(2, 1, 2, 1), 0, 0)); } catch (Exception e) { Log.error(e); } // Build ControlPanel List final ControlPanel controlPanel = new ControlPanel(new GridBagLayout()); final JSeparator sep = new JSeparator(JSeparator.HORIZONTAL); sep.setBackground(new Color(219, 228, 238)); muteButton = new RosterMemberCallButton(PhoneRes.getImageIcon("MUTE_IMAGE").getImage(), PhoneRes.getIString("phone.mute")); muteButton.setToolTipText(PhoneRes.getIString("phone.tips.mute")); controlPanel.add(muteButton, new GridBagConstraints(0, 0, 1, 1, 0.0, 1.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); controlPanel.add(sep, new GridBagConstraints(0, 1, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); holdButton = new RosterMemberCallButton(PhoneRes.getImageIcon("ON_HOLD_IMAGE").getImage(), PhoneRes.getIString("phone.hold")); holdButton.setToolTipText(PhoneRes.getIString("phone.tips.hold")); controlPanel.add(holdButton, new GridBagConstraints(0, 2, 1, 1, 0.0, 1.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); final JSeparator sep2 = new JSeparator(JSeparator.HORIZONTAL); sep2.setBackground(new Color(219, 228, 238)); controlPanel.add(sep2, new GridBagConstraints(0, 3, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); transferButton = new RosterMemberCallButton(PhoneRes.getImageIcon("TRANSFER_IMAGE").getImage(), PhoneRes.getIString("phone.transfer")); transferButton.setToolTipText(PhoneRes.getIString("phone.tips.transfer")); controlPanel.add(transferButton, new GridBagConstraints(0, 4, 1, 1, 0.0, 1.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); // Add Components to Main Panel mainPanel.add(controlPanel, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(2, 1, 2, 1), 0, 0)); // Add End Call button hangUpButton = new RolloverButton(" "+PhoneRes.getIString("phone.hangup"), PhoneRes.getImageIcon("HANG_UP_PHONE_77x24_IMAGE")); hangUpButton.setHorizontalTextPosition(JLabel.CENTER); hangUpButton.setFont(new Font("Dialog", Font.BOLD, 11)); hangUpButton.setForeground(new Color(153, 32, 10)); hangUpButton.setMargin(new Insets(0, 0, 0, 0)); mainPanel.add(hangUpButton, new GridBagConstraints(0, 1, 3, 1, 0.0, 0.8, GridBagConstraints.NORTH, GridBagConstraints.NONE, new Insets(2, 2, 2, 2), 0, 0)); return mainPanel; } public void setInterlocutorUI(final InterlocutorUI interlocutorUI) { this.activeCall = interlocutorUI; // Set defaults muted = false; onHold = false; this.phoneNumber = interlocutorUI.getCall().getNumber(); phoneLabel.setText(phoneNumber); callStarted(); } public void setupDefaults() { holdButton.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent mouseEvent) { toggleHold(); } }); muteButton.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent mouseEvent) { toggleMute(); } }); transferButton.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent mouseEvent) { TransferManager ui = new TransferManager(); final String number = ui.getNumber(SparkManager.getChatManager().getChatContainer().getChatFrame()); if (ModelUtil.hasLength(number)) { setStatus("Transferring...", blueColor); historyPanel.transferring(); SwingWorker transferringThread = new SwingWorker() { public Object construct() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } return true; } public void finished() { setStatus("Transferred", blueColor); historyPanel.transfer(number); callWasTransferred = true; softPhone.handleTransfer(getActiveCall().getID(), number); callEnded(); } }; transferringThread.start(); } } }); final SoftPhoneManager manager = SoftPhoneManager.getInstance(); hangUpButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent actionEvent) { manager.getDefaultGuiManager().hangup(activeCall); hangUpButton.setEnabled(false); } }); } /** * Called when a new call is established. */ private void callStarted() { // Show History historyPanel.removeAll(); historyPanel.addPreviousConversations(phoneNumber); hangUpButton.setEnabled(true); muteButton.setEnabled(true); holdButton.setEnabled(true); transferButton.setEnabled(true); setStatus(CONNECTED, false); // Add notification to ChatRoom if one exists. final ChatRoom chatRoom = callManager.getAssociatedChatRoom(this); if (chatRoom != null) { final SimpleDateFormat formatter = new SimpleDateFormat("h:mm a"); String time = formatter.format(new Date()); chatRoom.getTranscriptWindow().insertNotificationMessage(PhoneRes.getIString("phone.callstartedat")+" " + time, ChatManager.NOTIFICATION_COLOR); } } /** * Called when the call is ended. This does basic container cleanup. */ public void callEnded() { if (!callWasTransferred) { historyPanel.callEnded(); setStatus("Call Ended", redColor); } hangUpButton.setEnabled(false); hangUpButton.setOpaque(false); muteButton.setEnabled(false); muteButton.setOpaque(false); holdButton.setEnabled(false); holdButton.setOpaque(false); transferButton.setEnabled(false); setStatus("Call Ended", redColor); // Add notification to ChatRoom if one exists. final ChatRoom chatRoom = callManager.getAssociatedChatRoom(this); if (chatRoom != null) { final SimpleDateFormat formatter = new SimpleDateFormat("h:mm a"); String time = formatter.format(new Date()); chatRoom.getTranscriptWindow().insertNotificationMessage(PhoneRes.getIString("phone.callendedat")+" " + time, ChatManager.NOTIFICATION_COLOR); } // If this is a standalone phone call with no associated ChatRoom // gray out title and show off-phone icon. final ChatRoom room = callManager.getAssociatedChatRoom(this); softPhone.addCallSession(room, SoftPhoneManager.CallRoomState.callWasEnded); // Notify SparkManager.getChatManager().notifySparkTabHandlers(room); } private void setStatus(String status, boolean alert) { if (alert) { connectedLabel.setForeground(orangeColor); } else { connectedLabel.setForeground(greenColor); } connectedLabel.setText(status); } private void setStatus(String status, Color color) { connectedLabel.setForeground(color); connectedLabel.setText(status); } private void toggleMute() { if (onHold) { toggleHold(); } if (muted) { muted = false; muteButton.setToolTipText("Mute"); muteButton.setButtonSelected(false); setStatus(CONNECTED, false); // Change the current state. changeState(CallRoomState.inCall); } else { muted = true; muteButton.setToolTipText("Unmute"); muteButton.setButtonSelected(true); setStatus("Muted", true); // Change the current state changeState(CallRoomState.muted); } muteButton.invalidate(); muteButton.validate(); muteButton.repaint(); softPhone.getDefaultGuiManager().mute(activeCall, !muted); } private void toggleHold() { if (muted) { toggleMute(); } if (onHold) { onHold = false; holdButton.setToolTipText("Hold"); holdButton.setButtonSelected(false); setStatus(CONNECTED, false); // Change the current state changeState(CallRoomState.inCall); } else { onHold = true; holdButton.setToolTipText("Unhold"); holdButton.setButtonSelected(true); setStatus("On Hold", true); // Change the current state changeState(CallRoomState.onHold); } softPhone.getDefaultGuiManager().hold(activeCall); } public void actionPerformed(ActionEvent e) { } public String getTabTitle() { return phoneNumber; } public String getFrameTitle() { return PhoneRes.getIString("phone.onphonewith")+" " + phoneNumber; } public ImageIcon getTabIcon() { return PhoneRes.getImageIcon("RECEIVER2_IMAGE"); } public JComponent getGUI() { return this; } public String getToolTipDescription() { return phoneNumber; } public boolean closing() { return true; } public String getPhoneNumber() { return phoneNumber; } public void paintComponent(Graphics g) { BufferedImage cache = new BufferedImage(2, getHeight(), BufferedImage.TYPE_INT_RGB); Graphics2D g2d = cache.createGraphics(); GradientPaint paint = new GradientPaint(0, 0, new Color(241, 245, 250), 0, getHeight(), new Color(244, 250, 255), true); g2d.setPaint(paint); g2d.fillRect(0, 0, getWidth(), getHeight()); g2d.dispose(); g.drawImage(cache, 0, 0, getWidth(), getHeight(), null); } public Dimension getPreferredSize() { Dimension dim = super.getPreferredSize(); dim.width = 0; return dim; } public InterlocutorUI getActiveCall() { return activeCall; } private void changeState(SoftPhoneManager.CallRoomState state) { final ChatRoom room = callManager.getAssociatedChatRoom(this); softPhone.addCallSession(room, state); SparkManager.getChatManager().notifySparkTabHandlers(room); } }