/**
* $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.spark.ui.status;
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import org.jivesoftware.resource.Res;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.spark.PresenceManager;
import org.jivesoftware.spark.SparkManager;
import org.jivesoftware.spark.component.JiveTreeCellRenderer;
import org.jivesoftware.spark.component.JiveTreeNode;
import org.jivesoftware.spark.component.Tree;
import org.jivesoftware.spark.component.renderer.ListIconRenderer;
import org.jivesoftware.spark.util.ModelUtil;
import org.jivesoftware.spark.util.ResourceUtils;
import org.jivesoftware.spark.util.log.Log;
import com.thoughtworks.xstream.XStream;
public class CustomMessages {
private static File customMessages = new File(SparkManager.getUserDirectory(), "custom_messages.xml");
private static XStream xstream = new XStream();
private CustomMessages() {
}
static {
xstream.alias("custom-items", List.class);
xstream.alias("custom-status", CustomStatusItem.class);
}
// Handle Custom Messages
public static List<CustomStatusItem> load() {
List<CustomStatusItem> list = null;
if (customMessages.exists()) {
try {
list = (List<CustomStatusItem>)xstream.fromXML(new FileReader(customMessages));
}
catch (Exception e) {
xstream.alias("list", List.class);
xstream.alias("com.jivesoftware.workspaces.CustomStatusItem", CustomStatusItem.class);
try {
list = (List<CustomStatusItem>)xstream.fromXML(new FileReader(customMessages));
}
catch (Exception e1) {
Log.error(e1);
}
}
}
if (list == null) {
list = new ArrayList<CustomStatusItem>();
}
// Sort Custom Messages
Collections.sort( list, new Comparator<CustomStatusItem>()
{
public int compare( final CustomStatusItem a, final CustomStatusItem b )
{
return( a.getStatus().compareToIgnoreCase( b.getStatus() ) );
}
} );
return list;
}
public static void save(List<CustomStatusItem> list) {
xstream.alias("custom-items", List.class);
xstream.alias("custom-status", CustomStatusItem.class);
try {
xstream.toXML(list, new FileWriter(customMessages));
}
catch (IOException e) {
Log.error("Could not save custom messages.", e);
}
}
public static void addCustomMessage() {
CustomStatus status = new CustomStatus();
status.invoke(null);
}
public static void editCustomMessages() {
final JiveTreeNode rootNode = new JiveTreeNode(Res.getString("status.custom.messages"));
final Tree tree = new Tree(rootNode);
tree.setCellRenderer(new JiveTreeCellRenderer());
final List<CustomStatusItem> customItems = load();
final StatusBar statusBar = SparkManager.getWorkspace().getStatusBar();
Iterator<StatusItem> statusItems = statusBar.getStatusList().iterator();
while (statusItems.hasNext()) {
StatusItem item = statusItems.next();
JiveTreeNode node = new JiveTreeNode(item.getText(), false, item.getIcon());
Iterator<CustomStatusItem> cMessages = customItems.iterator();
node.setAllowsChildren(true);
while (cMessages.hasNext()) {
CustomStatusItem csi = cMessages.next();
if (csi.getType().equals(item.getText())) {
JiveTreeNode subNode = new JiveTreeNode(csi.getStatus(), false);
node.add(subNode);
}
}
rootNode.add(node);
}
final JScrollPane pane = new JScrollPane(tree);
// The user should only be able to close this dialog.
Object[] options = {Res.getString("close")};
final JOptionPane optionPane = new JOptionPane(pane, JOptionPane.PLAIN_MESSAGE,
JOptionPane.OK_CANCEL_OPTION, null, options, options[0]);
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
mainPanel.add(optionPane, BorderLayout.CENTER);
final JDialog optionsDialog = new JDialog(SparkManager.getMainWindow(), Res.getString("title.edit.custom.message"), true);
optionsDialog.setContentPane(mainPanel);
optionsDialog.pack();
optionsDialog.setLocationRelativeTo(SparkManager.getMainWindow());
optionPane.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent propertyChangeEvent) {
String value = (String)optionPane.getValue();
if (Res.getString("close").equals(value)) {
optionsDialog.setVisible(false);
}
}
});
for (int i = 0; i <= tree.getRowCount(); i++) {
tree.expandPath(tree.getPathForRow(i));
}
tree.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent mouseEvent) {
checkPopup(mouseEvent);
}
public void mouseReleased(MouseEvent mouseEvent) {
checkPopup(mouseEvent);
}
public void checkPopup(MouseEvent event) {
if (!event.isPopupTrigger()) {
return;
}
TreePath path = tree.getPathForLocation(event.getX(), event.getY());
if (path != null) {
tree.setSelectionPath(path);
}
final JiveTreeNode selectedNode = (JiveTreeNode)tree.getLastSelectedPathComponent();
if (selectedNode == null || selectedNode.getParent() == null) {
return;
}
else if (selectedNode.getParent() == rootNode) {
JPopupMenu popup = new JPopupMenu();
Action addAction = new AbstractAction() {
private static final long serialVersionUID = 2187174931315380754L;
public void actionPerformed(ActionEvent actionEvent) {
CustomStatus status = new CustomStatus();
String type = (String)selectedNode.getUserObject();
status.invoke(type);
reloadTree(rootNode, tree);
}
};
addAction.putValue(Action.NAME, Res.getString("menuitem.add"));
popup.add(addAction);
popup.show(tree, event.getX(), event.getY());
return;
}
final JiveTreeNode parentNode = (JiveTreeNode)selectedNode.getParent();
final String messageStatus = (String)selectedNode.getUserObject();
final String messageType = (String)parentNode.getUserObject();
if (event.isPopupTrigger()) {
JPopupMenu popup = new JPopupMenu();
Action deleteAction = new AbstractAction() {
private static final long serialVersionUID = -4421868467918912876L;
public void actionPerformed(ActionEvent actionEvent) {
List<CustomStatusItem> list = new ArrayList<CustomStatusItem>();
//Refresh customItems list
List<CustomStatusItem> customItems = load();
Iterator<CustomStatusItem> iter = customItems.iterator();
while (iter.hasNext()) {
CustomStatusItem item = iter.next();
if (item.getType().equals(messageType) && item.getStatus().equals(messageStatus)) {
}
else {
list.add(item);
}
}
parentNode.remove(selectedNode);
DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
model.nodeStructureChanged(parentNode);
save(list);
}
};
deleteAction.putValue(Action.NAME, Res.getString("menuitem.delete"));
popup.add(deleteAction);
Action editAction = new AbstractAction() {
private static final long serialVersionUID = 39916149252596354L;
public void actionPerformed(ActionEvent actionEvent) {
List<CustomStatusItem> newItems = load();
Iterator<CustomStatusItem> iter = newItems.iterator();
while (iter.hasNext()) {
CustomStatusItem item = iter.next();
if (item.getType().equals(messageType) && item.getStatus().equals(messageStatus)) {
CustomStatus customStatus = new CustomStatus();
customStatus.showEditDialog(item);
// Reload tree.
reloadTree(rootNode, tree);
break;
}
}
}
};
editAction.putValue(Action.NAME, Res.getString("menuitem.edit"));
popup.add(editAction);
popup.show(tree, event.getX(), event.getY());
}
}
});
optionsDialog.setVisible(true);
optionsDialog.toFront();
optionsDialog.requestFocus();
}
private static void reloadTree(JiveTreeNode rootNode, Tree tree) {
StatusBar statusBar = SparkManager.getWorkspace().getStatusBar();
rootNode.removeAllChildren();
Iterator<StatusItem> statusItems = statusBar.getStatusList().iterator();
while (statusItems.hasNext()) {
StatusItem statusItem = statusItems.next();
JiveTreeNode node = new JiveTreeNode(statusItem.getText(), false, statusItem.getIcon());
List<CustomStatusItem> newItems = load();
Iterator<CustomStatusItem> cMessages = newItems.iterator();
node.setAllowsChildren(true);
while (cMessages.hasNext()) {
CustomStatusItem csi = cMessages.next();
if (csi.getType().equals(statusItem.getText())) {
JiveTreeNode subNode = new JiveTreeNode(csi.getStatus(), false);
node.add(subNode);
}
}
rootNode.add(node);
}
DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
model.nodeStructureChanged(rootNode);
tree.expandTree();
}
private static class CustomStatus extends JPanel {
private static final long serialVersionUID = 1117350001209641469L;
private JLabel typeLabel = new JLabel();
private JComboBox typeBox = new JComboBox();
private JLabel statusLabel = new JLabel();
private JTextField statusField = new JTextField();
private JLabel priorityLabel = new JLabel();
private JTextField priorityField = new JTextField();
private JCheckBox persistBox = new JCheckBox();
public CustomStatus() {
StatusBar statusBar = SparkManager.getWorkspace().getStatusBar();
// Add Mnemonics
ResourceUtils.resLabel(typeLabel, typeBox, Res.getString("label.presence"));
ResourceUtils.resLabel(statusLabel, statusField, Res.getString("label.message"));
ResourceUtils.resLabel(priorityLabel, priorityField, Res.getString("label.priority"));
ResourceUtils.resButton(persistBox, Res.getString("button.save.for.future.use"));
setLayout(new GridBagLayout());
add(typeLabel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
add(statusLabel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
add(priorityLabel, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
add(typeBox, new GridBagConstraints(1, 0, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 150, 0));
add(statusField, new GridBagConstraints(1, 1, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
add(priorityField, new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
add(persistBox, new GridBagConstraints(0, 3, 2, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
persistBox.setSelected(true);
typeBox.setRenderer(new ListIconRenderer());
// Add Types
Iterator<StatusItem> statusIterator = statusBar.getStatusList().iterator();
while (statusIterator.hasNext()) {
final StatusItem statusItem = statusIterator.next();
if (!PresenceManager.isOnPhone(statusItem.getPresence())) {
ImageIcon icon = (ImageIcon)statusItem.getIcon();
ImageIcon newIcon = new ImageIcon(icon.getImage());
newIcon.setDescription(statusItem.getText());
typeBox.addItem(newIcon);
}
}
priorityField.setText("1");
statusField.setText(Res.getString("status.online"));
}
public String getType() {
ImageIcon icon = (ImageIcon)typeBox.getSelectedItem();
return icon.getDescription();
}
public String getStatus() {
return statusField.getText();
}
public int getPriority() {
try {
return Integer.parseInt(priorityField.getText());
}
catch (NumberFormatException e) {
return 1;
}
}
public void showEditDialog(final CustomStatusItem item) {
// Construct main panel w/ layout.
final JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
// The user should only be able to close this dialog.
Object[] options = {Res.getString("ok"), Res.getString("cancel")};
final JOptionPane optionPane = new JOptionPane(this, JOptionPane.PLAIN_MESSAGE,
JOptionPane.OK_CANCEL_OPTION, null, options, options[0]);
mainPanel.add(optionPane, BorderLayout.CENTER);
final JDialog optionsDialog = new JDialog(SparkManager.getMainWindow(), Res.getString("title.edit.custom.message"), true);
optionsDialog.setContentPane(mainPanel);
optionsDialog.pack();
persistBox.setVisible(false);
priorityField.setText(Integer.toString(item.getPriority()));
statusField.setText(item.getStatus());
String type = item.getType();
int count = typeBox.getItemCount();
for (int i = 0; i < count; i++) {
ImageIcon icon = (ImageIcon)typeBox.getItemAt(i);
if (icon.getDescription().equals(type)) {
typeBox.setSelectedIndex(i);
break;
}
}
optionsDialog.setLocationRelativeTo(SparkManager.getMainWindow());
optionPane.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent propertyChangeEvent) {
String value = (String)optionPane.getValue();
if (Res.getString("cancel").equals(value)) {
optionsDialog.setVisible(false);
}
else if (Res.getString("ok").equals(value)) {
List<CustomStatusItem> list = load();
Iterator<CustomStatusItem> iter = list.iterator();
CustomStatusItem changeItem = null;
while (iter.hasNext()) {
CustomStatusItem customItem = iter.next();
if (customItem.getType().equals(item.getType()) &&
customItem.getStatus().equals(item.getStatus()) &&
customItem.getPriority() == item.getPriority() ) {
changeItem = customItem;
break;
}
}
Iterator<CustomStatusItem> customListIterator = list.iterator();
boolean exists = false;
while (customListIterator.hasNext()) {
CustomStatusItem customItem = customListIterator.next();
String type = customItem.getType();
String status = customItem.getStatus();
int priority = customItem.getPriority();
if (type.equals(getType()) && status.equals(getStatus()) && priority == getPriority()) {
exists = true;
}
}
if (changeItem != null) {
changeItem.setPriority(getPriority());
changeItem.setStatus(getStatus());
changeItem.setType(getType());
}
// Otherwise save.
if (!exists) {
save(list);
}
optionsDialog.setVisible(false);
}
}
});
optionsDialog.setVisible(true);
optionsDialog.toFront();
optionsDialog.requestFocus();
}
public void invoke(String selectedType) {
final StatusBar statusBar = SparkManager.getWorkspace().getStatusBar();
// Construct main panel w/ layout.
final JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
// The user should only be able to close this dialog.
Object[] options = {Res.getString("ok"), Res.getString("cancel")};
final JOptionPane optionPane = new JOptionPane(this, JOptionPane.PLAIN_MESSAGE,
JOptionPane.OK_CANCEL_OPTION, null, options, options[0]);
mainPanel.add(optionPane, BorderLayout.CENTER);
final JDialog optionsDialog = new JDialog(SparkManager.getMainWindow(), Res.getString("title.set.status.message"), true);
optionsDialog.setContentPane(mainPanel);
optionsDialog.pack();
if (selectedType != null) {
int count = typeBox.getItemCount();
for (int i = 0; i < count; i++) {
ImageIcon icon = (ImageIcon)typeBox.getItemAt(i);
if (icon.getDescription().equals(selectedType)) {
typeBox.setSelectedIndex(i);
break;
}
}
persistBox.setSelected(true);
}
optionsDialog.setLocationRelativeTo(SparkManager.getMainWindow());
optionPane.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent propertyChangeEvent) {
String value = (String)optionPane.getValue();
if (Res.getString("cancel").equals(value)) {
optionsDialog.setVisible(false);
}
else if (Res.getString("ok").equals(value)) {
if (!ModelUtil.hasLength(getStatus())) {
JOptionPane.showMessageDialog(optionsDialog, Res.getString("message.invalid.status"));
optionPane.setValue(JOptionPane.UNINITIALIZED_VALUE);
return;
}
if (!persistBox.isSelected()) {
// Change presence and quit.
StatusItem item = statusBar.getStatusItem(getType());
Presence oldPresence = item.getPresence();
Presence presence = StatusBar.copyPresence(oldPresence);
presence.setStatus(getStatus());
presence.setPriority(getPriority());
SparkManager.getSessionManager().changePresence(presence);
statusBar.setStatus(getStatus());
optionsDialog.setVisible(false);
return;
}
List<CustomStatusItem> list = load();
CustomStatusItem customStatusItem = new CustomStatusItem();
customStatusItem.setPriority(getPriority());
customStatusItem.setStatus(getStatus());
customStatusItem.setType(getType());
Iterator<CustomStatusItem> customListIterator = list.iterator();
boolean exists = false;
while (customListIterator.hasNext()) {
CustomStatusItem customItem = customListIterator.next();
String type = customItem.getType();
String status = customItem.getStatus();
if (type.equals(customStatusItem.getType()) && status.equals(customStatusItem.getStatus())) {
exists = true;
}
}
// Otherwise save.
if (!exists) {
list.add(customStatusItem);
// Update current status.
StatusItem item = statusBar.getStatusItem(getType());
Presence oldPresence = item.getPresence();
Presence presence = StatusBar.copyPresence(oldPresence);
presence.setStatus(getStatus());
presence.setPriority(getPriority());
SparkManager.getSessionManager().changePresence(presence);
statusBar.setStatus(getStatus());
// Persist new item.
save(list);
}
optionsDialog.setVisible(false);
}
}
});
optionsDialog.setVisible(true);
optionsDialog.toFront();
optionsDialog.requestFocus();
}
}
}