diff --git a/resources/languages/resources.properties b/resources/languages/resources.properties index 37d25d12e..95ba0041e 100644 --- a/resources/languages/resources.properties +++ b/resources/languages/resources.properties @@ -106,6 +106,7 @@ service.gui.CHAT_ROOM_USER_LEFT=has left {0} service.gui.CHAT_ROOM_USER_KICKED=has been kicked from {0} service.gui.CHAT_ROOM_USER_QUIT=has quit {0} service.gui.CHAT_ROOM_NAME=Chat room name +service.gui.CLEAR_CUSTOM_MESSAGES=Clear custom messages service.gui.ROOM_NAME=Chat Room service.gui.AUTOJOIN=Autojoin service.gui.CHANGE_PASSWORD=Change password @@ -327,6 +328,7 @@ service.gui.NEW_ACCOUNT=Add &new account... service.gui.NEW_MESSAGE=New message service.gui.NEW_NAME=New name service.gui.NEW_STATUS_MESSAGE=New status message +service.gui.NEW_STATUS_MESSAGE_SAVE=Save as custom message service.gui.NO=No service.gui.NONE=None service.gui.NO_CAMERA_AVAILABLE=No camera available diff --git a/src/net/java/sip/communicator/impl/gui/main/presence/PresenceStatusMenu.java b/src/net/java/sip/communicator/impl/gui/main/presence/PresenceStatusMenu.java index b40c5148e..0ae6b8a9a 100644 --- a/src/net/java/sip/communicator/impl/gui/main/presence/PresenceStatusMenu.java +++ b/src/net/java/sip/communicator/impl/gui/main/presence/PresenceStatusMenu.java @@ -12,14 +12,13 @@ import javax.swing.*; import net.java.sip.communicator.impl.gui.*; -import net.java.sip.communicator.impl.gui.customcontrols.*; import net.java.sip.communicator.impl.gui.main.*; -import net.java.sip.communicator.impl.gui.main.login.*; import net.java.sip.communicator.impl.gui.main.presence.message.*; import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.protocol.*; -import net.java.sip.communicator.util.*; +import net.java.sip.communicator.util.Logger; import net.java.sip.communicator.util.swing.*; +import org.jitsi.util.*; /** * The StatusSelectorBox is a SIPCommMenu that contains @@ -51,7 +50,16 @@ public class PresenceStatusMenu private OperationSetPresence presence; - private JLabel titleLabel; + /** + * The area will display the account display name and its status message + * if any. + */ + private JEditorPane titleArea; + + /** + * The status message menu. + */ + private StatusMessageMenu statusMessageMenu; /** * Take care for global status items, that only one is selected. @@ -83,12 +91,17 @@ public PresenceStatusMenu(ProtocolProviderService protocolProvider) this.setToolTipText(tooltip); - titleLabel = new JLabel(protocolProvider.getAccountID().getDisplayName()); + titleArea = new JEditorPane(); + titleArea.setContentType("text/html"); + titleArea.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0)); + titleArea.setOpaque(false); + titleArea.setEditable(false); + titleArea.setAlignmentX(Component.RIGHT_ALIGNMENT); - titleLabel.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0)); - titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD)); + statusMessageMenu = new StatusMessageMenu(protocolProvider, this); + updateTitleArea(); - this.add(titleLabel); + this.add(titleArea); this.addSeparator(); while (statusIterator.hasNext()) @@ -116,7 +129,7 @@ else if ((onlineStatus != null this.addSeparator(); - this.add(new StatusMessageMenu(protocolProvider)); + this.add(statusMessageMenu); this.setSelectedStatus(offlineStatus); updateStatus(offlineStatus); @@ -205,12 +218,39 @@ public void updateStatus(PresenceStatus presenceStatus) if(item instanceof JCheckBoxMenuItem) { - if(item.getText().equals(presenceStatus.getStatusName())) + if(item.getName().equals(presenceStatus.getStatusName())) + { item.setSelected(true); + //item.setText("" + item.getName() + ""); + } + else + { + item.setText(item.getName()); + } } } } + /** + * Updates the current title area with the account display name + * and its status. + */ + public void updateTitleArea() + { + StringBuilder txt = new StringBuilder(); + txt.append("").append(""); + txt.append(protocolProvider.getAccountID().getDisplayName()) + .append(""); + + String statusMessage = statusMessageMenu.getCurrentMessage(); + if(!StringUtils.isNullOrEmpty(statusMessage)) + { + txt.append("
").append(statusMessage); + } + txt.append(""); + titleArea.setText(txt.toString()); + } + /** * Selects the given status in the status menu. * @@ -225,6 +265,7 @@ public void setSelectedStatus(PresenceStatus status) status.getStatusName()); this.setSelected(selectedObject); + lastSelectedStatus = status; String tooltip = this.getToolTipText(); diff --git a/src/net/java/sip/communicator/impl/gui/main/presence/message/NewStatusMessageDialog.java b/src/net/java/sip/communicator/impl/gui/main/presence/message/NewStatusMessageDialog.java index 0171db871..b9bfcf64a 100644 --- a/src/net/java/sip/communicator/impl/gui/main/presence/message/NewStatusMessageDialog.java +++ b/src/net/java/sip/communicator/impl/gui/main/presence/message/NewStatusMessageDialog.java @@ -56,16 +56,29 @@ public class NewStatusMessageDialog */ private JPanel messagePanel; + /** + * The parent menu. + */ + private StatusMessageMenu parentMenu; + + /** + * A checkbox when checked, the new message will be saved. + */ + private JCheckBox saveNewMessage; + /** * Creates an instance of NewStatusMessageDialog. * * @param protocolProvider the ProtocolProviderService. */ - public NewStatusMessageDialog (ProtocolProviderService protocolProvider) + public NewStatusMessageDialog (ProtocolProviderService protocolProvider, + StatusMessageMenu parentMenu) { + super(false); + presenceOpSet - = (OperationSetPersistentPresence) protocolProvider - .getOperationSet(OperationSetPresence.class); + = protocolProvider.getOperationSet(OperationSetPresence.class); + this.parentMenu = parentMenu; this.init(); pack(); @@ -100,6 +113,9 @@ private void init() JPanel buttonsPanel = new TransparentPanel(new FlowLayout(FlowLayout.RIGHT)); + saveNewMessage = new JCheckBox(GuiActivator.getResources() + .getI18NString("service.gui.NEW_STATUS_MESSAGE_SAVE")); + this.setTitle(GuiActivator.getResources() .getI18NString("service.gui.NEW_STATUS_MESSAGE")); @@ -121,6 +137,12 @@ private void init() infoTitleLabel.setFont( infoTitleLabel.getFont().deriveFont(Font.BOLD, 18.0f)); + saveNewMessage.setSelected(true); + /*JPanel saveToCustomPanel = new TransparentPanel( + new FlowLayout(FlowLayout.RIGHT)); + saveToCustomPanel.add(saveNewMessage); + dataPanel.add(saveToCustomPanel, BorderLayout.SOUTH);*/ + labelsPanel.add(infoTitleLabel); labelsPanel.add(infoArea); labelsPanel.add(dataPanel); @@ -194,7 +216,9 @@ public void actionPerformed(ActionEvent e) if (name.equals("ok")) { - new PublishStatusMessageThread(messageTextField.getText()).start(); + parentMenu.publishStatusMessage(messageTextField.getText(), + parentMenu.getNewMessageItem(), + saveNewMessage.isSelected()); } this.dispose(); @@ -209,71 +233,6 @@ public void requestFocusInField() this.messageTextField.requestFocus(); } - /** - * This class allow to use a thread to change the presence status message. - */ - private class PublishStatusMessageThread extends Thread - { - private String message; - - private PresenceStatus currentStatus; - - public PublishStatusMessageThread(String message) - { - this.message = message; - - this.currentStatus = presenceOpSet.getPresenceStatus(); - } - - public void run() - { - try - { - presenceOpSet.publishPresenceStatus(currentStatus, message); - } - catch (IllegalArgumentException e1) - { - - logger.error("Error - changing status", e1); - } - catch (IllegalStateException e1) - { - - logger.error("Error - changing status", e1); - } - catch (OperationFailedException e1) - { - - if (e1.getErrorCode() - == OperationFailedException.GENERAL_ERROR) - { - logger.error( - "General error occured while " - + "publishing presence status.", - e1); - } - else if (e1.getErrorCode() - == OperationFailedException - .NETWORK_FAILURE) - { - logger.error( - "Network failure occured while " - + "publishing presence status.", - e1); - } - else if (e1.getErrorCode() - == OperationFailedException - .PROVIDER_NOT_REGISTERED) - { - logger.error( - "Protocol provider must be" - + "registered in order to change status.", - e1); - } - } - } - } - /** * Artificially clicks the cancel button when this panel is escaped. * @param isEscaped indicates if this dialog is closed by the Esc shortcut diff --git a/src/net/java/sip/communicator/impl/gui/main/presence/message/StatusMessageMenu.java b/src/net/java/sip/communicator/impl/gui/main/presence/message/StatusMessageMenu.java index 21ee1f11c..20a20529f 100644 --- a/src/net/java/sip/communicator/impl/gui/main/presence/message/StatusMessageMenu.java +++ b/src/net/java/sip/communicator/impl/gui/main/presence/message/StatusMessageMenu.java @@ -12,8 +12,11 @@ import javax.swing.*; import net.java.sip.communicator.impl.gui.*; +import net.java.sip.communicator.impl.gui.main.presence.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.util.*; +import net.java.sip.communicator.util.Logger; +import org.jitsi.util.*; /** * The StatusMessageMenu is added to every status selector box in order @@ -25,7 +28,23 @@ public class StatusMessageMenu extends JMenu implements ActionListener { - private Logger logger = Logger.getLogger(StatusMessageMenu.class); + /** + * Our logger. + */ + private final static Logger logger + = Logger.getLogger(StatusMessageMenu.class); + + /** + * The prefix used to store custom status messages. + */ + private final static String CUSTOM_MESSAGES_PREFIX = + "service.gui.CUSTOM_STATUS_MESSAGE"; + + /** + * The prefix to search for provisioned messages. + */ + private final static String PROVISIONED_MESSAGES_PREFIX = + "service.gui.CUSTOM_STATUS_MESSAGE."; private static final String BRB_MESSAGE = GuiActivator.getResources().getI18NString("service.gui.BRB_MESSAGE"); @@ -39,12 +58,32 @@ public class StatusMessageMenu private JMenuItem newMessageItem = new JMenuItem( GuiActivator.getResources().getI18NString("service.gui.NEW_MESSAGE")); - private JMenuItem busyMessageItem = new JMenuItem(BUSY_MESSAGE); + /** + * To clear and delete currently saved custom messages. + */ + private JMenuItem clearCustomMessageItem = new JMenuItem( + GuiActivator.getResources() + .getI18NString("service.gui.CLEAR_CUSTOM_MESSAGES")); + + /** + * The pre-set busy message. + */ + private JCheckBoxMenuItem busyMessageItem + = new JCheckBoxMenuItem(BUSY_MESSAGE); - private JMenuItem brbMessageItem = new JMenuItem(BRB_MESSAGE); + /** + * The pre-set BRB message. + */ + private JCheckBoxMenuItem brbMessageItem + = new JCheckBoxMenuItem(BRB_MESSAGE); private ProtocolProviderService protocolProvider; + /** + * The parent menu of this menu. + */ + private PresenceStatusMenu parentMenu; + /** * Creates an instance of StatusMessageMenu, by specifying the * ProtocolProviderService to which this menu belongs. @@ -52,25 +91,41 @@ public class StatusMessageMenu * @param protocolProvider the protocol provider service to which this * menu belongs */ - public StatusMessageMenu(ProtocolProviderService protocolProvider) + public StatusMessageMenu(ProtocolProviderService protocolProvider, + PresenceStatusMenu parentMenu) { super(GuiActivator.getResources() - .getI18NString("service.gui.SET_STATUS_MESSAGE")); + .getI18NString("service.gui.SET_STATUS_MESSAGE")); this.protocolProvider = protocolProvider; + this.parentMenu = parentMenu; this.noMessageItem.addActionListener(this); this.newMessageItem.addActionListener(this); this.busyMessageItem.addActionListener(this); this.brbMessageItem.addActionListener(this); + this.clearCustomMessageItem.addActionListener(this); this.add(noMessageItem); this.add(newMessageItem); + this.add(clearCustomMessageItem); + + // check should we show the preset messages + if(ConfigurationUtils.isPresetStatusMessagesEnabled()) + { + busyMessageItem.setName(busyMessageItem.getText()); + brbMessageItem.setName(brbMessageItem.getText()); - this.addSeparator(); + this.addSeparator(); + this.add(busyMessageItem); + this.add(brbMessageItem); + } + + // load custom message + loadCustomStatusMessageIndex(); + + // load provisioned messages if any - this.add(busyMessageItem); - this.add(brbMessageItem); } public void actionPerformed(ActionEvent e) @@ -82,7 +137,7 @@ public void actionPerformed(ActionEvent e) if (menuItem.equals(newMessageItem)) { NewStatusMessageDialog dialog - = new NewStatusMessageDialog(protocolProvider); + = new NewStatusMessageDialog(protocolProvider, this); dialog.setLocation( Toolkit.getDefaultToolkit().getScreenSize().width/2 @@ -98,6 +153,34 @@ public void actionPerformed(ActionEvent e) // we will set status from the Status Message Dialog return; } + else if (menuItem.equals(clearCustomMessageItem)) + { + // lets remove, we need the latest index removed so we can + // remove and the separator that is before it + int lastIx = -1; + for(Component c : getMenuComponents()) + { + if(c instanceof CustomMessageItems) + { + lastIx = getPopupMenu().getComponentIndex(c); + remove((CustomMessageItems)c); + } + } + + // remove the separator + if(lastIx - 1 >= 0 ) + getPopupMenu().remove(lastIx - 1); + + // and now let's delete the saved values + java.util.List customMessagesProps = + GuiActivator.getConfigurationService() + .getPropertyNamesByPrefix(CUSTOM_MESSAGES_PREFIX, false); + + for(String p : customMessagesProps) + { + GuiActivator.getConfigurationService().removeProperty(p); + } + } else if (menuItem.equals(busyMessageItem)) { statusMessage = BUSY_MESSAGE; @@ -106,8 +189,255 @@ else if (menuItem.equals(brbMessageItem)) { statusMessage = BRB_MESSAGE; } + else if (menuItem instanceof CustomMessageItems) + { + statusMessage = menuItem.getName(); + } + else if (menuItem instanceof ProvisionedMessageItems) + { + statusMessage = menuItem.getName(); + } - new PublishStatusMessageThread(statusMessage).start(); + // we cannot get here after clicking 'new message' + publishStatusMessage(statusMessage, menuItem, false); + } + + /** + * Publishes the new message in separate thread. If successfully ended + * the message item is created and added to te list of current status + * messages and if needed the message is saved. + * @param message the message to save + * @param menuItem the item which was clicked to set this status + * @param saveIfNewMessage whether to save the status on the custom + * statuses list. + */ + void publishStatusMessage(String message, + JMenuItem menuItem, + boolean saveIfNewMessage) + { + new PublishStatusMessageThread(message, menuItem, saveIfNewMessage) + .start(); + } + + /** + * Returns the button for new messages. + * @return the button for new messages. + */ + JMenuItem getNewMessageItem() + { + return newMessageItem; + } + + /** + * Changes current message text in its item. + * @param message + * @param menuItem the menu item that was clicked + * @param saveNewMessage whether to save the newly created message + */ + private void setCurrentMessage(final String message, + final JMenuItem menuItem, + final boolean saveNewMessage) + { + if(menuItem == null) + return; + + /// we will be working with swing components, make sure it is in EDT + if(!SwingUtilities.isEventDispatchThread()) + { + SwingUtilities.invokeLater(new Runnable() + { + public void run() + { + setCurrentMessage(message, menuItem, saveNewMessage); + } + }); + + return; + } + + // if message is null we cleared the status message + if(StringUtils.isNullOrEmpty(message)) + { + clearSelectedItems(); + parentMenu.updateTitleArea(); + + return; + } + + // a ne message was created + if(menuItem.equals(newMessageItem)) + { + clearSelectedItems(); + + CustomMessageItems newMenuItem = new CustomMessageItems(message); + newMenuItem.setName(message); + newMenuItem.setSelected(true); + newMenuItem.addActionListener(this); + + int ix = getLastCustomMessageIndex(); + if(ix == -1) + { + this.addSeparator(); + this.add(newMenuItem); + } + else + { + insert(newMenuItem, ix + 1); + } + + parentMenu.updateTitleArea(); + + if(saveNewMessage) + { + // lets save it + int saveIx = getLastCustomStatusMessageIndex(); + GuiActivator.getConfigurationService().setProperty( + CUSTOM_MESSAGES_PREFIX + "." + String.valueOf(saveIx + 1), + message + ); + } + } + else if(menuItem instanceof JCheckBoxMenuItem) + { + clearSelectedItems(); + + menuItem.setSelected(true); + menuItem.setText("" + menuItem.getName() +""); + parentMenu.updateTitleArea(); + } + } + + /** + * Searches for custom messages in configuration service and + * gets the highest index. + * @return the highest index of custom status messages. + */ + private int getLastCustomStatusMessageIndex() + { + int ix = -1; + + java.util.List customMessagesProps = + GuiActivator.getConfigurationService() + .getPropertyNamesByPrefix(CUSTOM_MESSAGES_PREFIX, false); + + for(String p : customMessagesProps) + { + String s = p.substring(CUSTOM_MESSAGES_PREFIX.length() + 1); + + try + { + int i = Integer.parseInt(s); + if(i > ix) + ix = i; + } + catch(Throwable t) + {} + } + + return ix; + } + + /** + * Loads the previously saved custom status messages. + */ + private void loadCustomStatusMessageIndex() + { + java.util.List customMessagesProps = + GuiActivator.getConfigurationService() + .getPropertyNamesByPrefix(CUSTOM_MESSAGES_PREFIX, false); + + if(customMessagesProps.size() > 0) + { + this.addSeparator(); + } + + for(String p : customMessagesProps) + { + String message = + GuiActivator.getConfigurationService().getString(p); + + CustomMessageItems newMenuItem = new CustomMessageItems(message); + newMenuItem.setName(message); + newMenuItem.addActionListener(this); + + this.add(newMenuItem); + } + } + + /** + * Clears all items that they are not selected and its name is not bold. + */ + private void clearSelectedItems() + { + for(Component c : getMenuComponents()) + { + if(c instanceof JCheckBoxMenuItem) + { + JCheckBoxMenuItem checkItem = + (JCheckBoxMenuItem)c; + checkItem.setSelected(false); + checkItem.setText(checkItem.getName()); + } + } + } + + /** + * Checks for the index of the last component of CustomMessageItems class. + * @return the last component index of CustomMessageItems. + */ + private int getLastCustomMessageIndex() + { + int ix = -1; + JPopupMenu popupMenu = getPopupMenu(); + for(Component c : getMenuComponents()) + { + if(c instanceof CustomMessageItems) + { + int cIx = popupMenu.getComponentIndex(c); + if(cIx > ix) + ix = cIx; + } + } + + return ix; + } + + public String getCurrentMessage() + { + for(Component c : getMenuComponents()) + { + if(c instanceof JCheckBoxMenuItem + && ((JCheckBoxMenuItem) c).isSelected()) + { + return c.getName(); + } + } + + return null; + } + + /** + * The custom message items. + */ + private class CustomMessageItems + extends JCheckBoxMenuItem + { + public CustomMessageItems(String text) + { + super(text); + } + } + + /** + * The provisioned message items. + */ + private class ProvisionedMessageItems + extends JCheckBoxMenuItem + { + public ProvisionedMessageItems(String text) + { + super(text); + } } /** @@ -121,15 +451,25 @@ private class PublishStatusMessageThread extends Thread private OperationSetPresence presenceOpSet; - public PublishStatusMessageThread(String message) + private JMenuItem menuItem; + + private boolean saveIfNewMessage; + + public PublishStatusMessageThread( + String message, + JMenuItem menuItem, + boolean saveIfNewMessage) { this.message = message; presenceOpSet - = (OperationSetPersistentPresence) protocolProvider - .getOperationSet(OperationSetPresence.class); + = protocolProvider.getOperationSet(OperationSetPresence.class); this.currentStatus = presenceOpSet.getPresenceStatus(); + + this.menuItem = menuItem; + + this.saveIfNewMessage = saveIfNewMessage; } public void run() @@ -137,6 +477,8 @@ public void run() try { presenceOpSet.publishPresenceStatus(currentStatus, message); + + setCurrentMessage(message, menuItem, saveIfNewMessage); } catch (IllegalArgumentException e1) { diff --git a/src/net/java/sip/communicator/util/ConfigurationUtils.java b/src/net/java/sip/communicator/util/ConfigurationUtils.java index 2089eed62..632e6b2bb 100644 --- a/src/net/java/sip/communicator/util/ConfigurationUtils.java +++ b/src/net/java/sip/communicator/util/ConfigurationUtils.java @@ -175,6 +175,11 @@ public class ConfigurationUtils */ private static boolean isRemoveContactDisabled; + /** + * Indicates if the pre set status messages are enabled. + */ + private static boolean isPresetStatusMessagesEnabled; + /** * The last directory used in file transfer. */ @@ -627,6 +632,13 @@ public static void loadGuiConfigurations() "CONTACT_REMOVE_DISABLED", false); + // Load the "PRESET_STATUS_MESSAGES" property. + isPresetStatusMessagesEnabled + = configService.getBoolean( + "net.java.sip.communicator.impl.gui.main.presence." + + "PRESET_STATUS_MESSAGES", + true); + // Load the "net.java.sip.communicator.impl.gui.main.account // .ADVANCED_CONFIG_DISABLED" property. String advancedConfigDisabledDefaultProp @@ -1135,6 +1147,17 @@ public static boolean isRemoveContactDisabled() return isRemoveContactDisabled; } + /** + * Returns true if the "PRESET_STATUS_MESSAGES" property is + * true, otherwise - returns false. + * @return true if the "PRESET_STATUS_MESSAGES" property is + * true, otherwise - returns false. + */ + public static boolean isPresetStatusMessagesEnabled() + { + return isPresetStatusMessagesEnabled; + } + /** * Returns true if the "ADVANCED_CONFIG_DISABLED" property is * true, otherwise - returns false..