home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2009 June / maximum-cd-2009-06.iso / DiscContents / digsby_setup.exe / lib / gui / infobox / infobox.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2009-02-26  |  40.0 KB  |  1,165 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.5)
  3.  
  4. from __future__ import with_statement
  5. from util.vec import vector
  6. from util import linkify
  7. import sys
  8. from wx import RectPS, RectS, Point, CallLater, GetMouseState, FindWindowAtPointer, GetMousePosition, Size, PaintDC, BufferedPaintDC, BLACK, GREEN, WHITE, BLUE, RED_PEN
  9. import warnings
  10. import wx.html as html
  11. from gui.capabilitiesbar import CapabilitiesBar
  12. from contacts.Contact import Contact
  13. from contacts.metacontacts import MetaContact
  14. from common.emailaccount import EmailAccount
  15. from social.network import SocialNetwork
  16. from gui import skin
  17. from gui.skin.skinobjects import SkinColor, Margins
  18. from gui.infobox.emailpanels import EmailList, Header
  19. from common import pref, setpref, profile
  20. from gui.buddylist import BuddyList
  21. from gui.windowfx import fadein
  22. from gui.textutil import CopyFont, TagFont, default_font
  23. from util import Storage, Point2HTMLSize
  24. from gui.infobox.errorpanel import ErrorPanel
  25. from gui.windowfx import ApplySmokeAndMirrors
  26. from common import prefprop
  27. from gui.toolbox import Monitor
  28. from gui import imwin, clipboard
  29. from cgui import SplitImage4
  30. import wx.lib.wxpTag as wx
  31. from gui.windowfx import move_smoothly, resize_smoothly
  32. from gui.infobox.htmlgeneration import GetInfo
  33. from logging import getLogger
  34. log = getLogger('infobox')
  35. from common import bind
  36. import traceback
  37. from traceback import print_exc
  38. DEFAULT_INFOBOX_WIDTH = 330
  39. TRAY_TIMER_MS = 500
  40. from threading import currentThread
  41.  
  42. class ExpandoPanel(wx.Panel):
  43.     
  44.     def __init__(self, parent, infobox):
  45.         wx.Panel.__init__(self, parent, pos = (-300, -300))
  46.         self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
  47.         self.SetMinSize(wx.Size(20, 20))
  48.         self.infobox = infobox
  49.         Bind = self.Bind
  50.         Bind(wx.EVT_PAINT, self.OnPaint)
  51.         Bind(wx.EVT_LEFT_UP, self.OnLUp)
  52.         Bind(wx.EVT_LEFT_DCLICK, self.OnDClick)
  53.         Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnter)
  54.         Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeave)
  55.  
  56.     
  57.     def OnMouseEnter(self, event):
  58.         if not self.HasCapture():
  59.             self.CaptureMouse()
  60.         
  61.         self.Refresh(False)
  62.  
  63.     
  64.     def OnMouseLeave(self, event):
  65.         while self.HasCapture():
  66.             self.ReleaseMouse()
  67.         self.Refresh(False)
  68.  
  69.     
  70.     def OnPaint(self, event):
  71.         dc = BufferedPaintDC(self)
  72.         infobox = self.infobox
  73.         contact = infobox.metacontact[infobox.expandopanels.index(self)]
  74.         rect = RectS(self.Size)
  75.         iconsize = 16
  76.         padx = infobox.padding.x
  77.         i = None if infobox.account == contact else self.HasCapture()
  78.         infobox.contactbg[i].Draw(dc, rect)
  79.         dc.SetFont(infobox.headerfont)
  80.         dc.SetTextForeground(infobox.contactfontcolor[i])
  81.         name = contact.alias
  82.         servico = contact.serviceicon.Resized(iconsize)
  83.         statico = skin.get('statusicons.' + contact.status_orb).ResizedSmaller(iconsize)
  84.         dc.DrawBitmap(servico, 2 + padx, 2, True)
  85.         dc.DrawText(name, 21 + padx, 2)
  86.         dc.DrawBitmap(statico, (rect.width - 18) + (16 - statico.Size.width) // 2 - padx, rect.height // 2 - statico.Height // 2)
  87.  
  88.     
  89.     def OnDClick(self, event):
  90.         infobox = self.infobox
  91.         contact = infobox.metacontact[infobox.expandopanels.index(self)]
  92.         infobox.Hide()
  93.         imwin.begin_conversation(contact)
  94.  
  95.     
  96.     def OnLUp(self, event):
  97.         infobox = self.infobox
  98.         contact = infobox.metacontact[infobox.expandopanels.index(self)]
  99.         if self.HasCapture() and contact is not infobox.account:
  100.             infobox.SelectContact(contact)
  101.             infobox.cpanel.Refresh(False)
  102.         
  103.  
  104.  
  105.  
  106. class InfoBoxShowingTimer(wx.Timer):
  107.     
  108.     def __init__(self, infobox):
  109.         self.infobox = infobox
  110.         wx.Timer.__init__(self)
  111.  
  112.     
  113.     def Start(self, contact):
  114.         self.contact = contact
  115.         wx.Timer.Start(self, pref('infobox.show_delay', 1000), True)
  116.  
  117.     
  118.     def Notify(self):
  119.         i = self.infobox
  120.         if i is None or wx.IsDestroyed(i):
  121.             print >>sys.stderr, 'Infobox is dead but still getting notified!'
  122.             return None
  123.         
  124.         if i.FriendlyTouch():
  125.             i.ShowOnScreen()
  126.             i.InfoSync()
  127.             i.quickshow = True
  128.         
  129.  
  130.  
  131.  
  132. class InfoBoxHidingTimer(wx.Timer):
  133.     
  134.     def __init__(self, infobox):
  135.         self.infobox = infobox
  136.         wx.Timer.__init__(self)
  137.  
  138.     
  139.     def Notify(self):
  140.         i = self.infobox
  141.         if i is None or wx.IsDestroyed(i):
  142.             return None
  143.         
  144.         i.mouseouttimer.Stop()
  145.         i.showingtimer.Stop()
  146.         i.quickshow = False
  147.         i.Hide()
  148.  
  149.  
  150.  
  151. class InfoBoxTrayTimer(wx.Timer):
  152.     
  153.     def __init__(self, infobox):
  154.         wx.Timer.__init__(self)
  155.         self.infobox = infobox
  156.  
  157.     
  158.     def Notify(self):
  159.         
  160.         try:
  161.             mp = GetMousePosition()
  162.         except Exception:
  163.             return None
  164.  
  165.         import cgui
  166.         tray_rect = cgui.GetTrayRect()
  167.         i = self.infobox
  168.         if i is None or wx.IsDestroyed(i):
  169.             return None
  170.         
  171.         infobox_rect = i.Rect.Inflate(30, 30)
  172.         if not infobox_rect.Contains(mp) and not tray_rect.Contains(mp):
  173.             i.Hide()
  174.             self.Stop()
  175.         
  176.  
  177.  
  178.  
  179. class InfoBoxMouseOutTimer(wx.Timer):
  180.     
  181.     def __init__(self, infobox):
  182.         self.infobox = infobox
  183.         wx.Timer.__init__(self)
  184.         self.hider = InfoBoxHidingTimer(infobox)
  185.         self.noneweredown = False
  186.  
  187.     
  188.     def Start(self):
  189.         wx.Timer.Start(self, 200)
  190.         self.delayhide = False
  191.  
  192.     
  193.     def Notify(self):
  194.         
  195.         try:
  196.             mp = GetMousePosition()
  197.         except:
  198.             return None
  199.  
  200.         ms = GetMouseState()
  201.         if not ms.LeftDown() and ms.RightDown():
  202.             pass
  203.         button_down = ms.MiddleDown()
  204.         infobox = self.infobox
  205.         infobox_rect = infobox.Rect
  206.         inside = infobox_rect.Contains(mp)
  207.         ftouch = infobox.FriendlyTouch(mp)
  208.         if inside:
  209.             self.delayhide = True
  210.         elif ftouch:
  211.             self.delayhide = False
  212.         
  213.         hider = self.hider
  214.         if not inside and ftouch and infobox.capbar.cbar.overflowmenu.IsShown() and infobox.capbar.cto.menu.IsShown():
  215.             pass
  216.         if not infobox.capbar.cfrom.menu.IsShown() and self.noneweredown:
  217.             if button_down:
  218.                 hider.Start(1, True)
  219.             
  220.             if not hider.IsRunning():
  221.                 wap = wx.FindWindowAtPoint(mp)
  222.                 if wap is not None:
  223.                     if infobox.Parent.Top is wap.Top:
  224.                         pass
  225.                     inancestor = wap.Top is not wap
  226.                 else:
  227.                     inancestor = False
  228.                 None(hider.Start if self.delayhide or inancestor else 1, True)
  229.             
  230.         else:
  231.             self.noneweredown = False
  232.             if hider.IsRunning():
  233.                 hider.Stop()
  234.             
  235.         self.noneweredown = not button_down
  236.  
  237.  
  238.  
  239. class InfoBox(wx.Frame):
  240.     
  241.     def __dtor__(self):
  242.         for attr in ('mouseouttimer', 'showingtimer', 'hidingtimer', 'traytimer'):
  243.             obj = getattr(self, attr, None)
  244.             if obj is not None:
  245.                 obj.infobox = None
  246.                 obj.Stop()
  247.                 continue
  248.         
  249.  
  250.     
  251.     def __init__(self, parent):
  252.         wx.Frame.__init__(self, parent, -1, '', style = wx.FRAME_NO_TASKBAR | wx.STAY_ON_TOP | wx.NO_BORDER | wx.FRAME_TOOL_WINDOW)
  253.         self.friends = set()
  254.         self.quickshow = False
  255.         self.metacontact = None
  256.         self.account = None
  257.         self._doubleclickhide = False
  258.         self.expandopanels = []
  259.         self.mouseouttimer = InfoBoxMouseOutTimer(self)
  260.         self.showingtimer = InfoBoxShowingTimer(self)
  261.         self.hidingtimer = None
  262.         self.traytimer = InfoBoxTrayTimer(self)
  263.         timers = [
  264.             self.mouseouttimer,
  265.             self.showingtimer,
  266.             self.hidingtimer]
  267.         None((self.Bind, wx.EVT_WINDOW_DESTROY), (lambda e: [] if e.EventObject is self else None))
  268.         self.animationtimer = None
  269.         self.htmlcacher = HtmlCacher()
  270.         self.htmlcacher.load_format('res/infobox.yaml')
  271.         self.pl = 0
  272.         self.pr = 0
  273.         self.force_corner = False
  274.         self.Show(False)
  275.         panel = self.panel = wx.Panel(self, pos = (-400, -400))
  276.         self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
  277.         self.UpdateSkin()
  278.         self.content = wx.BoxSizer(wx.VERTICAL)
  279.         sizer = panel.Sizer = wx.GridBagSizer()
  280.         sizer.SetEmptyCellSize(wx.Size(0, 0))
  281.         sizer.AddGrowableCol(1, 1)
  282.         sizer.AddGrowableRow(1, 1)
  283.         sizer.Add(self.content, (1, 1), flag = wx.EXPAND)
  284.         sizer.Add(wx.Size(self.framesize.left, self.framesize.top), (0, 0))
  285.         sizer.Add(wx.Size(self.framesize.right, self.framesize.bottom), (2, 2))
  286.         caps = self.capbar = CapabilitiesBar((self.panel,), (lambda : self.account), True, True)
  287.         for b in ('info', 'im', 'email', 'sms'):
  288.             caps.GetButton(b).Bind(wx.EVT_BUTTON, (lambda e, b = (b,): (self.Hide(), wx.CallAfter(self.account.imwin_mode, b))))
  289.         
  290.         import gui.pref.prefsdialog as gui
  291.         (caps.OnSendFiles,) += (lambda : (self.Hide(), self.account.send_file()))
  292.         (caps.OnSendFolder,) += (lambda : (self.Hide(), self.account.send_folder()))
  293.         (caps.OnViewPastChats,) += (lambda : (self.Hide(), self.account.view_past_chats()))
  294.         (caps, caps.OnAlert) += (lambda : (self.Hide(), gui.pref.prefsdialog.show('notifications')))
  295.         wx.CallAfter(caps.ShowToFrom, False)
  296.         wx.CallAfter(caps.ShowCapabilities, pref('infobox.showcapabilities', True))
  297.         self.content.Add(self.capbar, 0, wx.EXPAND)
  298.         self.eheader = Header(panel)
  299.         self.content.Add(self.eheader, 0, wx.EXPAND)
  300.         self.eheader.Show(False)
  301.         self.cpanel = wx.Panel(panel)
  302.         self.cpanel.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
  303.         self.cpanel.Sizer = wx.BoxSizer(wx.VERTICAL)
  304.         self.content.Add(self.cpanel, 1, wx.EXPAND)
  305.         self.elist = EmailList(panel)
  306.         self.content.Add(self.elist, 1, wx.EXPAND)
  307.         self.elist.Show(False)
  308.         self.errorpanel = ErrorPanel(panel)
  309.         self.content.Add(self.errorpanel, 1, wx.EXPAND)
  310.         self.errorpanel.Show(False)
  311.         panel.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
  312.         panel.Bind(wx.EVT_PAINT, self.OnPaint)
  313.         panel.Bind(wx.EVT_ERASE_BACKGROUND, (lambda e: pass))
  314.         panel.SetSize(wx.Size(DEFAULT_INFOBOX_WIDTH, DEFAULT_INFOBOX_WIDTH))
  315.         pbox.SetMaxWordLength(self.width - 85)
  316.         pbox.SetBorders(self.padding.x)
  317.         self.Bind(wx.EVT_SIZE, self.OnSize)
  318.         
  319.         def set_fonts(val):
  320.             self.profilebox.SetFonts(pref('infobox.fonts.normal', default_font().FaceName), pref('infobox.fonts.fixed', 'Courier New'))
  321.  
  322.         profile.prefs.link('infobox.fonts.normal', set_fonts, callnow = False, obj = self)
  323.         profile.prefs.link('infobox.fonts.fixed', set_fonts, obj = self)
  324.         self.profilebox.Bind(html.EVT_HTML_LINK_CLICKED, self.OnLinkClicked)
  325.         self.cpanel.Sizer.Add(self.profilebox, 1, wx.EXPAND)
  326.         wx.CallAfter(self.DoSizeMagic)
  327.  
  328.     
  329.     def CtrlCHandler(self):
  330.         clipboard.copy(self.profilebox.SelectionToText())
  331.  
  332.     CtrlCHandler = bind('InfoBox.Copy')(CtrlCHandler)
  333.     
  334.     def do_focus(self):
  335.         for ctrl in (self.profilebox, self.elist, self.cpanel):
  336.             if ctrl.IsShownOnScreen():
  337.                 print 'focusing', ctrl
  338.                 self.ReallyRaise()
  339.                 ctrl.SetFocusFromKbd()
  340.                 break
  341.                 continue
  342.         
  343.  
  344.     
  345.     def UpdateSkin(self):
  346.         s = skin.get
  347.         self.framesize = s('infobox.framesize', (lambda : Margins([
  348. 0,
  349. 0,
  350. 0,
  351. 0])))
  352.         self.padding = s('infobox.padding', (lambda : Point(2, 2)))
  353.         if hasattr(self, 'profilebox'):
  354.             self.profilebox.SetBorders(self.padding.x)
  355.         
  356.         self.headerfont = s('infobox.fonts.header', default_font)
  357.         self.headerfc = s('infobox.fontcolors.header', BLACK)
  358.         self.headerhoverfc = s('infobox.fontcolors.contacthover', BLACK)
  359.         self.headerselfc = s('infobox.fontcolors.contactselected', BLACK)
  360.         titlefont = skin.get('infobox.fonts.title', default_font)
  361.         majorfont = skin.get('infobox.fonts.major', default_font)
  362.         minorfont = skin.get('infobox.fonts.minor', default_font)
  363.         linkfont = CopyFont(skin.get('infobox.fonts.link', default_font), underline = True)
  364.         h = self.htmlfonts = Storage()
  365.         h.header = self.headerfont
  366.         h.title = titlefont
  367.         h.major = majorfont
  368.         h.minor = minorfont
  369.         h.link = linkfont
  370.         h.headerfont = self.headerfont.FaceName
  371.         h.titlefont = titlefont.FaceName
  372.         h.majorfont = majorfont.FaceName
  373.         h.minorfont = minorfont.FaceName
  374.         h.linkfont = linkfont.FaceName
  375.         h.headersize = Point2HTMLSize(self.headerfont.PointSize)
  376.         h.titlesize = Point2HTMLSize(titlefont.PointSize)
  377.         h.majorsize = Point2HTMLSize(majorfont.PointSize)
  378.         h.minorsize = Point2HTMLSize(minorfont.PointSize)
  379.         h.linksize = Point2HTMLSize(linkfont.PointSize)
  380.         h.headerfc = self.headerfc.GetAsString(wx.C2S_HTML_SYNTAX)
  381.         h.titlefc = s('infobox.fontcolors.title', BLACK).GetAsString(wx.C2S_HTML_SYNTAX)
  382.         h.majorfc = s('infobox.fontcolors.major', BLACK).GetAsString(wx.C2S_HTML_SYNTAX)
  383.         h.minorfc = s('infobox.fontcolors.minor', (lambda : wx.Color(128, 128, 128))).GetAsString(wx.C2S_HTML_SYNTAX)
  384.         h.linkfc = s('infobox.fontcolors.link', BLUE).GetAsString(wx.C2S_HTML_SYNTAX)
  385.         self.bg = s('infobox.frame', (lambda : SkinColor(BLACK)))
  386.         self.barskin = s('capabilitiesbar', None)
  387.         self.contactbg = [
  388.             s('infobox.backgrounds.contact', (lambda : SkinColor(wx.Colour(128, 128, 128)))),
  389.             s('infobox.backgrounds.contacthover', (lambda : SkinColor(GREEN))),
  390.             s('infobox.backgrounds.contactselected', (lambda : SkinColor(WHITE)))]
  391.         self.contactfontcolor = [
  392.             s('infobox.fontcolors.contact', BLACK),
  393.             s('infobox.fontcolors.contacthover', BLACK),
  394.             s('infobox.fontcolors.contactselected', BLACK)]
  395.         s = self.panel.Sizer
  396.         if s:
  397.             s.Detach(1)
  398.             s.Detach(1)
  399.             s.Add(wx.Size(self.framesize.left, self.framesize.top), (0, 0))
  400.             s.Add(wx.Size(self.framesize.right, self.framesize.bottom), (2, 2))
  401.         
  402.         if hasattr(self, 'capbar') and hasattr(self, 'cpanel'):
  403.             sizer = self.content
  404.             sizer.Detach(self.capbar)
  405.             sizer.Detach(self.cpanel)
  406.             sizer.Add(self.capbar, 0, wx.EXPAND)
  407.             sizer.Add(self.cpanel, 1, wx.EXPAND)
  408.         
  409.         self.htmlcacher.clear()
  410.  
  411.     
  412.     def OnPaint(self, event):
  413.         self.bg.Draw(PaintDC(self.panel), RectS(self.panel.Size))
  414.  
  415.     
  416.     def DoSizeMagic(self):
  417.         width = self.width
  418.         filled = sum((lambda .0: for panel in .0:
  419. panel.Size.height)(self.expandopanels))
  420.         if self.capbar.Shown:
  421.             filled += self.capbar.Size.height
  422.         
  423.         if self.eheader.Shown:
  424.             filled += self.eheader.Size.height
  425.         
  426.         maxheight = Monitor.GetFromWindow(wx.FindWindowByName('Buddy List')).ClientArea.height * pref('infobox.ratio_to_screen', 0.75)
  427.         if self.elist.Shown:
  428.             content = self.elist
  429.             desired = content.GetFullHeight()
  430.         elif self.cpanel.Shown:
  431.             content = self.profilebox
  432.             content.SetSize(wx.Size(width, 1))
  433.             desired = content.VirtualSize.height + 16
  434.         elif self.errorpanel.Show:
  435.             content = self.errorpanel
  436.             desired = content.MinSize.height
  437.         
  438.         allotted = min(desired + filled, maxheight)
  439.         if getattr(self.account, 'service', None) == 'twitter':
  440.             allotted = maxheight
  441.         
  442.         contentsize = None if isinstance(content, EmailList) and allotted == maxheight else allotted - filled
  443.         content.SetSize(wx.Size(width, contentsize))
  444.         sz = Size(width + self.framesize.left + self.framesize.right, contentsize + filled + self.framesize.top + self.framesize.bottom)
  445.         if getattr(self, '_resizingto', None) != sz and pref('infobox.animation.resizing', False):
  446.             resize_smoothly(self, sz)
  447.             self._resizingto = sz
  448.         else:
  449.             self.Size = sz
  450.         self.panel.SetSize(sz)
  451.         wx.CallAfter(self.panel.Layout)
  452.         wx.CallAfter(self.cpanel.Layout)
  453.         if hasattr(self, 'bg') and isinstance(self.bg, SplitImage4):
  454.             ApplySmokeAndMirrors(self, self.bg.GetBitmap(self.Size))
  455.         else:
  456.             ApplySmokeAndMirrors(self)
  457.  
  458.     
  459.     def DelayedHide(self):
  460.         if not self.hidingtimer:
  461.             self.hidingtimer = CallLater(1000, self.DoDelayedHide)
  462.         
  463.  
  464.     
  465.     def DoDelayedHide(self):
  466.         self.hidingtimer = None
  467.         if not self.Rect.Contains(GetMousePosition()):
  468.             self.Hide()
  469.         
  470.  
  471.     
  472.     def Hide(self):
  473.         if self.hidingtimer:
  474.             self.hidingtimer.Stop()
  475.             self.hidingtimer = None
  476.         
  477.         if self.showingtimer.IsRunning():
  478.             self.showingtimer.Stop()
  479.         
  480.         if self.traytimer.IsRunning():
  481.             self.traytimer.Stop()
  482.         
  483.         self.Show(False)
  484.  
  485.     
  486.     def DoubleclickHide(self):
  487.         self._doubleclickhide = True
  488.         self.Hide()
  489.  
  490.     
  491.     def InvalidateDoubleclickHide(self):
  492.         self._doubleclickhide = False
  493.  
  494.     
  495.     def DrawCrap(self, c1, c2, mp):
  496.         tan = tan
  497.         radians = radians
  498.         import math
  499.         DX = abs(c1.x - mp.x)
  500.         LA = self.min_angle_of_entry
  501.         HA = self.max_angle_of_entry
  502.         minDY = int(abs(tan(radians(LA)) * DX))
  503.         maxDY = int(abs(tan(radians(HA)) * DX))
  504.         DY1 = min(max(abs(c1.y - mp.y), minDY), maxDY)
  505.         DY2 = min(max(abs(c2.y - mp.y), minDY), maxDY)
  506.         AP1 = Point(c1.x, mp.y - DY1)
  507.         AP2 = Point(c1.x, mp.y + DY2)
  508.         sdc = wx.ScreenDC()
  509.         sdc.SetBrush(wx.Brush(wx.Color(0, 255, 0, 125)))
  510.         sdc.SetPen(wx.Pen(wx.Color(0, 0, 255, 255)))
  511.         sdc.DrawPolygon((AP1, AP2, mp))
  512.         sdc.Pen = RED_PEN
  513.         sdc.DrawLinePoint(mp, c1)
  514.         sdc.DrawLinePoint(mp, c2)
  515.  
  516.     
  517.     def StateChanged(self, *a):
  518.         wx.CallAfter(self._StateChanged, *a)
  519.  
  520.     
  521.     def _StateChanged(self, *a):
  522.         account = self.account
  523.         online = account.state in (account.Statuses.ONLINE, account.Statuses.CHECKING)
  524.         issocnet = isinstance(account, SocialNetwork)
  525.         isemail = isinstance(account, EmailAccount)
  526.         self.capbar.Show(False)
  527.         if issocnet:
  528.             pass
  529.         self.cpanel.Show(online)
  530.         self.eheader.SetAccount(account)
  531.         self.eheader.Show(True)
  532.         if isemail and online:
  533.             self.elist.SetAccount(account)
  534.         else:
  535.             self.elist.Show(False)
  536.         if issocnet and online and account.dirty:
  537.             self.InfoSync()
  538.         
  539.         if account.state == account.Statuses.OFFLINE:
  540.             pass
  541.         active = account.offline_reason == account.Reasons.WILL_RECONNECT
  542.         if active:
  543.             
  544.             message = lambda : profile.account_manager.state_desc(account)
  545.         elif not online or profile.account_manager.state_desc(account):
  546.             pass
  547.         
  548.         message = None
  549.         error_link = account.error_link()
  550.         if error_link is None:
  551.             self.errorpanel.Error(message)
  552.         else:
  553.             (link, cb) = error_link
  554.             self.errorpanel.Error(message, link, cb)
  555.  
  556.     
  557.     def BuddyListItem(self):
  558.         return None if self.metacontact else self.account
  559.  
  560.     BuddyListItem = property(BuddyListItem)
  561.     
  562.     def SelectNext(self):
  563.         mc = self.metacontact
  564.         if mc:
  565.             i = mc.index(self.account) + 1
  566.             l = len(mc)
  567.             if i >= l:
  568.                 i -= l
  569.             
  570.             self.SelectContact(mc[i])
  571.         
  572.         for panel in self.expandopanels:
  573.             panel.Refresh()
  574.         
  575.  
  576.     
  577.     def SelectLast(self):
  578.         mc = self.metacontact
  579.         if mc:
  580.             i = mc.index(self.account) - 1
  581.             self.SelectContact(mc[i])
  582.         
  583.         for panel in self.expandopanels:
  584.             panel.Refresh()
  585.         
  586.  
  587.     
  588.     def MetaContactObserver(self, obj, attr, old, new):
  589.         wx.CallAfter(self._MetaContactObserver, obj, attr, old, new)
  590.  
  591.     
  592.     def _MetaContactObserver(self, obj, attr, old, new):
  593.         if wx.IsDestroyed(self):
  594.             warnings.warn('Infobox is dead but is still getting notified from MetaContactOberver')
  595.             return None
  596.         
  597.         if self.account not in self.metacontact or not (self.Shown):
  598.             
  599.             try:
  600.                 self.account = self.metacontact.first_online
  601.             except AttributeError:
  602.                 err = ''.join([
  603.                     'The obj: ',
  604.                     str(obj),
  605.                     '\nThe attr: ',
  606.                     attr,
  607.                     '\nold -> new: ',
  608.                     str(old),
  609.                     '->',
  610.                     str(new),
  611.                     '\n\nThe Metacontact: ',
  612.                     str(self.metacontact)])
  613.                 log.error(err)
  614.             except:
  615.                 None<EXCEPTION MATCH>AttributeError
  616.             
  617.  
  618.         None<EXCEPTION MATCH>AttributeError
  619.         self.Repanelmater()
  620.         self.Reposition()
  621.  
  622.     
  623.     def ContactObserver(self, obj, attr, old, new):
  624.         wx.CallAfter(self._ContactObserver, obj, attr, old, new)
  625.  
  626.     
  627.     def _ContactObserver(self, obj, attr, old, new):
  628.         self.InfoSync()
  629.         for panel in self.expandopanels:
  630.             panel.Refresh()
  631.         
  632.  
  633.     
  634.     def Display(self, pl, pr, caller, force_corner = False, force_change = False):
  635.         self.hidingtimer = None
  636.         ht = getattr(self, 'hidingtimer', None)
  637.         if ht is not None:
  638.             ht.Stop()
  639.         
  640.         if self._doubleclickhide and caller is self.BuddyListItem:
  641.             return None
  642.         
  643.         if not pl == self.pl and pr == self.pr and caller is self.metacontact or caller is self.account:
  644.             self.pausedover = None
  645.             po_timer = getattr(self, 'pausedover', None)
  646.             if po_timer is not None:
  647.                 po_timer.Stop()
  648.             
  649.             mp = GetMousePosition()
  650.             rect = self.Rect
  651.             onleft = rect.x < mp.x
  652.             if self.Shown:
  653.                 if not force_change:
  654.                     pass
  655.                 if not force_corner:
  656.                     lp = getattr(self, 'LastMousePoint', mp)
  657.                     dp = mp - lp
  658.                     lmd = getattr(self, 'LastMouseDirection', [
  659.                         False,
  660.                         False])
  661.                     d = self.LastMouseDirection = (None, None if dp.x else lmd[0] if dp.y else lmd[1])
  662.                     c1 = rect.Position
  663.                     c2 = c1 + wx.Point(0, rect.height)
  664.                     if pref('infobox.tracelines', False):
  665.                         self.DrawCrap(c1, c2, mp)
  666.                     
  667.                     if (d[0] or not onleft or not d[0]) and onleft:
  668.                         c = None if d[1] else c1
  669.                         am = (vector(*lp) - vector(*mp)).angle
  670.                         ac = max(min((vector(*lp) - vector(*c)).angle, self.max_angle_of_entry), self.min_angle_of_entry)
  671.                         if am < ac and mp.y > c1.y and mp.y < c2.y:
  672.                             self.LastMousePoint = None + mp if onleft else (-1, 0)
  673.                             self.pausedover = None((None, None, None, CallLater, self.pause_time), (lambda : None if self.FriendlyTouch(mp) else None))
  674.                             return None
  675.                         
  676.                     
  677.                 
  678.             self.LastMousePoint = None + mp(*wx.Point if onleft else (-1, 0))
  679.             if isinstance(self.account, SocialNetwork):
  680.                 self.errorpanel.Error()
  681.                 self.account.unobserve_count(self.InfoSync)
  682.                 self.account.remove_observer(self.StateChanged, 'state')
  683.             elif isinstance(self.account, EmailAccount):
  684.                 self.errorpanel.Error()
  685.                 self.account.remove_observer(self.StateChanged, 'state')
  686.             elif isinstance(self.account, Contact):
  687.                 if self.metacontact:
  688.                     mco = getattr(self, 'metacontact_observer', None)
  689.                     self.metacontact_observer = None
  690.                     if mco is not None:
  691.                         mco.disconnect()
  692.                     else:
  693.                         log.warning("unobserving a MetaContact, but didn't have a metacontact_observer")
  694.                 else:
  695.                     self.account.remove_observer(self.ContactObserver, 'status', 'status_message', 'idle', 'icon')
  696.             
  697.             self.pl = pl
  698.             self.pr = pr
  699.             if force_corner != self.force_corner:
  700.                 self.Show(False)
  701.             
  702.             self.force_corner = force_corner
  703.             if isinstance(caller, (Contact, MetaContact)):
  704.                 self.eheader.Show(False)
  705.                 self.elist.Show(False)
  706.                 self.capbar.Show(True)
  707.                 self.cpanel.Show(True)
  708.                 if isinstance(caller, MetaContact):
  709.                     metacontact = caller
  710.                     contact = caller.first_online
  711.                 else:
  712.                     metacontact = []
  713.                     contact = caller
  714.                 if not self.IsShown() and metacontact != self.metacontact or contact is not self.account:
  715.                     if metacontact:
  716.                         pass
  717.                     elif True:
  718.                         self.metacontact = metacontact
  719.                         self.account = contact
  720.                     
  721.                 if metacontact:
  722.                     self.metacontact_observer = metacontact.add_list_observer(self.MetaContactObserver, self.ContactObserver, 'status', 'status_message', 'idle', 'icon')
  723.                 else:
  724.                     contact.add_observer(self.ContactObserver, 'status', 'status_message', 'idle', 'icon')
  725.                 if self.account is not None:
  726.                     caps = self.capbar
  727.                     if isinstance(self.account, MetaContact):
  728.                         buddies = self.account
  729.                         name = buddies.alias
  730.                     else:
  731.                         buddies = [
  732.                             self.account]
  733.                         name = self.account.name
  734.                     if any((lambda .0: for b in .0:
  735. b.blocked)(buddies)):
  736.                         content = _('Unblock %s')
  737.                     else:
  738.                         content = _('Block %s')
  739.                     caps.iblock.content = [
  740.                         content % name]
  741.                 
  742.             elif isinstance(caller, EmailAccount):
  743.                 self.metacontact = []
  744.                 self.account = caller
  745.                 self.account.add_observer(self.StateChanged, 'state')
  746.                 self._StateChanged()
  747.             elif isinstance(caller, SocialNetwork):
  748.                 self.metacontact = []
  749.                 self.account = caller
  750.                 self.account.observe_count(self.InfoSync)
  751.                 self.account.add_observer(self.StateChanged, 'state')
  752.                 self._StateChanged()
  753.             
  754.             self.Repanelmater()
  755.             self.Reposition()
  756.         
  757.         if not self.IsShown():
  758.             if force_corner:
  759.                 fadein(self, 'xfast')
  760.                 self.traytimer.Start(TRAY_TIMER_MS)
  761.             elif self.quickshow:
  762.                 self.ShowOnScreen()
  763.             elif not self.showingtimer.IsRunning() or self.account is not self.showingtimer.contact:
  764.                 self.showingtimer.Start(self.account)
  765.             
  766.             if not force_corner and not self.mouseouttimer.IsRunning():
  767.                 self.mouseouttimer.Start()
  768.             
  769.         
  770.         if self.panel.IsFrozen():
  771.             self.panel.Thaw()
  772.         
  773.  
  774.     
  775.     def ShowOnScreen(self):
  776.         self.ShowNoActivate(True)
  777.         if 'wxMSW' in wx.PlatformInfo:
  778.             show_on_top(self)
  779.         
  780.  
  781.     
  782.     def OnSize(self, event):
  783.         event.Skip()
  784.         if self.pl and self.pr:
  785.             if self.ScreenRect.Contains(wx.GetMousePosition()):
  786.                 wx.CallLater(250, self.Reposition)
  787.             else:
  788.                 self.Reposition()
  789.         
  790.         self.Refresh()
  791.  
  792.     
  793.     def Reposition(self):
  794.         pl = self.pl
  795.         pr = self.pr
  796.         force_corner = self.force_corner
  797.         size = self.Size
  798.         if not force_corner:
  799.             primaryPoint = None if self.right_of_list else (pl[0] - self.Size.width, pl[1])
  800.             primaryRect = RectPS(wx.Point(*primaryPoint), wx.Size(*size))
  801.             secondaryPoint = None if self.right_of_list else pr
  802.             screenrect = Monitor.GetFromWindow(self.Parent.Top).ClientArea
  803.             offscreen = None if self.right_of_list else primaryRect.left < screenrect.left
  804.             pos = None if offscreen else primaryPoint
  805.             direction = wx.TOP | wx.BOTTOM
  806.         else:
  807.             pos = (force_corner - Point(*size)) + Point(1, 1)
  808.             direction = wx.TOP | wx.BOTTOM | wx.LEFT | wx.RIGHT
  809.         r = wx.RectPS(wx.Point(*pos), wx.Size(*size))
  810.         screenrect = Monitor.GetFromRect(r).ClientArea
  811.         pos = screenrect.Clamp(r, direction).Position
  812.         if not force_corner and self.animate and self.Shown:
  813.             if self.animation_method == 2:
  814.                 if getattr(self, '_moving_to', None) != pos:
  815.                     self.animationtimer = move_smoothly(self, pos, time = self.animation_time, interval = self.animation_interval)
  816.                 
  817.             else:
  818.                 self.animationtimer = self.SlideTo(pos)
  819.         elif self.animationtimer:
  820.             self.animationtimer.stop()
  821.             self.animationtimer = None
  822.         
  823.         self.SetPosition(pos)
  824.         if force_corner:
  825.             self.traytimer.Start(TRAY_TIMER_MS)
  826.         
  827.         self._moving_to = pos
  828.  
  829.     animation_time = prefprop('infobox.animation.time', 200)
  830.     animation_interval = prefprop('infobox.animation.interval', 10)
  831.     animation_method = prefprop('infobox.animation.method', 1)
  832.     animate = prefprop('infobox.animate', False)
  833.     right_of_list = prefprop('infobox.right_of_list', True)
  834.     max_angle_of_entry = prefprop('infobox.max_angle_of_entry', 60)
  835.     min_angle_of_entry = prefprop('infobox.max_angle_of_entry', 30)
  836.     pause_time = prefprop('infobox.pause_time', 250)
  837.     width = prefprop('infobox.width', DEFAULT_INFOBOX_WIDTH)
  838.     
  839.     def on_synctimer(self):
  840.         t = self.synctimer
  841.         t.Stop()
  842.         if t.needs_sync:
  843.             t.needs_sync = False
  844.             self.InfoSync()
  845.         
  846.  
  847.     
  848.     def InfoSync(self, *a):
  849.         if not hasattr(self, 'synctimer'):
  850.             self.synctimer = wx.PyTimer(self.on_synctimer)
  851.             self.synctimer.needs_sync = False
  852.         
  853.         if self.synctimer.IsRunning():
  854.             self.synctimer.needs_sync = True
  855.             return None
  856.         
  857.         pb = self.profilebox
  858.         cpanel = self.cpanel
  859.         self.Frozen().__enter__()
  860.         
  861.         try:
  862.             if cpanel.IsShown():
  863.                 if self.capbar.Shown:
  864.                     self.capbar.ApplyCaps(self.account)
  865.                 
  866.                 
  867.                 try:
  868.                     pfile = self.htmlcacher.GetGeneratedProfile(self.account, self.htmlfonts)
  869.                 except Exception:
  870.                     traceback.print_exc()
  871.                     pfile = _(u'Error generating content')
  872.  
  873.                 pb._page = pfile
  874.                 
  875.                 pb.GetPage = lambda : pb._page
  876.                 pb.SetPage(pfile)
  877.             
  878.             self.DoSizeMagic()
  879.         finally:
  880.             pass
  881.  
  882.         self.synctimer.StartOneShot(300)
  883.  
  884.     
  885.     def Repanelmater(self):
  886.         panelsneeded = len(self.metacontact)
  887.         exp = self.expandopanels
  888.         sz = self.cpanel.Sizer
  889.         if panelsneeded > 0:
  890.             while len(exp) < panelsneeded:
  891.                 panel = ExpandoPanel(self.cpanel, self)
  892.                 exp.insert(0, panel)
  893.                 sz.Insert(0, panel, 0, wx.EXPAND)
  894.             while len(exp) > panelsneeded:
  895.                 panel = exp[0]
  896.                 panel.Show(False)
  897.                 exp.remove(panel)
  898.                 sz.Detach(panel)
  899.                 panel.Destroy()
  900.         else:
  901.             for panel in exp[:]:
  902.                 panel.Show(False)
  903.                 exp.remove(panel)
  904.                 sz.Detach(panel)
  905.                 panel.Destroy()
  906.             
  907.         self.cpanel.Refresh()
  908.         self.InfoSync()
  909.  
  910.     
  911.     def SelectContact(self, contact):
  912.         self.account = contact
  913.         self.InfoSync()
  914.  
  915.     
  916.     def OnLinkClicked(self, event):
  917.         href = event.GetLinkInfo().GetHref()
  918.         should_not_hide = False
  919.         if href == '#profile':
  920.             setpref('infobox.showprofile', not pref('infobox.showprofile'))
  921.             self.InfoSync()
  922.             return None
  923.         elif href.decode('url')[:3] == '^_^':
  924.             href = href.decode('url')
  925.             href = href[3:].split('/')
  926.             fname = href.pop(0)
  927.             args = href
  928.             
  929.             try:
  930.                 should_not_hide = getattr(self.account, fname)(*args)
  931.             except Exception:
  932.                 e = None
  933.                 print_exc()
  934.             except:
  935.                 None<EXCEPTION MATCH>Exception
  936.             
  937.  
  938.         None<EXCEPTION MATCH>Exception
  939.         wx.CallAfter(wx.LaunchDefaultBrowser, href)
  940.         if pref('infobox.hide_on_click', True):
  941.             if not should_not_hide:
  942.                 self.Hide()
  943.             
  944.         
  945.  
  946.     
  947.     def Befriend(self, friend):
  948.         self.friends.add(friend)
  949.  
  950.     
  951.     def Defriend(self, friend):
  952.         self.friends.discard(friend)
  953.  
  954.     
  955.     def FriendlyTouch(self, mp = None):
  956.         windowatpointer = FindWindowAtPointer()
  957.         for friend in self.friends:
  958.             if friend and windowatpointer is friend:
  959.                 if isinstance(friend, BuddyList):
  960.                     if not mp:
  961.                         pass
  962.                 None if not friend.ClientRect.Contains(friend.Parent.ScreenToClient(GetMousePosition())) and GetMouseState().LeftDown() else GetMouseState().LeftDown()
  963.                 return True
  964.                 continue
  965.         
  966.         return False
  967.  
  968.  
  969.  
  970. class HtmlCacher(object):
  971.     
  972.     def __init__(self):
  973.         self._cache = { }
  974.  
  975.     
  976.     def clear(self):
  977.         self._cache.clear()
  978.  
  979.     
  980.     def GetGeneratedProfile(self, acct, htmlfonts):
  981.         import protocols
  982.         IInfoboxHTMLProvider = IInfoboxHTMLProvider
  983.         import interfaces
  984.         
  985.         try:
  986.             ibp = IInfoboxHTMLProvider(acct)
  987.         except protocols.AdaptationFailure:
  988.             pass
  989.  
  990.         if ibp._dirty or acct not in self._cache:
  991.             self._cache[acct] = ibp.get_html(htmlfonts)
  992.         
  993.         return self._cache[acct]
  994.         if isinstance(acct, SocialNetwork):
  995.             cachekey = acct
  996.             if getattr(acct, 'header_tabs', False):
  997.                 currtab = acct._current_tab
  998.                 cachekey = (acct, currtab)
  999.                 dirty = acct._dirty[currtab]
  1000.             elif getattr(acct, '_dirty', False):
  1001.                 cachekey = acct
  1002.                 dirty = True
  1003.             else:
  1004.                 dirty = False
  1005.             if dirty or cachekey not in self._cache:
  1006.                 print 'Regenerating profile for %r' % acct
  1007.                 self._cache[cachekey] = linkify(self.make_format(htmlfonts, cachekey))
  1008.                 if getattr(acct, 'header_tabs', False):
  1009.                     acct._dirty[cachekey[1]] = False
  1010.                 else:
  1011.                     acct._dirty = False
  1012.                 self._cache[cachekey] = ''.join((lambda .0: for y in .0:
  1013. y.strip())(self._cache[cachekey].split('\n')))
  1014.             
  1015.             return self._cache[cachekey]
  1016.         elif isinstance(acct, EmailAccount):
  1017.             print >>sys.stderr, 'WARNING: FillInProfile called with an email account'
  1018.         else:
  1019.             
  1020.             try:
  1021.                 return GetInfo(acct, pref('infobox.showprofile', False))
  1022.             except Exception:
  1023.                 print_exc()
  1024.                 return ''
  1025.  
  1026.  
  1027.     
  1028.     def make_format(self, htmlfonts, cachekey, obj = None, data = None):
  1029.         if isinstance(cachekey, tuple):
  1030.             acct = cachekey[0]
  1031.         else:
  1032.             acct = cachekey
  1033.         if acct.service not in ('digsby', 'facebook', 'myspace', 'twitter'):
  1034.             warnings.warn("Don't know how to make an infobox for %r" % acct)
  1035.             return _(u'No additional information')
  1036.         
  1037.         return self.memo_format(htmlfonts, cachekey)
  1038.  
  1039.     
  1040.     def memo_format(self, htmlfonts, cachekey):
  1041.         if isinstance(cachekey, tuple):
  1042.             acct = cachekey[0]
  1043.             return format(self.format[acct.service][cachekey[1]], acct, htmlfonts)
  1044.         else:
  1045.             acct = cachekey
  1046.             return format(self.format[acct.service], acct, htmlfonts)
  1047.  
  1048.     
  1049.     def load_format(self, fname):
  1050.         import syck
  1051.         
  1052.         try:
  1053.             
  1054.             try:
  1055.                 f = _[2]
  1056.                 self.format = dict(syck.load(f))
  1057.             finally:
  1058.                 pass
  1059.  
  1060.         except:
  1061.             self.format = { }
  1062.             print_exc()
  1063.  
  1064.  
  1065.  
  1066. from copy import deepcopy as copy
  1067. from util import curly, get
  1068.  
  1069. def format(fmt, obj, htmlfonts, data = None):
  1070.     if data is None:
  1071.         data = []
  1072.         return_str = True
  1073.     else:
  1074.         return_str = False
  1075.     mysentinel = Sentinel()
  1076.     
  1077.     sget = lambda o, k: get(o, k, mysentinel)
  1078.     mydata = []
  1079.     mydata_append = mydata.append
  1080.     order = get(fmt, 'order', fmt.keys())
  1081.     curlylocals = copy(fmt)
  1082.     curlylocals['fonts'] = htmlfonts
  1083.     curlylocals['TagFont'] = TagFont
  1084.     for key in order:
  1085.         fmtval = sget(fmt, key)
  1086.         objval = sget(obj, key)
  1087.         if not objval and get(fmtval, 'hide_empty', False):
  1088.             continue
  1089.         
  1090.         if mysentinel in (fmtval, objval):
  1091.             continue
  1092.             continue
  1093.         if isinstance(objval, list):
  1094.             hdr = curly(get(fmtval, 'header', ''), source = curlylocals)
  1095.             sep = curly(get(fmtval, 'separator', ''), source = curlylocals)
  1096.             ftr = curly(get(fmtval, 'footer', ''), source = curlylocals)
  1097.             mydata.append(hdr)
  1098.             if not objval:
  1099.                 curlylocals['obj'] = obj
  1100.                 mydata_append(curly(get(fmtval, 'none', ''), source = curlylocals))
  1101.             else:
  1102.                 for thing in objval:
  1103.                     type_d = get(fmtval, type(thing).__name__, { })
  1104.                     if not type_d:
  1105.                         continue
  1106.                     
  1107.                     mydata_append(sep)
  1108.                     mydata_append(make_icon_str(get(type_d, 'icon', '')))
  1109.                     curlylocals['obj'] = thing
  1110.                     mesgstr = get(type_d, 'message', '')
  1111.                     mydata_append(curly(mesgstr, source = curlylocals))
  1112.                 
  1113.                 mydata_append(sep)
  1114.             mydata_append(ftr)
  1115.             continue
  1116.         if isinstance(fmtval, dict):
  1117.             format(fmtval, objval, htmlfonts, mydata)
  1118.             continue
  1119.         if not objval:
  1120.             continue
  1121.         
  1122.         curlylocals['obj'] = obj
  1123.         mydata_append(curly(fmtval, source = curlylocals))
  1124.     
  1125.     if len(mydata) == 0:
  1126.         curlylocals['obj'] = obj
  1127.         mydata_append(curly(get(fmt, 'none', ''), source = curlylocals))
  1128.     
  1129.     mydata = make_header(fmt, curlylocals) + mydata + make_footer(fmt, curlylocals)
  1130.     data.extend(mydata)
  1131.     if return_str:
  1132.         return ''.join(data)
  1133.     else:
  1134.         return data
  1135.  
  1136.  
  1137. def make_icon_str(s):
  1138.     if not s:
  1139.         return ''
  1140.     
  1141.     s = s[5:]
  1142.     sent = object()
  1143.     return '<wxp module="gui.infobox.htmlbitmaps"class="BitmapFromSkin" width ="99%%" height="-1"><param name="key" value="%s"></wxp>' % s
  1144.  
  1145.  
  1146. def make_header(fmt, obj):
  1147.     return [ curly(get(fmt, k, ''), source = obj) for k in ('header', 'separator') ]
  1148.  
  1149.  
  1150. def make_footer(fmt, obj):
  1151.     return [ curly(get(fmt, k, ''), source = obj) for k in ('separator', 'footer') ]
  1152.  
  1153. if 'wxMSW' in wx.PlatformInfo:
  1154.     from gui.native.win.winconstants import HWND_TOPMOST, SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOSIZE, SWP_SHOWWINDOW
  1155.     WINDOWPOS_FLAGS = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW
  1156.     from ctypes import windll
  1157.     SetWindowPos = windll.user32.SetWindowPos
  1158.     
  1159.     def show_on_top(win):
  1160.         SetWindowPos(win.Handle, HWND_TOPMOST, 0, 0, 0, 0, WINDOWPOS_FLAGS)
  1161.  
  1162.  
  1163. import gui.input as gui
  1164. gui.input.add_class_context(_('InfoBox'), 'InfoBox', cls = InfoBox)
  1165.