aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-x.classpath1
-rw-r--r--build.xml5
-rw-r--r--lib/felix.client.run.properties1
-rw-r--r--lib/installer-exclude/jcalendar-1.4.jarbin0 -> 169029 bytes
-rw-r--r--resources/images/images.properties1
-rw-r--r--resources/images/impl/gui/buttons/accountEditIcon.pngbin0 -> 1559 bytes
-rw-r--r--resources/languages/resources.properties18
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/MainFrame.java2
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/account/AccountList.java34
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/account/AccountRightButtonMenu.java260
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/presence/AccountStatusPanel.java10
-rw-r--r--src/net/java/sip/communicator/impl/gui/swing.ui.manifest.mf1
-rw-r--r--src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java6
-rw-r--r--src/net/java/sip/communicator/impl/protocol/icq/OperationSetServerStoredAccountInfoIcqImpl.java30
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/InfoRetreiver.java39
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/OperationSetServerStoredAccountInfoJabberImpl.java297
-rw-r--r--src/net/java/sip/communicator/impl/protocol/msn/OperationSetServerStoredAccountInfoMsnImpl.java29
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/OperationSetServerStoredAccountInfoSipImpl.java29
-rw-r--r--src/net/java/sip/communicator/plugin/accountinfo/AccountDetailsPanel.java1384
-rw-r--r--src/net/java/sip/communicator/plugin/accountinfo/AccountInfoActivator.java78
-rw-r--r--src/net/java/sip/communicator/plugin/accountinfo/AccountInfoMenuItemComponent.java119
-rw-r--r--src/net/java/sip/communicator/plugin/accountinfo/AccountInfoPanel.java246
-rw-r--r--src/net/java/sip/communicator/plugin/accountinfo/accountinfo.manifest.mf24
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/DesktopUtilActivator.java77
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/FramedImage.java42
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/FramedImageWithMenu.java18
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/desktoputil.manifest.mf2
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/presence/avatar/AvatarStackManager.java (renamed from src/net/java/sip/communicator/impl/gui/main/presence/avatar/AvatarStackManager.java)34
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/presence/avatar/SelectAvatarMenu.java (renamed from src/net/java/sip/communicator/impl/gui/main/presence/avatar/SelectAvatarMenu.java)118
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/presence/avatar/imagepicker/EditPanel.java (renamed from src/net/java/sip/communicator/impl/gui/main/presence/avatar/imagepicker/EditPanel.java)13
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/presence/avatar/imagepicker/ImageClipper.java (renamed from src/net/java/sip/communicator/impl/gui/main/presence/avatar/imagepicker/ImageClipper.java)2
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/presence/avatar/imagepicker/ImagePickerDialog.java (renamed from src/net/java/sip/communicator/impl/gui/main/presence/avatar/imagepicker/ImagePickerDialog.java)20
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/presence/avatar/imagepicker/WebcamDialog.java (renamed from src/net/java/sip/communicator/impl/gui/main/presence/avatar/imagepicker/WebcamDialog.java)18
-rw-r--r--src/net/java/sip/communicator/plugin/spellcheck/LanguageMenuBar.java5
-rw-r--r--src/net/java/sip/communicator/service/gui/AbstractPluginComponent.java7
-rw-r--r--src/net/java/sip/communicator/service/gui/Container.java6
-rw-r--r--src/net/java/sip/communicator/service/gui/PluginComponent.java15
-rw-r--r--src/net/java/sip/communicator/service/protocol/AbstractOperationSetAvatar.java1
-rw-r--r--src/net/java/sip/communicator/service/protocol/OperationSetServerStoredAccountInfo.java37
-rw-r--r--src/net/java/sip/communicator/service/protocol/ServerStoredDetails.java151
40 files changed, 2409 insertions, 771 deletions
diff --git a/.classpath b/.classpath
index 9a9bf4c..fb0eda4 100755
--- a/.classpath
+++ b/.classpath
@@ -83,5 +83,6 @@
<classpathentry kind="lib" path="lib/installer-exclude/bcprov-jdk15on-149.jar"/>
<classpathentry kind="lib" path="lib/installer-exclude/bccontrib-1.0-SNAPSHOT.jar"/>
<classpathentry kind="lib" path="lib/installer-exclude/zrtp4j-light.jar"/>
+ <classpathentry kind="lib" path="lib/installer-exclude/jcalendar-1.4.jar"/>
<classpathentry kind="output" path="classes"/>
</classpath>
diff --git a/build.xml b/build.xml
index 3d14c5e..d513fa1 100644
--- a/build.xml
+++ b/build.xml
@@ -1079,8 +1079,8 @@
bundle-globalshortcut,bundle-plugin-msofficecomm,bundle-libjitsi,
bundle-customcontactactions, bundle-phonenumbercontactsource,
bundle-demuxcontactsource, bundle-muc,
- bundle-desktoputil,
- bundle-globaldisplaydetails,bundle-plugin-propertieseditor"/>
+ bundle-desktoputil,bundle-globaldisplaydetails,
+ bundle-plugin-propertieseditor,bundle-plugin-accountinfo"/>
<!--BUNDLE-SC-LAUNCHER-->
<target name="bundle-sc-launcher">
@@ -2226,6 +2226,7 @@ javax.swing.event, javax.swing.border"/>
manifest="${src}/net/java/sip/communicator/plugin/accountinfo/accountinfo.manifest.mf">
<zipfileset dir="${dest}/net/java/sip/communicator/plugin/accountinfo"
prefix="net/java/sip/communicator/plugin/accountinfo"/>
+ <zipfileset src="${lib.noinst}/jcalendar-1.4.jar"/>
</jar>
</target>
diff --git a/lib/felix.client.run.properties b/lib/felix.client.run.properties
index cf8c6e4..f567442 100644
--- a/lib/felix.client.run.properties
+++ b/lib/felix.client.run.properties
@@ -134,6 +134,7 @@ felix.auto.start.60= \
felix.auto.start.66= \
reference:file:sc-bundles/swing-ui.jar \
reference:file:sc-bundles/update.jar \
+ reference:file:sc-bundles/accountinfo.jar \
reference:file:sc-bundles/swingnotification.jar \
reference:file:sc-bundles/systray-service.jar \
reference:file:sc-bundles/osdependent.jar \
diff --git a/lib/installer-exclude/jcalendar-1.4.jar b/lib/installer-exclude/jcalendar-1.4.jar
new file mode 100644
index 0000000..8b0bff6
--- /dev/null
+++ b/lib/installer-exclude/jcalendar-1.4.jar
Binary files differ
diff --git a/resources/images/images.properties b/resources/images/images.properties
index b313f79..eed832e 100644
--- a/resources/images/images.properties
+++ b/resources/images/images.properties
@@ -123,6 +123,7 @@ service.gui.statusicons.USER_FFC_ICON=resources/images/impl/gui/common/statusico
service.gui.statusicons.USER_ON_THE_PHONE_ICON=resources/images/impl/gui/common/statusicons/onThePhone.png
# service gui buttons
+service.gui.buttons.ACCOUNT_EDIT_ICON=resources/images/impl/gui/buttons/accountEditIcon.png
service.gui.buttons.CONTACT_LIST_BUTTON_BG_LEFT=resources/images/impl/gui/buttons/contactListButtonBgLeft.png
service.gui.buttons.CONTACT_LIST_BUTTON_BG_RIGHT=resources/images/impl/gui/buttons/contactListButtonBgRight.png
service.gui.buttons.CONTACT_LIST_BUTTON_BG_MIDDLE=resources/images/impl/gui/buttons/contactListButtonBgMiddle.png
diff --git a/resources/images/impl/gui/buttons/accountEditIcon.png b/resources/images/impl/gui/buttons/accountEditIcon.png
new file mode 100644
index 0000000..a13ecc1
--- /dev/null
+++ b/resources/images/impl/gui/buttons/accountEditIcon.png
Binary files differ
diff --git a/resources/languages/resources.properties b/resources/languages/resources.properties
index bee961c..a410494 100644
--- a/resources/languages/resources.properties
+++ b/resources/languages/resources.properties
@@ -857,15 +857,33 @@ impl.googlecontacts.WRONG_CREDENTIALS=Wrong credentials for Google account {0}
plugin.accountinfo.TITLE=Account Info
plugin.accountinfo.EXTENDED=Extended
plugin.accountinfo.NOT_SUPPORTED=Account info not available.
+plugin.accountinfo.SELECT_ACCOUNT=Please select an account:
+plugin.accountinfo.DISPLAY_NAME=Display name:
plugin.accountinfo.FIRST_NAME=First Name:
plugin.accountinfo.MIDDLE_NAME=Middle Name:
plugin.accountinfo.LAST_NAME=Last Name:
+plugin.accountinfo.NICKNAME=Nickname:
+plugin.accountinfo.URL=URL:
plugin.accountinfo.AGE=Age:
plugin.accountinfo.BDAY=Birth Date:
+plugin.accountinfo.BDAY_FORMAT=MMM dd, yyyy
plugin.accountinfo.GENDER=Gender:
+plugin.accountinfo.STREET=Street Address:
+plugin.accountinfo.CITY=City:
+plugin.accountinfo.REGION=Region:
+plugin.accountinfo.POST=Postal code:
+plugin.accountinfo.COUNTRY=Country:
plugin.accountinfo.EMAIL=E-mail:
+plugin.accountinfo.WORK_EMAIL=Work E-mail:
plugin.accountinfo.PHONE=Phone:
+plugin.accountinfo.WORK_PHONE=Work Phone:
+plugin.accountinfo.ORGANIZATION=Organization Name:
+plugin.accountinfo.JOB_TITLE=Job Title:
+plugin.accountinfo.ABOUT_ME=About Me:
+plugin.accountinfo.ABOUT_ME_MAX_CHARACTERS=200
plugin.accountinfo.USER_PICTURES=User Pictures
+plugin.accountinfo.GLOBAL_ICON=Use global icon
+plugin.accountinfo.LOCAL_ICON=Use this icon:
plugin.accountinfo.CHANGE=Change
plugin.accountinfo.ONLY_MESSAGE=Only messages
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 2313cdb..a0fd2ae 100644
--- a/src/net/java/sip/communicator/impl/gui/main/MainFrame.java
+++ b/src/net/java/sip/communicator/impl/gui/main/MainFrame.java
@@ -186,7 +186,7 @@ public class MainFrame
this.contactListPanel = new ContactListPane(this);
- this.accountStatusPanel = new AccountStatusPanel(this);
+ this.accountStatusPanel = new AccountStatusPanel();
this.searchField = new SearchField( this,
TreeContactList.searchFilter,
diff --git a/src/net/java/sip/communicator/impl/gui/main/account/AccountList.java b/src/net/java/sip/communicator/impl/gui/main/account/AccountList.java
index ae0a105..c2cc0ae 100644
--- a/src/net/java/sip/communicator/impl/gui/main/account/AccountList.java
+++ b/src/net/java/sip/communicator/impl/gui/main/account/AccountList.java
@@ -57,6 +57,12 @@ public class AccountList
private final JButton editButton;
/**
+ * The menu that appears when right click on account is detected.
+ */
+ private final AccountRightButtonMenu rightButtonMenu
+ = new AccountRightButtonMenu();
+
+ /**
* Creates an instance of this account list by specifying the parent
* container of the list.
*
@@ -69,6 +75,29 @@ public class AccountList
this.addMouseListener(this);
+ this.addMouseListener(new MouseAdapter()
+ {
+ public void mousePressed(MouseEvent e)
+ {
+ if (SwingUtilities.isRightMouseButton(e))
+ {
+ Point point = e.getPoint();
+
+ AccountList.this.setSelectedIndex(getRow(point));
+
+ rightButtonMenu.setAccount(getSelectedAccount());
+
+ SwingUtilities.convertPointToScreen(
+ point, AccountList.this);
+
+ ((JPopupMenu) rightButtonMenu).setInvoker(AccountList.this);
+
+ rightButtonMenu.setLocation(point.x, point.y);
+ rightButtonMenu.setVisible(true);
+ }
+ }
+ });
+
this.accountsInit();
GuiActivator.bundleContext.addServiceListener(this);
@@ -76,6 +105,11 @@ public class AccountList
this.editButton = parentConfigPanel.getEditButton();
}
+ private int getRow(Point point)
+ {
+ return locationToIndex(point);
+ }
+
/**
* Initializes the accounts table.
*/
diff --git a/src/net/java/sip/communicator/impl/gui/main/account/AccountRightButtonMenu.java b/src/net/java/sip/communicator/impl/gui/main/account/AccountRightButtonMenu.java
new file mode 100644
index 0000000..f74ffb9
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/account/AccountRightButtonMenu.java
@@ -0,0 +1,260 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.gui.main.account;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.impl.gui.*;
+import net.java.sip.communicator.impl.gui.event.*;
+import net.java.sip.communicator.impl.gui.utils.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
+import net.java.sip.communicator.service.gui.*;
+import net.java.sip.communicator.service.gui.Container;
+import net.java.sip.communicator.util.*;
+import net.java.sip.communicator.util.skin.*;
+
+import org.jitsi.service.resources.*;
+import org.osgi.framework.*;
+
+/**
+ * AccountRightButtonMenu is the menu that opens when user right clicks on any
+ * of his accounts in the account list section.
+ *
+ * @author Marin Dzhigarov
+ */
+public class AccountRightButtonMenu
+ extends SIPCommPopupMenu
+ implements ActionListener,
+ PluginComponentListener,
+ Skinnable
+{
+ /**
+ * The serial version UID.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The logger of this class.
+ */
+ private final Logger logger
+ = Logger.getLogger(AccountRightButtonMenu.class);
+
+ /**
+ * The Account that is clicked on.
+ */
+ private Account account = null;
+
+ /**
+ * A list of all PluginComponents that are registered through the OSGi
+ * bundle context.
+ */
+ private java.util.List<PluginComponent> pluginComponents
+ = new ArrayList<PluginComponent>();
+
+ /**
+ * The edit item.
+ */
+ private final JMenuItem editItem = new JMenuItem(
+ GuiActivator.getResources().getI18NString(
+ "service.gui.EDIT"));
+
+ /**
+ * Creates an instance of AccountRightButtonMenu
+ */
+ public AccountRightButtonMenu()
+ {
+ super();
+
+ this.setLocation(getLocation());
+
+ this.init();
+
+ loadSkin();
+ }
+
+ /**
+ * Sets the current Account that is clicked on.
+ * @param account the Account that is clicked on.
+ */
+ public void setAccount(Account account)
+ {
+ this.account = account;
+ editItem.setEnabled(account != null && this.account.isEnabled());
+ for (PluginComponent pluginComponent : pluginComponents)
+ pluginComponent.setCurrentAccountID(account.getAccountID());
+ }
+
+ /**
+ * Returns the Account that was last clicked on.
+ * @return the Account that was last clicked on.
+ */
+ public Account getAccount()
+ {
+ return account;
+ }
+
+ /**
+ * Initialized the menu by adding all containing menu items.
+ */
+ private void init()
+ {
+ initPluginComponents();
+ add(editItem);
+ editItem.addActionListener(this);
+ }
+
+ /**
+ * Initializes plug-in components for this container.
+ */
+ private void initPluginComponents()
+ {
+ // Search for plugin components registered through the OSGI bundle
+ // context.
+ ServiceReference[] serRefs = null;
+
+ String osgiFilter = "("
+ + Container.CONTAINER_ID
+ + "="+Container.CONTAINER_ACCOUNT_RIGHT_BUTTON_MENU.getID()+")";
+
+ try
+ {
+ serRefs = GuiActivator.bundleContext.getServiceReferences(
+ PluginComponentFactory.class.getName(),
+ osgiFilter);
+ }
+ catch (InvalidSyntaxException exc)
+ {
+ logger.error("Could not obtain plugin reference.", exc);
+ }
+
+ if (serRefs != null)
+ {
+ for (int i = 0; i < serRefs.length; i ++)
+ {
+ PluginComponentFactory factory =
+ (PluginComponentFactory) GuiActivator
+ .bundleContext.getService(serRefs[i]);
+
+ PluginComponent component =
+ factory.getPluginComponentInstance(this);
+
+ if (component.getComponent() == null)
+ continue;
+
+ pluginComponents.add(component);
+
+ if (factory.getPositionIndex() != -1)
+ this.add((Component)component.getComponent(),
+ factory.getPositionIndex());
+ else
+ this.add((Component)component.getComponent());
+ }
+ }
+ GuiActivator.getUIService().addPluginComponentListener(this);
+ }
+
+ /**
+ * Reloads skin related information.
+ */
+ public void loadSkin()
+ {
+ editItem.setIcon(new ImageIcon(
+ ImageLoader.getImage(ImageLoader.ACCOUNT_EDIT_ICON)));
+ }
+
+ /**
+ * Indicates that a plugin component has been added to this container.
+ *
+ * @param event the <tt>PluginComponentEvent</tt> that notified us
+ */
+ /**
+ * Indicates that a new plugin component has been added. Adds it to this
+ * container if it belongs to it.
+ *
+ * @param event the <tt>PluginComponentEvent</tt> that notified us
+ */
+ public void pluginComponentAdded(PluginComponentEvent event)
+ {
+ PluginComponentFactory factory = event.getPluginComponentFactory();
+
+ if (!factory.getContainer().equals(
+ Container.CONTAINER_ACCOUNT_RIGHT_BUTTON_MENU))
+ return;
+
+ PluginComponent c = factory.getPluginComponentInstance(this);
+
+ this.add((Component) c.getComponent());
+
+ this.repaint();
+ }
+
+ /**
+ * Removes the according plug-in component from this container.
+ * @param event the <tt>PluginComponentEvent</tt> that notified us
+ */
+ public void pluginComponentRemoved(PluginComponentEvent event)
+ {
+ PluginComponentFactory factory = event.getPluginComponentFactory();
+
+ if(factory.getContainer()
+ .equals(Container.CONTAINER_ACCOUNT_RIGHT_BUTTON_MENU))
+ {
+ Component c =
+ (Component)factory.getPluginComponentInstance(this)
+ .getComponent();
+ this.remove(c);
+ pluginComponents.remove(c);
+ }
+ }
+
+ /**
+ * Handles the <tt>ActionEvent</tt>. Determines which menu item was
+ * selected and performs the appropriate operations.
+ * @param e the <tt>ActionEvent</tt>, which notified us of the action
+ */
+ public void actionPerformed(ActionEvent e)
+ {
+ JMenuItem menuItem = (JMenuItem) e.getSource();
+
+ if (menuItem.equals(editItem))
+ {
+ 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);
+ }
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/presence/AccountStatusPanel.java b/src/net/java/sip/communicator/impl/gui/main/presence/AccountStatusPanel.java
index 9b39b5d..5e7d615 100644
--- a/src/net/java/sip/communicator/impl/gui/main/presence/AccountStatusPanel.java
+++ b/src/net/java/sip/communicator/impl/gui/main/presence/AccountStatusPanel.java
@@ -14,9 +14,9 @@ import javax.swing.*;
import net.java.sip.communicator.impl.gui.*;
import net.java.sip.communicator.impl.gui.event.*;
import net.java.sip.communicator.impl.gui.lookandfeel.*;
-import net.java.sip.communicator.impl.gui.main.*;
-import net.java.sip.communicator.impl.gui.main.presence.avatar.*;
import net.java.sip.communicator.impl.gui.utils.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
+import net.java.sip.communicator.plugin.desktoputil.presence.avatar.*;
import net.java.sip.communicator.service.globaldisplaydetails.event.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.gui.Container;
@@ -25,8 +25,6 @@ import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.skin.*;
-import net.java.sip.communicator.plugin.desktoputil.*;
-
import org.jitsi.util.*;
/**
@@ -126,15 +124,13 @@ public class AccountStatusPanel
/**
* Creates an instance of <tt>AccountStatusPanel</tt> by specifying the
* main window, where this panel is added.
- * @param mainFrame the main window, where this panel is added
*/
- public AccountStatusPanel(MainFrame mainFrame)
+ public AccountStatusPanel()
{
super(new BorderLayout(10, 0));
FramedImageWithMenu imageWithMenu
= new FramedImageWithMenu(
- mainFrame,
new ImageIcon(
ImageLoader
.getImage(ImageLoader.DEFAULT_USER_PHOTO)),
diff --git a/src/net/java/sip/communicator/impl/gui/swing.ui.manifest.mf b/src/net/java/sip/communicator/impl/gui/swing.ui.manifest.mf
index ce04afb..607dffc 100644
--- a/src/net/java/sip/communicator/impl/gui/swing.ui.manifest.mf
+++ b/src/net/java/sip/communicator/impl/gui/swing.ui.manifest.mf
@@ -58,6 +58,7 @@ Import-Package: com.apple.eawt,
net.java.sip.communicator.plugin.desktoputil.event,
net.java.sip.communicator.plugin.desktoputil.plaf,
net.java.sip.communicator.plugin.desktoputil.presence,
+ net.java.sip.communicator.plugin.desktoputil.presence.avatar,
net.java.sip.communicator.plugin.desktoputil.transparent,
net.java.sip.communicator.service.customcontactactions,
net.java.sip.communicator.service.globaldisplaydetails,
diff --git a/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java b/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java
index 083e2d1..c2dba57 100644
--- a/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java
+++ b/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java
@@ -161,6 +161,12 @@ public class ImageLoader
= new ImageID("service.gui.icons.RIGHT_ARROW_ICON");
/**
+ * The edit icon that is shown when account is right clicked on.
+ */
+ public static final ImageID ACCOUNT_EDIT_ICON
+ = new ImageID("service.gui.buttons.ACCOUNT_EDIT_ICON");
+
+ /**
* The call button image.
*/
public static final ImageID INCOMING_CALL_BUTTON_BG
diff --git a/src/net/java/sip/communicator/impl/protocol/icq/OperationSetServerStoredAccountInfoIcqImpl.java b/src/net/java/sip/communicator/impl/protocol/icq/OperationSetServerStoredAccountInfoIcqImpl.java
index 19c0992..0d10453 100644
--- a/src/net/java/sip/communicator/impl/protocol/icq/OperationSetServerStoredAccountInfoIcqImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/icq/OperationSetServerStoredAccountInfoIcqImpl.java
@@ -52,6 +52,7 @@ public class OperationSetServerStoredAccountInfoIcqImpl
public static final Map<Class<? extends GenericDetail>, int[]> supportedTypes
= new Hashtable<Class<? extends GenericDetail>, int[]>();
static {
+ supportedTypes.put(ServerStoredDetails.ImageDetail.class, new int[]{1});
supportedTypes.put(ServerStoredDetails.CountryDetail.class, new int[]{1, 0x01A4});
supportedTypes.put(ServerStoredDetails.NicknameDetail.class, new int[]{1, 0x0154});
supportedTypes.put(ServerStoredDetails.FirstNameDetail.class, new int[]{1, 0x0140});
@@ -227,6 +228,23 @@ public class OperationSetServerStoredAccountInfoIcqImpl
}
/**
+ * Determines whether the underlying implementation supports edition
+ * of this detail class.
+ * <p>
+ * @param detailClass the class whose edition we'd like to determine if it's
+ * possible
+ * @return true if the underlying implementation supports edition of this
+ * type of detail and false otherwise.
+ */
+ public boolean isDetailClassEditable(
+ Class<? extends GenericDetail> detailClass)
+ {
+ return
+ isDetailClassSupported(detailClass)
+ && ImageDetail.class.isAssignableFrom(detailClass);
+ }
+
+ /**
* Utility method throwing an exception if the icq stack is not properly
* initialized.
* @throws java.lang.IllegalStateException if the underlying ICQ stack is
@@ -794,6 +812,18 @@ public class OperationSetServerStoredAccountInfoIcqImpl
return false;
}
+ /*
+ * (non-Javadoc)
+ * @see net.java.sip.communicator.service.protocol.OperationSetServerStoredAccountInfo#save()
+ * This method is currently unimplemented.
+ * The idea behind this method is for users to call it only once, meaning
+ * that all ServerStoredDetails previously modified by addDetail/removeDetail
+ * and/or replaceDetail will be saved online on the server in one step.
+ * Currently, addDetail/removeDetail/replaceDetail methods are doing the
+ * actual saving but in the future the saving part must be carried here.
+ */
+ public void save() throws OperationFailedException {}
+
/**
* Requests the account image if its missing.
* @return the new image or the one that has been already downloaded.
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/InfoRetreiver.java b/src/net/java/sip/communicator/impl/protocol/jabber/InfoRetreiver.java
index af1be57..869e51d 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/InfoRetreiver.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/InfoRetreiver.java
@@ -8,6 +8,7 @@ package net.java.sip.communicator.impl.protocol.jabber;
import java.lang.reflect.*;
import java.net.*;
+import java.text.*;
import java.util.*;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.*;
@@ -175,6 +176,24 @@ public class InfoRetreiver
if(tmp != null)
result.add(new NicknameDetail(tmp));
+ tmp = card.getField("BDAY");
+ if (tmp != null)
+ {
+ try
+ {
+ Calendar birthDateCalendar = Calendar.getInstance();
+ DateFormat dateFormat =
+ new SimpleDateFormat(
+ JabberActivator.getResources().getI18NString(
+ "plugin.accountinfo.BDAY_FORMAT"));
+ Date birthDate =
+ dateFormat.parse(tmp);
+ birthDateCalendar.setTime(birthDate);
+ BirthDateDetail bd = new BirthDateDetail(birthDateCalendar);
+ result.add(bd);
+ }
+ catch (ParseException e) {}
+ }
// Home Details
// addrField one of
// POSTAL, PARCEL, (DOM | INTL), PREF, POBOX, EXTADR, STREET,
@@ -195,9 +214,9 @@ public class InfoRetreiver
if(tmp != null)
result.add(new PostalCodeDetail(tmp));
-// tmp = card.getAddressFieldHome("CTRY");
-// if(tmp != null)
-// result.add(new CountryDetail(tmp);
+ tmp = card.getAddressFieldHome("CTRY");
+ if(tmp != null)
+ result.add(new CountryDetail(tmp));
// phoneType one of
//VOICE, FAX, PAGER, MSG, CELL, VIDEO, BBS, MODEM, ISDN, PCS, PREF
@@ -276,7 +295,7 @@ public class InfoRetreiver
tmp = card.getEmailWork();
if(tmp != null)
- result.add(new EmailAddressDetail(tmp));
+ result.add(new WorkEmailAddressDetail(tmp));
tmp = card.getOrganization();
if(tmp != null)
@@ -286,15 +305,25 @@ public class InfoRetreiver
if(tmp != null)
result.add(new WorkDepartmentNameDetail(tmp));
+ tmp = card.getField("TITLE");
+ if(tmp != null)
+ result.add(new JobTitleDetail(tmp));
+
+ tmp = card.getField("ABOUTME");
+ if (tmp != null)
+ result.add(new AboutMeDetail(tmp));
+
byte[] imageBytes = card.getAvatar();
if(imageBytes != null && imageBytes.length > 0)
+ {
result.add(new ImageDetail("Image", imageBytes));
+ }
try
{
tmp = card.getField("URL");
if(tmp != null)
- result.add(new WebPageDetail(new URL(tmp)));
+ result.add(new URLDetail("URL", new URL(tmp)));
}
catch(MalformedURLException e){}
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetServerStoredAccountInfoJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetServerStoredAccountInfoJabberImpl.java
index 9d148e8..09b9e5f 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetServerStoredAccountInfoJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetServerStoredAccountInfoJabberImpl.java
@@ -6,11 +6,12 @@
*/
package net.java.sip.communicator.impl.protocol.jabber;
+import java.net.*;
+import java.text.*;
import java.util.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.ServerStoredDetails.GenericDetail;
-import net.java.sip.communicator.service.protocol.ServerStoredDetails.ImageDetail;
+import net.java.sip.communicator.service.protocol.ServerStoredDetails.*;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
@@ -22,6 +23,7 @@ import org.jivesoftware.smack.*;
* provider.
*
* @author Damian Minkov
+ * @author Marin Dzhigarov
*/
public class OperationSetServerStoredAccountInfoJabberImpl
extends AbstractOperationSetServerStoredAccountInfo
@@ -43,6 +45,35 @@ public class OperationSetServerStoredAccountInfoJabberImpl
private ProtocolProviderServiceJabberImpl jabberProvider = null;
/**
+ * List of all supported <tt>ServerStoredDetails</tt>
+ * for this implementation.
+ */
+ public static final List<Class<? extends GenericDetail>> supportedTypes
+ = new ArrayList<Class<? extends GenericDetail>>();
+
+ static {
+ supportedTypes.add(ImageDetail.class);
+ supportedTypes.add(FirstNameDetail.class);
+ supportedTypes.add(MiddleNameDetail.class);
+ supportedTypes.add(LastNameDetail.class);
+ supportedTypes.add(NicknameDetail.class);
+ supportedTypes.add(AddressDetail.class);
+ supportedTypes.add(CityDetail.class);
+ supportedTypes.add(ProvinceDetail.class);
+ supportedTypes.add(PostalCodeDetail.class);
+ supportedTypes.add(CountryDetail.class);
+ supportedTypes.add(EmailAddressDetail.class);
+ supportedTypes.add(WorkEmailAddressDetail.class);
+ supportedTypes.add(PhoneNumberDetail.class);
+ supportedTypes.add(WorkPhoneDetail.class);
+ supportedTypes.add(WorkOrganizationNameDetail.class);
+ supportedTypes.add(URLDetail.class);
+ supportedTypes.add(BirthDateDetail.class);
+ supportedTypes.add(JobTitleDetail.class);
+ supportedTypes.add(AboutMeDetail.class);
+ }
+
+ /**
* Our account UIN.
*/
private String uin = null;
@@ -124,14 +155,7 @@ public class OperationSetServerStoredAccountInfoJabberImpl
*/
public Iterator<Class<? extends GenericDetail>> getSupportedDetailTypes()
{
- List<GenericDetail> details = infoRetreiver.getContactDetails(uin);
- List<Class<? extends GenericDetail>> result
- = new Vector<Class<? extends GenericDetail>>();
-
- for (GenericDetail obj : details)
- result.add(obj.getClass());
-
- return result.iterator();
+ return supportedTypes.iterator();
}
/**
@@ -150,12 +174,7 @@ public class OperationSetServerStoredAccountInfoJabberImpl
public boolean isDetailClassSupported(
Class<? extends GenericDetail> detailClass)
{
- List<GenericDetail> details = infoRetreiver.getContactDetails(uin);
-
- for (GenericDetail obj : details)
- if(detailClass.isAssignableFrom(obj.getClass()))
- return true;
- return false;
+ return supportedTypes.contains(detailClass);
}
/**
@@ -173,7 +192,7 @@ public class OperationSetServerStoredAccountInfoJabberImpl
}
/**
- * Adds the specified detail to the list of details registered on-line
+ * Adds the specified detail to the list of details ready to be saved online
* for this account. If such a detail already exists its max instance number
* is consulted and if it allows it - a second instance is added or otherwise
* and illegal argument exception is thrown. An IllegalArgumentException is
@@ -187,67 +206,50 @@ public class OperationSetServerStoredAccountInfoJabberImpl
* max instances number has been attained or if the underlying
* implementation does not support setting details of the corresponding
* class.
- * @throws OperationFailedException with code Network Failure if putting the
- * new value online has failed
* @throws java.lang.ArrayIndexOutOfBoundsException if the number of
* instances currently registered by the application is already equal to the
* maximum number of supported instances (@see getMaxDetailInstances())
*/
public void addDetail(ServerStoredDetails.GenericDetail detail)
throws IllegalArgumentException,
- OperationFailedException,
ArrayIndexOutOfBoundsException
{
- assertConnected();
-
- /*
- Currently as the function only provided the list of classes that
- currently have data associated with them
- in Jabber InfoRetreiver we have to skip this check*/
- //if (!isDetailClassSupported(detail.getClass())) {
- // throw new IllegalArgumentException(
- // "implementation does not support such details " +
- // detail.getClass());
- //}
+ if (!isDetailClassSupported(detail.getClass())) {
+ throw new IllegalArgumentException(
+ "implementation does not support such details " +
+ detail.getClass());
+ }
Iterator<GenericDetail> iter = getDetails(detail.getClass());
int currentDetailsSize = 0;
while (iter.hasNext())
{
currentDetailsSize++;
+ iter.next();
}
- if (currentDetailsSize >= getMaxDetailInstances(detail.getClass()))
+ if (currentDetailsSize > getMaxDetailInstances(detail.getClass()))
{
throw new ArrayIndexOutOfBoundsException(
"Max count for this detail is already reached");
}
- if(detail instanceof ImageDetail)
- {
- // Push the avatar photo to the server.
- this.uploadImageDetail(
- ServerStoredDetailsChangeEvent.DETAIL_ADDED,
- null,
- detail);
- }
+ infoRetreiver.getCachedContactDetails(uin).add(detail);
}
/**
- * Removes the specified detail from the list of details stored online for
- * this account. The method returns a boolean indicating if such a detail
- * was found (and removed) or not.
+ * Removes the specified detail from the list of details ready to be saved
+ * online this account. The method returns a boolean indicating if such a
+ * detail was found (and removed) or not.
* <p>
* @param detail the detail to remove
* @return true if the specified detail existed and was successfully removed
* and false otherwise.
- * @throws OperationFailedException with code Network Failure if removing the
- * detail from the server has failed
*/
public boolean removeDetail(ServerStoredDetails.GenericDetail detail)
- throws OperationFailedException
{
- return false;
+
+ return infoRetreiver.getCachedContactDetails(uin).remove(detail);
}
/**
@@ -264,16 +266,12 @@ public class OperationSetServerStoredAccountInfoJabberImpl
* call to addDetail is required).
* @throws ClassCastException if newDetailValue is not an instance of the
* same class as currentDetailValue.
- * @throws OperationFailedException with code Network Failure if putting the
- * new value back online has failed
*/
public boolean replaceDetail(
ServerStoredDetails.GenericDetail currentDetailValue,
ServerStoredDetails.GenericDetail newDetailValue)
- throws ClassCastException, OperationFailedException
+ throws ClassCastException
{
- assertConnected();
-
if (!newDetailValue.getClass().equals(currentDetailValue.getClass()))
{
throw new ClassCastException(
@@ -304,22 +302,130 @@ public class OperationSetServerStoredAccountInfoJabberImpl
return false;
}
- if(newDetailValue instanceof ImageDetail)
+ removeDetail(currentDetailValue);
+ addDetail(newDetailValue);
+ return true;
+ }
+
+ /**
+ * Saves the list of details for this account that were ready to be stored
+ * online on the server. This method performs the actual saving of details
+ * online on the server and is supposed to be invoked after addDetail(),
+ * replaceDetail() and/or removeDetail().
+ * <p>
+ * @throws OperationFailedException with code Network Failure if putting the
+ * new values back online has failed.
+ */
+ public void save() throws OperationFailedException
+ {
+ assertConnected();
+
+ List<GenericDetail> details = infoRetreiver.getContactDetails(uin);
+ VCardXEP0153 vCard = new VCardXEP0153();
+ for (GenericDetail detail : details)
+ {
+ if (detail instanceof ImageDetail)
+ {
+ byte[] avatar = ((ImageDetail) detail).getBytes();
+ if (avatar == null) vCard.setAvatar(new byte[0]);
+ else vCard.setAvatar(avatar);
+ fireServerStoredDetailsChangeEvent(
+ jabberProvider,
+ ServerStoredDetailsChangeEvent.DETAIL_ADDED,
+ null,
+ detail);
+ }
+ else if (detail.getClass().equals(FirstNameDetail.class))
+ vCard.setFirstName((String)detail.getDetailValue());
+ else if (detail.getClass().equals(MiddleNameDetail.class))
+ vCard.setMiddleName((String)detail.getDetailValue());
+ else if (detail.getClass().equals(LastNameDetail.class))
+ vCard.setLastName((String)detail.getDetailValue());
+ else if (detail.getClass().equals(NicknameDetail.class))
+ vCard.setNickName((String)detail.getDetailValue());
+ else if (detail.getClass().equals(URLDetail.class))
+ {
+ if (detail.getDetailValue() != null)
+ vCard.setField(
+ "URL", ((URL)detail.getDetailValue()).toString());
+ }
+ else if (detail.getClass().equals(BirthDateDetail.class))
+ {
+ if (detail.getDetailValue() != null)
+ {
+ Calendar c = ((BirthDateDetail)detail).getCalendar();
+ DateFormat dateFormat =
+ new SimpleDateFormat(
+ JabberActivator.getResources().getI18NString(
+ "plugin.accountinfo.BDAY_FORMAT"));
+ String strdate = dateFormat.format(c.getTime());
+ vCard.setField("BDAY", strdate);
+ }
+ }
+ else if (detail.getClass().equals(AddressDetail.class))
+ vCard.setAddressFieldHome(
+ "STREET", (String)detail.getDetailValue());
+ else if (detail.getClass().equals(CityDetail.class))
+ vCard.setAddressFieldHome(
+ "LOCALITY", (String)detail.getDetailValue());
+ else if (detail.getClass().equals(ProvinceDetail.class))
+ vCard.setAddressFieldHome(
+ "REGION", (String)detail.getDetailValue());
+ else if (detail.getClass().equals(PostalCodeDetail.class))
+ vCard.setAddressFieldHome(
+ "PCODE", (String)detail.getDetailValue());
+ else if (detail.getClass().equals(CountryDetail.class))
+ vCard.setAddressFieldHome(
+ "CTRY", (String)detail.getDetailValue());
+ else if (detail.getClass().equals(PhoneNumberDetail.class))
+ vCard.setPhoneHome("VOICE", (String)detail.getDetailValue());
+ else if (detail.getClass().equals(WorkPhoneDetail.class))
+ vCard.setPhoneWork("VOICE", (String)detail.getDetailValue());
+ else if (detail.getClass().equals(EmailAddressDetail.class))
+ vCard.setEmailHome((String)detail.getDetailValue());
+ else if (detail.getClass().equals(WorkEmailAddressDetail.class))
+ vCard.setEmailWork((String)detail.getDetailValue());
+ else if (detail.getClass().equals(WorkOrganizationNameDetail.class))
+ vCard.setOrganization((String)detail.getDetailValue());
+ else if (detail.getClass().equals(JobTitleDetail.class))
+ vCard.setField("TITLE", (String)detail.getDetailValue());
+ else if (detail.getClass().equals(AboutMeDetail.class))
+ vCard.setField("ABOUTME", (String)detail.getDetailValue());
+ }
+ try
{
- // Push the new avatar photo to the server.
- return this.uploadImageDetail(
- ServerStoredDetailsChangeEvent.DETAIL_REPLACED,
- currentDetailValue,
- newDetailValue);
+ vCard.save(jabberProvider.getConnection());
}
+ catch (XMPPException xmppe)
+ {
+ logger.error("Error loading/saving vcard: ", xmppe);
+ throw new OperationFailedException(
+ "Error loading/saving vcard: ", 1, xmppe);
+ }
+ }
+ /**
+ * Determines whether the underlying implementation supports edition
+ * of this detail class.
+ * <p>
+ * @param detailClass the class whose edition we'd like to determine if it's
+ * possible
+ * @return true if the underlying implementation supports edition of this
+ * type of detail and false otherwise.
+ */
+ public boolean isDetailClassEditable(
+ Class<? extends GenericDetail> detailClass)
+ {
+ if (isDetailClassSupported(detailClass)) {
+ return true;
+ }
return false;
}
/**
- * Utility method throwing an exception if the icq stack is not properly
+ * Utility method throwing an exception if the jabber stack is not properly
* initialized.
- * @throws java.lang.IllegalStateException if the underlying ICQ stack is
+ * @throws java.lang.IllegalStateException if the underlying jabber stack is
* not registered and initialized.
*/
private void assertConnected() throws IllegalStateException
@@ -333,73 +439,4 @@ public class OperationSetServerStoredAccountInfoJabberImpl
"The jabber provider must be signed on before "
+"being able to communicate.");
}
-
- /**
- * Uploads the new avatar image to the server via the vCard mechanism
- * (XEP-0153).
- *
- * @param changeEventID the int ID of the event to dispatch
- * @param currentDetailValue the detail value we'd like to replace.
- * @param newDetailValue the value of the detail that we'd like to replace
- * currentDetailValue with. If ((ImageDetail) newDetailValue).getBytes() is
- * null, then this function removes the current avatar from the server by
- * sending a vCard with a "photo" tag without any content.
- *
- * @return "true" if the new avatar image has been uploaded (even if the
- * current avatar image is removed). "false" if an XMPPException occurs.
- */
- private boolean uploadImageDetail(
- int changeEventID,
- ServerStoredDetails.GenericDetail currentDetailValue,
- ServerStoredDetails.GenericDetail newDetailValue)
- {
- boolean isPhotoChanged = false;
-
- try
- {
- byte[] newAvatar = ((ImageDetail) newDetailValue).getBytes();
-
- VCardXEP0153 v1 = new VCardXEP0153();
- // Retrieve the old vCard.
- v1.load(jabberProvider.getConnection());
- // Checks if the new avatar photo is diferent form the server one.
- // If yes, then upload the new avatar photo.
- if(!Arrays.equals(v1.getAvatar(), newAvatar))
- {
- if(newAvatar == null)
- {
- v1.setAvatar(new byte[0]);
- }
- else
- {
- v1.setAvatar(newAvatar);
- }
- // Saves the new vCard.
- v1.save(jabberProvider.getConnection());
- }
-
- // Sets the new avatar photo advertised in all presence messages,
- // and send one presence messge immediately.
- ((OperationSetPersistentPresenceJabberImpl)
- this.jabberProvider.getOperationSet(
- OperationSetPersistentPresence.class))
- .updateAccountPhotoPresenceExtension(newAvatar);
-
- // Advertises all detail change listeners, that the server stored
- // details have changed.
- fireServerStoredDetailsChangeEvent(
- jabberProvider,
- changeEventID,
- currentDetailValue,
- newDetailValue);
-
- isPhotoChanged = true;
- }
- catch (XMPPException xmppe)
- {
- logger.error("Error loading/saving vcard: ", xmppe);
- }
-
- return isPhotoChanged;
- }
-}
+} \ No newline at end of file
diff --git a/src/net/java/sip/communicator/impl/protocol/msn/OperationSetServerStoredAccountInfoMsnImpl.java b/src/net/java/sip/communicator/impl/protocol/msn/OperationSetServerStoredAccountInfoMsnImpl.java
index 81aa89a..fb43723 100644
--- a/src/net/java/sip/communicator/impl/protocol/msn/OperationSetServerStoredAccountInfoMsnImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/msn/OperationSetServerStoredAccountInfoMsnImpl.java
@@ -268,6 +268,23 @@ public class OperationSetServerStoredAccountInfoMsnImpl
}
/**
+ * Determines whether the underlying implementation supports edition
+ * of this detail class.
+ * <p>
+ * @param detailClass the class whose edition we'd like to determine if it's
+ * possible
+ * @return true if the underlying implementation supports edition of this
+ * type of detail and false otherwise.
+ */
+ public boolean isDetailClassEditable(
+ Class<? extends GenericDetail> detailClass)
+ {
+ return
+ isDetailClassSupported(detailClass)
+ && ImageDetail.class.isAssignableFrom(detailClass);
+ }
+
+ /**
* The method returns the number of instances supported for a particular
* detail type. Some protocols offer storing multiple values for a
* particular detail type. Spoken languages are a good example.
@@ -518,6 +535,18 @@ public class OperationSetServerStoredAccountInfoMsnImpl
return false;
}
+ /*
+ * (non-Javadoc)
+ * @see net.java.sip.communicator.service.protocol.OperationSetServerStoredAccountInfo#save()
+ * This method is currently unimplemented.
+ * The idea behind this method is for users to call it only once, meaning
+ * that all ServerStoredDetails previously modified by addDetail/removeDetail
+ * and/or replaceDetail will be saved online on the server in one step.
+ * Currently, addDetail/removeDetail/replaceDetail methods are doing the
+ * actual saving but in the future the saving part must be carried here.
+ */
+ public void save() throws OperationFailedException {}
+
/**
* Utility method throwing an exception if the icq stack is not properly
* initialized.
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetServerStoredAccountInfoSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetServerStoredAccountInfoSipImpl.java
index 4ad22a7..6b528ae 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetServerStoredAccountInfoSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetServerStoredAccountInfoSipImpl.java
@@ -195,6 +195,23 @@ public class OperationSetServerStoredAccountInfoSipImpl
}
/**
+ * Determines whether the underlying implementation supports the edition
+ * of this detail class.
+ * <p>
+ * @param detailClass the class whose edition we'd like to determine if it's
+ * possible
+ * @return true if the underlying implementation supports edition of this
+ * type of detail and false otherwise.
+ */
+ public boolean isDetailClassEditable(
+ Class<? extends GenericDetail> detailClass)
+ {
+ return
+ isDetailClassSupported(detailClass)
+ && ImageDetail.class.isAssignableFrom(detailClass);
+ }
+
+ /**
* The method returns the number of instances supported for a particular
* detail type.
*
@@ -411,6 +428,18 @@ public class OperationSetServerStoredAccountInfoSipImpl
return true;
}
+ /*
+ * (non-Javadoc)
+ * @see net.java.sip.communicator.service.protocol.OperationSetServerStoredAccountInfo#save()
+ * This method is currently unimplemented.
+ * The idea behind this method is for users to call it only once, meaning
+ * that all ServerStoredDetails previously modified by addDetail/removeDetail
+ * and/or replaceDetail will be saved online on the server in one step.
+ * Currently, addDetail/removeDetail/replaceDetail methods are doing the
+ * actual saving but in the future the saving part must be carried here.
+ */
+ public void save() throws OperationFailedException {}
+
/**
* Determines if image details is supported.
*
diff --git a/src/net/java/sip/communicator/plugin/accountinfo/AccountDetailsPanel.java b/src/net/java/sip/communicator/plugin/accountinfo/AccountDetailsPanel.java
index 7ddf425..fa96f03 100644
--- a/src/net/java/sip/communicator/plugin/accountinfo/AccountDetailsPanel.java
+++ b/src/net/java/sip/communicator/plugin/accountinfo/AccountDetailsPanel.java
@@ -7,75 +7,150 @@ package net.java.sip.communicator.plugin.accountinfo;
import java.awt.*;
import java.awt.event.*;
-import java.io.*;
-import java.text.*;
+import java.beans.*;
+import java.net.*;
import java.util.*;
-import javax.imageio.*;
import javax.swing.*;
+import javax.swing.text.*;
+
+import org.jitsi.util.*;
import net.java.sip.communicator.plugin.desktoputil.*;
+import net.java.sip.communicator.plugin.desktoputil.presence.avatar.*;
+import net.java.sip.communicator.service.globaldisplaydetails.*;
import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.ServerStoredDetails.BinaryDetail;
+import net.java.sip.communicator.service.protocol.ServerStoredDetails.AboutMeDetail;
+import net.java.sip.communicator.service.protocol.ServerStoredDetails.AddressDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.BirthDateDetail;
+import net.java.sip.communicator.service.protocol.ServerStoredDetails.CityDetail;
+import net.java.sip.communicator.service.protocol.ServerStoredDetails.CountryDetail;
+import net.java.sip.communicator.service.protocol.ServerStoredDetails.DisplayNameDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.EmailAddressDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.FirstNameDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.GenderDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.GenericDetail;
+import net.java.sip.communicator.service.protocol.ServerStoredDetails.ImageDetail;
+import net.java.sip.communicator.service.protocol.ServerStoredDetails.JobTitleDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.LastNameDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.MiddleNameDetail;
+import net.java.sip.communicator.service.protocol.ServerStoredDetails.NicknameDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.PhoneNumberDetail;
-import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.skin.*;
+import net.java.sip.communicator.service.protocol.ServerStoredDetails.PostalCodeDetail;
+import net.java.sip.communicator.service.protocol.ServerStoredDetails.ProvinceDetail;
+import net.java.sip.communicator.service.protocol.ServerStoredDetails.URLDetail;
+import net.java.sip.communicator.service.protocol.ServerStoredDetails.WorkEmailAddressDetail;
+import net.java.sip.communicator.service.protocol.ServerStoredDetails.WorkOrganizationNameDetail;
+import net.java.sip.communicator.service.protocol.ServerStoredDetails.WorkPhoneDetail;
+
+import net.java.sip.communicator.util.Logger;
+
+import com.toedter.calendar.*;
/**
- * The right side panel of AccountDetailsDialog. Shows one tab of a summary of
- * contact information for the selected subcontact, and has an extended tab
- * listing all of the details.
+ * The main panel that allows users to view and edit their account information.
+ * Different instances of this class are created for every registered
+ * <tt>ProtocolProviderService</tt>.
+ * Currently, supported account details are first/middle/last names, nickname,
+ * street/city/region/country address, postal code, birth date, gender,
+ * organization name, job title, about me, home/work email, home/work phone.
*
* @author Yana Stamcheva
* @author Adam Netocny
+ * @author Marin Dzhigarov
*/
public class AccountDetailsPanel
extends TransparentPanel
- implements Skinnable
{
- private static final long serialVersionUID = 5524135388175045624L;
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 1L;
+ /**
+ * The logger
+ */
private Logger logger = Logger.getLogger(AccountDetailsPanel.class);
/**
+ * Mapping between all supported by this plugin <tt>ServerStoredDetails</tt>
+ * and their respective <tt>JTextField</tt> that are used for modifying
+ * the details.
+ */
+ private final Map<Class<? extends GenericDetail>, JTextField>
+ detailToTextField
+ = new HashMap<Class<? extends GenericDetail>, JTextField>();
+
+ /**
+ * The <tt>ProtocolProviderService</tt> that this panel is associated with.
+ */
+ ProtocolProviderService protocolProvider;
+
+ /**
* The operation set giving access to the server stored account details.
*/
private OperationSetServerStoredAccountInfo accountInfoOpSet;
- private JTextField firstNameField = new JTextField();
+ private JTextField displayNameField;
+
+ private JTextField firstNameField;
+
+ private JTextField middleNameField;
+
+ private JTextField lastNameField;
+
+ private JTextField nicknameField;
+
+ private JTextField urlField;
+
+ private JTextField streetAddressField;
+
+ private JTextField cityField;
- private JTextField middleNameField = new JTextField();
+ private JTextField regionField;
- private JTextField lastNameField = new JTextField();
+ private JTextField postalCodeField;
- private JTextField genderField = new JTextField();
+ private JTextField countryField;
- private JTextField ageField = new JTextField();
+ private JTextField phoneField;
- private JTextField birthdayField = new JTextField();
+ private JTextField workPhoneField;
- private JTextField emailField = new JTextField();
+ private JTextField emailField;
- private JTextField phoneField = new JTextField();
+ private JTextField workEmailField;
- private JLabel avatarLabel = new JLabel();
+ private JTextField organizationField;
+ private JTextField jobTitleField;
+
+ private JTextArea aboutMeArea;
+
+ private JTextField genderField;
+
+ private JTextField ageField;
+
+ private JDateChooser birthDayCalendar;
+
+ private JRadioButton globalIcon;
+
+ private JRadioButton localIcon;
+
+ private FramedImageWithMenu imageWithMenu;
+ /**
+ * The "apply" button.
+ */
private JButton applyButton
= new JButton(Resources.getString("service.gui.APPLY"));
+ /**
+ * The panel containing all buttons.
+ */
private JPanel buttonPanel =
new TransparentPanel(new FlowLayout(FlowLayout.CENTER));
- private JScrollPane mainScrollPane = new JScrollPane();
-
- private boolean isDataLoaded = false;
+ private DisplayNameDetail displayNameDetail;
private FirstNameDetail firstNameDetail;
@@ -83,24 +158,47 @@ public class AccountDetailsPanel
private LastNameDetail lastNameDetail;
- private GenderDetail genderDetail;
+ private NicknameDetail nicknameDetail;
- private BirthDateDetail birthDateDetail;
+ private URLDetail urlDetail;
- private EmailAddressDetail emailDetail;
+ private AddressDetail streetAddressDetail;
+
+ private CityDetail cityDetail;
+
+ private ProvinceDetail regionDetail;
+
+ private PostalCodeDetail postalCodeDetail;
+
+ private CountryDetail countryDetail;
private PhoneNumberDetail phoneDetail;
+
+ private WorkPhoneDetail workPhoneDetail;
+
+ private EmailAddressDetail emailDetail;
+
+ private WorkEmailAddressDetail workEmailDetail;
+
+ private WorkOrganizationNameDetail organizationDetail;
+
+ private JobTitleDetail jobTitleDetail;
+
+ private AboutMeDetail aboutMeDetail;
- private BinaryDetail avatarDetail;
+ private GenderDetail genderDetail;
- private byte[] newAvatarImage;
+ private BirthDateDetail birthDateDetail;
- private ImageIcon avatarImageIcon = null;
+ private ImageDetail avatarDetail;
/**
- * The last avatar file directory open.
+ * The panel that contains description labels and text fields
+ * for every account detail.
*/
- private File lastAvatarDir;
+ private JPanel valuesPanel;
+
+ private JScrollPane mainScrollPane;
/**
* Construct a panel containing all account details for the given protocol
@@ -110,10 +208,11 @@ public class AccountDetailsPanel
*/
public AccountDetailsPanel(ProtocolProviderService protocolProvider)
{
- super(new BorderLayout());
-
+ setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+ setOpaque(false);
+ this.setPreferredSize(new Dimension(600, 400));
+ this.protocolProvider = protocolProvider;
this.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
-// this.setPreferredSize(new Dimension(500, 400));
accountInfoOpSet
= protocolProvider
@@ -134,550 +233,931 @@ public class AccountDetailsPanel
}
}
+ /**
+ * Creates the panel that indicates to the user that the currently selected
+ * contact does not support server stored contact info.
+ */
+ private void initUnsupportedPanel()
+ {
+ JTextArea unsupportedTextArea =
+ new JTextArea(Resources.getString(
+ "plugin.accountinfo.NOT_SUPPORTED"));
+
+ unsupportedTextArea.setEditable(false);
+ unsupportedTextArea.setOpaque(false);
+
+ JPanel unsupportedPanel
+ = new TransparentPanel();
+
+ unsupportedPanel.setBorder(
+ BorderFactory.createEmptyBorder(50, 20, 50, 20));
+
+ unsupportedPanel.add(unsupportedTextArea);
+
+ this.add(unsupportedPanel, BorderLayout.NORTH);
+ }
+
+ /**
+ * Initialized the main panel that contains all <tt>ServerStoredDetails</tt>
+ */
private void initSummaryPanel()
{
JPanel summaryPanel = new TransparentPanel(new BorderLayout(10, 10));
summaryPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
- summaryPanel.setSize(this.getWidth(), this.getHeight());
// Create the avatar panel.
JPanel leftPanel = new TransparentPanel(new BorderLayout());
JPanel avatarPanel = new TransparentPanel(new BorderLayout());
- JButton changeAvatarButton = new JButton(Resources.getString("plugin.accountinfo.CHANGE"));
- JPanel changeButtonPanel
- = new TransparentPanel(new FlowLayout(FlowLayout.CENTER));
-
- changeAvatarButton.addActionListener(new ChangeAvatarActionListener());
- changeButtonPanel.add(changeAvatarButton);
-
- avatarPanel.add(avatarLabel, BorderLayout.CENTER);
- avatarPanel.add(changeButtonPanel, BorderLayout.SOUTH);
+ JPanel radioButtonPanel = new TransparentPanel(new GridLayout(2, 1));
+ globalIcon =
+ new JRadioButton(
+ Resources.getString("plugin.accountinfo.GLOBAL_ICON"));
+ globalIcon.setSelected(true);
+ globalIcon.setOpaque(false);
+ globalIcon.setEnabled(false);
+ localIcon =
+ new JRadioButton(
+ Resources.getString("plugin.accountinfo.LOCAL_ICON"));
+ localIcon.setOpaque(false);
+ localIcon.setEnabled(false);
+ ButtonGroup group = new ButtonGroup();
+ group.add(globalIcon);
+ group.add(localIcon);
+ radioButtonPanel.add(globalIcon);
+ radioButtonPanel.add(localIcon);
+ avatarPanel.add(radioButtonPanel, BorderLayout.NORTH);
leftPanel.add(avatarPanel, BorderLayout.NORTH);
-
summaryPanel.add(leftPanel, BorderLayout.WEST);
+ detailToTextField.put(ImageDetail.class, new JTextField());
+
+ imageWithMenu
+ = new FramedImageWithMenu(
+ Resources.getImage(
+ "service.gui.DEFAULT_USER_PHOTO"),
+ Resources.getImage(
+ "service.gui.DEFAULT_USER_PHOTO").getIconWidth(),
+ Resources.getImage(
+ "service.gui.DEFAULT_USER_PHOTO").getIconHeight());
+ SelectAvatarMenu selectAvatarMenu = new SelectAvatarMenu(imageWithMenu);
+ selectAvatarMenu.setAccountID(protocolProvider.getAccountID());
+ imageWithMenu.setPopupMenu(selectAvatarMenu);
+ avatarPanel.add(imageWithMenu, BorderLayout.SOUTH);
+
+ globalIcon.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ imageWithMenu.setEnabled(false);
+ }
+ });
+ localIcon.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ imageWithMenu.setEnabled(true);
+ }
+ });
+ imageWithMenu.setEnabled(false);
+
+ valuesPanel = new TransparentPanel(new GridBagLayout());
+ valuesPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+
+ GridBagConstraints first = new GridBagConstraints();
+ first.gridx = 0;
+ first.gridy = 0;
+ first.weightx = 0;
+ first.anchor = GridBagConstraints.LINE_START;
+ first.gridwidth = 1;
+ first.insets = new Insets(4, 4, 4, 4);
+ first.fill = GridBagConstraints.HORIZONTAL;
+ GridBagConstraints second = new GridBagConstraints();
+ second.gridx = 1;
+ second.gridy = 0;
+ second.weightx = 2;
+ second.anchor = GridBagConstraints.LINE_START;
+ second.gridwidth = 1; // GridBagConstraints.REMAINDER;
+ second.insets = first.insets;
+ second.fill = GridBagConstraints.HORIZONTAL;
+
+ if (accountInfoOpSet.isDetailClassSupported(DisplayNameDetail.class))
+ {
+ displayNameField = new JTextField();
+ valuesPanel.add(new JLabel(
+ Resources.getString("plugin.accountinfo.DISPLAY_NAME"))
+ , first);
+ valuesPanel.add(displayNameField, second);
+ first.gridy = ++second.gridy;
+ detailToTextField.put(DisplayNameDetail.class, displayNameField);
+ }
- // Create the summary details panel.
- JPanel detailsPanel = new TransparentPanel(new BorderLayout(10, 10));
- detailsPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+ firstNameField = new JTextField();
+ valuesPanel.add(new JLabel(
+ Resources.getString("plugin.accountinfo.FIRST_NAME"))
+ , first);
+ valuesPanel.add(firstNameField, second);
+ first.gridy = ++second.gridy;
+ detailToTextField.put(FirstNameDetail.class, firstNameField);
+
+ middleNameField = new JTextField();
+ valuesPanel.add(new JLabel(
+ Resources.getString("plugin.accountinfo.MIDDLE_NAME"))
+ , first);
+ valuesPanel.add(middleNameField, second);
+ first.gridy = ++second.gridy;
+ detailToTextField.put(MiddleNameDetail.class, middleNameField);
+
+ lastNameField = new JTextField();
+ valuesPanel.add(new JLabel(
+ Resources.getString("plugin.accountinfo.LAST_NAME"))
+ , first);
+ valuesPanel.add(lastNameField, second);
+ first.gridy = ++second.gridy;
+ detailToTextField.put(LastNameDetail.class, lastNameField);
+
+ if (accountInfoOpSet.isDetailClassSupported(NicknameDetail.class))
+ {
+ nicknameField = new JTextField();
+ valuesPanel.add(new JLabel(
+ Resources.getString("plugin.accountinfo.NICKNAME"))
+ , first);
+ valuesPanel.add(nicknameField, second);
+ first.gridy = ++second.gridy;
+ detailToTextField.put(NicknameDetail.class, nicknameField);
+ }
+ if (accountInfoOpSet.isDetailClassSupported(URLDetail.class))
+ {
+ urlField = new JTextField();
+ valuesPanel.add(new JLabel(
+ Resources.getString("plugin.accountinfo.URL"))
+ , first);
+ valuesPanel.add(urlField, second);
+ first.gridy = ++second.gridy;
+ detailToTextField.put(URLDetail.class, urlField);
+ }
+ if (accountInfoOpSet.isDetailClassSupported(GenderDetail.class))
+ {
+ genderField = new JTextField();
+ valuesPanel.add(new JLabel(
+ Resources.getString("plugin.accountinfo.GENDER"))
+ , first);
+ valuesPanel.add(genderField, second);
+ first.gridy = ++second.gridy;
+ detailToTextField.put(GenderDetail.class, genderField);
+ }
- summaryPanel.add(detailsPanel, BorderLayout.CENTER);
+ birthDayCalendar = new JDateChooser();
+ valuesPanel.add(new JLabel(
+ Resources.getString("plugin.accountinfo.BDAY"))
+ , first);
+ valuesPanel.add(birthDayCalendar, second);
+ birthDayCalendar.setDateFormatString(
+ Resources.getString("plugin.accountinfo.BDAY_FORMAT"));
+ birthDayCalendar.addPropertyChangeListener(
+ new PropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent evt)
+ {
+ if (evt.getPropertyName().equals("date"))
+ {
+ Date date = (Date) evt.getNewValue();
+ if (date != null)
+ {
+ Calendar currentDate = Calendar.getInstance();
+ Calendar c = Calendar.getInstance();
+ c.setTime(date);
+ int age =
+ currentDate.get(Calendar.YEAR) -
+ c.get(Calendar.YEAR);
+
+ if (currentDate.get(Calendar.MONTH) <
+ c.get(Calendar.MONTH))
+ age--;
+ if ((currentDate.get(Calendar.MONTH) ==
+ c.get(Calendar.MONTH))
+ &&
+ (currentDate.get(Calendar.DAY_OF_MONTH) <
+ c.get(Calendar.DAY_OF_MONTH)))
+ age--;
+ String ageDetail = Integer.toString(age).trim();
+ ageField.setText(ageDetail);
+ }
+ }
+ }
+ });
+ first.gridy = ++second.gridy;
+ ageField = new JTextField();
+ valuesPanel.add(new JLabel(
+ Resources.getString("plugin.accountinfo.AGE")), first);
+ valuesPanel.add(ageField, second);
+ first.gridy = ++second.gridy;
+ ageField.setEditable(false);
+ detailToTextField.put(BirthDateDetail.class, new JTextField());
+
+ if (accountInfoOpSet.isDetailClassSupported(AddressDetail.class))
+ {
+ streetAddressField = new JTextField();
+ valuesPanel.add(new JLabel(
+ Resources.getString("plugin.accountinfo.STREET"))
+ , first);
+ valuesPanel.add(streetAddressField, second);
+ first.gridy = ++second.gridy;
+ detailToTextField.put(AddressDetail.class, streetAddressField);
+ }
+ if (accountInfoOpSet.isDetailClassSupported(CityDetail.class))
+ {
+ cityField = new JTextField();
+ valuesPanel.add(new JLabel(
+ Resources.getString("plugin.accountinfo.CITY")), first);
+ valuesPanel.add(cityField, second);
+ first.gridy = ++second.gridy;
+ detailToTextField.put(CityDetail.class, cityField);
+ }
+ if (accountInfoOpSet.isDetailClassSupported(ProvinceDetail.class))
+ {
+ regionField = new JTextField();
+ valuesPanel.add(new JLabel(
+ Resources.getString("plugin.accountinfo.REGION"))
+ , first);
+ valuesPanel.add(regionField, second);
+ first.gridy = ++second.gridy;
+ detailToTextField.put(ProvinceDetail.class, regionField);
+ }
+ if (accountInfoOpSet.isDetailClassSupported(PostalCodeDetail.class))
+ {
+ postalCodeField = new JTextField();
+ valuesPanel.add(new JLabel(
+ Resources.getString("plugin.accountinfo.POST"))
+ , first);
+ valuesPanel.add(postalCodeField, second);
+ first.gridy = ++second.gridy;
+ detailToTextField.put(PostalCodeDetail.class, postalCodeField);
+ }
+ if (accountInfoOpSet.isDetailClassSupported(CountryDetail.class))
+ {
+ countryField = new JTextField();
+ valuesPanel.add(new JLabel(
+ Resources.getString("plugin.accountinfo.COUNTRY"))
+ , first);
+ valuesPanel.add(countryField, second);
+ first.gridy = ++second.gridy;
+ detailToTextField.put(CountryDetail.class, countryField);
+ }
- // Labels panel.
- JPanel labelsPanel = new TransparentPanel(new GridLayout(0, 1, 5, 5));
+ emailField = new JTextField();
+ valuesPanel.add(new JLabel(
+ Resources.getString("plugin.accountinfo.EMAIL"))
+ , first);
+ valuesPanel.add(emailField, second);
+ first.gridy = ++second.gridy;
+ detailToTextField.put(EmailAddressDetail.class, emailField);
- labelsPanel.add(new JLabel(
- Resources.getString("plugin.accountinfo.FIRST_NAME")));
-// labelsPanel.add(new JLabel(Resources.getString("plugin.accountinfo.MIDDLE_NAME")));
- labelsPanel.add(new JLabel(
- Resources.getString("plugin.accountinfo.LAST_NAME")));
- labelsPanel.add(new JLabel(
- Resources.getString("plugin.accountinfo.GENDER")));
- labelsPanel.add(new JLabel(
- Resources.getString("plugin.accountinfo.AGE")));
- labelsPanel.add(new JLabel(
- Resources.getString("plugin.accountinfo.BDAY")));
- labelsPanel.add(new JLabel(
- Resources.getString("plugin.accountinfo.EMAIL")));
- labelsPanel.add(new JLabel(
- Resources.getString("plugin.accountinfo.PHONE")));
+ if (accountInfoOpSet.isDetailClassSupported(
+ WorkEmailAddressDetail.class))
+ {
+ workEmailField = new JTextField();
+ valuesPanel.add(new JLabel(
+ Resources.getString("plugin.accountinfo.WORK_EMAIL"))
+ , first);
+ valuesPanel.add(workEmailField, second);
+ first.gridy = ++second.gridy;
+ detailToTextField.put(WorkEmailAddressDetail.class, workEmailField);
+ }
- detailsPanel.add(labelsPanel, BorderLayout.WEST);
+ phoneField = new JTextField();
+ valuesPanel.add(new JLabel(
+ Resources.getString("plugin.accountinfo.PHONE"))
+ , first);
+ valuesPanel.add(phoneField, second);
+ first.gridy = ++second.gridy;
+ detailToTextField.put(PhoneNumberDetail.class, phoneField);
- // Values panel.
- JPanel valuesPanel = new TransparentPanel(new GridLayout(0, 1, 5, 5));
+ if (accountInfoOpSet.isDetailClassSupported(WorkPhoneDetail.class))
+ {
+ workPhoneField = new JTextField();
+ valuesPanel.add(new JLabel(
+ Resources.getString("plugin.accountinfo.WORK_PHONE"))
+ , first);
+ valuesPanel.add(workPhoneField, second);
+ first.gridy = ++second.gridy;
+ detailToTextField.put(
+ WorkPhoneDetail.class, workPhoneField);
+ }
+ if (accountInfoOpSet.isDetailClassSupported(
+ WorkOrganizationNameDetail.class))
+ {
+ organizationField = new JTextField();
+ valuesPanel.add(new JLabel(
+ Resources.getString("plugin.accountinfo.ORGANIZATION"))
+ , first);
+ valuesPanel.add(organizationField, second);
+ first.gridy = ++second.gridy;
+ detailToTextField.put(
+ WorkOrganizationNameDetail.class, organizationField);
+ }
+ if (accountInfoOpSet.isDetailClassSupported(JobTitleDetail.class))
+ {
+ jobTitleField = new JTextField();
+ valuesPanel.add(new JLabel(
+ Resources.getString("plugin.accountinfo.JOB_TITLE"))
+ , first);
+ valuesPanel.add(jobTitleField, second);
+ first.gridy = ++second.gridy;
+ detailToTextField.put(
+ JobTitleDetail.class, jobTitleField);
+ }
+ if (accountInfoOpSet.isDetailClassSupported(AboutMeDetail.class))
+ {
+ aboutMeArea = new JTextArea(3, 0);
+ valuesPanel.add(new JLabel(
+ Resources.getString("plugin.accountinfo.ABOUT_ME"))
+ , first);
+ second.gridheight = 3;
+ JScrollPane areaScrollPane = new JScrollPane(aboutMeArea);
+ areaScrollPane.setOpaque(false);
+ areaScrollPane.setBorder(BorderFactory.createEmptyBorder());
+ areaScrollPane.setVerticalScrollBarPolicy(
+ JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+ valuesPanel.add(areaScrollPane, second);
+ first.gridy = ++second.gridy;
+
+ DefaultStyledDocument doc = new DefaultStyledDocument();
+ doc.setDocumentFilter(new DocumentFilter() {
+
+ private final int MAX_CHARACTERS =
+ Integer.valueOf(Resources.getString(
+ "plugin.accountinfo.ABOUT_ME_MAX_CHARACTERS"));
+
+ public void insertString(FilterBypass fb, int offs,
+ String str, AttributeSet a)
+ throws BadLocationException {
+ //This rejects the entire insertion if it would make
+ //the contents too long. Another option would be
+ //to truncate the inserted string so the contents
+ //would be exactly maxCharacters in length.
+ if ((fb.getDocument().getLength() + str.length())
+ <= MAX_CHARACTERS)
+ super.insertString(fb, offs, str, a);
+ else
+ Toolkit.getDefaultToolkit().beep();
+ }
- valuesPanel.add(firstNameField);
-// valuesPanel.add(middleNameField);
- valuesPanel.add(lastNameField);
- valuesPanel.add(genderField);
- valuesPanel.add(ageField);
- valuesPanel.add(birthdayField);
- valuesPanel.add(emailField);
- valuesPanel.add(phoneField);
+ public void replace(FilterBypass fb, int offs,
+ int length,
+ String str, AttributeSet a)
+ throws BadLocationException {
+ //This rejects the entire replacement if it would make
+ //the contents too long. Another option would be
+ //to truncate the replacement string so the contents
+ //would be exactly maxCharacters in length.
+ if ((fb.getDocument().getLength() + str.length()
+ - length) <= MAX_CHARACTERS)
+ super.replace(fb, offs, length, str, a);
+ else
+ Toolkit.getDefaultToolkit().beep();
+ }
+ });
+
+ aboutMeArea.setDocument(doc);
+ aboutMeArea.setBorder(firstNameField.getBorder());
+ aboutMeArea.setLineWrap(true);
+ aboutMeArea.setWrapStyleWord(true);
+ aboutMeArea.setPreferredSize(new Dimension(50, 100));
+ aboutMeArea.setMinimumSize(new Dimension(50, 100));
+ detailToTextField.put(AboutMeDetail.class, new JTextField());
+ }
- detailsPanel.add(valuesPanel, BorderLayout.CENTER);
+ mainScrollPane = new JScrollPane(summaryPanel,
+ JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+ JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+ mainScrollPane.getViewport().setOpaque(false);
+ mainScrollPane.setOpaque(false);
+ mainScrollPane.setBorder(BorderFactory.createEmptyBorder());
- this.mainScrollPane.getViewport().add(summaryPanel);
+ summaryPanel.add(valuesPanel, BorderLayout.CENTER);
- this.add(mainScrollPane, BorderLayout.NORTH);
+ this.add(mainScrollPane);
this.applyButton.addActionListener(new SubmitActionListener());
+ JButton cancelButton =
+ new JButton(Resources.getString("service.gui.CANCEL"));
+ cancelButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent evt)
+ {
+ AccountInfoMenuItemComponent.dialog.setVisible(false);
+ mainScrollPane.getVerticalScrollBar().setValue(0);
+ }
+ });
this.buttonPanel.add(applyButton);
+ this.buttonPanel.add(cancelButton);
- this.add(buttonPanel, BorderLayout.SOUTH);
+ this.add(buttonPanel);
- // All items are now instantiated and could safely load the skin.
- loadSkin();
+ for (Component component : valuesPanel.getComponents())
+ component.setEnabled(false);
+ if (aboutMeArea != null)
+ aboutMeArea.setEnabled(false);
+ applyButton.setEnabled(false);
}
/**
- * Loads details for
+ * Loads all <tt>ServerStoredDetails</tt> which are currently supported by
+ * this plugin. Note that some <tt>OperationSetServerStoredAccountInfo</tt>
+ * implementations may support details that are not supported by this plugin.
+ * In this case they will not be loaded.
*/
public void loadDetails()
{
- this.loadSummaryDetails();
- this.isDataLoaded = true;
+ if (accountInfoOpSet != null)
+ {
+ Iterator<GenericDetail> allDetails =
+ accountInfoOpSet.getAllAvailableDetails();
+
+ while (allDetails.hasNext())
+ {
+ GenericDetail detail = allDetails.next();
+ loadDetail(detail);
+ }
+
+ boolean isAnyDetailEditable = false;
+ for (Class<? extends GenericDetail> editable :
+ detailToTextField.keySet())
+ {
+ if (accountInfoOpSet.isDetailClassEditable(editable))
+ {
+ isAnyDetailEditable = true;
+ if (editable.equals(AboutMeDetail.class))
+ aboutMeArea.setEnabled(true);
+ else if (editable.equals(BirthDateDetail.class))
+ birthDayCalendar.setEnabled(true);
+ else if (editable.equals(ImageDetail.class))
+ {
+ globalIcon.setEnabled(true);
+ localIcon.setEnabled(true);
+ imageWithMenu.setEnabled(true);
+ }
+ else
+ {
+ JTextField field = detailToTextField.get(editable);
+ field.setEnabled(true);
+ }
+ }
+ }
+ if (isAnyDetailEditable)
+ applyButton.setEnabled(true);
+ }
}
/**
- * Creates the panel that indicates to the user that the currently selected
- * contact does not support server stored contact info.
+ * Loads a single <tt>GenericDetail</tt> obtained from the
+ * <tt>OperationSetServerStoredAccountInfo</tt> into this plugin.
+ * @param detail to be loaded.
*/
- private void initUnsupportedPanel()
+ private void loadDetail(GenericDetail detail)
{
- JTextArea unsupportedTextArea =
- new JTextArea(Resources.getString(
- "plugin.accountinfo.NOT_SUPPORTED"));
-
- unsupportedTextArea.setEditable(false);
- unsupportedTextArea.setLineWrap(true);
-
- JPanel unsupportedPanel
- = new TransparentPanel(new FlowLayout(FlowLayout.CENTER));
-
- unsupportedTextArea.setPreferredSize(new Dimension(200, 200));
+ if (detail.getClass().equals(AboutMeDetail.class))
+ {
+ aboutMeDetail = (AboutMeDetail) detail;
+ aboutMeArea.setText((String) detail.getDetailValue());
+ return;
+ }
+ if (detail instanceof BirthDateDetail)
+ {
+ birthDateDetail = (BirthDateDetail) detail;
- unsupportedPanel.setBorder(
- BorderFactory.createEmptyBorder(50, 20, 50, 20));
+ Calendar calendarDetail =
+ (Calendar) birthDateDetail.getDetailValue();
- unsupportedPanel.add(unsupportedTextArea);
+ birthDayCalendar.setCalendar(calendarDetail);
+ return;
+ }
- this.add(unsupportedPanel);
+ JTextField field = detailToTextField.get(detail.getClass());
+ if (field != null)
+ {
+ if (detail instanceof ImageDetail)
+ {
+ localIcon.setSelected(true);
+ avatarDetail = (ImageDetail) detail;
+ byte[] avatarImage = avatarDetail.getBytes();
+ imageWithMenu.setImageIcon(avatarImage);
+ }
+ else if (detail instanceof URLDetail)
+ {
+ urlDetail = (URLDetail) detail;
+ urlField.setText(urlDetail.getURL().toString());
+ }
+ else
+ {
+ field.setText((String) detail.getDetailValue());
+ if (detail.getClass().equals(DisplayNameDetail.class))
+ displayNameDetail = (DisplayNameDetail) detail;
+ else if (detail.getClass().equals(FirstNameDetail.class))
+ firstNameDetail = (FirstNameDetail) detail;
+ else if (detail.getClass().equals(MiddleNameDetail.class))
+ middleNameDetail = (MiddleNameDetail) detail;
+ else if (detail.getClass().equals(LastNameDetail.class))
+ lastNameDetail = (LastNameDetail) detail;
+ else if (detail.getClass().equals(NicknameDetail.class))
+ nicknameDetail = (NicknameDetail) detail;
+ else if (detail.getClass().equals(URLDetail.class))
+ urlDetail = (URLDetail) detail;
+ else if (detail.getClass().equals(GenderDetail.class))
+ genderDetail = (GenderDetail) detail;
+ else if (detail.getClass().equals(AddressDetail.class))
+ streetAddressDetail = (AddressDetail) detail;
+ else if (detail.getClass().equals(CityDetail.class))
+ cityDetail = (CityDetail) detail;
+ else if (detail.getClass().equals(ProvinceDetail.class))
+ regionDetail = (ProvinceDetail) detail;
+ else if (detail.getClass().equals(PostalCodeDetail.class))
+ postalCodeDetail = (PostalCodeDetail) detail;
+ else if (detail.getClass().equals(CountryDetail.class))
+ countryDetail = (CountryDetail) detail;
+ else if (detail.getClass().equals(PhoneNumberDetail.class))
+ phoneDetail = (PhoneNumberDetail) detail;
+ else if (detail.getClass().equals(WorkPhoneDetail.class))
+ workPhoneDetail = (WorkPhoneDetail) detail;
+ else if (detail.getClass().equals(EmailAddressDetail.class))
+ emailDetail = (EmailAddressDetail) detail;
+ else if (detail.getClass().equals(WorkEmailAddressDetail.class))
+ workEmailDetail = (WorkEmailAddressDetail) detail;
+ else if (detail.getClass().equals(
+ WorkOrganizationNameDetail.class))
+ organizationDetail = (WorkOrganizationNameDetail) detail;
+ else if (detail.getClass().equals(JobTitleDetail.class))
+ jobTitleDetail = (JobTitleDetail) detail;
+ else if (detail.getClass().equals(AboutMeDetail.class))
+ aboutMeDetail = (AboutMeDetail) detail;
+ }
+ }
}
/**
- * Creates a panel that can be added as the summary tab that displays the
- * following details: -
- * <p>
- * Avatar(Contact image) - FirstNameDetail - MiddleNameDetail -
- * LastNameDetail - BirthdateDetail (and calculate age) - GenderDetail -
- * EmailAddressDetail - PhoneNumberDetail. All other details will be* added
- * to our list of extended details.
+ * Attempts to upload all <tt>ServerStoredDetails</tt> on the server using
+ * <tt>OperationSetServerStoredAccountInfo</tt>
+ *
*/
- private void loadSummaryDetails()
+ private class SubmitActionListener implements ActionListener
{
- Iterator<GenericDetail> contactDetails;
-
- // Avatar details.
- contactDetails
- = accountInfoOpSet.getDetails(BinaryDetail.class);
-
- byte[] avatarImage = null;
- if (contactDetails.hasNext())
+ public void actionPerformed(ActionEvent e)
{
- avatarDetail = (BinaryDetail) contactDetails.next();
+ if (accountInfoOpSet.isDetailClassSupported(ImageDetail.class))
+ {
+ if (globalIcon.isSelected())
+ {
+ GlobalDisplayDetailsService serv =
+ AccountInfoActivator.getGlobalDisplayDetailsService();
- avatarImage = avatarDetail.getBytes();
- }
+ byte[] newIcon = serv.getGlobalDisplayAvatar();
- if (avatarImage != null && avatarImage.length > 0)
- {
- avatarImageIcon = new ImageIcon(
- getScaledImageInstance(avatarImage));
- avatarLabel.setIcon(avatarImageIcon);
- }
+ ImageDetail newDetail = null;
+ if (newIcon != null)
+ newDetail =
+ new ImageDetail(
+ "avatar", serv.getGlobalDisplayAvatar());
- // First name details.
- contactDetails =
- accountInfoOpSet.getDetails(FirstNameDetail.class);
+ if (avatarDetail != null || newDetail != null)
+ changeDetail(avatarDetail, newDetail);
+ }
+ }
+ if (accountInfoOpSet.isDetailClassSupported
+ (DisplayNameDetail.class))
+ {
+ String text =
+ detailToTextField.get(DisplayNameDetail.class).getText();
- String firstNameDetailString = "";
- while (contactDetails.hasNext())
- {
- firstNameDetail = (FirstNameDetail) contactDetails.next();
+ DisplayNameDetail newDetail = null;
+ if (!StringUtils.isNullOrEmpty(text, true))
+ newDetail = new DisplayNameDetail(text);
- firstNameDetailString =
- firstNameDetailString + " " + firstNameDetail.getDetailValue();
- }
+ if (displayNameDetail != null || newDetail != null)
+ changeDetail(displayNameDetail, newDetail);
+ }
+ if (accountInfoOpSet.isDetailClassSupported(
+ FirstNameDetail.class))
+ {
+ String text =
+ detailToTextField.get(FirstNameDetail.class).getText();
- firstNameField.setText(firstNameDetailString);
+ FirstNameDetail newDetail = null;
+ if (!StringUtils.isNullOrEmpty(text, true))
+ newDetail = new FirstNameDetail(text);
- // Middle name details.
- contactDetails =
- accountInfoOpSet.getDetails(MiddleNameDetail.class);
+ if (firstNameDetail != null || newDetail != null)
+ changeDetail(firstNameDetail, newDetail);
+ }
+ if (accountInfoOpSet.isDetailClassSupported(
+ MiddleNameDetail.class))
+ {
+ String text =
+ detailToTextField.get(MiddleNameDetail.class).getText();
- String middleNameDetailString = "";
- while (contactDetails.hasNext())
- {
- middleNameDetail = (MiddleNameDetail) contactDetails.next();
- middleNameDetailString =
- middleNameDetailString + " " + middleNameDetail.getDetailValue();
- }
+ MiddleNameDetail newDetail = null;
+ if (!StringUtils.isNullOrEmpty(text, true))
+ newDetail = new MiddleNameDetail(text);
- middleNameField.setText(middleNameDetailString);
+ if (middleNameDetail != null || newDetail != null)
+ changeDetail(middleNameDetail, newDetail);
+ }
+ if (accountInfoOpSet.isDetailClassSupported(
+ LastNameDetail.class))
+ {
+ String text =
+ detailToTextField.get(LastNameDetail.class).getText();
+ LastNameDetail newDetail = null;
- // Last name details.
- contactDetails =
- accountInfoOpSet.getDetails(LastNameDetail.class);
+ if (!StringUtils.isNullOrEmpty(text, true))
+ newDetail = new LastNameDetail(text);
- String lastNameDetailString = "";
- while (contactDetails.hasNext())
- {
- lastNameDetail = (LastNameDetail) contactDetails.next();
+ if (lastNameDetail != null || newDetail != null)
+ changeDetail(lastNameDetail, newDetail);
+ }
+ if (accountInfoOpSet.isDetailClassSupported(NicknameDetail.class))
+ {
+ String text =
+ detailToTextField.get(NicknameDetail.class).getText();
- lastNameDetailString =
- lastNameDetailString + " " + lastNameDetail.getDetailValue();
- }
+ NicknameDetail newDetail = null;
+ if (!StringUtils.isNullOrEmpty(text, true))
+ newDetail = new NicknameDetail(text);
- lastNameField.setText(lastNameDetailString);
+ if (nicknameDetail != null || newDetail != null)
+ changeDetail(nicknameDetail, newDetail);
+ }
- // Gender details.
- contactDetails =
- accountInfoOpSet.getDetails(GenderDetail.class);
+ if (accountInfoOpSet.isDetailClassSupported(URLDetail.class))
+ {
+ String text
+ = detailToTextField.get(URLDetail.class).getText();
- String genderDetailString = "";
- while (contactDetails.hasNext())
- {
- genderDetail = (GenderDetail) contactDetails.next();
- genderDetailString = genderDetailString + " "
- + genderDetail.getDetailValue();
- }
+ URL url = null;
+ if (!StringUtils.isNullOrEmpty(text, true))
+ try
+ {
+ url = new URL(text);
+ }
+ catch (MalformedURLException e1)
+ {
+ logger.debug("Failed to update URL detail due to " +
+ "malformed URL.");
+ }
- genderField.setText(genderDetailString);
+ URLDetail newDetail = null;
- // Birthday details.
- contactDetails =
- accountInfoOpSet.getDetails(BirthDateDetail.class);
+ if (url != null)
+ newDetail = new URLDetail("URL", url);
- String birthDateDetailString = "";
- String ageDetail = "";
- if (contactDetails.hasNext())
- {
- birthDateDetail = (BirthDateDetail) contactDetails.next();
+ if (urlDetail != null || newDetail != null)
+ changeDetail(urlDetail, newDetail);
+ }
- Calendar calendarDetail =
- (Calendar) birthDateDetail.getDetailValue();
+ if (accountInfoOpSet.isDetailClassSupported(
+ GenderDetail.class))
+ {
+ String text =
+ detailToTextField.get(GenderDetail.class).getText();
- Date birthDate = calendarDetail.getTime();
- DateFormat dateFormat = DateFormat.getDateInstance();
+ GenderDetail newDetail = null;
- birthDateDetailString = dateFormat.format(birthDate).trim();
+ if (!StringUtils.isNullOrEmpty(text, true))
+ newDetail = new GenderDetail(text);
- Calendar c = Calendar.getInstance();
- int age = c.get(Calendar.YEAR) - calendarDetail.get(Calendar.YEAR);
+ if (genderDetail != null || newDetail != null)
+ changeDetail(genderDetail, newDetail);
+ }
- if (c.get(Calendar.MONTH) < calendarDetail.get(Calendar.MONTH))
- age--;
+ if (accountInfoOpSet.isDetailClassSupported(
+ BirthDateDetail.class))
+ {
+ BirthDateDetail newDetail = null;
- ageDetail = Integer.toString(age).trim();
- }
+ if (birthDayCalendar.getDate() != null)
+ {
+ newDetail =
+ new BirthDateDetail(birthDayCalendar.getCalendar());
+ }
- birthdayField.setText(birthDateDetailString);
- ageField.setText(ageDetail);
+ if (birthDateDetail != null || newDetail != null)
+ changeDetail(birthDateDetail, newDetail);
+ }
- // Email details.
- contactDetails =
- accountInfoOpSet.getDetails(EmailAddressDetail.class);
+ if (accountInfoOpSet.isDetailClassSupported(
+ AddressDetail.class))
+ {
+ String text =
+ detailToTextField.get(AddressDetail.class).getText();
- String emailDetailString = "";
- while (contactDetails.hasNext())
- {
- emailDetail = (EmailAddressDetail) contactDetails.next();
- emailDetailString = emailDetailString + " "
- + emailDetail.getDetailValue();
- }
+ AddressDetail newDetail = null;
+ if (!StringUtils.isNullOrEmpty(text, true))
+ newDetail = new AddressDetail(text);
- emailField.setText(emailDetailString);
+ if (streetAddressDetail != null || newDetail != null)
+ changeDetail(streetAddressDetail, newDetail);
+ }
- // Phone number details.
- contactDetails =
- accountInfoOpSet.getDetails(PhoneNumberDetail.class);
+ if (accountInfoOpSet.isDetailClassSupported(
+ CityDetail.class))
+ {
+ String text =
+ detailToTextField.get(CityDetail.class).getText();
- String phoneNumberDetailString = "";
- while (contactDetails.hasNext())
- {
- phoneDetail = (PhoneNumberDetail) contactDetails.next();
- phoneNumberDetailString =
- phoneNumberDetailString + " " + phoneDetail.getDetailValue();
- }
+ CityDetail newDetail = null;
+ if (!StringUtils.isNullOrEmpty(text, true))
+ newDetail = new CityDetail(text);
- phoneField.setText(phoneNumberDetailString);
- }
+ if (cityDetail != null || newDetail != null)
+ changeDetail(cityDetail, newDetail);
+ }
- private class SubmitActionListener implements ActionListener
- {
- public void actionPerformed(ActionEvent e)
- {
- String firstName = firstNameField.getText();
-// String middleName = middleNameField.getText();
- String lastName = lastNameField.getText();
- String gender = genderField.getText();
- String email = emailField.getText();
- String phoneNumber = phoneField.getText();
+ if (accountInfoOpSet.isDetailClassSupported(
+ ProvinceDetail.class))
+ {
+ String text =
+ detailToTextField.get(ProvinceDetail.class).getText();
- Calendar birthDateCalendar = Calendar.getInstance();
+ ProvinceDetail newDetail = null;
+ if (!StringUtils.isNullOrEmpty(text, true))
+ newDetail = new ProvinceDetail(text);
- if(birthdayField.getText() != null
- && birthdayField.getText().length() > 0)
+ if (regionDetail != null || newDetail != null)
+ changeDetail(regionDetail, newDetail);
+ }
+
+ if (accountInfoOpSet.isDetailClassSupported(
+ PostalCodeDetail.class))
{
- try
- {
- DateFormat dateFormat
- = DateFormat.getDateInstance(DateFormat.DEFAULT);
+ String text =
+ detailToTextField.get(PostalCodeDetail.class).getText();
- Date birthDate = dateFormat.parse(birthdayField.getText());
+ PostalCodeDetail newDetail = null;
+ if (!StringUtils.isNullOrEmpty(text, true))
+ newDetail = new PostalCodeDetail(text);
- birthDateCalendar.setTime(birthDate);
- }
- catch (ParseException e2)
- {
- logger.error("Failed to parse birth date.", e2);
- }
+ if (postalCodeDetail != null || newDetail != null)
+ changeDetail(postalCodeDetail, newDetail);
}
- try
+ if (accountInfoOpSet.isDetailClassSupported(CountryDetail.class))
{
- FirstNameDetail newFirstNameDetail
- = new ServerStoredDetails.FirstNameDetail(firstName);
+ String text = detailToTextField.get(CountryDetail.class).getText();
- if (firstNameDetail == null)
- accountInfoOpSet.addDetail(newFirstNameDetail);
- else
- accountInfoOpSet.replaceDetail( firstNameDetail,
- newFirstNameDetail);
-
-// MiddleNameDetail newMiddleNameDetail
-// = new ServerStoredDetails.MiddleNameDetail(middleName);
-//
-// if (middleNameDetail == null)
-// accountInfoOpSet.addDetail(newMiddleNameDetail);
-// else
-// accountInfoOpSet.replaceDetail( middleNameDetail,
-// newMiddleNameDetail);
-
- LastNameDetail newLastNameDetail
- = new ServerStoredDetails.LastNameDetail(lastName);
-
- if (lastNameDetail == null)
- accountInfoOpSet.addDetail(newLastNameDetail);
- else
- accountInfoOpSet.replaceDetail( lastNameDetail,
- newLastNameDetail);
+ CountryDetail newDetail = null;
+ if (!StringUtils.isNullOrEmpty(text, true))
+ newDetail = new CountryDetail(text);
- GenderDetail newGenderDetail
- = new ServerStoredDetails.GenderDetail(gender);
+ if (countryDetail != null || newDetail != null)
+ changeDetail(countryDetail, newDetail);
+ }
- if (genderDetail == null)
- accountInfoOpSet.addDetail(newGenderDetail);
- else
- accountInfoOpSet.replaceDetail( genderDetail,
- newGenderDetail);
+ if (accountInfoOpSet.isDetailClassSupported(
+ EmailAddressDetail.class))
+ {
+ String text =
+ detailToTextField.get(EmailAddressDetail.class).getText();
- BirthDateDetail newBirthDateDetail
- = new ServerStoredDetails.BirthDateDetail(birthDateCalendar);
+ EmailAddressDetail newDetail = null;
+ if (!StringUtils.isNullOrEmpty(text, true))
+ newDetail = new EmailAddressDetail(text);
- if (birthDateDetail == null)
- accountInfoOpSet.addDetail(newBirthDateDetail);
- else
- accountInfoOpSet.replaceDetail( birthDateDetail,
- newBirthDateDetail);
+ if (emailDetail != null || newDetail != null)
+ changeDetail(emailDetail, newDetail);
+ }
- EmailAddressDetail newEmailDetail
- = new ServerStoredDetails.EmailAddressDetail(email);
+ if (accountInfoOpSet.isDetailClassSupported(
+ WorkEmailAddressDetail.class))
+ {
+ String text =
+ detailToTextField.get(WorkEmailAddressDetail.class)
+ .getText();
- if (emailDetail == null)
- accountInfoOpSet.addDetail(newEmailDetail);
- else
- accountInfoOpSet.replaceDetail( emailDetail,
- newEmailDetail);
+ WorkEmailAddressDetail newDetail = null;
+ if (!StringUtils.isNullOrEmpty(text, true))
+ newDetail = new WorkEmailAddressDetail(text);
- PhoneNumberDetail newPhoneDetail
- = new ServerStoredDetails.PhoneNumberDetail(phoneNumber);
+ if (workEmailDetail != null || newDetail != null)
+ changeDetail(workEmailDetail, newDetail);
+ }
- if (phoneDetail == null)
- accountInfoOpSet.addDetail(newPhoneDetail);
- else
- accountInfoOpSet.replaceDetail( phoneDetail,
- newPhoneDetail);
+ if (accountInfoOpSet.isDetailClassSupported(
+ PhoneNumberDetail.class))
+ {
+ String text =
+ detailToTextField.get(PhoneNumberDetail.class).getText();
- BinaryDetail newAvatarDetail
- = new ServerStoredDetails.BinaryDetail(
- "Avatar",
- newAvatarImage);
+ PhoneNumberDetail newDetail = null;
+ if (!StringUtils.isNullOrEmpty(text, true))
+ newDetail = new PhoneNumberDetail(text);
- if (avatarDetail == null)
- accountInfoOpSet.addDetail(newAvatarDetail);
- else
- accountInfoOpSet.replaceDetail( avatarDetail,
- newAvatarDetail);
+ if (phoneDetail != null || newDetail != null)
+ changeDetail(phoneDetail, newDetail);
}
- catch (ClassCastException e1)
+ if (accountInfoOpSet.isDetailClassSupported(
+ WorkPhoneDetail.class))
{
- logger.error("Failed to update account details.", e1);
+ String text =
+ detailToTextField.get(WorkPhoneDetail.class).getText();
+
+ WorkPhoneDetail newDetail = null;
+ if (!StringUtils.isNullOrEmpty(text, true))
+ newDetail = new WorkPhoneDetail(text);
+
+ if (workPhoneDetail != null || newDetail != null)
+ changeDetail(workPhoneDetail, newDetail);
}
- catch (OperationFailedException e1)
+ if (accountInfoOpSet.isDetailClassSupported(
+ WorkOrganizationNameDetail.class))
{
- logger.error("Failed to update account details.", e1);
- }
- }
- }
+ String text =
+ detailToTextField.get(WorkOrganizationNameDetail.class)
+ .getText();
- private class ChangeAvatarActionListener implements ActionListener
- {
- public void actionPerformed(ActionEvent e)
- {
- SipCommFileChooser chooser = GenericFileDialog.create(
- null, "Change avatar...",
- SipCommFileChooser.LOAD_FILE_OPERATION,
- lastAvatarDir.getAbsolutePath());
- chooser.addFilter(new ImageFilter());
+ WorkOrganizationNameDetail newDetail = null;
+ if (!StringUtils.isNullOrEmpty(text, true))
+ newDetail = new WorkOrganizationNameDetail(text);
- File file = chooser.getFileFromDialog();
+ if (organizationDetail != null || newDetail != null)
+ changeDetail(organizationDetail, newDetail);
+ }
- if (file != null)
+ if (accountInfoOpSet.isDetailClassSupported(JobTitleDetail.class))
{
- try
- {
- lastAvatarDir = file.getParentFile();
+ String text =
+ detailToTextField.get(JobTitleDetail.class)
+ .getText();
- FileInputStream in = new FileInputStream(file);
- byte[] buffer;
+ JobTitleDetail newDetail = null;
+ if (!StringUtils.isNullOrEmpty(text, true))
+ newDetail = new JobTitleDetail(text);
- try
- {
- buffer = new byte[in.available()];
- in.read(buffer);
- }
- finally
- {
- in.close();
- }
- if (buffer == null || buffer.length <= 0)
- return;
+ if (jobTitleDetail != null || newDetail != null)
+ changeDetail(jobTitleDetail, newDetail);
+ }
+ if (accountInfoOpSet.isDetailClassSupported(AboutMeDetail.class))
+ {
+ String text =
+ aboutMeArea.getText();
- newAvatarImage = buffer;
+ AboutMeDetail newDetail = null;
+ if (!StringUtils.isNullOrEmpty(text, true))
+ newDetail = new AboutMeDetail(text);
- avatarImageIcon = new ImageIcon(
- getScaledImageInstance(newAvatarImage));
- avatarLabel.setIcon(avatarImageIcon);
- }
- catch (IOException ex)
- {
- logger.error("Failed to load image.", ex);
- }
+ if (aboutMeDetail != null || newDetail != null)
+ changeDetail(aboutMeDetail, newDetail);
+ }
+
+ try
+ {
+ AccountInfoMenuItemComponent.dialog.setVisible(false);
+ mainScrollPane.getVerticalScrollBar().setValue(0);
+ accountInfoOpSet.save();
+ }
+ catch (OperationFailedException e1)
+ {
+ logger.debug("Failed to update account details.", e1);
}
}
- }
- /**
- * A custom filter that would accept only image files.
- */
- private static class ImageFilter extends SipCommFileFilter
- {
/**
- * Accept all directories and all gif, jpg, tiff, or png files.
- * Method implemented from FileFilter abstract class.
- *
- * @param f a file to accept or not
+ * A helper method to decide whether to add new
+ * <tt>ServerStoredDetails</tt> or to replace an old one.
+ * @param oldDetail the detail to be replaced.
+ * @param newDetail the replacement.
*/
- @Override
- public boolean accept(File f)
+ private void changeDetail( GenericDetail oldDetail,
+ GenericDetail newDetail)
{
- if (f.isDirectory())
- {
- return true;
- }
-
- String extension = getExtension(f);
- if (extension != null)
+ try
{
- if (extension.equals("tiff") ||
- extension.equals("tif") ||
- extension.equals("gif") ||
- extension.equals("jpeg") ||
- extension.equals("jpg") ||
- extension.equals("png"))
+ if (newDetail == null)
+ {
+ accountInfoOpSet.removeDetail(oldDetail);
+ }
+ else if (oldDetail == null)
{
- return true;
+ accountInfoOpSet.addDetail(newDetail);
}
else
{
- return false;
+ accountInfoOpSet.replaceDetail(oldDetail, newDetail);
}
}
-
- return false;
- }
-
- /**
- * Get the extension of a file.
- *
- * @param f the file
- * @return the extension of the file
- */
- public String getExtension(File f)
- {
- String ext = null;
- String s = f.getName();
- int i = s.lastIndexOf('.');
-
- if (i > 0 && i < s.length() - 1) {
- ext = s.substring(i+1).toLowerCase();
+ catch (ArrayIndexOutOfBoundsException e1)
+ {
+ logger.debug("Failed to update account details. " +
+ newDetail.getDetailDisplayName() + " " + e1);
+ }
+ catch (OperationFailedException e1)
+ {
+ logger.debug("Failed to update account details. " +
+ newDetail.getDetailDisplayName() + " " + e1);
}
- return ext;
- }
-
- /**
- * The description of this filter.
- */
- @Override
- public String getDescription()
- {
- return Resources.getString("plugin.accountinfo.ONLY_MESSAGE");
- }
-
- }
-
- /**
- * Returns a scaled <tt>Image</tt> instance of the given byte image.
- *
- * @param image the image in bytes
- * @return a scaled <tt>Image</tt> instance of the given byte image.
- */
- private Image getScaledImageInstance(byte[] image)
- {
- Image resultImage = null;
-
- try
- {
- resultImage = ImageIO.read(
- new ByteArrayInputStream(image));
- }
- catch (Exception e)
- {
- logger.error("Failed to convert bytes to image.", e);
}
-
- if(resultImage == null)
- return null;
-
- return resultImage.getScaledInstance(
- avatarLabel.getWidth(),
- avatarLabel.getHeight(),
- Image.SCALE_SMOOTH);
- }
-
- /**
- * Returns <code>true</code> if the account details are loaded,
- * <code>false</code> - otherwise.
- *
- * @return <code>true</code> if the account details are loaded,
- * <code>false</code> - otherwise
- */
- public boolean isDataLoaded()
- {
- return isDataLoaded;
- }
-
- /**
- * Loads the avatar default icon.
- */
- public void loadSkin()
- {
- avatarLabel.setIcon(Resources.getImage("accountInfoDefaultPersonIcon"));
}
}
diff --git a/src/net/java/sip/communicator/plugin/accountinfo/AccountInfoActivator.java b/src/net/java/sip/communicator/plugin/accountinfo/AccountInfoActivator.java
index 9f34c9c..6e1692b 100644
--- a/src/net/java/sip/communicator/plugin/accountinfo/AccountInfoActivator.java
+++ b/src/net/java/sip/communicator/plugin/accountinfo/AccountInfoActivator.java
@@ -8,7 +8,8 @@ package net.java.sip.communicator.plugin.accountinfo;
import java.util.*;
-import net.java.sip.communicator.service.browserlauncher.*;
+import net.java.sip.communicator.service.globaldisplaydetails.*;
+import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.*;
@@ -18,6 +19,7 @@ import org.osgi.framework.*;
* Starts the account info bundle.
*
* @author Adam Glodstein
+ * @author Marin Dzhigarov
*/
public class AccountInfoActivator
implements BundleActivator
@@ -30,21 +32,52 @@ public class AccountInfoActivator
*/
public static BundleContext bundleContext;
- private static BrowserLauncherService browserLauncherService;
+ private static GlobalDisplayDetailsService globalDisplayDetailsService;
public void start(BundleContext bc) throws Exception
{
AccountInfoActivator.bundleContext = bc;
-// new LazyConfigurationForm(
-// "net.java.sip.communicator.plugin.accountinfo.AccountInfoPanel",
-// getClass().getClassLoader(), "plugin.accountinfo.PLUGIN_ICON",
-// "plugin.accountinfo.TITLE");
+ Hashtable<String, String> containerFilter
+ = new Hashtable<String, String>();
+ containerFilter.put(
+ Container.CONTAINER_ID,
+ Container.CONTAINER_TOOLS_MENU.getID());
+
+ bundleContext.registerService(
+ PluginComponentFactory.class.getName(),
+ new PluginComponentFactory(Container.CONTAINER_TOOLS_MENU)
+ {
+ @Override
+ protected PluginComponent getPluginInstance()
+ {
+ return new AccountInfoMenuItemComponent(
+ getContainer(), this);
+ }
+ },
+ containerFilter);
+
+ containerFilter = new Hashtable<String, String>();
+ containerFilter.put(
+ Container.CONTAINER_ID,
+ Container.CONTAINER_ACCOUNT_RIGHT_BUTTON_MENU.getID());
+
+ bundleContext.registerService(
+ PluginComponentFactory.class.getName(),
+ new PluginComponentFactory(
+ Container.CONTAINER_ACCOUNT_RIGHT_BUTTON_MENU)
+ {
+ @Override
+ protected PluginComponent getPluginInstance()
+ {
+ return new AccountInfoMenuItemComponent(
+ getContainer(), this);
+ }
+ },
+ containerFilter);
}
- public void stop(BundleContext bc) throws Exception
- {
- }
+ public void stop(BundleContext bc) throws Exception {}
/**
* Returns all <tt>ProtocolProviderFactory</tt>s obtained from the bundle
@@ -53,7 +86,8 @@ public class AccountInfoActivator
* @return all <tt>ProtocolProviderFactory</tt>s obtained from the bundle
* context
*/
- public static Map<Object, ProtocolProviderFactory> getProtocolProviderFactories()
+ public static Map<Object, ProtocolProviderFactory>
+ getProtocolProviderFactories()
{
Map<Object, ProtocolProviderFactory> providerFactoriesMap =
new Hashtable<Object, ProtocolProviderFactory>();
@@ -87,23 +121,21 @@ public class AccountInfoActivator
}
/**
- * Returns the <tt>BrowserLauncherService</tt> currently registered.
+ * Returns the <tt>GlobalDisplayDetailsService</tt> obtained from the bundle
+ * context.
*
- * @return the <tt>BrowserLauncherService</tt>
+ * @return the <tt>GlobalDisplayDetailsService</tt> obtained from the bundle
+ * context
*/
- public static BrowserLauncherService getBrowserLauncher()
+ public static GlobalDisplayDetailsService getGlobalDisplayDetailsService()
{
- if (browserLauncherService == null)
+ if (globalDisplayDetailsService == null)
{
- ServiceReference serviceReference =
- bundleContext.getServiceReference(BrowserLauncherService.class
- .getName());
-
- browserLauncherService =
- (BrowserLauncherService) bundleContext
- .getService(serviceReference);
+ globalDisplayDetailsService
+ = ServiceUtils.getService(
+ bundleContext,
+ GlobalDisplayDetailsService.class);
}
-
- return browserLauncherService;
+ return globalDisplayDetailsService;
}
}
diff --git a/src/net/java/sip/communicator/plugin/accountinfo/AccountInfoMenuItemComponent.java b/src/net/java/sip/communicator/plugin/accountinfo/AccountInfoMenuItemComponent.java
new file mode 100644
index 0000000..7ce1ad6
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/accountinfo/AccountInfoMenuItemComponent.java
@@ -0,0 +1,119 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.accountinfo;
+
+import java.awt.event.*;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.plugin.desktoputil.*;
+import net.java.sip.communicator.service.gui.*;
+import net.java.sip.communicator.service.protocol.*;
+
+/**
+ * Implements <tt>PluginComponent</tt> for the "Account Info" menu item.
+ *
+ * @author Marin Dzhigarov
+ */
+public class AccountInfoMenuItemComponent
+ extends AbstractPluginComponent
+{
+ /**
+ * The "Account Info" menu item.
+ */
+ JMenuItem accountInfoMenuItem;
+
+ /**
+ * The dialog that appears when "Account Info" menu item is clicked.
+ */
+ static final SIPCommDialog dialog = new SIPCommDialog() {
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Presses programmatically the cancel button, when Esc key is pressed.
+ *
+ * @param isEscaped indicates if the Esc button was pressed on close
+ */
+ protected void close(boolean isEscaped)
+ {
+ this.setVisible(false);
+ }
+ };
+
+ /**
+ * The main panel containing account information.
+ */
+ static final AccountInfoPanel accountInfoPanel = new AccountInfoPanel();
+
+ /**
+ * Initializes a new "Account Info" menu item.
+ *
+ * @param container the container of the update menu component
+ */
+ public AccountInfoMenuItemComponent(Container container,
+ PluginComponentFactory parentFactory)
+ {
+ super(container, parentFactory);
+
+ AccountInfoActivator.bundleContext.addServiceListener(accountInfoPanel);
+
+ dialog.setPreferredSize(new java.awt.Dimension(600, 400));
+ dialog.setTitle(Resources.getString("plugin.accountinfo.TITLE"));
+ dialog.add(accountInfoPanel);
+ }
+
+ public void setCurrentAccountID(AccountID accountID)
+ {
+ accountInfoMenuItem.setEnabled(
+ accountID != null && accountID.isEnabled());
+ accountInfoPanel.getAccountsComboBox().setSelectedItem(
+ accountInfoPanel.getAccountsTable().get(accountID));
+ }
+
+ /**
+ * Gets the UI <tt>Component</tt> of this <tt>PluginComponent</tt>.
+ *
+ * @return the UI <tt>Component</tt> of this <tt>PluginComponent</tt>
+ * @see PluginComponent#getComponent()
+ */
+ public Object getComponent()
+ {
+ if(accountInfoMenuItem == null)
+ {
+ accountInfoMenuItem
+ = new JMenuItem(
+ Resources.getString("plugin.accountinfo.TITLE"));
+ accountInfoMenuItem.setIcon(
+ Resources.getImage(
+ "plugin.contactinfo.CONTACT_INFO_ICON"));
+ accountInfoMenuItem.addActionListener(
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ dialog.setVisible(true);
+ accountInfoPanel.setVisible(true);
+ }
+ });
+ }
+ return accountInfoMenuItem;
+ }
+
+ /**
+ * Gets the name of this <tt>PluginComponent</tt>.
+ *
+ * @return the name of this <tt>PluginComponent</tt>
+ * @see PluginComponent#getName()
+ */
+ public String getName()
+ {
+ return
+ Resources.getString("plugin.accountinfo.TITLE");
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/accountinfo/AccountInfoPanel.java b/src/net/java/sip/communicator/plugin/accountinfo/AccountInfoPanel.java
index 99d8c40..4e052c5 100644
--- a/src/net/java/sip/communicator/plugin/accountinfo/AccountInfoPanel.java
+++ b/src/net/java/sip/communicator/plugin/accountinfo/AccountInfoPanel.java
@@ -6,6 +6,7 @@
package net.java.sip.communicator.plugin.accountinfo;
import java.awt.*;
+import java.awt.event.*;
import java.util.*;
import javax.swing.*;
@@ -17,13 +18,15 @@ import net.java.sip.communicator.service.protocol.event.*;
import org.osgi.framework.*;
/**
- * A GUI plug-in for SIP Communicator that will allow users to set cross
+ * A GUI plug-in for Jitsi that will allow users to set cross
* protocol account information.
*
* @author Adam Goldstein
+ * @author Marin Dzhigarov
*/
public class AccountInfoPanel
extends TransparentPanel
+ implements ServiceListener
{
/**
* Serial version UID.
@@ -31,25 +34,86 @@ public class AccountInfoPanel
private static final long serialVersionUID = 0L;
/**
- * The right side of the AccountInfo frame that contains protocol specific
- * account details.
+ * The panel that contains the currently active <tt>AccountDetailsPanel</tt>
*/
- private AccountDetailsPanel detailsPanel;
+ private final JPanel centerPanel =
+ new TransparentPanel(new BorderLayout(10, 10));
- private final Map<ProtocolProviderService, AccountDetailsPanel> accountsTable =
- new Hashtable<ProtocolProviderService, AccountDetailsPanel>();
+ /**
+ * The currently active <tt>AccountDetailsPanel</tt>
+ */
+ private AccountDetailsPanel currentDetailsPanel;
+
+ /**
+ * Combo box that is used for switching between accounts.
+ */
+ private final JComboBox accountsComboBox;
/**
- * Constructs a frame with an AccuontInfoAccountPanel to display all
- * registered accounts on the left, and an information interface,
- * AccountDetailsPanel, on the right.
+ * Instances of the <tt>AccountDetailsPanel</tt> are created for every
+ * registered <tt>AccountID</tt>. All such pairs are stored in
+ * this map.
+ */
+ private final Map<AccountID, AccountDetailsPanel>
+ accountsTable =
+ new HashMap<AccountID, AccountDetailsPanel>();
+
+ /**
+ * Creates an instance of <tt>AccountInfoPanel</tt> that contains combo box
+ * component with active user accounts and <tt>AccountDetailsPanel</tt> to
+ * display and edit account information.
*/
public AccountInfoPanel()
{
- super(new BorderLayout());
+ setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+
+ accountsComboBox = new JComboBox();
+ accountsComboBox.addItemListener(new ItemListener()
+ {
+ @Override
+ public void itemStateChanged(ItemEvent e)
+ {
+ if (e.getStateChange() == ItemEvent.SELECTED)
+ {
+ AccountDetailsPanel panel =
+ (AccountDetailsPanel) e.getItem();
+ panel.setOpaque(false);
+ centerPanel.removeAll();
+ centerPanel.add(panel, BorderLayout.CENTER);
+ centerPanel.revalidate();
+ centerPanel.repaint();
+ currentDetailsPanel = panel;
+ }
+ }
+ });
+
+ init();
+
+ centerPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+
+ ComboBoxRenderer renderer = new ComboBoxRenderer();
+ accountsComboBox.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
+ accountsComboBox.setRenderer(renderer);
+
+ JLabel comboLabel = new JLabel(
+ Resources.getString(
+ "plugin.accountinfo.SELECT_ACCOUNT"));
+ comboLabel.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
- JTabbedPane accountsTabbedPane = new SIPCommTabbedPane();
+ JPanel comboBoxPanel = new TransparentPanel();
+ comboBoxPanel.setLayout(new BoxLayout(comboBoxPanel, BoxLayout.X_AXIS));
+ comboBoxPanel.setBorder(
+ BorderFactory.createEmptyBorder(10, 10, 10, 10));
+ comboBoxPanel.add(comboLabel);
+ comboBoxPanel.add(accountsComboBox);
+
+ add(comboBoxPanel);
+ add(centerPanel);
+ }
+
+ private void init()
+ {
for (ProtocolProviderFactory providerFactory : AccountInfoActivator
.getProtocolProviderFactories().values())
{
@@ -63,22 +127,56 @@ public class AccountInfoPanel
{
serRef = providerFactory.getProviderForAccount(accountID);
- protocolProvider = (ProtocolProviderService) AccountInfoActivator
+ protocolProvider = (ProtocolProviderService)AccountInfoActivator
.bundleContext.getService(serRef);
- detailsPanel = new AccountDetailsPanel(protocolProvider);
+ currentDetailsPanel = new AccountDetailsPanel(protocolProvider);
+
+ accountsTable.put(
+ protocolProvider.getAccountID(), currentDetailsPanel);
- accountsTable.put(protocolProvider, detailsPanel);
+ accountsComboBox.addItem(currentDetailsPanel);
protocolProvider.addRegistrationStateChangeListener(
new RegistrationStateChangeListenerImpl());
-
- accountsTabbedPane.addTab(
- accountID.getUserID(), detailsPanel);
}
}
+ }
+
+ /**
+ * A custom renderer to display properly <tt>AccountDetailsPanel</tt>
+ * in a combo box.
+ */
+ private class ComboBoxRenderer extends DefaultListCellRenderer
+ {
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
- this.add(accountsTabbedPane, BorderLayout.CENTER);
+ @Override
+ public Component getListCellRendererComponent(
+ JList list, Object value, int index,
+ boolean isSelected, boolean hasFocus)
+ {
+ JLabel renderer
+ = (JLabel) super.getListCellRendererComponent(
+ list, value, index, isSelected, hasFocus);
+
+ if (value != null)
+ {
+ AccountDetailsPanel panel = (AccountDetailsPanel) value;
+
+ renderer.setText(
+ panel.protocolProvider.getAccountID().getUserID());
+ ImageIcon protocolIcon =
+ new ImageIcon(panel.protocolProvider.getProtocolIcon().
+ getIcon((ProtocolIcon.ICON_SIZE_16x16)));
+ renderer.setIcon(protocolIcon);
+ }
+
+ return renderer;
+ }
}
private class RegistrationStateChangeListenerImpl
@@ -88,19 +186,117 @@ public class AccountInfoPanel
{
ProtocolProviderService protocolProvider = evt.getProvider();
- if (protocolProvider.getOperationSet(
- OperationSetServerStoredAccountInfo.class) != null
- && evt.getNewState() == RegistrationState.REGISTERED)
+ if (evt.getNewState() == RegistrationState.REGISTERED)
{
- if (accountsTable.containsKey(protocolProvider))
+ if (accountsTable.containsKey(protocolProvider.getAccountID()))
{
AccountDetailsPanel detailsPanel
- = accountsTable.get(protocolProvider);
+ = accountsTable.get(protocolProvider.getAccountID());
+ detailsPanel.loadDetails();
+ }
+ else
+ {
+ AccountDetailsPanel panel =
+ new AccountDetailsPanel(protocolProvider);
+ accountsTable.put(protocolProvider.getAccountID(), panel);
+ accountsComboBox.addItem(panel);
+ }
+ }
+ else if (evt.getNewState() == RegistrationState.UNREGISTERING)
+ {
+ AccountDetailsPanel panel
+ = accountsTable.get(protocolProvider.getAccountID());
+ if (panel != null)
+ {
+ accountsTable.remove(protocolProvider.getAccountID());
+ accountsComboBox.removeItem(panel);
+ if (currentDetailsPanel == panel)
+ {
+ currentDetailsPanel = null;
+ centerPanel.removeAll();
+ centerPanel.revalidate();
+ centerPanel.repaint();
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Handles registration and unregistration of
+ * <tt>ProtocolProviderService</tt>
+ *
+ * @param event
+ */
+ @Override
+ public void serviceChanged(ServiceEvent event)
+ {
+ // Get the service from the event.
+ Object service
+ = AccountInfoActivator.bundleContext.getService(
+ event.getServiceReference());
- if(!detailsPanel.isDataLoaded())
- detailsPanel.loadDetails();
+ // We are not interested in any services
+ // other than ProtocolProviderService
+ if (!(service instanceof ProtocolProviderService))
+ return;
+
+ ProtocolProviderService protocolProvider =
+ (ProtocolProviderService) service;
+
+ // If a new protocol provider is registered we to add new
+ // AccountDetailsPanel to the combo box containing active accounts.
+ if (event.getType() == ServiceEvent.REGISTERED)
+ {
+ if (accountsTable.get(protocolProvider.getAccountID()) == null)
+ {
+ AccountDetailsPanel panel =
+ new AccountDetailsPanel(protocolProvider);
+ accountsTable.put(protocolProvider.getAccountID(), panel);
+ accountsComboBox.addItem(panel);
+ protocolProvider.addRegistrationStateChangeListener(
+ new RegistrationStateChangeListenerImpl());
+ }
+ }
+ // If the protocol provider is being unregistered we have to remove
+ // a AccountDetailsPanel from the combo box containing active accounts.
+ else if (event.getType() == ServiceEvent.UNREGISTERING)
+ {
+ AccountDetailsPanel panel
+ = accountsTable.get(protocolProvider.getAccountID());
+ if (panel != null)
+ {
+ accountsTable.remove(protocolProvider.getAccountID());
+ accountsComboBox.removeItem(panel);
+ if (currentDetailsPanel == panel)
+ {
+ currentDetailsPanel = null;
+ centerPanel.removeAll();
+ centerPanel.revalidate();
+ centerPanel.repaint();
}
}
}
}
+
+ /**
+ * Returns the combo box that switches between account detail panels.
+ *
+ * @return The combo box that switches between account detail panels.
+ */
+ public JComboBox getAccountsComboBox()
+ {
+ return accountsComboBox;
+ }
+
+ /**
+ * Returns mapping between registered AccountIDs and their respective
+ * AccountDetailsPanel that contains all the details for the account.
+ *
+ * @return mapping between registered AccountIDs and AccountDetailsPanel.
+ */
+ public Map<AccountID, AccountDetailsPanel> getAccountsTable()
+ {
+ return accountsTable;
+ }
}
diff --git a/src/net/java/sip/communicator/plugin/accountinfo/accountinfo.manifest.mf b/src/net/java/sip/communicator/plugin/accountinfo/accountinfo.manifest.mf
index 3426abd..fca236b 100644
--- a/src/net/java/sip/communicator/plugin/accountinfo/accountinfo.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/accountinfo/accountinfo.manifest.mf
@@ -5,27 +5,19 @@ Bundle-Vendor: jitsi.org
Bundle-Version: 0.0.1
System-Bundle: yes
Import-Package: org.osgi.framework,
- net.java.sip.communicator.service.browserlauncher,
- net.java.sip.communicator.service.contactlist,
- net.java.sip.communicator.service.contactlist.event,
net.java.sip.communicator.service.gui,
- net.java.sip.communicator.service.gui.event,
+ net.java.sip.communicator.service.globaldisplaydetails,
net.java.sip.communicator.service.protocol,
net.java.sip.communicator.service.protocol.event,
- org.jitsi.service.resources, net.java.sip.communicator.service.resources,
+ org.jitsi.service.resources,
+ org.jitsi.util,
+ net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
+ net.java.sip.communicator.util.skin,
net.java.sip.communicator.plugin.desktoputil,
+ net.java.sip.communicator.plugin.desktoputil.presence.avatar,
javax.swing,
javax.swing.event,
- javax.swing.table,
+ javax.swing.border,
javax.swing.text,
- javax.swing.text.html,
- javax.accessibility,
- javax.swing.plaf,
- javax.swing.plaf.metal,
- javax.swing.plaf.basic,
- javax.imageio,
- javax.swing.filechooser,
- javax.swing.tree,
- javax.swing.undo,
- javax.swing.border
+ javax.imageio
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/DesktopUtilActivator.java b/src/net/java/sip/communicator/plugin/desktoputil/DesktopUtilActivator.java
index de92b28..23bb10d 100644
--- a/src/net/java/sip/communicator/plugin/desktoputil/DesktopUtilActivator.java
+++ b/src/net/java/sip/communicator/plugin/desktoputil/DesktopUtilActivator.java
@@ -12,10 +12,14 @@ import net.java.sip.communicator.service.certificate.*;
import net.java.sip.communicator.service.credentialsstorage.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.keybindings.*;
+import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.resources.*;
import net.java.sip.communicator.util.*;
+import org.jitsi.service.audionotifier.*;
import org.jitsi.service.configuration.*;
+import org.jitsi.service.fileaccess.*;
+import org.jitsi.service.neomedia.*;
import org.jitsi.service.resources.*;
import org.osgi.framework.*;
@@ -40,6 +44,14 @@ public class DesktopUtilActivator
private static UIService uiService;
+ private static AccountManager accountManager;
+
+ private static FileAccessService fileAccessService;
+
+ private static MediaService mediaService;
+
+ private static AudioNotifierService audioNotifierService;
+
static BundleContext bundleContext;
/**
@@ -247,4 +259,69 @@ public class DesktopUtilActivator
{
return new VerifyCertificateDialogImpl(certs, title, message);
}
+
+ /**
+ * Returns the <tt>AccountManager</tt> obtained from the bundle context.
+ * @return the <tt>AccountManager</tt> obtained from the bundle context
+ */
+ public static AccountManager getAccountManager()
+ {
+ if(accountManager == null)
+ {
+ accountManager
+ = ServiceUtils.getService(bundleContext, AccountManager.class);
+ }
+ return accountManager;
+ }
+
+ /**
+ * Returns the <tt>FileAccessService</tt> obtained from the bundle context.
+ *
+ * @return the <tt>FileAccessService</tt> obtained from the bundle context
+ */
+ public static FileAccessService getFileAccessService()
+ {
+ if (fileAccessService == null)
+ {
+ fileAccessService
+ = ServiceUtils.getService(
+ bundleContext,
+ FileAccessService.class);
+ }
+ return fileAccessService;
+ }
+
+ /**
+ * Returns an instance of the <tt>MediaService</tt> obtained from the
+ * bundle context.
+ * @return an instance of the <tt>MediaService</tt> obtained from the
+ * bundle context
+ */
+ public static MediaService getMediaService()
+ {
+ if (mediaService == null)
+ {
+ mediaService
+ = ServiceUtils.getService(bundleContext, MediaService.class);
+ }
+ return mediaService;
+ }
+
+ /**
+ * Returns the <tt>AudioNotifierService</tt> obtained from the bundle
+ * context.
+ * @return the <tt>AudioNotifierService</tt> obtained from the bundle
+ * context
+ */
+ public static AudioNotifierService getAudioNotifier()
+ {
+ if (audioNotifierService == null)
+ {
+ audioNotifierService
+ = ServiceUtils.getService(
+ bundleContext,
+ AudioNotifierService.class);
+ }
+ return audioNotifierService;
+ }
} \ No newline at end of file
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/FramedImage.java b/src/net/java/sip/communicator/plugin/desktoputil/FramedImage.java
index a60df48..de85557 100644
--- a/src/net/java/sip/communicator/plugin/desktoputil/FramedImage.java
+++ b/src/net/java/sip/communicator/plugin/desktoputil/FramedImage.java
@@ -142,14 +142,17 @@ public class FramedImage
null);
}
- int frameWidth = frameImage.getWidth(this);
- int frameHeight = frameImage.getHeight(this);
- if ((frameWidth != -1) && (frameHeight != -1))
- g.drawImage(
- frameImage,
- width / 2 - frameWidth / 2,
- height / 2 - frameHeight / 2,
- null);
+ if (frameImage != null)
+ {
+ int frameWidth = frameImage.getWidth(this);
+ int frameHeight = frameImage.getHeight(this);
+ if ((frameWidth != -1) && (frameHeight != -1))
+ g.drawImage(
+ frameImage,
+ width / 2 - frameWidth / 2,
+ height / 2 - frameHeight / 2,
+ null);
+ }
}
/**
@@ -157,14 +160,21 @@ public class FramedImage
*/
public void loadSkin()
{
- this.frameImage
- = ImageUtils
- .scaleImageWithinBounds(
- DesktopUtilActivator
- .getResources()
- .getImage("service.gui.USER_PHOTO_FRAME").getImage(),
- width,
- height);
+ ImageIcon frameIcon = DesktopUtilActivator
+ .getResources()
+ .getImage("service.gui.USER_PHOTO_FRAME");
+
+ // Frame image will be drawn only if's bigger or equal to the underlying
+ // image. We would like to avoid pixelated results!
+ if (frameIcon.getIconWidth() >= width
+ && frameIcon.getIconHeight() >= frameIcon.getIconHeight())
+ {
+ this.frameImage
+ = ImageUtils
+ .scaleImageWithinBounds(frameIcon.getImage(),
+ width,
+ height);
+ }
}
/**
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/FramedImageWithMenu.java b/src/net/java/sip/communicator/plugin/desktoputil/FramedImageWithMenu.java
index f50ca68..4262e3b 100644
--- a/src/net/java/sip/communicator/plugin/desktoputil/FramedImageWithMenu.java
+++ b/src/net/java/sip/communicator/plugin/desktoputil/FramedImageWithMenu.java
@@ -35,11 +35,6 @@ public class FramedImageWithMenu
private JPopupMenu popupMenu;
/**
- * The parent frame.
- */
- private JFrame mainFrame;
-
- /**
* Should we currently draw overlay.
*/
private boolean drawOverlay = false;
@@ -62,14 +57,12 @@ public class FramedImageWithMenu
* @param height height of component.
*/
public FramedImageWithMenu(
- JFrame mainFrame,
ImageIcon imageIcon,
int width,
int height)
{
super(imageIcon, width, height);
- this.mainFrame = mainFrame;
this.addMouseListener(this);
}
@@ -189,9 +182,9 @@ public class FramedImageWithMenu
if (show)
{
Point imageLoc = this.getLocationOnScreen();
- Point rootPaneLoc = mainFrame.getRootPane().getLocationOnScreen();
+ Point rootPaneLoc = this.getRootPane().getLocationOnScreen();
- this.popupMenu.setSize(mainFrame.getRootPane().getWidth(),
+ this.popupMenu.setSize(this.getRootPane().getWidth(),
this.popupMenu.getHeight());
this.popupMenu.show(this, (rootPaneLoc.x - imageLoc.x),
@@ -206,7 +199,7 @@ public class FramedImageWithMenu
public void mouseEntered(MouseEvent e)
{
- if (this.drawOverlay)
+ if (this.drawOverlay || !this.isEnabled())
return;
this.drawOverlay = true;
@@ -222,7 +215,7 @@ public class FramedImageWithMenu
public void mouseExited(MouseEvent e)
{
// Remove overlay only if the dialog isn't visible
- if (!popupMenu.isVisible())
+ if (!popupMenu.isVisible() && this.isEnabled())
{
this.drawOverlay = false;
this.repaint();
@@ -231,7 +224,8 @@ public class FramedImageWithMenu
public void mouseReleased(MouseEvent e)
{
- showDialog(e, !popupMenu.isVisible());
+ if (this.isEnabled())
+ showDialog(e, !popupMenu.isVisible());
}
/**
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/desktoputil.manifest.mf b/src/net/java/sip/communicator/plugin/desktoputil/desktoputil.manifest.mf
index 56edae3..4b91013 100644
--- a/src/net/java/sip/communicator/plugin/desktoputil/desktoputil.manifest.mf
+++ b/src/net/java/sip/communicator/plugin/desktoputil/desktoputil.manifest.mf
@@ -30,6 +30,7 @@ Import-Package: com.sun.awt,
javax.xml.transform.dom,
javax.xml.transform.stream,
net.java.sip.communicator.util,
+ net.java.sip.communicator.util.account,
net.java.sip.communicator.util.skin,
net.java.sip.communicator.util.wizard,
net.java.sip.communicator.service.certificate,
@@ -64,5 +65,6 @@ Export-Package: net.java.sip.communicator.plugin.desktoputil,
net.java.sip.communicator.plugin.desktoputil.event,
net.java.sip.communicator.plugin.desktoputil.plaf,
net.java.sip.communicator.plugin.desktoputil.presence,
+ net.java.sip.communicator.plugin.desktoputil.presence.avatar,
net.java.sip.communicator.plugin.desktoputil.transparent,
net.java.sip.communicator.plugin.desktoputil.wizard
diff --git a/src/net/java/sip/communicator/impl/gui/main/presence/avatar/AvatarStackManager.java b/src/net/java/sip/communicator/plugin/desktoputil/presence/avatar/AvatarStackManager.java
index 948716e..3a81a24 100644
--- a/src/net/java/sip/communicator/impl/gui/main/presence/avatar/AvatarStackManager.java
+++ b/src/net/java/sip/communicator/plugin/desktoputil/presence/avatar/AvatarStackManager.java
@@ -4,18 +4,18 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
-package net.java.sip.communicator.impl.gui.main.presence.avatar;
+package net.java.sip.communicator.plugin.desktoputil.presence.avatar;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
-import org.jitsi.service.fileaccess.*;
-
-import net.java.sip.communicator.impl.gui.*;
+import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.util.*;
+import org.jitsi.service.fileaccess.*;
+
/**
* Take cares of storing(deleting, moving) images with the given indexes.
*/
@@ -44,8 +44,9 @@ public class AvatarStackManager
try
{
File imageFile
- = GuiActivator.getFileAccessService().getPrivatePersistentFile(
- fileName, FileCategory.CACHE);
+ = DesktopUtilActivator.getFileAccessService()
+ .getPrivatePersistentFile(
+ fileName);
if (imageFile.exists() && !imageFile.delete())
logger.error("Failed to delete stored image at index " + index);
@@ -71,8 +72,9 @@ public class AvatarStackManager
String imagePath = STORE_DIR + index + ".png";
imageFile
- = GuiActivator.getFileAccessService().getPrivatePersistentFile(
- imagePath, FileCategory.CACHE);
+ = DesktopUtilActivator.getFileAccessService().
+ getPrivatePersistentFile(
+ imagePath);
}
catch (Exception e)
{
@@ -107,14 +109,12 @@ public class AvatarStackManager
try
{
- FileAccessService fas = GuiActivator.getFileAccessService();
- File oldFile = fas.getPrivatePersistentFile(oldImagePath,
- FileCategory.CACHE);
+ FileAccessService fas = DesktopUtilActivator.getFileAccessService();
+ File oldFile = fas.getPrivatePersistentFile(oldImagePath);
if (oldFile.exists())
{
- File newFile = fas.getPrivatePersistentFile(newImagePath,
- FileCategory.CACHE);
+ File newFile = fas.getPrivatePersistentFile(newImagePath);
oldFile.renameTo(newFile);
}
@@ -148,15 +148,13 @@ public class AvatarStackManager
try
{
- FileAccessService fas = GuiActivator.getFileAccessService();
- File storeDir = fas.getPrivatePersistentDirectory(STORE_DIR,
- FileCategory.CACHE);
+ FileAccessService fas = DesktopUtilActivator.getFileAccessService();
+ File storeDir = fas.getPrivatePersistentDirectory(STORE_DIR);
// if dir doesn't exist create it
storeDir.mkdirs();
- File file = fas.getPrivatePersistentFile(imagePath,
- FileCategory.CACHE);
+ File file = fas.getPrivatePersistentFile(imagePath);
ImageIO.write(image, "png", file);
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/presence/avatar/SelectAvatarMenu.java b/src/net/java/sip/communicator/plugin/desktoputil/presence/avatar/SelectAvatarMenu.java
index 01c70aa..7b00fcc 100644
--- a/src/net/java/sip/communicator/impl/gui/main/presence/avatar/SelectAvatarMenu.java
+++ b/src/net/java/sip/communicator/plugin/desktoputil/presence/avatar/SelectAvatarMenu.java
@@ -4,18 +4,20 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
-package net.java.sip.communicator.impl.gui.main.presence.avatar;
+package net.java.sip.communicator.plugin.desktoputil.presence.avatar;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
+import java.util.*;
import javax.swing.*;
-import net.java.sip.communicator.impl.gui.*;
-import net.java.sip.communicator.impl.gui.main.presence.avatar.imagepicker.*;
import net.java.sip.communicator.plugin.desktoputil.*;
+import net.java.sip.communicator.plugin.desktoputil.presence.avatar.imagepicker.*;
import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.ServerStoredDetails.GenericDetail;
+import net.java.sip.communicator.service.protocol.ServerStoredDetails.ImageDetail;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.account.*;
@@ -86,6 +88,12 @@ public class SelectAvatarMenu
private FramedImageWithMenu avatarImage;
/**
+ * The AccountID that we want to select avatar for. Could be null if
+ * we want to select a global avatar.
+ */
+ private AccountID accountID;
+
+ /**
* Creates the dialog.
* @param avatarImage the button that will trigger this menu.
*/
@@ -98,6 +106,11 @@ public class SelectAvatarMenu
this.pack();
}
+ public void setAccountID(AccountID accountID)
+ {
+ this.accountID = accountID;
+ }
+
/**
* Init visible components.
*/
@@ -108,7 +121,7 @@ public class SelectAvatarMenu
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
// Title label
- JLabel titleLabel = new JLabel(GuiActivator.getResources()
+ JLabel titleLabel = new JLabel(DesktopUtilActivator.getResources()
.getI18NString("service.gui.avatar.RECENT_ICONS"));
titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD));
@@ -146,17 +159,17 @@ public class SelectAvatarMenu
Color linkColor = new JMenuItem().getForeground();
addActionButton(buttonsPanel, this,
- GuiActivator.getResources().getI18NString(
+ DesktopUtilActivator.getResources().getI18NString(
"service.gui.avatar.CHOOSE_ICON"),
CHOSE_BUTTON_NAME,
linkColor);
addActionButton(buttonsPanel, this,
- GuiActivator.getResources().getI18NString(
+ DesktopUtilActivator.getResources().getI18NString(
"service.gui.avatar.REMOVE_ICON"),
REMOVE_BUTTON_NAME,
linkColor);
addActionButton(buttonsPanel, this,
- GuiActivator.getResources().getI18NString(
+ DesktopUtilActivator.getResources().getI18NString(
"service.gui.avatar.CLEAR_RECENT"),
CLEAR_BUTTON_NAME,
linkColor);
@@ -267,11 +280,11 @@ public class SelectAvatarMenu
public void run()
{
AccountManager accountManager
- = GuiActivator.getAccountManager();
+ = DesktopUtilActivator.getAccountManager();
- for(AccountID accountID : accountManager.getStoredAccounts())
+ for (AccountID accountID : accountManager.getStoredAccounts())
{
- if(accountManager.isAccountLoaded(accountID))
+ if (accountManager.isAccountLoaded(accountID))
{
ProtocolProviderService protocolProvider
= AccountUtils.getRegisteredProviderForAccount(
@@ -280,27 +293,78 @@ public class SelectAvatarMenu
if(protocolProvider != null
&& protocolProvider.isRegistered())
{
- OperationSetAvatar opSetAvatar
- = protocolProvider
- .getOperationSet(OperationSetAvatar.class);
-
- if(opSetAvatar != null)
+ // If account id is set this means that we want to
+ // edit our current account image, not the global
+ // avatar. Hence, we might not want to save this
+ // account image on the server yet. For example: in
+ // the account info plugin the user might set a new
+ // avatar and then click the cancel button.
+ if (SelectAvatarMenu.this.accountID != null)
{
- byte[] imageByte = null;
- // Sets new avatar if not null. Otherwise, the
- // opSetAvatar.setAvatar(null) will removes the
- // current one.
- if(image != null)
- {
- imageByte = ImageUtils.toByteArray(image);
- }
- try
+ if (accountID.equals(
+ SelectAvatarMenu.this.accountID))
{
- opSetAvatar.setAvatar(imageByte);
+ OperationSetServerStoredAccountInfo opSet =
+ protocolProvider.getOperationSet(
+ OperationSetServerStoredAccountInfo.class);
+ if (opSet != null)
+ {
+ byte[] imageByte = null;
+ if (image != null)
+ {
+ imageByte =
+ ImageUtils.toByteArray(image);
+ }
+ avatarImage.setImageIcon(imageByte);
+ ImageDetail newDetail =
+ new ImageDetail(
+ "avatar", imageByte);
+
+ Iterator<GenericDetail> oldDetail =
+ opSet.getDetails(ImageDetail.class);
+ try
+ {
+ if (oldDetail.hasNext())
+ {
+ opSet.replaceDetail(
+ oldDetail.next(),
+ newDetail);
+ }
+ else
+ opSet.addDetail(newDetail);
+ }
+ catch (Throwable t)
+ {
+ logger.error(
+ "Error setting image", t);
+ }
+ }
}
- catch(Throwable t)
+ }
+ else
+ {
+ OperationSetAvatar opSetAvatar
+ = protocolProvider
+ .getOperationSet(OperationSetAvatar.class);
+
+ if(opSetAvatar != null)
{
- logger.error("Error setting image", t);
+ byte[] imageByte = null;
+ // Sets new avatar if not null. Otherwise, the
+ // opSetAvatar.setAvatar(null) will removes the
+ // current one.
+ if(image != null)
+ {
+ imageByte = ImageUtils.toByteArray(image);
+ }
+ try
+ {
+ opSetAvatar.setAvatar(imageByte);
+ }
+ catch(Throwable t)
+ {
+ logger.error("Error setting image", t);
+ }
}
}
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/presence/avatar/imagepicker/EditPanel.java b/src/net/java/sip/communicator/plugin/desktoputil/presence/avatar/imagepicker/EditPanel.java
index b8273c8..aff0280 100644
--- a/src/net/java/sip/communicator/impl/gui/main/presence/avatar/imagepicker/EditPanel.java
+++ b/src/net/java/sip/communicator/plugin/desktoputil/presence/avatar/imagepicker/EditPanel.java
@@ -4,7 +4,7 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
-package net.java.sip.communicator.impl.gui.main.presence.avatar.imagepicker;
+package net.java.sip.communicator.plugin.desktoputil.presence.avatar.imagepicker;
import java.awt.*;
import java.awt.event.*;
@@ -13,7 +13,6 @@ import java.awt.image.*;
import javax.swing.*;
import javax.swing.event.*;
-import net.java.sip.communicator.impl.gui.*;
import net.java.sip.communicator.plugin.desktoputil.*;
/**
@@ -53,15 +52,15 @@ public class EditPanel
this.clippingZoneWidth = clippingZoneWidth;
this.clippingZoneHeight = clippingZoneHeight;
- this.zoomOut = new JButton(GuiActivator.getResources()
+ this.zoomOut = new JButton(DesktopUtilActivator.getResources()
.getImage("service.gui.buttons.ZOOM_OUT"));
this.zoomOut.addActionListener(this);
- this.zoomIn = new JButton(GuiActivator.getResources()
+ this.zoomIn = new JButton(DesktopUtilActivator.getResources()
.getImage("service.gui.buttons.ZOOM_IN"));
this.zoomIn.addActionListener(this);
- this.reset = new JButton(GuiActivator.getResources()
+ this.reset = new JButton(DesktopUtilActivator.getResources()
.getImage("service.gui.buttons.RESET"));
- this.reset.setToolTipText(GuiActivator.getResources()
+ this.reset.setToolTipText(DesktopUtilActivator.getResources()
.getI18NString("service.gui.avatar.imagepicker.RESET"));
this.reset.addActionListener(this);
@@ -69,7 +68,7 @@ public class EditPanel
clippingZoneWidth);
imageSizeSlider.addChangeListener(this);
imageSizeSlider.setOpaque(false);
- imageSizeSlider.setToolTipText(GuiActivator.getResources()
+ imageSizeSlider.setToolTipText(DesktopUtilActivator.getResources()
.getI18NString("service.gui.avatar.imagepicker.IMAGE_SIZE"));
TransparentPanel sliderPanel = new TransparentPanel();
diff --git a/src/net/java/sip/communicator/impl/gui/main/presence/avatar/imagepicker/ImageClipper.java b/src/net/java/sip/communicator/plugin/desktoputil/presence/avatar/imagepicker/ImageClipper.java
index 5f42a26..853b906 100644
--- a/src/net/java/sip/communicator/impl/gui/main/presence/avatar/imagepicker/ImageClipper.java
+++ b/src/net/java/sip/communicator/plugin/desktoputil/presence/avatar/imagepicker/ImageClipper.java
@@ -4,7 +4,7 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
-package net.java.sip.communicator.impl.gui.main.presence.avatar.imagepicker;
+package net.java.sip.communicator.plugin.desktoputil.presence.avatar.imagepicker;
import java.awt.*;
import java.awt.event.*;
diff --git a/src/net/java/sip/communicator/impl/gui/main/presence/avatar/imagepicker/ImagePickerDialog.java b/src/net/java/sip/communicator/plugin/desktoputil/presence/avatar/imagepicker/ImagePickerDialog.java
index 06e135b..8a1b2f4 100644
--- a/src/net/java/sip/communicator/impl/gui/main/presence/avatar/imagepicker/ImagePickerDialog.java
+++ b/src/net/java/sip/communicator/plugin/desktoputil/presence/avatar/imagepicker/ImagePickerDialog.java
@@ -4,7 +4,7 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
-package net.java.sip.communicator.impl.gui.main.presence.avatar.imagepicker;
+package net.java.sip.communicator.plugin.desktoputil.presence.avatar.imagepicker;
import java.awt.*;
import java.awt.event.*;
@@ -14,7 +14,6 @@ import java.io.*;
import javax.imageio.*;
import javax.swing.*;
-import net.java.sip.communicator.impl.gui.*;
import net.java.sip.communicator.plugin.desktoputil.*;
/**
@@ -51,7 +50,7 @@ public class ImagePickerDialog
*/
private void initDialog()
{
- this.setTitle(GuiActivator.getResources()
+ this.setTitle(DesktopUtilActivator.getResources()
.getI18NString("service.gui.avatar.imagepicker.IMAGE_PICKER"));
this.setModal(true);
this.setResizable(true);
@@ -91,22 +90,22 @@ public class ImagePickerDialog
this.editPanel = new EditPanel(clipperZoneWidth, clipperZoneHeight);
// Buttons
- this.okButton = new JButton(GuiActivator.getResources()
+ this.okButton = new JButton(DesktopUtilActivator.getResources()
.getI18NString("service.gui.avatar.imagepicker.SET"));
this.okButton.addActionListener(this);
this.okButton.setName("okButton");
- this.cancelButton = new JButton(GuiActivator.getResources()
+ this.cancelButton = new JButton(DesktopUtilActivator.getResources()
.getI18NString("service.gui.avatar.imagepicker.CANCEL"));
this.cancelButton.addActionListener(this);
this.cancelButton.setName("cancelButton");
- this.selectFileButton = new JButton(GuiActivator.getResources()
+ this.selectFileButton = new JButton(DesktopUtilActivator.getResources()
.getI18NString("service.gui.avatar.imagepicker.CHOOSE_FILE"));
this.selectFileButton.addActionListener(this);
this.selectFileButton.setName("selectFileButton");
- this.webcamButton = new JButton(GuiActivator.getResources()
+ this.webcamButton = new JButton(DesktopUtilActivator.getResources()
.getI18NString("service.gui.avatar.imagepicker.TAKE_PHOTO"));
this.webcamButton.addActionListener(this);
@@ -146,8 +145,9 @@ public class ImagePickerDialog
else if (name.equals("selectFileButton"))
{
SipCommFileChooser chooser = GenericFileDialog.create(
- GuiActivator.getUIService().getMainFrame(),
- GuiActivator.getResources().getI18NString(
+ //GuiActivator.getUIService().getMainFrame(),
+ null,
+ DesktopUtilActivator.getResources().getI18NString(
"service.gui.avatar.imagepicker.CHOOSE_FILE"),
SipCommFileChooser.LOAD_FILE_OPERATION);
@@ -217,7 +217,7 @@ public class ImagePickerDialog
@Override
public String getDescription()
{
- return GuiActivator.getResources()
+ return DesktopUtilActivator.getResources()
.getI18NString("service.gui.avatar.imagepicker.IMAGE_FILES");
}
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/presence/avatar/imagepicker/WebcamDialog.java b/src/net/java/sip/communicator/plugin/desktoputil/presence/avatar/imagepicker/WebcamDialog.java
index a72f13d..ed4a8ba 100644
--- a/src/net/java/sip/communicator/impl/gui/main/presence/avatar/imagepicker/WebcamDialog.java
+++ b/src/net/java/sip/communicator/plugin/desktoputil/presence/avatar/imagepicker/WebcamDialog.java
@@ -4,7 +4,7 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
-package net.java.sip.communicator.impl.gui.main.presence.avatar.imagepicker;
+package net.java.sip.communicator.plugin.desktoputil.presence.avatar.imagepicker;
import java.awt.*;
import java.awt.event.*;
@@ -12,10 +12,8 @@ import java.awt.image.*;
import javax.swing.*;
-import net.java.sip.communicator.impl.gui.*;
-import net.java.sip.communicator.util.*;
import net.java.sip.communicator.plugin.desktoputil.*;
-import net.java.sip.communicator.plugin.desktoputil.TransparentPanel;
+import net.java.sip.communicator.util.*;
import org.jitsi.service.audionotifier.*;
import org.jitsi.service.neomedia.*;
@@ -51,7 +49,7 @@ public class WebcamDialog
public WebcamDialog(ImagePickerDialog parent)
{
super(false);
- this.setTitle(GuiActivator.getResources()
+ this.setTitle(DesktopUtilActivator.getResources()
.getI18NString("service.gui.avatar.imagepicker.TAKE_PHOTO"));
this.setModal(true);
@@ -66,13 +64,13 @@ public class WebcamDialog
private void init()
{
this.grabSnapshot = new JButton();
- this.grabSnapshot.setText(GuiActivator.getResources()
+ this.grabSnapshot.setText(DesktopUtilActivator.getResources()
.getI18NString("service.gui.avatar.imagepicker.CLICK"));
this.grabSnapshot.setName("grab");
this.grabSnapshot.addActionListener(this);
this.grabSnapshot.setEnabled(false);
- JButton cancelButton = new JButton(GuiActivator.getResources()
+ JButton cancelButton = new JButton(DesktopUtilActivator.getResources()
.getI18NString("service.gui.avatar.imagepicker.CANCEL"));
cancelButton.setName("cancel");
cancelButton.addActionListener(this);
@@ -120,7 +118,7 @@ public class WebcamDialog
private void initAccessWebcam()
{
//Call the method in the media service
- MediaService mediaService = GuiActivator.getMediaService();
+ MediaService mediaService = DesktopUtilActivator.getMediaService();
this.videoContainer
= (Component)
@@ -174,10 +172,10 @@ public class WebcamDialog
*/
private void playSound()
{
- String soundKey = GuiActivator.getResources()
+ String soundKey = DesktopUtilActivator.getResources()
.getSoundPath("WEBCAM_SNAPSHOT");
- SCAudioClip audio = GuiActivator.getAudioNotifier()
+ SCAudioClip audio = DesktopUtilActivator.getAudioNotifier()
.createAudio(soundKey);
audio.play();
diff --git a/src/net/java/sip/communicator/plugin/spellcheck/LanguageMenuBar.java b/src/net/java/sip/communicator/plugin/spellcheck/LanguageMenuBar.java
index 2bdf423..a79b535 100644
--- a/src/net/java/sip/communicator/plugin/spellcheck/LanguageMenuBar.java
+++ b/src/net/java/sip/communicator/plugin/spellcheck/LanguageMenuBar.java
@@ -261,6 +261,11 @@ public class LanguageMenuBar
}
+ public void setCurrentAccountID(AccountID account)
+ {
+
+ }
+
private static ImageIcon getLocaleIcon(Parameters.Locale locale,
boolean isAvailable)
{
diff --git a/src/net/java/sip/communicator/service/gui/AbstractPluginComponent.java b/src/net/java/sip/communicator/service/gui/AbstractPluginComponent.java
index fd6ab6c..c5ec1da 100644
--- a/src/net/java/sip/communicator/service/gui/AbstractPluginComponent.java
+++ b/src/net/java/sip/communicator/service/gui/AbstractPluginComponent.java
@@ -106,6 +106,13 @@ public abstract class AbstractPluginComponent
{
}
+ /*
+ * Implements PluginComponent#setCurrentAccountID(AccountID).
+ */
+ public void setCurrentAccountID(AccountID accountID)
+ {
+ }
+
/**
* Returns the factory that has created the component.
* @return the parent factory.
diff --git a/src/net/java/sip/communicator/service/gui/Container.java b/src/net/java/sip/communicator/service/gui/Container.java
index 03434fb..a493d86 100644
--- a/src/net/java/sip/communicator/service/gui/Container.java
+++ b/src/net/java/sip/communicator/service/gui/Container.java
@@ -72,6 +72,12 @@ public class Container
= new Container("CONTAINER_CONTACT_RIGHT_BUTTON_MENU");
/**
+ * Accounts window "right button menu" over an account.
+ */
+ public static final Container CONTAINER_ACCOUNT_RIGHT_BUTTON_MENU
+ = new Container("CONTAINER_ACCOUNT_RIGHT_BUTTON_MENU");
+
+ /**
* Main application window "right button menu" over a group container.
*/
public static final Container CONTAINER_GROUP_RIGHT_BUTTON_MENU
diff --git a/src/net/java/sip/communicator/service/gui/PluginComponent.java b/src/net/java/sip/communicator/service/gui/PluginComponent.java
index 3d039f3..f1984cf 100644
--- a/src/net/java/sip/communicator/service/gui/PluginComponent.java
+++ b/src/net/java/sip/communicator/service/gui/PluginComponent.java
@@ -21,6 +21,11 @@ import net.java.sip.communicator.service.protocol.*;
* implement the <tt>setCurrentContact</tt> and
* <tt>setCurrentContactGroup</tt> methods.
* <p>
+ * <p>
+ * All components interested in the current account that they're dealing
+ * with (i.g. the one selected in the account list for example), should
+ * implement the <tt>setCurrentAccountID</tt> method.
+ * <p>
* Note that <tt>getComponent</tt> should return a valid AWT, SWT or Swing
* control in order to appear properly in the GUI.
*
@@ -77,6 +82,16 @@ public interface PluginComponent
public void setCurrentContactGroup(MetaContactGroup metaGroup);
/**
+ * Sets the current AccountID. Meant to be used by plugin components that are
+ * interested in the current AccountID. The current AccountID could be that
+ * of a currently selected account in the account list. It depends on the
+ * container, where this component is meant to be added.
+ *
+ * @param account the current account.
+ */
+ public void setCurrentAccountID(AccountID accountID);
+
+ /**
* Returns the factory that has created the component.
* @return the parent factory.
*/
diff --git a/src/net/java/sip/communicator/service/protocol/AbstractOperationSetAvatar.java b/src/net/java/sip/communicator/service/protocol/AbstractOperationSetAvatar.java
index f997238..7f1e192 100644
--- a/src/net/java/sip/communicator/service/protocol/AbstractOperationSetAvatar.java
+++ b/src/net/java/sip/communicator/service/protocol/AbstractOperationSetAvatar.java
@@ -107,6 +107,7 @@ public abstract class AbstractOperationSetAvatar<T extends ProtocolProviderServi
this.accountInfoOpSet.addDetail(newDetail);
else
this.accountInfoOpSet.replaceDetail(oldDetail, newDetail);
+ accountInfoOpSet.save();
} catch (OperationFailedException e)
{
logger.warn("Unable to set new avatar", e);
diff --git a/src/net/java/sip/communicator/service/protocol/OperationSetServerStoredAccountInfo.java b/src/net/java/sip/communicator/service/protocol/OperationSetServerStoredAccountInfo.java
index 3b859c6..82f281c 100644
--- a/src/net/java/sip/communicator/service/protocol/OperationSetServerStoredAccountInfo.java
+++ b/src/net/java/sip/communicator/service/protocol/OperationSetServerStoredAccountInfo.java
@@ -116,6 +116,18 @@ public interface OperationSetServerStoredAccountInfo
Class<? extends GenericDetail> detailClass);
/**
+ * Determines whether the underlying implementation supports edition
+ * of this detail class.
+ * <p>
+ * @param detailClass the class whose edition we'd like to determine if it's
+ * possible
+ * @return true if the underlying implementation supports edition of this
+ * type of detail and false otherwise.
+ */
+ public boolean isDetailClassEditable(
+ Class<? extends GenericDetail> detailClass);
+
+ /**
* The method returns the number of instances supported for a particular
* detail type. Some protocols offer storing mutliple values for a
* particular detail type. Spoken languages are a good example.
@@ -128,7 +140,7 @@ public interface OperationSetServerStoredAccountInfo
Class<? extends GenericDetail> detailClass);
/**
- * Adds the specified detail to the list of details registered on-line
+ * Adds the specified detail to the list of details ready to be saved online
* for this account. If such a detail already exists its max instance number
* is consulted and if it allows it - a second instance is added or otherwise
* and illegal argument exception is thrown. An IllegalArgumentException is
@@ -139,11 +151,9 @@ public interface OperationSetServerStoredAccountInfo
* @param detail the detail that we'd like registered on the server.
* <p>
* @throws IllegalArgumentException if such a detail already exists and its
- * max instances number has been atteined or if the underlying
+ * max instances number has been attained or if the underlying
* implementation does not support setting details of the corresponding
* class.
- * @throws OperationFailedException with code Network Failure if putting the
- * new value online has failed
* @throws java.lang.ArrayIndexOutOfBoundsException if the number of
* instances currently registered by the application is already equal to the
* maximum number of supported instances (@see getMaxDetailInstances())
@@ -154,15 +164,13 @@ public interface OperationSetServerStoredAccountInfo
ArrayIndexOutOfBoundsException;
/**
- * Removes the specified detail from the list of details stored online for
- * this account. The method returns a boolean indicating if such a detail
- * was found (and removed) or not.
+ * Removes the specified detail from the list of details ready to be saved
+ * online this account. The method returns a boolean indicating if such a
+ * detail was found (and removed) or not.
* <p>
* @param detail the detail to remove
* @return true if the specified detail existed and was successfully removed
* and false otherwise.
- * @throws OperationFailedException with code Network Failure if removing the
- * detail from the server has failed
*/
public boolean removeDetail(ServerStoredDetails.GenericDetail detail)
throws OperationFailedException;
@@ -187,6 +195,17 @@ public interface OperationSetServerStoredAccountInfo
throws ClassCastException, OperationFailedException;
/**
+ * Saves the list of details for this account that were ready to be stored
+ * online on the server. This method performs the actual saving of details
+ * online on the server and is supposed to be invoked after addDetail(),
+ * replaceDetail() and/or removeDetail().
+ * <p>
+ * @throws OperationFailedException with code Network Failure if putting the
+ * new values back online has failed.
+ */
+ public void save() throws OperationFailedException;
+
+ /**
* Registers a ServerStoredDetailsChangeListener with this operation set so
* that it gets notifications of details change.
*
diff --git a/src/net/java/sip/communicator/service/protocol/ServerStoredDetails.java b/src/net/java/sip/communicator/service/protocol/ServerStoredDetails.java
index 4002e18..16b7e01 100644
--- a/src/net/java/sip/communicator/service/protocol/ServerStoredDetails.java
+++ b/src/net/java/sip/communicator/service/protocol/ServerStoredDetails.java
@@ -306,6 +306,12 @@ public class ServerStoredDetails
{
super("Country", locale);
}
+
+ public CountryDetail(String country)
+ {
+ super("Country", null);
+ value = country;
+ }
}
/**
@@ -317,6 +323,11 @@ public class ServerStoredDetails
{
super(locale);
}
+
+ public WorkCountryDetail(String country)
+ {
+ super(country);
+ }
}
//-------------------------------- Language ------------------------------------
@@ -447,6 +458,43 @@ public class ServerStoredDetails
{
return (URL)getDetailValue();
}
+
+ /**
+ * Compares two URLDetails according their name
+ * and URLs
+ *
+ * @param obj Object expected URLDetail otherwise return false
+ * @return <tt>true</tt> if this object has the same name and
+ * URL value as <tt>obj</tt> and false otherwise
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (!(obj instanceof URLDetail))
+ return false;
+
+ if (this == obj)
+ {
+ return true;
+ }
+
+ URLDetail other = (URLDetail)obj;
+ boolean equalsDisplayName =
+ this.detailDisplayName != null
+ && other.getDetailDisplayName() != null
+ && this.detailDisplayName.equals(other.getDetailDisplayName());
+ boolean equalValues =
+ this.value != null
+ && other.getDetailValue() != null
+ && this.value.equals(other.getDetailValue());
+
+ boolean bothNullValues =
+ this.value == null && other.value == null;
+ if (equalsDisplayName && (equalValues || bothNullValues))
+ return true;
+ else
+ return false;
+ }
}
/**
@@ -487,6 +535,44 @@ public class ServerStoredDetails
{
return (byte[])getDetailValue();
}
+
+ /**
+ * Compares two BinaryDetails according their DetailDisplayName
+ * and the result of invoking their getBytes() methods.
+ *
+ * @param obj Object expected BinaryDetail otherwise return false
+ * @return <tt>true</tt> if this object has the same display name and
+ * value as <tt>obj</tt> and false otherwise
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (!(obj instanceof BinaryDetail))
+ return false;
+
+ if (this == obj)
+ {
+ return true;
+ }
+
+ BinaryDetail other = (BinaryDetail)obj;
+ boolean equalsDisplayName =
+ this.detailDisplayName != null
+ && other.getDetailDisplayName() != null
+ && this.detailDisplayName.equals(other.getDetailDisplayName());
+ boolean equalsNotNull =
+ this.value != null
+ && other.getDetailValue() != null
+ && Arrays.equals(this.getBytes(), other.getBytes());
+ boolean nullOrEmpty =
+ (this.value == null || this.getBytes().length == 0)
+ && (other.getDetailValue() == null
+ || other.getBytes().length == 0);
+ if (equalsDisplayName && (equalsNotNull || nullOrEmpty))
+ return true;
+ else
+ return false;
+ }
}
/**
@@ -641,6 +727,48 @@ public class ServerStoredDetails
{
super("Birth Date", date);
}
+
+ /**
+ * Compares two BirthDateDetails according to their
+ * Calender's year, month and day.
+ *
+ * @param obj Object expected BirthDateDetail otherwise return false
+ * @return <tt>true</tt> if this object has the same value as
+ * <tt>obj</tt> and false otherwise
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if(!(obj instanceof BirthDateDetail))
+ return false;
+
+ if(this == obj)
+ {
+ return true;
+ }
+
+ BirthDateDetail other = (BirthDateDetail)obj;
+
+ // both null dates
+ if (this.value == null && other.getDetailValue() == null)
+ return true;
+
+ if (this.value != null && other.getDetailValue() != null)
+ {
+ boolean yearEquals =
+ ((Calendar)this.value).get(Calendar.YEAR) ==
+ ((Calendar)other.value).get(Calendar.YEAR);
+ boolean monthEquals =
+ ((Calendar)this.value).get(Calendar.MONTH) ==
+ ((Calendar)other.value).get(Calendar.MONTH);
+ boolean dayEquals =
+ ((Calendar)this.value).get(Calendar.DAY_OF_MONTH) ==
+ ((Calendar)other.value).get(Calendar.DAY_OF_MONTH);
+ return yearEquals && monthEquals && dayEquals;
+ }
+ else
+ return false;
+ }
}
/**
@@ -747,4 +875,27 @@ public class ServerStoredDetails
return ((Boolean)getDetailValue()).booleanValue();
}
}
+
+//---------------------------- Others ------------------------------------------
+ /**
+ * A job title.
+ */
+ public static class JobTitleDetail extends StringDetail
+ {
+ public JobTitleDetail(String jobTitle)
+ {
+ super("Job Title", jobTitle);
+ }
+ }
+
+ /**
+ * Represents a (personal) "about me" short description.
+ */
+ public static class AboutMeDetail extends StringDetail
+ {
+ public AboutMeDetail(String description)
+ {
+ super("Description", description);
+ }
+ }
}