Mercurial > libervia-backend
diff frontends/wix/main_window.py @ 0:c4bc297b82f0
sat:
- first public release, initial commit
author | goffi@necton2 |
---|---|
date | Sat, 29 Aug 2009 13:34:59 +0200 |
parents | |
children | a06a151fc31f |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/frontends/wix/main_window.py Sat Aug 29 13:34:59 2009 +0200 @@ -0,0 +1,377 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +wix: a SAT frontend +Copyright (C) 2009 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/>. +""" + + +import wx +from chat import Chat +from param import Param +import gobject +import os.path +import pdb +from tools.jid import JID +from logging import debug, info, error +from quick_frontend.quick_chat_list import QuickChatList +from quick_frontend.quick_contact_list import QuickContactList +from quick_frontend.quick_app import QuickApp + + +msgOFFLINE = "offline" +msgONLINE = "online" +idCONNECT = 1 +idEXIT = 2 +idPARAM = 3 +idADD_CONTACT = 4 +idREMOVE_CONTACT = 5 +const_DEFAULT_GROUP = "Unclassed" +const_STATUS = {"Online":"", + "Want to discuss":"chat", + "AFK":"away", + "Do Not Disturb":"dnd", + "Away":"xa"} + +class ChatList(QuickChatList): + """This class manage the list of chat windows""" + + def __init__(self, host): + QuickChatList.__init__(self, host) + + def createChat(self, name): + return Chat(name, self.host) + + + +class ContactList(wx.TreeCtrl, QuickContactList): + """Customized control to manage contacts.""" + + def __init__(self, parent): + wx.TreeCtrl.__init__(self, parent, style = wx.TR_HIDE_ROOT | wx.TR_HAS_BUTTONS) + QuickContactList.__init__(self) + self.jid_ids={} + self.groups={} + self.root=self.AddRoot("") + self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.onActivated, self) + + #icons + isz = (16,16) + il = wx.ImageList(isz[0], isz[1]) + self.icon_online = il.Add(wx.ArtProvider_GetBitmap(wx.ART_TICK_MARK, wx.ART_OTHER, isz)) + self.icon_unavailable = il.Add(wx.ArtProvider_GetBitmap(wx.ART_CROSS_MARK, wx.ART_OTHER, isz)) + self.AssignImageList(il) + + self.__addNode(const_DEFAULT_GROUP) + + def __addNode(self, label): + """Add an item container""" + ret=self.AppendItem(self.root, label) + self.SetPyData(ret, "[node]") + self.SetItemBold(ret) + self.groups[label]=ret + + def replace(self, jid, name="", show="", status="", group=""): + debug("status = %s show = %s",status, show) + if not self.jid_ids.has_key(jid): + self.add(jid, name, show, status, group) + else: + debug ("updating %s",jid) + self.__presentItem(jid, name, show, status, group) + + def __presentItem(self, jid, name, show, status, group): + """Make a nice presentation of the contact in the list.""" + id=self.jid_ids[jid] + label= "%s [%s] \n %s" % ((name or jid), (show or "online"), status) + self.SetItemText(id, label) + + # icon + if not show or show=="chat": + self.SetItemImage(id, self.icon_online) + else: + self.SetItemImage(id, self.icon_unavailable) + + #colour + if not show: + self.SetItemTextColour(id, wx.BLACK) + elif show=="chat": + self.SetItemTextColour(id, wx.GREEN) + elif show=="away": + self.SetItemTextColour(id, wx.BLUE) + else: + self.SetItemTextColour(id, wx.RED) + + def add(self, jid, name="", show="", status="", group=""): + """add a contact to the list""" + debug ("adding %s",jid) + dest_group=group or const_DEFAULT_GROUP + if not self.groups.has_key(dest_group): + self.__addNode(dest_group) + self.jid_ids[jid]=self.AppendItem(self.groups[dest_group], "") + self.__presentItem(jid, name, show, status, group) + self.SetPyData(self.jid_ids[jid], "[contact]"+jid) + self.EnsureVisible(self.jid_ids[jid]) + self.Refresh() #FIXME: Best way ? + + def remove(self, jid): + """remove a contact from the list""" + debug ("removing %s",jid) + self.Delete(self.jid_ids[jid]) + del self.jid_ids[jid] + self.Refresh() #FIXME: Best way ? + + def onActivated(self, event): + """Called when a contact is clicked or activated with keyboard.""" + if self.GetPyData(event.GetItem()).startswith("[contact]"): + self.onActivatedCB(self.GetPyData(event.GetItem())[9:]) + else: + event.Skip() + + def getSelection(self): + """Return the selected contact, or an empty string if there is not""" + data = self.GetPyData(self.GetSelection()) + if not data or not data.startswith("[contact]"): + return "" + return JID(data[9:]) + + def registerActivatedCB(self, cb): + """Register a callback with manage contact activation.""" + self.onActivatedCB=cb + +class MainWindow(wx.Frame, QuickApp): + """main app window""" + + def __init__(self): + wx.Frame.__init__(self,None, title="SAT Wix", size=(400,200)) + + + #Frame elements + self.contactList = ContactList(self) + self.contactList.registerActivatedCB(self.onContactActivated) + self.chat_wins=ChatList(self) + self.CreateStatusBar() + self.SetStatusText(msgOFFLINE) + self.createMenus() + + #ToolBar + self.tools=self.CreateToolBar() + self.statusBox = wx.ComboBox(self.tools, -1, "Online", choices=const_STATUS.keys(), + 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() + + #events + self.Bind(wx.EVT_CLOSE, self.onClose, self) + + QuickApp.__init__(self) + + self.Show() + + def createMenus(self): + info("Creating menus") + connectMenu = wx.Menu() + connectMenu.Append(idCONNECT, "&Connect CTRL-c"," Connect to the server") + connectMenu.Append(idPARAM,"&Parameters"," Configure the program") + connectMenu.AppendSeparator() + 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") + menuBar = wx.MenuBar() + menuBar.Append(connectMenu,"&General") + menuBar.Append(contactMenu,"&Contacts") + self.SetMenuBar(menuBar) + + #events + wx.EVT_MENU(self, idCONNECT, self.onConnectRequest) + wx.EVT_MENU(self, idPARAM, self.onParam) + wx.EVT_MENU(self, idEXIT, self.onExit) + wx.EVT_MENU(self, idADD_CONTACT, self.onAddContact) + wx.EVT_MENU(self, idREMOVE_CONTACT, self.onRemoveContact) + + + def newMessage(self, from_jid, msg, type, to_jid): + QuickApp.newMessage(self, from_jid, msg, type, to_jid) + + 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"): + if type == 'info': + flags = wx.OK | wx.ICON_INFORMATION + elif type == 'error': + flags = wx.OK | wx.ICON_ERROR + elif type == 'question': + flags = wx.OK | wx.ICON_QUESTION + else: + flags = wx.OK | wx.ICON_INFORMATION + dlg = wx.MessageDialog(self, message, title, flags) + answer = dlg.ShowModal() + dlg.Destroy() + return True if (answer == wx.ID_YES or answer == wx.ID_OK) else False + + 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 presenceUpdate(self, jabber_id, type, show, status, priority): + QuickApp.presenceUpdate(self, jabber_id, type, show, status, priority) + + 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 %s wants to send you the file %s\nDo you accept ?" % (data["from"], 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() + + + + + def progressCB(self, id, title, message): + data = self.bridge.getProgress(id) + if data: + if not data['position']: + data['position'] = '0' + if not self.pbar: + #first answer, we must construct the bar + self.pbar = wx.ProgressDialog(title, message, int(data['size']), None, + wx.PD_SMOOTH | wx.PD_ELAPSED_TIME | wx.PD_ESTIMATED_TIME | wx.PD_REMAINING_TIME) + self.pbar.finish_value = int(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].IsShown(): + self.chat_wins[jid].Hide() + else: + self.chat_wins[jid].Show() + + def onConnectRequest(self, e): + self.bridge.connect() + + def __updateStatus(self): + show = const_STATUS[self.statusBox.GetValue()] + status = self.statusTxt.GetValue() + self.bridge.setPresence(show=show, status=status) + + def onStatusChange(self, e): + debug("Status change request") + self.__updateStatus() + + def onParam(self, e): + debug("Param request") + param=Param(self.bridge.setParam, self.bridge.getParam, self.bridge.getParams, self.bridge.getParamsCategories) + + 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.ext') + + if dlg.ShowModal() == wx.ID_OK: + jid=JID(dlg.GetValue()) + if jid.is_valid(): + self.bridge.addContact(jid.short) + 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("Unsubsribing %s presence", target.short) + self.bridge.delContact(target.short) + + dlg.Destroy() + + def onClose(self, e): + info("Exiting...") + e.Skip() +