Files reorganisation
This commit is contained in:
parent
c8b5f1db90
commit
e4452c4b03
1 changed files with 10 additions and 8 deletions
498
frontends/src/wix/main_window.py
Normal file
498
frontends/src/wix/main_window.py
Normal file
|
|
@ -0,0 +1,498 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
wix: a SAT frontend
|
||||
Copyright (C) 2009, 2010 Jérôme Poisson (goffi@goffi.org)
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
|
||||
from quick_frontend.quick_chat_list import QuickChatList
|
||||
from quick_frontend.quick_app import QuickApp
|
||||
from quick_frontend.quick_contact_management import QuickContactManagement
|
||||
import wx
|
||||
from contact_list import ContactList
|
||||
from chat import Chat
|
||||
from param import Param
|
||||
from xmlui import XMLUI
|
||||
from gateways import GatewaysManager
|
||||
from profile import Profile
|
||||
from profile_manager import ProfileManager
|
||||
import gobject
|
||||
import os.path
|
||||
import pdb
|
||||
from tools.jid import JID
|
||||
from logging import debug, info, warning, error
|
||||
import constants
|
||||
|
||||
idCONNECT,\
|
||||
idDISCONNECT,\
|
||||
idEXIT,\
|
||||
idABOUT,\
|
||||
idPARAM,\
|
||||
idADD_CONTACT,\
|
||||
idREMOVE_CONTACT,\
|
||||
idSHOW_PROFILE,\
|
||||
idJOIN_ROOM,\
|
||||
idFIND_GATEWAYS = range(10)
|
||||
|
||||
class ChatList(QuickChatList):
|
||||
"""This class manage the list of chat windows"""
|
||||
|
||||
def __init__(self, host):
|
||||
QuickChatList.__init__(self, host)
|
||||
|
||||
def createChat(self, target):
|
||||
return Chat(target, self.host)
|
||||
|
||||
class MainWindow(wx.Frame, QuickApp):
|
||||
"""main app window"""
|
||||
|
||||
def __init__(self):
|
||||
wx.Frame.__init__(self,None, title="SàT Wix", size=(300,500))
|
||||
self.CM = QuickContactManagement() #FIXME: not the best place
|
||||
|
||||
#sizer
|
||||
self.sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
self.SetSizer(self.sizer)
|
||||
|
||||
#Frame elements
|
||||
self.contactList = ContactList(self, self)
|
||||
self.contactList.registerActivatedCB(self.onContactActivated)
|
||||
self.contactList.Hide()
|
||||
self.sizer.Add(self.contactList, 1, flag=wx.EXPAND)
|
||||
|
||||
self.chat_wins=ChatList(self)
|
||||
self.CreateStatusBar()
|
||||
|
||||
#ToolBar
|
||||
self.tools=self.CreateToolBar()
|
||||
self.statusBox = wx.ComboBox(self.tools, -1, "Online", choices=[status[1] for status in const_STATUS],
|
||||
style=wx.CB_DROPDOWN | wx.CB_READONLY)
|
||||
self.tools.AddControl(self.statusBox)
|
||||
self.tools.AddSeparator()
|
||||
self.statusTxt=wx.TextCtrl(self.tools, -1, style = wx.TE_PROCESS_ENTER)
|
||||
self.tools.AddControl(self.statusTxt)
|
||||
self.Bind(wx.EVT_COMBOBOX, self.onStatusChange, self.statusBox)
|
||||
self.Bind(wx.EVT_TEXT_ENTER, self.onStatusChange, self.statusTxt)
|
||||
self.tools.Disable()
|
||||
|
||||
#tray icon
|
||||
ticon = wx.Icon(IMAGE_DIR+'/crystal/tray_icon.xpm', wx.BITMAP_TYPE_XPM)
|
||||
self.tray_icon = wx.TaskBarIcon()
|
||||
self.tray_icon.SetIcon(ticon, _("Wix jabber client"))
|
||||
wx.EVT_TASKBAR_LEFT_UP(self.tray_icon, self.onTrayClick)
|
||||
|
||||
|
||||
#events
|
||||
self.Bind(wx.EVT_CLOSE, self.onClose, self)
|
||||
|
||||
|
||||
QuickApp.__init__(self)
|
||||
|
||||
#menus
|
||||
self.createMenus()
|
||||
for i in range(self.menuBar.GetMenuCount()):
|
||||
self.menuBar.EnableTop(i, False)
|
||||
|
||||
#profile panel
|
||||
self.profile_pan = ProfileManager(self)
|
||||
self.sizer.Add(self.profile_pan, 1, flag=wx.EXPAND)
|
||||
|
||||
self.postInit()
|
||||
|
||||
self.Show()
|
||||
|
||||
def plug_profile(self, profile_key='@DEFAULT@'):
|
||||
"""Hide profile panel then plug profile"""
|
||||
debug (_('plugin profile %s' % profile_key))
|
||||
self.profile_pan.Hide()
|
||||
self.contactList.Show()
|
||||
self.sizer.Layout()
|
||||
for i in range(self.menuBar.GetMenuCount()):
|
||||
self.menuBar.EnableTop(i, True)
|
||||
super(MainWindow, self).plug_profile(profile_key)
|
||||
|
||||
def createMenus(self):
|
||||
info(_("Creating menus"))
|
||||
connectMenu = wx.Menu()
|
||||
connectMenu.Append(idCONNECT, _("&Connect CTRL-c"),_(" Connect to the server"))
|
||||
connectMenu.Append(idDISCONNECT, _("&Disconnect CTRL-d"),_(" Disconnect from the server"))
|
||||
connectMenu.Append(idPARAM,_("&Parameters"),_(" Configure the program"))
|
||||
connectMenu.AppendSeparator()
|
||||
connectMenu.Append(idABOUT,_("A&bout"),_(" About %s") % APP_NAME)
|
||||
connectMenu.Append(idEXIT,_("E&xit"),_(" Terminate the program"))
|
||||
contactMenu = wx.Menu()
|
||||
contactMenu.Append(idADD_CONTACT, _("&Add contact"),_(" Add a contact to your list"))
|
||||
contactMenu.Append(idREMOVE_CONTACT, _("&Remove contact"),_(" Remove the selected contact from your list"))
|
||||
contactMenu.AppendSeparator()
|
||||
contactMenu.Append(idSHOW_PROFILE, _("&Show profile"), _(" Show contact's profile"))
|
||||
communicationMenu = wx.Menu()
|
||||
communicationMenu.Append(idJOIN_ROOM, _("&Join Room"),_(" Join a Multi-User Chat room"))
|
||||
communicationMenu.Append(idFIND_GATEWAYS, _("&Find Gateways"),_(" Find gateways to legacy IM"))
|
||||
self.menuBar = wx.MenuBar()
|
||||
self.menuBar.Append(connectMenu,_("&General"))
|
||||
self.menuBar.Append(contactMenu,_("&Contacts"))
|
||||
self.menuBar.Append(communicationMenu,_("&Communication"))
|
||||
self.SetMenuBar(self.menuBar)
|
||||
|
||||
#additionals menus
|
||||
#FIXME: do this in a more generic way (in quickapp)
|
||||
add_menus = self.bridge.getMenus()
|
||||
for menu in add_menus:
|
||||
category,item,type = menu
|
||||
assert(type=="NORMAL") #TODO: manage other types
|
||||
menu_idx = self.menuBar.FindMenu(category)
|
||||
current_menu = None
|
||||
if menu_idx == wx.NOT_FOUND:
|
||||
#the menu is new, we create it
|
||||
current_menu = wx.Menu()
|
||||
self.menuBar.Append(current_menu, category)
|
||||
else:
|
||||
current_menu = self.menuBar.GetMenu(menu_idx)
|
||||
assert(current_menu != None)
|
||||
item_id = wx.NewId()
|
||||
help_string = self.bridge.getMenuHelp(category, item, type)
|
||||
current_menu.Append(item_id, item, help = help_string)
|
||||
#now we register the event
|
||||
def event_answer(e):
|
||||
id = self.bridge.callMenu(category, item, type, self.profile)
|
||||
self.current_action_ids.add(id)
|
||||
wx.EVT_MENU(self, item_id, event_answer)
|
||||
|
||||
|
||||
#events
|
||||
wx.EVT_MENU(self, idCONNECT, self.onConnectRequest)
|
||||
wx.EVT_MENU(self, idDISCONNECT, self.onDisconnectRequest)
|
||||
wx.EVT_MENU(self, idPARAM, self.onParam)
|
||||
wx.EVT_MENU(self, idABOUT, self.onAbout)
|
||||
wx.EVT_MENU(self, idEXIT, self.onExit)
|
||||
wx.EVT_MENU(self, idADD_CONTACT, self.onAddContact)
|
||||
wx.EVT_MENU(self, idREMOVE_CONTACT, self.onRemoveContact)
|
||||
wx.EVT_MENU(self, idSHOW_PROFILE, self.onShowProfile)
|
||||
wx.EVT_MENU(self, idJOIN_ROOM, self.onJoinRoom)
|
||||
wx.EVT_MENU(self, idFIND_GATEWAYS, self.onFindGateways)
|
||||
|
||||
|
||||
def newMessage(self, from_jid, msg, type, to_jid, profile):
|
||||
QuickApp.newMessage(self, from_jid, msg, type, to_jid, profile)
|
||||
|
||||
def roomJoined(self, room_id, room_service, room_nicks, user_nick, profile):
|
||||
super(MainWindow, self).roomJoined(room_id, room_service, room_nicks, user_nick, profile)
|
||||
|
||||
def showAlert(self, message):
|
||||
# TODO: place this in a separate class
|
||||
popup=wx.PopupWindow(self)
|
||||
### following code come from wxpython demo
|
||||
popup.SetBackgroundColour("CADET BLUE")
|
||||
st = wx.StaticText(popup, -1, message, pos=(10,10))
|
||||
sz = st.GetBestSize()
|
||||
popup.SetSize( (sz.width+20, sz.height+20) )
|
||||
x=(wx.DisplaySize()[0]-popup.GetSize()[0])/2
|
||||
popup.SetPosition((x,0))
|
||||
popup.Show()
|
||||
wx.CallLater(5000,popup.Destroy)
|
||||
|
||||
def showDialog(self, message, title="", type="info", answer_cb = None, answer_data = None):
|
||||
if type == 'info':
|
||||
flags = wx.OK | wx.ICON_INFORMATION
|
||||
elif type == 'error':
|
||||
flags = wx.OK | wx.ICON_ERROR
|
||||
elif type == 'yes/no':
|
||||
flags = wx.YES_NO | wx.ICON_QUESTION
|
||||
else:
|
||||
flags = wx.OK | wx.ICON_INFORMATION
|
||||
error(_('unmanaged dialog type: %s'), type)
|
||||
dlg = wx.MessageDialog(self, message, title, flags)
|
||||
answer = dlg.ShowModal()
|
||||
dlg.Destroy()
|
||||
if answer_cb:
|
||||
data = [answer_data] if answer_data else []
|
||||
answer_cb(True if (answer == wx.ID_YES or answer == wx.ID_OK) else False, *data)
|
||||
|
||||
def setStatusOnline(self, online=True):
|
||||
"""enable/disable controls, must be called when local user online status change"""
|
||||
if online:
|
||||
self.SetStatusText(msgONLINE)
|
||||
self.tools.Enable()
|
||||
else:
|
||||
self.SetStatusText(msgOFFLINE)
|
||||
self.tools.Disable()
|
||||
return
|
||||
|
||||
def askConfirmation(self, type, id, data):
|
||||
#TODO: refactor this in QuickApp
|
||||
debug (_("Confirmation asked"))
|
||||
answer_data={}
|
||||
if type == "FILE_TRANSFERT":
|
||||
debug (_("File transfert confirmation asked"))
|
||||
dlg = wx.MessageDialog(self, _("The contact %(jid)s wants to send you the file %(filename)s\nDo you accept ?") % {'jid':data["from"], 'filename':data["filename"]},
|
||||
_('File Request'),
|
||||
wx.YES_NO | wx.ICON_QUESTION
|
||||
)
|
||||
answer=dlg.ShowModal()
|
||||
if answer==wx.ID_YES:
|
||||
filename = wx.FileSelector(_("Where do you want to save the file ?"), flags = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
|
||||
if filename:
|
||||
answer_data["dest_path"] = filename
|
||||
self.bridge.confirmationAnswer(id, True, answer_data)
|
||||
self.waitProgress(id, _("File Transfer"), _("Copying %s") % os.path.basename(filename))
|
||||
else:
|
||||
answer = wx.ID_NO
|
||||
if answer==wx.ID_NO:
|
||||
self.bridge.confirmationAnswer(id, False, answer_data)
|
||||
|
||||
dlg.Destroy()
|
||||
|
||||
elif type == "YES/NO":
|
||||
debug (_("Yes/No confirmation asked"))
|
||||
dlg = wx.MessageDialog(self, data["message"],
|
||||
_('Confirmation'),
|
||||
wx.YES_NO | wx.ICON_QUESTION
|
||||
)
|
||||
answer=dlg.ShowModal()
|
||||
if answer==wx.ID_YES:
|
||||
self.bridge.confirmationAnswer(id, True, {})
|
||||
if answer==wx.ID_NO:
|
||||
self.bridge.confirmationAnswer(id, False, {})
|
||||
|
||||
dlg.Destroy()
|
||||
|
||||
def actionResult(self, type, id, data):
|
||||
debug (_("actionResult: type = [%(type)s] id = [%(id)s] data = [%(data)s]") % {'type':type, 'id':id, 'data':data})
|
||||
if not id in self.current_action_ids:
|
||||
debug (_('unknown id, ignoring'))
|
||||
return
|
||||
if type == "SUPPRESS":
|
||||
self.current_action_ids.remove(id)
|
||||
elif type == "SUCCESS":
|
||||
self.current_action_ids.remove(id)
|
||||
dlg = wx.MessageDialog(self, data["message"],
|
||||
_('Success'),
|
||||
wx.OK | wx.ICON_INFORMATION
|
||||
)
|
||||
dlg.ShowModal()
|
||||
dlg.Destroy()
|
||||
elif type == "ERROR":
|
||||
self.current_action_ids.remove(id)
|
||||
dlg = wx.MessageDialog(self, data["message"],
|
||||
_('Error'),
|
||||
wx.OK | wx.ICON_ERROR
|
||||
)
|
||||
dlg.ShowModal()
|
||||
dlg.Destroy()
|
||||
elif type == "XMLUI":
|
||||
self.current_action_ids.remove(id)
|
||||
debug (_("XML user interface received"))
|
||||
misc = {}
|
||||
#FIXME FIXME FIXME: must clean all this crap !
|
||||
title = _('Form')
|
||||
if data['type'] == _('registration'):
|
||||
title = _('Registration')
|
||||
misc['target'] = data['target']
|
||||
misc['action_back'] = self.bridge.gatewayRegister
|
||||
XMLUI(self, title=title, xml_data = data['xml'], misc = misc)
|
||||
elif type == "RESULT":
|
||||
self.current_action_ids.remove(id)
|
||||
if self.current_action_ids_cb.has_key(id):
|
||||
callback = self.current_action_ids_cb[id]
|
||||
del self.current_action_ids_cb[id]
|
||||
callback(data)
|
||||
elif type == "DICT_DICT":
|
||||
self.current_action_ids.remove(id)
|
||||
if self.current_action_ids_cb.has_key(id):
|
||||
callback = self.current_action_ids_cb[id]
|
||||
del self.current_action_ids_cb[id]
|
||||
callback(data)
|
||||
else:
|
||||
error (_("FIXME FIXME FIXME: type [%s] not implemented") % type)
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
|
||||
def progressCB(self, id, title, message):
|
||||
data = self.bridge.getProgress(id)
|
||||
if data:
|
||||
if not self.pbar:
|
||||
#first answer, we must construct the bar
|
||||
self.pbar = wx.ProgressDialog(title, message, float(data['size']), None,
|
||||
wx.PD_SMOOTH | wx.PD_ELAPSED_TIME | wx.PD_ESTIMATED_TIME | wx.PD_REMAINING_TIME)
|
||||
self.pbar.finish_value = float(data['size'])
|
||||
|
||||
self.pbar.Update(int(data['position']))
|
||||
elif self.pbar:
|
||||
self.pbar.Update(self.pbar.finish_value)
|
||||
return
|
||||
|
||||
wx.CallLater(10, self.progressCB, id, title, message)
|
||||
|
||||
def waitProgress (self, id, title, message):
|
||||
self.pbar = None
|
||||
wx.CallLater(10, self.progressCB, id, title, message)
|
||||
|
||||
|
||||
|
||||
### events ###
|
||||
|
||||
def onContactActivated(self, jid):
|
||||
debug (_("onContactActivated: %s"), jid)
|
||||
if self.chat_wins[jid.short].IsShown():
|
||||
self.chat_wins[jid.short].Hide()
|
||||
else:
|
||||
self.chat_wins[jid.short].Show()
|
||||
|
||||
def onConnectRequest(self, e):
|
||||
self.bridge.connect(self.profile)
|
||||
|
||||
def onDisconnectRequest(self, e):
|
||||
self.bridge.disconnect(self.profile)
|
||||
|
||||
def __updateStatus(self):
|
||||
show = filter(lambda x:x[1] == self.statusBox.GetValue(), const_STATUS)[0][0]
|
||||
status = self.statusTxt.GetValue()
|
||||
self.bridge.setPresence(show=show, statuses={'default':status}, profile_key=self.profile) #FIXME: manage multilingual statuses
|
||||
|
||||
def onStatusChange(self, e):
|
||||
debug(_("Status change request"))
|
||||
self.__updateStatus()
|
||||
|
||||
def onParam(self, e):
|
||||
debug(_("Param request"))
|
||||
#xmlui = self.bridge.getParamsUI(self.profile)
|
||||
#XMLUI(self, xml_data = xmlui)
|
||||
param=Param(self)
|
||||
|
||||
def onAbout(self, e):
|
||||
about = wx.AboutDialogInfo()
|
||||
about.SetName(APP_NAME)
|
||||
about.SetVersion (unicode(self.bridge.getVersion()))
|
||||
about.SetCopyright(u"(C) 2009,2010 Jérôme Poisson aka Goffi")
|
||||
about.SetDescription( _(u"%(name)s is a SàT (Salut à Toi) frontend\n"+
|
||||
u"%(name)s is based on WxPython, and is the standard graphic interface of SàT") % {'name':APP_NAME})
|
||||
about.SetWebSite(("http://www.goffi.org", "Goffi's non-hebdo (french)"))
|
||||
about.SetDevelopers([ "Goffi (Jérôme Poisson)"])
|
||||
try:
|
||||
with open(LICENCE_PATH,"r") as licence:
|
||||
about.SetLicence(''.join(licence.readlines()))
|
||||
except:
|
||||
pass
|
||||
|
||||
wx.AboutBox(about)
|
||||
|
||||
def onExit(self, e):
|
||||
self.Close()
|
||||
|
||||
def onAddContact(self, e):
|
||||
debug(_("Add contact request"))
|
||||
dlg = wx.TextEntryDialog(
|
||||
self, _('Please enter new contact JID'),
|
||||
_('Adding a contact'), _('name@server.tld'))
|
||||
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
jid=JID(dlg.GetValue())
|
||||
if jid.is_valid():
|
||||
self.bridge.addContact(jid.short, profile_key=self.profile)
|
||||
else:
|
||||
error (_("'%s' is an invalid JID !"), jid)
|
||||
#TODO: notice the user
|
||||
|
||||
dlg.Destroy()
|
||||
|
||||
def onRemoveContact(self, e):
|
||||
debug(_("Remove contact request"))
|
||||
target = self.contactList.getSelection()
|
||||
if not target:
|
||||
dlg = wx.MessageDialog(self, _("You haven't selected any contact !"),
|
||||
_('Error'),
|
||||
wx.OK | wx.ICON_ERROR
|
||||
)
|
||||
dlg.ShowModal()
|
||||
dlg.Destroy()
|
||||
return
|
||||
|
||||
dlg = wx.MessageDialog(self, _("Are you sure you want to delete %s from your roster list ?") % target.short,
|
||||
_('Contact suppression'),
|
||||
wx.YES_NO | wx.ICON_QUESTION
|
||||
)
|
||||
|
||||
if dlg.ShowModal() == wx.ID_YES:
|
||||
info(_("Unsubscribing %s presence"), target.short)
|
||||
self.bridge.delContact(target.short, profile_key=self.profile)
|
||||
|
||||
dlg.Destroy()
|
||||
|
||||
def onShowProfile(self, e):
|
||||
debug(_("Show contact's profile request"))
|
||||
target = self.contactList.getSelection()
|
||||
if not target:
|
||||
dlg = wx.MessageDialog(self, _("You haven't selected any contact !"),
|
||||
_('Error'),
|
||||
wx.OK | wx.ICON_ERROR
|
||||
)
|
||||
dlg.ShowModal()
|
||||
dlg.Destroy()
|
||||
return
|
||||
id = self.bridge.getCard(target.short, profile_key=self.profile)
|
||||
self.current_action_ids.add(id)
|
||||
self.current_action_ids_cb[id] = self.onProfileReceived
|
||||
|
||||
def onProfileReceived(self, data):
|
||||
"""Called when a profile is received"""
|
||||
debug (_('Profile received: [%s]') % data)
|
||||
profile=Profile(self, data)
|
||||
|
||||
def onJoinRoom(self, e):
|
||||
warning('FIXME: temporary menu, must be improved')
|
||||
#TODO: a proper MUC room joining dialog with nickname etc
|
||||
dlg = wx.TextEntryDialog(
|
||||
self, _("Please enter MUC's JID"),
|
||||
#_('Entering a MUC room'), 'test@conference.necton2.int')
|
||||
_('Entering a MUC room'), 'room@muc_service.server.tld')
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
room_jid=JID(dlg.GetValue())
|
||||
if room_jid.is_valid():
|
||||
self.bridge.joinMUC(room_jid.domain, room_jid.node, self.profiles[self.profile]['whoami'].node, self.profile)
|
||||
else:
|
||||
error (_("'%s' is an invalid JID !"), room_jid)
|
||||
|
||||
def onFindGateways(self, e):
|
||||
debug(_("Find Gateways request"))
|
||||
id = self.bridge.findGateways(self.profiles[self.profile]['whoami'].domain, self.profile)
|
||||
self.current_action_ids.add(id)
|
||||
self.current_action_ids_cb[id] = self.onGatewaysFound
|
||||
|
||||
def onGatewaysFound(self, data):
|
||||
"""Called when SàT has found the server gateways"""
|
||||
target = data['__private__']['target']
|
||||
del data['__private__']
|
||||
gatewayManager = GatewaysManager(self, data, server=target)
|
||||
|
||||
def onClose(self, e):
|
||||
QuickApp.onExit(self)
|
||||
info(_("Exiting..."))
|
||||
for win in self.chat_wins:
|
||||
self.chat_wins[win].Destroy()
|
||||
e.Skip()
|
||||
|
||||
def onTrayClick(self, e):
|
||||
debug(_("Tray Click"))
|
||||
if self.IsShown():
|
||||
self.Hide()
|
||||
else:
|
||||
self.Show()
|
||||
self.Raise()
|
||||
e.Skip()
|
||||
|
||||
Loading…
Reference in a new issue