/*
* Gamer's Own Instant Messenger
* Copyright (C) 2005-2006 Herbert Poul (kahless@sphene.net)
* http://goim.sphene.net
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package net.sphene.goim.rcp;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import net.sphene.goim.rcp.beans.GOIMAbstractListEvent;
import net.sphene.goim.rcp.beans.GOIMAccount;
import net.sphene.goim.rcp.beans.GOIMAccountList;
import net.sphene.goim.rcp.beans.GameStatusChangeEvent;
import net.sphene.goim.rcp.beans.IGOIMPreferenceObject;
import net.sphene.goim.rcp.extensionpoints.IContactListView;
import net.sphene.goim.rcp.extensionpoints.IconSetExtensionPoint;
import net.sphene.goim.rcp.preferences.PreferenceConstants;
import net.sphene.goim.rcp.sniffer.GOIMSniffUdpConns;
import net.sphene.goim.rcp.ui.GOIMIcons;
import net.sphene.goim.rcp.ui.actions.StartFirstStartWizard;
import net.sphene.goim.rcp.ui.menu.GOIMGlobalMenu;
import net.sphene.goim.rcp.xmpp.StatusChangedEvent;
import net.sphene.libs.SpheneEvent;
import net.sphene.libs.SpheneListener;
import net.sphene.libs.SpheneListenerList;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialogWithToggle;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceStore;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tray;
import org.eclipse.swt.widgets.TrayItem;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IViewReference;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.util.StringUtils;
import org.osgi.framework.BundleContext;
/**
* The main plugin class to be used in the desktop.
*/
public class GOIMPlugin extends AbstractUIPlugin {
static Logger logger = Logger.getLogger(GOIMPlugin.class.getName());
public static final String ID = "net.sphene.goim.rcp";
public static final String goimSiteURL = "http://goim.us";
public static final String goimSiteURLhelp = goimSiteURL + "/wiki/show/HelpContents";
public static final String goimSiteURLreportBug = "http://goim.us/inosit2tracker/post";
public static final String goimSiteURLrequestFeature = "http://goim.us/inosit2tracker/post";
public static final String defaultSearchService = "users.jabber.org";
public static final String defaultGOIMroom = "goim@conference.sphene.net";
public static final String LINESEPARATOR = System.getProperty("line.separator");
//The shared instance.
private static GOIMPlugin plugin;
private static FormToolkit formToolkit;
private static Map<String,IGOIMPreferenceObject> parsedPreferenceObjects = new HashMap<String,IGOIMPreferenceObject>();
public static SpheneListenerList<GameStatusChangeEvent,SpheneListener<GameStatusChangeEvent>> gameStatusChanged = new SpheneListenerList<GameStatusChangeEvent,SpheneListener<GameStatusChangeEvent>>();
@SuppressWarnings("unused")
private GOIMSniffUdpConns goimUdpSniffer;
private IContactListView registeredContactListOfAllAccounts;
private HashMap<GOIMAccount,IContactListView> registeredContactLists = new HashMap<GOIMAccount,IContactListView>();
private IPropertyChangeListener propertyChangeListener;
private SpheneListener<SpheneEvent> accountListChangeListener;
private TrayItem trayItem;
private static int contactListCounter = 0;
/**
* The constructor.
*/
public GOIMPlugin() {
plugin = this;
}
public boolean registerContactListOfAllAccounts(IContactListView part) {
if(registeredContactListOfAllAccounts != null) return false;
registeredContactListOfAllAccounts = part;
return true;
}
public boolean unregisterContactListOfAllAccounts(IContactListView part) {
if(registeredContactListOfAllAccounts != part) return false;
registeredContactListOfAllAccounts = null;
return true;
}
public boolean registerContactList(GOIMAccount account, IContactListView part) {
if(registeredContactLists.containsKey(account)) return false;
logger.finer("registerContactList: " + account.name);
registeredContactLists.put(account,part);
return true;
}
public boolean unregisterContactList(GOIMAccount account, IContactListView part) {
if(registeredContactLists.get(account) != part) return false;
registeredContactLists.remove(account);
return true;
}
public IContactListView getContactList(GOIMAccount account) {
IContactListView contactList = registeredContactLists.get(account);
if(contactList != null) return contactList;
return registeredContactListOfAllAccounts;
}
public IViewPart openContactList(final String viewid) {
IWorkbenchWindow window_ = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if(window_ == null) window_ = PlatformUI.getWorkbench().getWorkbenchWindows()[0];
final IWorkbenchWindow window = window_;
try {
IWorkbenchPage page = window.getActivePage();
if(page == null) page = window.getPages()[0];
return page.showView(viewid,Long.toString(System.currentTimeMillis() + ++contactListCounter),IWorkbenchPage.VIEW_ACTIVATE);
} catch (PartInitException e) {
e.printStackTrace();
}
return null;
}
public void openContactList(final String viewid, final GOIMAccount account) {
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { public void run() {
IViewPart part = openContactList(viewid);
if(part instanceof IContactListView)
((IContactListView)part).initWithAccount(account);
}});
}
void openRemainingContactLists() {
IPreferenceStore store = getMyPreferenceStore();
final GOIMAccountList accountList = getPreferenceObject(GOIMAccountList.class);
if(store.getBoolean(PreferenceConstants.P_CONTACTLIST_AUTOOPEN)) {
String viewid = store.getString(PreferenceConstants.P_CONTACTLIST);
if(!store.getBoolean(PreferenceConstants.P_CONTACTLIST_ALLACCOUNTS)) {
for(GOIMAccount account : accountList) {
if(!registeredContactLists.containsKey(account))
openContactList(viewid,account);
}
} else {
if(registeredContactListOfAllAccounts == null && accountList.size() > 0) {
IViewPart part = openContactList(viewid);
if(part instanceof IContactListView)
((IContactListView)part).initWithAccountList(accountList);
}
}
}
if(accountListChangeListener == null)
accountList.addChangeListener(accountListChangeListener = new SpheneListener<SpheneEvent>(){
public void handleEvent(SpheneEvent event_) {
GOIMAbstractListEvent event = (GOIMAbstractListEvent)event_;
if(event.type == GOIMAbstractListEvent.TYPE_ADD)
openRemainingContactLists();
// if(getMyPreferenceStore().getBoolean(PreferenceConstants.P_CONTACTLIST_AUTOOPEN) &&
// !getMyPreferenceStore().getBoolean(PreferenceConstants.P_CONTACTLIST_ALLACCOUNTS))
// openContactList(getMyPreferenceStore().getString(PreferenceConstants.P_CONTACTLIST),(GOIMAccount)event.source);
}});
if(propertyChangeListener == null)
store.addPropertyChangeListener(propertyChangeListener = new IPropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
logger.finest("Property changed: " + event.getProperty());
if(accountList.size() > 0 && getMyPreferenceStore().getBoolean(PreferenceConstants.P_CONTACTLIST_AUTOOPEN)) {
if(event.getProperty().equals(PreferenceConstants.P_CONTACTLIST)) {
int code = -1;
if(getMyPreferenceStore().getString(PreferenceConstants.P_CONTACTLIST_CHANGED_OPEN).equals("")) {
MessageDialogWithToggle dialog = MessageDialogWithToggle.openYesNoQuestion(
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
"Reopen ContactList",
"You have changed the default ContactList. - Do you want to close all contact lists and start the selected ?",
null,
false,
getMyPreferenceStore(),
PreferenceConstants.P_CONTACTLIST_CHANGED_OPEN);
code = dialog.getReturnCode();
} else {
if(getMyPreferenceStore().getString(PreferenceConstants.P_CONTACTLIST_CHANGED_OPEN).equals(MessageDialogWithToggle.ALWAYS))
code = IDialogConstants.YES_ID;
else
code = IDialogConstants.NO_ID;
}
if(code != IDialogConstants.YES_ID) return;
if(getMyPreferenceStore().getBoolean(PreferenceConstants.P_CONTACTLIST_ALLACCOUNTS)) {
registeredContactListOfAllAccounts.closeContactList();
} else {
for(IContactListView view : registeredContactLists.values()) {
view.closeContactList();
}
}
openRemainingContactLists();
} else if(event.getProperty().equals(PreferenceConstants.P_CONTACTLIST_ALLACCOUNTS)) {
int code = -1;
if(getMyPreferenceStore().getString(PreferenceConstants.P_CONTACTLIST_CHANGED_OPEN).equals("")) {
MessageDialogWithToggle dialog = MessageDialogWithToggle.openYesNoQuestion(
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
"Reopen ContactList",
"You have changed the behaviour of the ContactList. - Do you want to close all contact lists and apply the changes?",
null,
false,
getMyPreferenceStore(),
PreferenceConstants.P_CONTACTLIST_CHANGED_OPEN);
code = dialog.getReturnCode();
} else {
if(getMyPreferenceStore().getString(PreferenceConstants.P_CONTACTLIST_CHANGED_OPEN).equals(MessageDialogWithToggle.ALWAYS))
code = IDialogConstants.YES_ID;
else
code = IDialogConstants.NO_ID;
}
if(code != IDialogConstants.YES_ID) return;
boolean oldval;
if(event.getOldValue() != null)
oldval = (Boolean)event.getOldValue();
else
oldval = !getMyPreferenceStore().getBoolean(PreferenceConstants.P_CONTACTLIST_ALLACCOUNTS);
if(oldval) {
registeredContactListOfAllAccounts.closeContactList();
} else {
List<IContactListView> contactLists = new ArrayList<IContactListView>(registeredContactLists.values());
for(IContactListView view : contactLists) {
view.closeContactList();
}
}
openRemainingContactLists();
}
}
} });
}
/**
* This method is called upon plug-in activation
*/
public void start(BundleContext context) throws Exception {
super.start(context);
logger.finest("GOIMPlugin.start");
IconSetExtensionPoint.getIconSetExtensions();
if(getMyPreferenceStore().getBoolean(PreferenceConstants.P_STARTSNIFFER)) {
try {
goimUdpSniffer = new GOIMSniffUdpConns();
goimUdpSniffer.go();
} catch(UnsatisfiedLinkError e) {
// ignore ...
}
}
}
/**
* This method is called when the plug-in is stopped
*/
public void stop(BundleContext context) throws Exception {
super.stop(context);
plugin = null;
}
/**
* Returns the shared instance.
*/
public static GOIMPlugin getDefault() {
return plugin;
}
//PreferenceStore mystore = null;
public IPreferenceStore getMyPreferenceStore() {
try {
String baseDir = FileLocator.resolve(Platform.getInstanceLocation().getURL()).getFile();
String prefs = baseDir + ".metadata/.plugins/org.eclipse.core.runtime/.settings/net.sphene.goim.rcp.prefs";
PreferenceStore store = new PreferenceStore(prefs);
store.load();
} catch (IOException e) {
// Ignoring for now .. because the first start would always throw this exception.
//e.printStackTrace();
}
return super.getPreferenceStore();
}
@SuppressWarnings("unchecked")
public static synchronized <T extends IGOIMPreferenceObject> T getPreferenceObject(Class<T> cls) {
String key = cls.getName();
IGOIMPreferenceObject obj = parsedPreferenceObjects.get(key);
if(obj != null) return (T)obj;
IPreferenceStore preferenceStore = getDefault().getMyPreferenceStore();
String str = preferenceStore.getString(key);
if(!str.equals("")) {
byte[] bytes = StringUtils.decodeBase64(str);
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
try {
ObjectInputStream in = new ObjectInputStream(inputStream);
Object bobj = in.readObject();
in.close();
if(bobj instanceof IGOIMPreferenceObject) obj = (IGOIMPreferenceObject)bobj;
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
if(obj == null) {
try {
obj = cls.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
parsedPreferenceObjects.put(key,obj);
final Class saveCls = cls;
obj.addChangeListener(new SpheneListener<SpheneEvent>(){
public void handleEvent(SpheneEvent event) {
//saveAccountList();
savePreferenceObject(saveCls);
}});
return (T)obj;
}
public static synchronized void savePreferenceObject(Class<? extends IGOIMPreferenceObject> cls) {
String key = cls.getName();
IGOIMPreferenceObject obj = parsedPreferenceObjects.get(key);
if(obj == null) return;
IPreferenceStore preferenceStore = getDefault().getPreferenceStore();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try {
ObjectOutputStream out = new ObjectOutputStream(outputStream);
out.writeObject(obj);
out.flush();
out.close();
outputStream.close();
String str = StringUtils.encodeBase64(outputStream.toByteArray());
preferenceStore.setValue(key,str);
logger.finest("Saved key: " + key + " value: " + str);
} catch (IOException e) {
e.printStackTrace();
}
}
public static synchronized GOIMAccountList getAccountList() {
return getPreferenceObject(GOIMAccountList.class);
}
public static void saveAccountList() {
savePreferenceObject(GOIMAccountList.class);
}
/**
* Returns an image descriptor for the image file at the given
* plug-in relative path.
*
* @param path the path
* @return the image descriptor
*/
public static ImageDescriptor getImageDescriptor(String path) {
return AbstractUIPlugin.imageDescriptorFromPlugin("net.sphene.goim.rcp", path);
}
public static FormToolkit getFormToolkit(Display display) {
if(formToolkit == null) formToolkit = new FormToolkit(display);
return formToolkit;
}
public TrayItem getTrayItem() { return trayItem; }
public void openTrayIcon() {
final Tray tray = PlatformUI.getWorkbench().getDisplay().getSystemTray();
if(tray == null) {
logger.finest("System tray not available."); return;
}
trayItem = new TrayItem(tray,SWT.NONE);
trayItem.setToolTipText("Gamers Own Instant Messenger");
trayItem.setImage(GOIMIcons.getImage(GOIMIcons.TRAY_ICON_DEFAULT));
final MenuManager trayMenu = new MenuManager("TrayMenu");
trayMenu.createContextMenu(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell());
trayMenu.add(new StartFirstStartWizard());
// MenuItem exit = new MenuItem(trayMenu,SWT.PUSH);
// exit.setText("Exit");
//
// exit.addListener(SWT.Selection,new Listener() {
// public void handleEvent(Event event) {
// PlatformUI.getWorkbench().close();
// }
// });
GOIMGlobalMenu globalMenu = new GOIMGlobalMenu(trayMenu);
globalMenu.createDefaultMenuItems(trayMenu);
trayItem.addListener(SWT.MenuDetect,new Listener() {
public void handleEvent(Event event) {
trayMenu.setVisible(true);
}
});
trayItem.addListener(SWT.DefaultSelection,new Listener() {
public void handleEvent(Event event) {
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
shell.setVisible(true);
shell.setMinimized(false);
shell.forceActive();
shell.forceFocus();
}});
trayItem.addListener(SWT.Selection,new Listener() {
public void handleEvent(Event event) {
Boolean makeVisible = null;
IWorkbenchWindow[] windows = PlatformUI.getWorkbench().getWorkbenchWindows();
for(IWorkbenchWindow window : windows) {
boolean containsOnlyContactList = true;
IWorkbenchPage[] pages = window.getPages();
lookForContactList:
for(IWorkbenchPage page : pages) {
IViewReference[] refs = page.getViewReferences();
for(IViewReference ref : refs) {
if(!(ref.getView(false) instanceof IContactListView)) {
containsOnlyContactList = false;
break lookForContactList;
}
}
}
if(containsOnlyContactList) {
Shell shell = window.getShell();
if(makeVisible == null)
makeVisible = !shell.getVisible();
shell.setVisible(makeVisible);
if(makeVisible.booleanValue()) {
shell.setMinimized(false);
shell.forceActive();
shell.forceFocus();
}
}
}
// Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
// boolean visible = !shell.getVisible();
// shell.setVisible(visible);
// if(visible) {
// shell.setMinimized(false);
// shell.forceActive();
// shell.forceFocus();
// }
}});
// register listener to handle menu requests
trayItem.addListener(SWT.MenuDetect, new Listener() {
public void handleEvent(Event event) {
Shell hiddenShell = new Shell(trayItem.getDisplay());
Menu menu = trayMenu.createContextMenu(hiddenShell);
menu.setLocation(trayItem.getDisplay().getCursorLocation());
menu.setVisible(true);
}
});
trayItem.addListener(SWT.MouseDown,new Listener() {
public void handleEvent(Event event) {
if(event.button == 3) {
logger.finest("second");
}
} });
GOIMAccountList list = getAccountList();
final SpheneListener<StatusChangedEvent> presenceListener = new SpheneListener<StatusChangedEvent>() {
public void handleEvent(StatusChangedEvent event) {
tray.getDisplay().asyncExec(new Runnable() {
public void run() {
trayItem.setImage(GOIMIcons.getImageForPresence(null,getGlobalPresence()));
}
});
}
};
for(GOIMAccount account : list)
account.xmpp.ownPresenceChanged.addListener(presenceListener);
list.addChangeListener(new SpheneListener<SpheneEvent>() {
public void handleEvent(SpheneEvent event_) {
GOIMAbstractListEvent event = (GOIMAbstractListEvent)event_;
switch(event.type) {
case GOIMAbstractListEvent.TYPE_ADD:
((GOIMAccount)event.source).xmpp.ownPresenceChanged.addListener(presenceListener);
break;
case GOIMAbstractListEvent.TYPE_DEL:
((GOIMAccount)event.source).xmpp.ownPresenceChanged.removeListener(presenceListener);
}
} });
}
public Presence getGlobalPresence() { // TODO improve this method :)
GOIMAccountList list = getAccountList();
Presence leastpresence = null;
for(GOIMAccount account : list) {
Presence p = account.xmpp.getOwnPresence();
if(p == null) return null;
if(leastpresence == null)
leastpresence = p;
else if(leastpresence.getType() == Presence.Type.AVAILABLE)
leastpresence = p;
}
return leastpresence;
}
}