source: trunk/src/testing/ui/sageui.py @ 4

Revision 4, 49.9 KB checked in by ajaworski, 13 years ago (diff)

Added modified SAGE sources

  • Property svn:executable set to *
Line 
1#!/usr/bin/env python
2
3############################################################################
4#
5# SAGE UI - A Graphical User Interface for SAGE
6# Copyright (C) 2005 Electronic Visualization Laboratory,
7# University of Illinois at Chicago
8#
9# All rights reserved.
10#
11# Redistribution and use in source and binary forms, with or without
12# modification, are permitted provided that the following conditions are met:
13#
14#  * Redistributions of source code must retain the above copyright
15#    notice, this list of conditions and the following disclaimer.
16#  * Redistributions in binary form must reproduce the above
17#    copyright notice, this list of conditions and the following disclaimer
18#    in the documentation and/or other materials provided with the distribution.
19#  * Neither the name of the University of Illinois at Chicago nor
20#    the names of its contributors may be used to endorse or promote
21#    products derived from this software without specific prior written permission.
22#
23# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
27# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34#
35# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
36#
37# Author: Ratko Jagodic
38#         Allan Spale
39#
40############################################################################
41
42
43
44
45############################################################################
46#
47#  IMPORTS
48#
49############################################################################
50
51# python and wx stuff
52import string, sys, os, copy, optparse, time
53from threading import Timer
54import traceback as tb
55
56# hyperlink module is not (yet) included with wxPython as a standard module
57# so not all distributions have it
58global use_hyperlink
59use_hyperlink = True
60try:
61    import wx.lib.hyperlink as hyperlink    #for the about box
62except:
63    use_hyperlink = False
64
65# if this UI should autosave
66global autosave
67
68# my stuff
69import Graph
70from sageGate import *
71from sageData import *
72from canvases import *
73from globals import *
74from users import *
75import preferences as prefs
76import launcherAdmin as lAdmin
77from sagePath import getUserPath
78
79
80############################################################################
81#
82#  GLOBAL CONSTANTS
83#
84############################################################################
85
86# current version of the UI
87VERSION = "3.0a"
88setUIVersion(VERSION)
89
90
91### IDS used for the menu items:
92SAVE_STATE = 10
93LOAD_STATE = 1
94ASPECT_RATIO = 2
95SAGE_COLOR = 3
96PERF_DATA = 4
97LOG_PERF_DATA = 5
98RENDER_BW = 6
99DISPLAY_BW = 7
100RECORD_SESSION = 8
101READ_SESSION = 9
102SAGE_SHUTDOWN = 11
103TILE_WINDOWS = 12
104
105
106
107############################################################################
108
109class Log:
110    def WriteText(self, text):
111        if text[-1:] == '\n':
112            text = text[:-1]
113        wx.LogMessage(text)
114    write = WriteText
115
116
117assertMode = wx.PYAPP_ASSERT_DIALOG
118
119
120
121############################################################################
122#
123#  CLASS: DisplayNotebook
124
125#  DESCRIPTION: This is the main container (notebook) for the UI. It holds
126#               one DisplayPage for every connection to SAGE. It also handles
127#               page changes and menu changes when switching pages.
128#
129#  DATE:        June, 2005
130#
131############################################################################
132
133class DisplayNotebook(wx.Notebook):
134
135    def __init__(self, parent):
136        wx.Notebook.__init__(self, parent, -1, style=wx.NO_BORDER)
137        self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChange)
138
139        # open the file for recording totals for all sites
140        try:
141            stDateTime = time.strftime("%Y%m%d-%H%M%S", time.localtime())
142            stFilename = "ALL_SITES_TOTALS-" + stDateTime
143            stPath = opj(DATA_DIR, stFilename + ".txt")
144            self._totalsFile = open(stPath, "w")
145            self._totalsFile.write( time.asctime() + "\n" )
146            self._totalsFile.write( '-' * 40 + "\n" )
147            tempString = (' Timestamp(s)    Disp BW(Gbps)    Rend BW(Gbps)   Num Sites\n')
148            self._totalsFile.write(tempString)
149            self._totalsFile.write( '-' * len(tempString) + "\n" )
150            self._totalsFile.flush()
151        except:
152            print "\n\nERROR: Unable to record performance totals in a file:\n"
153            print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
154            self._totalsFile = None
155
156        # start the timer to periodically record totals
157        self.Bind(wx.EVT_TIMER, self.onPerfTimer)
158        self.perfTimer = wx.Timer(self)
159        self.perfTimer.Start(1000)
160
161
162        ### this timer is called once per second to write the performance
163        ### data totals to a file (for each sage connection)
164    def onPerfTimer(self, event):
165        totalR,totalD = 0,0  # totals for ALL sites... render and display
166        recordTotals = False
167       
168        for pageIndex in range(0, self.GetPageCount()):
169            p = self.GetPage(pageIndex)
170            p.SaveSiteTotals()
171            totalR += p.GetRenderTotal()
172            totalD += p.GetDisplayTotal()
173
174            # if no sites are logging data, dont record totals either
175            if p.sageData.isLoggingEnabled():
176                recordTotals = True
177               
178       
179        # now save the total of all sites
180        if recordTotals and self._totalsFile:
181            temp = "%12d    %12.4f    %12.4f       %d\n" % (getTimeStamp(),
182                                                            totalD,
183                                                            totalR,
184                                                            self.GetPageCount())
185            self._totalsFile.write(temp)
186            self._totalsFile.flush()
187
188
189        ### test whether an application window was dropped on a notebook tab
190        ### if it was, send a message to SAGE about the request
191        ### used to request streaming of an application to multiple displays
192    def DropTest(self, windowId, pt):
193        tab_tuple = self.HitTest((pt[0], pt[1]*(-1)))  # *(-1) since tabs are above the canvas (negative y coordinate with respect to it)
194        newTab = tab_tuple[0]
195        currentTab = self.GetSelection()
196       
197        if newTab == wx.NOT_FOUND or newTab == currentTab:
198            return False
199        else:
200            currentPage = self.GetPage(currentTab)
201            newPageMachine = self.GetPage(newTab).GetMachine()
202            fsmIP = newPageMachine.GetSystemIP()
203            fsmPort = newPageMachine.GetSystemPort()
204            currentPage.sageGate.streamApp(windowId, fsmIP, fsmPort)  #send a message
205            self.SetSelection( newTab )  #open the new tab
206            return True
207
208
209
210    def GetFrame(self):
211        return self.GetParent()
212
213
214        ### this takes care of setting the proper menu items in the frame when a page changes
215        ### it basically pulls the state of all the menu check items from the newly selected
216        ### page and copies that hash into the hash of menu check items of the frame
217    def OnPageChange(self, event):
218        currentPageIndex = event.GetSelection() #must use event.GetSelection() instead of self.GetSelection() because WXMSW and WXMAC report the old selection otherwise
219        if not currentPageIndex == -1:  #windows reports -1 for some reason during creation
220            newPage = self.GetPage(currentPageIndex)
221            self.GetFrame().UpdateMenuItems(newPage.GetCurrentMenuItems())  #refresh the menu now so that it reflects the menu Items from the different page
222        event.Skip()
223
224
225    def SetDefaultMenuCheckItems(self, hashItems):
226        self.defaultMenuCheckItems = hashItems.copy()
227
228
229    def GetDefaultMenuCheckItems(self):
230        return self.defaultMenuCheckItems.copy()
231
232
233    def CloseCurrentPage(self, closeUI=True):
234        if self.GetPageCount() < 2 and closeUI:
235            self.GetFrame().Close(True)
236        elif self.GetPageCount() > 1:
237            currentPageIndex = self.GetSelection()
238            if not currentPageIndex == -1:  #windows reports -1 for some reason during creation
239                page = self.GetPage(currentPageIndex)
240                page.OnClose()
241                self.DeletePage(currentPageIndex)
242
243                #refresh the menu now so that it reflects the menu Items from the different page
244                newPageIndex = self.GetSelection()
245                newPage = self.GetPage(newPageIndex)
246                self.GetFrame().UpdateMenuItems(newPage.GetCurrentMenuItems())
247        else:   # this is the case if the user reconnected to SAGE when there was only one tab open previously
248            currentPageIndex = self.GetSelection()
249            if not currentPageIndex == -1:  #windows reports -1 for some reason during creation
250                page = self.GetPage(currentPageIndex)
251                page.OnClose()
252                self.DeletePage(currentPageIndex)
253
254   
255    def OnClose(self, event):
256        for pageIndex in range(0, self.GetPageCount()):
257            self.GetPage(pageIndex).OnClose(event)
258
259        if self._totalsFile: self._totalsFile.close()
260        self.perfTimer.Stop()
261       
262
263    def OnKeyEvent(self, event):
264        if event.GetKeyCode() == wx.WXK_F9:
265            currentPage = self.GetPage(self.GetSelection())
266            currentPage.GetDisplayCanvas().TileShapes()
267
268 
269    def OnMenuEvent(self, event):
270        eventId = event.GetId() 
271        menuItem = self.GetFrame().GetMenuBar().FindItemById(eventId)
272        currentPage = self.GetPage(self.GetSelection())
273       
274        # this ONLY changes the specific page's state of the selected menu item
275        if menuItem.IsCheckable():
276            if menuItem.IsChecked():
277                currentPage.CheckMenuItem(eventId)
278            else:
279                currentPage.UncheckMenuItem(eventId)
280               
281        # call the correct menu event handler
282        if eventId == SAVE_STATE:
283            currentPage.OnSaveState()
284        elif eventId == LOAD_STATE:
285            currentPage.OnLoadState()
286        elif eventId == ASPECT_RATIO:
287            currentPage.OnMaintainAspectRatio(menuItem)
288        elif eventId == SAGE_COLOR:
289            currentPage.OnSAGEColorChange()
290        elif eventId == PERF_DATA:
291            currentPage.OnReceivePerfData(menuItem)
292        elif eventId == LOG_PERF_DATA:
293            currentPage.OnLogPerfData(menuItem)
294        elif eventId == RENDER_BW:
295            currentPage.OnShowRenderBW(menuItem)
296        elif eventId == DISPLAY_BW:
297            currentPage.OnShowDisplayBW(menuItem)
298        elif eventId == RECORD_SESSION:
299            currentPage.OnRecordSession(menuItem)
300        elif eventId == READ_SESSION:
301            currentPage.OnReadSession()
302        elif eventId == SAGE_SHUTDOWN:
303            currentPage.OnSAGEShutdown()
304        else:
305            pass  #nothing... we dont know how to handle anything else
306
307
308
309
310
311############################################################################
312#
313#  CLASS: DisplayPage
314
315#  DESCRIPTION: DisplayPage is a panel that holds all the controls associated
316#               with one SAGE connection (DisplayCanvas and AppInfoPanel). There
317#               is one for every connection and they are all placed in a notebook
318#               (DisplayNotebook).
319#
320#  DATE:        June, 2005
321#
322############################################################################
323
324class DisplayPage(wx.Panel):
325    def __init__(self, parent, sageGate, usersClient, machineId, title):
326        wx.Panel.__init__(self, parent, -1, style=wx.NO_BORDER)
327
328        self.parent = parent
329        # create main data storage and conectivity objects
330        self.machineId = machineId
331        self.usersClient = usersClient
332        self.usersData = getUsersData()
333        self.sageGate = sageGate
334        self.sageData = SageData(sageGate, autosave, title.split('@')[1])
335        self.RegisterCallbacks()
336        self.menuCheckItems = self.GetParent().GetDefaultMenuCheckItems()
337        self.GetParent().GetFrame().UpdateMenuItems(self.GetCurrentMenuItems()) #update the menu items
338
339        self.Bind(wx.EVT_SIZE, self.OnSize)
340
341        # get the machine name
342        self.siteName = machineId
343        m = self.usersData.GetMachine(machineId)
344        if m:
345            self.siteName = m.GetName()
346       
347        # (AKS 2005-01-27) Performance graph object
348        self.gmGraphManager = Graph.GraphManager( self, self.sageData )
349        # (AKS 2005-05-07) Create constants to identify totals graphs
350        self.I_RENDER_BW_GRAPH = 1
351        self.I_DISPLAY_BW_GRAPH = 2
352       
353        self.displayCanvas = DisplayCanvas(Log(), self, self.sageGate, self.sageData, self.gmGraphManager, title)
354        self.appPanel = AppInfoPanel(self, self.sageGate, self, -1, (0,0), (self.displayCanvas.GetCanvasWidth(), 200), wx.NO_BORDER | wx.NO_FULL_REPAINT_ON_RESIZE)
355        self.sageGate.getAppList()  # this will get the list and fill the appPanel with it
356        #self.Show()  < -- this is done in DisplayCanvas.OnStatusMessage()  (canvases.py)
357
358
359    def GetFrame(self):
360        return self.GetParent().GetParent()
361
362    def GetNotebook(self):
363        return self.GetParent()
364
365    def GetNumPages(self):
366        return self.GetNotebook().GetPageCount()
367
368    def GetCurrentMenuItems(self):
369        return self.menuCheckItems.copy()  #return the current state of menu items specific to this display
370
371    def CheckMenuItem(self, menuItemId):
372        self.menuCheckItems[menuItemId] = True
373
374    def UncheckMenuItem(self, menuItemId):
375        self.menuCheckItems[menuItemId] = False
376
377    def GetMachineId(self):
378        return self.machineId
379
380    def GetMachine(self):
381        return self.usersData.GetMachine(self.machineId)
382
383   
384    #----------------------------------------------------------------------   
385
386    def RegisterCallbacks(self):
387        # (AKS 2005-01-13)
388        # Register callbacks from SageData with SageGate
389        # Whenever SageGate receives an update message from SAGE,
390        # the client-side "app database" stored in SageData
391        # will be updated and then issue its own callback function
392        # to tell the registering app to retrieve and process
393        # the updated data
394
395        self.sageGate.registerCallbackFunction( 40000, self.sageData.setSageStatus )
396        self.sageGate.registerCallbackFunction( 40001, self.sageData.setSageAppInfo )
397        self.sageGate.registerCallbackFunction( 40002, self.sageData.setSagePerfInfo )
398        self.sageGate.registerCallbackFunction( 40003, self.sageData.sageAppShutDown )
399        self.sageGate.registerCallbackFunction( 40004, self.sageData.setDisplayInfo )
400        self.sageGate.registerCallbackFunction( 40005, self.sageData.setSageZValue )
401        self.sageGate.registerCallbackFunction( 40006, self.sageData.setSageAppExecConfig )
402        self.sageGate.registerCallbackFunction( 40007, self.sageData.setDisplayConnections )
403       
404        return self.sageData
405
406
407    #----------------------------------------------------------------------
408   
409
410    def GetDisplayCanvas(self):
411        return self.displayCanvas
412
413    def GetAppInfoPanel(self):
414        return self.appPanel
415
416    def GetAppPanel(self):
417        return self.appPanel.GetAppPanel()
418
419    def GetInfoPanel(self):
420        return self.appPanel.GetInfoPanel()
421
422    def HideAppInfoPanel(self):
423        self.oldHeight = self.GetClientSize().height
424        newHeight = self.oldHeight - self.GetAppInfoPanel().GetSize().height + 60
425        self.GetFrame().SetClientSize( (self.GetFrame().GetClientSize().width, newHeight) )
426        self.GetAppInfoPanel().OnSize()
427           
428    def ShowAppInfoPanel(self):
429        self.GetFrame().SetClientSize( (self.GetFrame().GetClientSize().width, self.oldHeight) )
430        self.GetAppInfoPanel().OnSize()
431   
432
433    def SaveSiteTotals(self):
434        self.sageData.saveSiteTotals(self.siteName)
435
436    def GetRenderTotal(self):
437        """ returns total display bandwidth in gbps """
438        return self.sageData.getRenderBWTotal()
439
440    def GetDisplayTotal(self):
441        """ returns total rendering bandwidth in gbps """
442        return self.sageData.getDisplayBWTotal()
443   
444
445    #----------------------------------------------------------------------
446    # EVENT HANDLERS
447    #----------------------------------------------------------------------
448
449    def OnDisplayInfo(self):
450        pass
451       
452       
453    def OnSize(self, event=None):
454        self.SetSize(self.GetParent().GetClientSize())#event.GetSize())
455        if "__WXMSW__" in wx.PlatformInfo:   #to bypass MS Windows' deferred resizing crap
456            def doResize():
457                self.GetDisplayCanvas().OnSize(event)
458                self.GetAppInfoPanel().OnSize(event)
459            wx.CallAfter(doResize)
460        else:
461            self.GetDisplayCanvas().OnSize(event)
462            self.GetAppInfoPanel().OnSize(event)
463       
464
465    def OnClose(self, evt=None):
466        self.GetDisplayCanvas().Close()
467        self.gmGraphManager.shutdown()  # close all the graphs that might be open
468       
469        # close the "Totals" graphs (if open)
470        #if self.menuCheckItems[RENDER_BW]:
471        #    self.removeGraph(self.I_RENDER_BW_GRAPH)
472        #if self.menuCheckItems[DISPLAY_BW]:
473        #    self.removeGraph(self.I_DISPLAY_BW_GRAPH)
474
475        # stop all the running features
476        self.usersClient.Unregister(self.machineId)  #tell the server that we are not registered in this room anymore
477        self.sageData.stopLogging()
478        #self.sageGate.StopRecording()
479        self.sageGate.disconnectFromSage()  #break the connection with SAGE
480
481
482       # Menu -> Options -> Change SAGE Background Color
483    def OnSAGEColorChange(self):
484        (r,g,b) = self.sageData.getSAGEColor()
485        colorData = wx.ColourData()
486        colorData.SetColour(wx.Colour(r,g,b))
487        dlg = wx.ColourDialog(None, colorData)
488        dlg.GetColourData().SetChooseFull(True)
489        if dlg.ShowModal() == wx.ID_OK:
490            data = dlg.GetColourData()
491            self.sageData.setSAGEColor(data.GetColour().Get())
492            self.sageGate.setBgColor(self.sageData.getSAGEColor())
493            self.GetDisplayCanvas().ChangeBackgroundColor(self.sageData.getSAGEColor())
494        dlg.Destroy()
495
496
497        # Menu -> File -> Shutdown SAGE
498    def OnSAGEShutdown(self):
499        dlg = wx.MessageDialog(self, "You are about to shutdown SAGE. All the currently connected "+
500                                     "users will be disconnected and all applications closed. \nAre "+
501                                     "you sure you want to continue?", "SAGE Shutdown", wx.YES_NO | wx.ICON_EXCLAMATION)
502        if dlg.ShowModal() == wx.ID_YES:
503            self.sageGate.shutdownSAGE()
504           
505
506    # Menu -> File -> Save State
507    def OnSaveState(self):
508        def OnStateSelected(evt):
509            if nameText.GetValue() in stateHash:
510                descriptionText.SetValue( stateHash[nameText.GetValue()] )
511               
512        def OnDeleteState(evt):
513            stateName = nameText.GetValue()
514            if stateName in stateHash:
515                if self.sageData.deleteState(stateName):
516                    descriptionText.Clear()
517                    nameText.Delete(nameText.FindString(stateName))
518                    nameText.SetValue("")
519                else:
520                    Message("Error deleting the saved state. Do you have the required permissions?", "Error Deleting")
521                                 
522       
523        stateHash = self.sageData.getStateList()
524       
525        dlg = wx.Dialog(self, -1, "Save Display Session")
526        okBtn = wx.Button(dlg, wx.ID_OK, "Save")
527        delBtn = wx.Button(dlg, wx.ID_OK, " Delete ", style=wx.BU_EXACTFIT)
528        delBtn.Bind(wx.EVT_BUTTON, OnDeleteState)
529
530        states = stateHash.keys()
531        states.sort()
532        nameLabel = wx.StaticText(dlg, -1, "Session name:")
533        nameText = wx.ComboBox(dlg, -1, "", choices=states, style=wx.CB_DROPDOWN)
534        nameText.Bind(wx.EVT_COMBOBOX, OnStateSelected)
535        nameText.SetFocus()
536        descriptionLabel = wx.StaticText(dlg, -1, "Description:")
537        descriptionText = wx.TextCtrl(dlg, -1, "", style=wx.TE_MULTILINE)
538       
539        nameSizer = wx.BoxSizer(wx.HORIZONTAL)
540        nameSizer.Add(nameLabel, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, border=5)
541        nameSizer.Add(nameText, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
542        nameSizer.Add(delBtn, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=5)
543
544        sizer = wx.BoxSizer(wx.VERTICAL)
545        sizer.Add(nameSizer, 0, wx.EXPAND | wx.ALIGN_LEFT | wx.ALL, border=10)
546        sizer.Add(descriptionLabel, 0, wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, border=10)
547        sizer.Add(descriptionText, 1, wx.EXPAND | wx.ALIGN_LEFT | wx.RIGHT | wx.LEFT, border=10)
548        sizer.AddSpacer((15,15))
549        sizer.Add(okBtn, 0, wx.ALIGN_CENTER)
550        sizer.AddSpacer((5,5))
551
552        dlg.SetSizer(sizer)
553        dlg.SetSize((350, 300))
554
555        stateName = ""
556        description = ""
557        while dlg.ShowModal() == wx.ID_OK:
558            stateName = nameText.GetValue()
559            description = descriptionText.GetValue()
560            if stateName == "":
561                Message("Please name the session you are saving", "Session name required")
562                continue
563            elif stateName in stateHash:
564                if wx.MessageBox("Session with that name already exists. Overwrite?",
565                                 "Overwrite?", style=wx.YES_NO) == wx.YES:
566                    dlg.Destroy()
567                else:
568                    continue
569            self.sageData.saveState(stateName, description)
570            break
571           
572        return
573       
574
575
576    # Menu -> File -> Load State
577    def OnLoadState(self):
578        def OnStateSelected(evt):
579            descriptionText.SetLabel( stateHash[stateList.GetStringSelection()] )
580           
581        def OnDeleteState(evt):
582            stateName = stateList.GetStringSelection()
583            if stateName in stateHash:
584                if self.sageData.deleteState(stateName):
585                    stateList.Delete(stateList.FindString(stateName))
586                    if not stateList.IsEmpty():
587                        stateList.Select(0)
588                        descriptionText.SetLabel(stateHash[stateList.GetString(0)])
589                    else:
590                        descriptionText.SetLabel("")
591                else:
592                    Message("Error deleting the saved state. Do you have the required file permissions?", "Error Deleting")
593
594                                 
595        stateHash = self.sageData.getStateList()
596        if len(stateHash) == 0:
597            Message("No saved sessions exist", "")
598            return
599   
600        dlg = wx.Dialog(self, -1, "Load Saved Session")
601        okBtn = wx.Button(dlg, wx.ID_OK, "Load")
602        okBtn.Disable()
603        delBtn = wx.Button(dlg, wx.ID_OK, " Delete ", style=wx.BU_EXACTFIT)
604        delBtn.Bind(wx.EVT_BUTTON, OnDeleteState)
605
606        states = stateHash.keys()
607        states.sort()
608        states = stateHash.keys()
609        states.sort()
610        stateLabel = wx.StaticText(dlg, -1, "Saved Sessions:")
611        stateList = wx.Choice(dlg, -1, choices=states)
612        stateList.Bind(wx.EVT_CHOICE, OnStateSelected)
613        descriptionBox = wx.StaticBox(dlg, -1, "Description:")
614        descriptionText = wx.StaticText(dlg, -1, "", style=wx.ST_NO_AUTORESIZE)
615
616        dbSizer = wx.StaticBoxSizer(descriptionBox, wx.VERTICAL)
617        dbSizer.Add(descriptionText, 1, wx.EXPAND | wx.ALL, border=5)
618       
619        if len(stateHash) > 0:
620            stateList.SetSelection(0)
621            descriptionText.SetLabel( stateHash[stateList.GetString(0)] )
622            okBtn.Enable()
623       
624        stateSizer = wx.BoxSizer(wx.HORIZONTAL)
625        stateSizer.Add(stateLabel, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, border=5)
626        stateSizer.Add(stateList, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
627        stateSizer.Add(delBtn, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=5)
628       
629        sizer = wx.BoxSizer(wx.VERTICAL)
630        sizer.Add(stateSizer, 0, wx.EXPAND | wx.ALIGN_LEFT | wx.ALL, border=10)
631        sizer.Add(dbSizer, 1, wx.EXPAND | wx.ALIGN_LEFT | wx.RIGHT | wx.LEFT, border=10)
632        sizer.AddSpacer((15,15))
633        sizer.Add(okBtn, 0, wx.ALIGN_CENTER)
634        sizer.AddSpacer((5,5))
635
636        dlg.SetSizer(sizer)
637        dlg.SetSize((350, 300))
638
639        if dlg.ShowModal() == wx.ID_OK:
640            stateName = stateList.GetStringSelection()
641            dlg.Destroy()
642            if stateName == "":
643                Message("No saved sessions exist", "")
644                return
645            self.sageData.loadState(stateName)
646
647        return
648       
649       
650
651    # Menu -> Options -> RecordSession
652    def OnRecordSession(self, menuItem):
653        if menuItem.IsChecked():
654            self.sageGate.StartRecording(menuItem)
655        else:
656            self.sageGate.StopRecording()
657
658
659    # Menu -> Options -> ReadSession
660    def OnReadSession(self):
661        self.sageGate.PlaySession(self)
662       
663       
664    # Menu -> Options -> MaintainAspectRatio
665    def OnMaintainAspectRatio(self, menuItem):
666        diagram = self.GetDisplayCanvas().GetDiagram()
667        shapeList = diagram.GetShapeList()
668
669        # store the flag for future apps
670        self.GetDisplayCanvas().SetMaintainAspectRatio( menuItem.IsChecked() )
671
672        # change all the current apps' flags
673        for s in shapeList:
674            if ( s.__class__.__name__ == MyRectangleShape.__name__ ):
675                s.SetMaintainAspectRatio( self.displayCanvas.GetMaintainAspectRatio() )
676
677
678    # Menu -> Performance -> Logging
679    def OnLogPerfData(self, menuItem):
680        self.sageData.setLoggingFlag( menuItem.IsChecked() )
681
682
683    # Menu -> Performance -> Receive Performance Data
684    def OnReceivePerfData(self, menuItem):
685        self.GetDisplayCanvas().ReceivePerformanceData( menuItem.IsChecked() )
686
687
688    # (AKS 2005-05-07)
689    def OnShowRenderBW( self, menuItem ):
690        if ( menuItem.IsChecked() == True ):
691            self.__sgRenderBWGraph = Graph.SingleGraph(
692                self, self.sageData.getRenderBandwidthGraph(), "Totals: Render Bandwidth",
693                "Totals: Render Bandwidth", "Bandwidth (Mbps)", self.I_RENDER_BW_GRAPH )
694            self.__sgRenderBWGraph.registerShutdownCallback( self.removeGraph )
695            self.gmGraphManager.AddToUpdateList(self.__sgRenderBWGraph)
696        else:
697            self.gmGraphManager.RemoveFromUpdateList(self.__sgRenderBWGraph)
698            self.__sgRenderBWGraph.manualShutdown()
699
700        # end if
701
702
703    # (AKS 2005-05-07)
704    def OnShowDisplayBW( self, menuItem ):
705        if ( menuItem.IsChecked() == True ):
706            self.__sgDisplayBWGraph = Graph.SingleGraph(
707                self, self.sageData.getDisplayBandwidthGraph(), "Totals: Display Bandwidth",
708                "Totals: Display Bandwidth", "Bandwidth (Mbps)", self.I_DISPLAY_BW_GRAPH )
709            self.__sgDisplayBWGraph.registerShutdownCallback( self.removeGraph )
710            self.gmGraphManager.AddToUpdateList(self.__sgDisplayBWGraph)
711        else:
712            self.gmGraphManager.RemoveFromUpdateList(self.__sgDisplayBWGraph)
713            self.__sgDisplayBWGraph.manualShutdown()
714
715        # end if
716       
717
718    # (AKS 2005-05-07)
719    def removeGraph( self, iGraphID ):
720        if ( iGraphID == self.I_RENDER_BW_GRAPH ):
721            self.gmGraphManager.RemoveFromUpdateList(self.__sgRenderBWGraph)
722            self.__sgRenderBWGraph.manualShutdown()
723            self.UncheckMenuItem(RENDER_BW)
724            self.GetFrame().UpdateMenuItems(self.GetCurrentMenuItems())  #we must manually update the frame
725
726        elif ( iGraphID == self.I_DISPLAY_BW_GRAPH ):
727            self.gmGraphManager.RemoveFromUpdateList(self.__sgDisplayBWGraph)
728            self.__sgDisplayBWGraph.manualShutdown()
729            self.UncheckMenuItem(DISPLAY_BW)
730            self.GetFrame().UpdateMenuItems(self.GetCurrentMenuItems())  #we must manually update the frame
731
732        # end if; else, do nothing
733
734
735
736
737
738
739
740############################################################################
741#
742#  CLASS: SAGEuiFrame
743
744#  DESCRIPTION: It describes the main frame that holds all the other controls.
745#               It creates the two main canvases for the UI:
746#                       - the tiled display representation (upper canvas)
747#                       - the area for displaying app info (lower canvas)
748#
749#  DATE:        February 28, 2005
750#
751############################################################################
752
753class SAGEuiFrame(wx.Frame):
754
755    def __init__(self, sageGate, usersClient, firstMachineId, loadState, title=""):
756        self.loadState = loadState  # for automatically loading a saved display state upon startup
757       
758        if prefs.visual.GetFramePos() != None:
759            position = prefs.visual.GetFramePos()
760        else:
761            position = (50,0)
762            if "__WXMAC__" in wx.PlatformInfo:
763                position = (50,50)
764               
765        wx.Frame.__init__(self, None, -1, "SAGE UI",
766                          pos=position,
767                          size=(500,300),
768                          style=wx.DEFAULT_FRAME_STYLE )#| wx.FULL_REPAINT_ON_RESIZE)
769       
770        # this is the only common thing between the pages
771        self.usersClient = usersClient
772        self.usersData = getUsersData()
773
774        # so that we can kill SAGE from the UI
775        self.sageGate = sageGate
776       
777        # make the menu
778        self.SetMenuBar( self.CreateMenu() )
779
780        # bind any events we need
781        self.Bind(wx.EVT_CLOSE, self.OnCloseFrame)
782        self.Bind(wx.EVT_SIZE, self.OnSize)
783        self.Bind(wx.EVT_MOVE, self.OnMove)
784        self.Bind(wx.EVT_ACTIVATE, self.OnActivated)
785                 
786        # This creates some pens and brushes that the OGL library uses.
787        # It should be called after the app object has been created, but
788        # before OGL is used.
789        ogl.OGLInitialize()   
790       
791        self.notebook = DisplayNotebook(self)
792        tempHash = {}    #extract the values of all the checkable menu items and send them to the notebook as default values
793        for key, mi in self.menuCheckItems.iteritems():
794            tempHash[key] = mi.IsChecked()
795        self.notebook.SetDefaultMenuCheckItems(tempHash)
796        self.notebook.AddPage(DisplayPage(self.notebook, sageGate, usersClient, firstMachineId, title), title.split('@')[1], True)
797        self.usersPanel = UsersPanel(self, usersClient)
798        #self.Show()  < -- this is done in DisplayCanvas.OnSAGEDisplaysConnection()  (canvases.py)
799
800
801    #----------------------------------------------------------------------
802
803
804    def CreateMenu(self):     
805        self.menuBar = wx.MenuBar()
806
807        # File
808        menuFile = wx.Menu()
809
810        miFileNew = menuFile.Append(-1, "&New Connection\tCtrl-N", "Connect to another display")
811        self.Bind(wx.EVT_MENU, self.OnNewConnection, miFileNew)
812
813        miFileClose = menuFile.Append(-1, "Close Connection\tCtrl-W", "Close connection with this display")
814        self.Bind(wx.EVT_MENU, self.OnCloseConnection, miFileClose)
815
816        menuFile.AppendSeparator()
817       
818        miFileSave = menuFile.Append(SAVE_STATE, "&Save Session\tCtrl-S", "Save current session")
819        self.Bind(wx.EVT_MENU, self.OnMenuItem, miFileSave)
820
821        miFileLoad = menuFile.Append(LOAD_STATE, "&Load Session\tCtrl-O", "Load previously saved session")
822        self.Bind(wx.EVT_MENU, self.OnMenuItem, miFileLoad)
823
824        menuFile.AppendSeparator()
825
826        miFileSAGEShutdown = menuFile.Append(SAGE_SHUTDOWN, "Shutdown SAGE", "Shutdown SAGE")
827        self.Bind(wx.EVT_MENU, self.OnMenuItem, miFileSAGEShutdown)
828
829        menuFile.AppendSeparator()
830
831        miFileExit = menuFile.Append(-1, "E&xit\tAlt-X", "Exit demo")
832        self.Bind(wx.EVT_MENU, self.OnExitButton, miFileExit)
833       
834        self.menuBar.Append(menuFile, "&File")
835
836
837        # Options
838        menuOptions = wx.Menu()
839
840        self.miOptionsLibrary = menuOptions.Append(-1, "&File Library\tF2" , "Show File Library")
841        self.Bind(wx.EVT_MENU, self.OnShowLibrary, self.miOptionsLibrary)
842       
843        self.miOptionsAspectRatio = menuOptions.Append(ASPECT_RATIO, "Preserve Aspect Ratio" , "Maintain Aspect Ratio?", wx.ITEM_CHECK)
844        self.Bind(wx.EVT_MENU, self.OnMenuItem, self.miOptionsAspectRatio)
845        self.miOptionsAspectRatio.Check(prefs.visual.GetKeepAspectRatio())
846
847        self.miOptionsSAGEColor = menuOptions.Append(SAGE_COLOR, "Change SAGE Background Color" , "Change SAGE Background Color?")
848        self.Bind(wx.EVT_MENU, self.OnMenuItem, self.miOptionsSAGEColor)
849
850        self.miOptionsShowChat = menuOptions.Append(-1, "Show Chat Window", "", wx.ITEM_CHECK)
851        if self.usersClient.connected:
852            if prefs.visual.IsChatShown() != None:
853                self.miOptionsShowChat.Check(prefs.visual.IsChatShown())
854        self.Bind(wx.EVT_MENU, self.OnChatShow, self.miOptionsShowChat)
855
856        self.miOptionsOutput = menuOptions.Append(-1, "Show Console Output", "", wx.ITEM_CHECK)
857        self.Bind(wx.EVT_MENU, self.OnShowConsoleOutput, self.miOptionsOutput)
858        self.miOptionsOutput.Check(False)
859
860        self.miOptionsLauncherAdmin = menuOptions.Append(-1, "AppLauncher Admin" , "AppLauncher Admin Tool")
861        self.Bind(wx.EVT_MENU, self.OnLauncherAdmin, self.miOptionsLauncherAdmin)
862
863        self.menuBar.Append(menuOptions, "&Options")
864
865
866        # Performance
867        menuPerformance = wx.Menu()
868
869        self.miPerformancePerformance = menuPerformance.Append(PERF_DATA, "Receive Performance Data", "", wx.ITEM_CHECK)
870        self.Bind(wx.EVT_MENU, self.OnMenuItem, self.miPerformancePerformance)
871        self.miPerformancePerformance.Check(prefs.visual.GetReceivePerformanceData())
872
873        self.miPerformanceLogging = menuPerformance.Append(LOG_PERF_DATA, "Log Performance Data" , "Permit performance data logging to a file.", wx.ITEM_CHECK)
874        self.Bind(wx.EVT_MENU, self.OnMenuItem, self.miPerformanceLogging)
875        self.miPerformanceLogging.Check(True)
876
877        self.miPerformanceRenderBWGraph = menuPerformance.Append(RENDER_BW, "Show Total Rendering Bandwidth" , "Show the graph for Total Rendering Bandwidth.", wx.ITEM_CHECK)
878        self.Bind(wx.EVT_MENU, self.OnMenuItem, self.miPerformanceRenderBWGraph)
879        self.miPerformanceRenderBWGraph.Check(False)
880
881        self.miPerformanceDisplayBWGraph = menuPerformance.Append(DISPLAY_BW, "Show Total Display Bandwidth" , "Show the graph for Total Display Bandwidth.", wx.ITEM_CHECK)
882        self.Bind(wx.EVT_MENU, self.OnMenuItem, self.miPerformanceDisplayBWGraph)
883        self.miPerformanceDisplayBWGraph.Check(False)
884
885        self.menuBar.Append(menuPerformance, "&Performance")
886       
887
888        # Session
889        ## menuSession = wx.Menu()
890##         self.miSessionRecord = menuSession.Append(RECORD_SESSION, "Record Session" , "", wx.ITEM_CHECK)
891##         self.Bind(wx.EVT_MENU, self.OnMenuItem, self.miSessionRecord)
892##         self.miSessionRead = menuSession.Append(READ_SESSION, "Read Session" , "")
893##         self.Bind(wx.EVT_MENU, self.OnMenuItem, self.miSessionRead)
894##         self.menuBar.Append(menuSession, "&Session")
895
896
897        # Help
898        menuHelp = wx.Menu()
899        self.miAbout = menuHelp.Append(-1, "About SAGE UI\tF1", "")
900        self.Bind(wx.EVT_MENU, self.OnAbout, self.miAbout)
901        self.menuBar.Append(menuHelp, "&Help")
902
903
904        # store all the menu check items that are display dependent
905        self.menuCheckItems = {}
906        self.menuCheckItems[ASPECT_RATIO] = self.miOptionsAspectRatio#.IsChecked()
907        self.menuCheckItems[PERF_DATA] = self.miPerformancePerformance#.IsChecked()
908        self.menuCheckItems[LOG_PERF_DATA] = self.miPerformanceLogging#.IsChecked()
909        self.menuCheckItems[RENDER_BW] = self.miPerformanceRenderBWGraph#.IsChecked()
910        self.menuCheckItems[DISPLAY_BW] = self.miPerformanceDisplayBWGraph#.IsChecked()
911        #self.menuCheckItems[RECORD_SESSION] = self.miSessionRecord#.IsChecked()
912
913
914        # bind keystrokes to the frame
915        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyEvent)
916
917        return self.menuBar
918
919
920    #----------------------------------------------------------------------
921
922    def UpdateMenuItems(self, newMenuItems):
923        # update the menu with the specific menu items from the current page
924        for k,mi in self.menuCheckItems.iteritems():
925            mi.Check(newMenuItems[k])
926        self.menuBar.Refresh()
927           
928   
929    def GetUsersPanel(self):
930        return self.usersPanel
931
932
933
934##     def Reconnect(self):
935##         dlg = wx.MessageDialog(None, "Connection to SAGE has closed.\nYou will have to reconnect when SAGE becomes available again.", "SAGE Connection Closed", style=wx.OK)
936##         #btn = wx.Button(dlg, 999, "Reconnect")
937##         if dlg.ShowModal() == wx.ID_OK:
938##             self.notebook.CloseCurrentPage(closeUI=False)
939##             sageGate = SageGate()
940##             cd = ConnectionDialog(sageGate, self.usersClient, firstConnection=False)
941##             title = self.usersData.GetMyUsername() + " @ " + cd.hostname
942##             self.notebook.AddPage(DisplayPage(self.notebook, sageGate, self.usersData, self.usersClient, cd.host, title), title, True)
943                         
944##         dlg.Destroy()
945
946    #----------------------------------------------------------------------
947    # EVENT HANDLERS
948    #----------------------------------------------------------------------
949
950
951    def OnActivated(self, evt):
952        """ happens only when the frame is shown because we unbind the event below """
953        self.Disconnect(-1,-1,wx.wxEVT_ACTIVATE)
954       
955        # load the saved state of the display if requested
956        if self.loadState:
957            sageData = self.notebook.GetPage(self.notebook.GetSelection()).sageData
958            t = Timer(4, sageData.loadState, [self.loadState])
959            t.start()
960       
961
962    def OnSize(self, event=None):
963        if "__WXMSW__" in wx.PlatformInfo:   #to bypass windows' deferred resizing crap
964            def doResize():
965                #self.notebook.OnSize(event)
966                if self.usersClient.connected:
967                    self.usersPanel.OnFrameMove()
968            wx.CallAfter(doResize)
969        else:
970            #self.notebook.OnSize(event)
971            if self.usersClient.connected:
972                self.usersPanel.OnFrameMove()
973        event.Skip()  #resize the notebook
974       
975
976    def OnMove(self, event):
977        if self.usersClient.connected:
978            self.usersPanel.OnFrameMove()
979
980
981    def OnKeyEvent(self, event):
982        #self.notebook.OnKeyEvent(event)
983        event.Skip()
984
985       
986    def OnCloseFrame(self, evt):
987        # save the visual preferences (frame size, position, chat panel)
988        prefs.visual.SetAll(self.GetClientSize(), self.GetPosition(), self.usersPanel.IsShown())
989       
990        # close all connections to SAGEs
991        self.notebook.OnClose(evt)
992       
993        #if self.usersClient.connected:
994        self.usersPanel.Disconnect()
995
996       
997        # (AKS 2005-05-06) Delete all temp files of size 0 created when ignoring logging function
998        # Instead of allowing for the possibility that new apps start and their respective log
999        # files are not made causing an error, allow the new app's file to be created but do
1000        # not write to it.  Later, delete the 0-size file.
1001        try:   #in case the file and directory permissions are not right
1002            listFilenames = os.listdir( DATA_DIR )
1003
1004            # remove files that were never written or minimally written (i.e. <= 1K)
1005            for stFilename in listFilenames:
1006                stFilename = opj(DATA_DIR, stFilename)
1007                stCompleteFilename = os.path.normcase( stFilename )
1008                structStats = os.stat( stCompleteFilename )
1009
1010                if ( structStats.st_size <= 1024 ):
1011                    os.remove( stCompleteFilename )
1012                    print "Deleting", stCompleteFilename
1013                # end if
1014            # end loop
1015        except:
1016            pass
1017       
1018        self.DestroyChildren()
1019        self.Destroy()
1020        wx.GetApp().ExitMainLoop()
1021
1022
1023    #----------------------------------------------------------------------
1024    # MENU HANDLERS
1025    #----------------------------------------------------------------------
1026
1027
1028    ### this catches all the menu events that are display specific
1029    def OnMenuItem(self, event):
1030        self.notebook.OnMenuEvent(event)
1031
1032    # Menu -> File -> Exit
1033    def OnExitButton(self, evt):
1034        self.Close(True)
1035
1036    # Menu -> Help -> About
1037    def OnAbout(self, evt):
1038        AboutDialog(self)
1039
1040    # Menu -> Chat -> Show
1041    def OnChatShow(self, evt):
1042        if self.miOptionsShowChat.IsChecked():
1043            self.usersPanel.Show()
1044        else:
1045            self.usersPanel.Hide()
1046
1047    # Menu -> Options -> AppLauncher Admin
1048    def OnLauncherAdmin(self, evt):
1049        lAdmin.MainFrame(getSAGEServer())
1050
1051    # Menu -> Options -> Show File Library
1052    def OnShowLibrary(self, evt):
1053        self.notebook.GetPage(self.notebook.GetSelection()).displayCanvas.ShowLibrary()
1054
1055    # Menu -> Options -> Show Console Output
1056    def OnShowConsoleOutput(self, evt):
1057        if self.miOptionsOutput.IsChecked():
1058            wx.GetApp().RestoreStdio()
1059        else:
1060            try:
1061                wx.GetApp().RedirectStdio( LOG_FILE )
1062            except IOError:
1063                message = "\nCould not redirect output to a log file. Probably because of file permissions."
1064                message = message+"\nInstead, output will be printed in the console"
1065                dlg = wx.MessageDialog(self, message, "Error redirecting output", style=wx.OK)
1066                dlg.ShowModal()
1067                dlg.Destroy()
1068                wx.GetApp().RestoreStdio()
1069                self.miOptionsOutput.Check(True)
1070
1071    # Menu -> File -> New
1072    def OnNewConnection(self, event):
1073        sageGate = SageGate()
1074
1075        # initialize the dialog and show it. If it returns False, the user pressed quit
1076        # otherwise the connection to SAGE was successful and the username was accepted
1077        # so create the tab, show it and continue with execution
1078        cd = ConnectionDialog(sageGate, self.usersClient, firstConnection=False)
1079        if cd.ShowDialog():       
1080            title = self.usersData.GetMyUsername() + " @ " + cd.GetMachine().GetName()
1081            self.notebook.AddPage(DisplayPage(self.notebook, sageGate, self.usersClient, cd.GetMachine().GetId(), title), cd.GetMachine().GetName(), True)
1082                         
1083        return True
1084
1085    # Menu -> File -> Close
1086    def OnCloseConnection(self, event):
1087        self.notebook.CloseCurrentPage()
1088
1089
1090############################################################################
1091#
1092#  CLASS: AboutDialog
1093
1094#  DESCRIPTION: It just displays the about box.
1095#
1096#  DATE:        June 2005
1097#
1098############################################################################
1099
1100class AboutDialog(wx.Dialog):
1101    def __init__(self, parent):
1102        titleText = "SAGE Graphical User Interface"
1103        contentText = "version " + str(VERSION) + "\n\n\n" + "For more information go to:"
1104        linkUrl = "www.evl.uic.edu/cavern/sage"
1105        link2Text = "Direct questions or comments to:"
1106        link2Url = "www.evl.uic.edu/cavern/forum"
1107               
1108        wx.Dialog.__init__(self, parent, -1, "About SAGE UI", style=wx.CLOSE_BOX)
1109        okBtn = wx.Button(self, wx.ID_OK, "OK")
1110        title = wx.StaticText(self, -1, titleText, style=wx.ALIGN_CENTER)
1111        title.SetFont(BoldFont(title))
1112       
1113        if use_hyperlink:
1114            link = hyperlink.HyperLinkCtrl(self, wx.ID_ANY, linkUrl, URL="http://"+linkUrl)
1115            link.AutoBrowse(True)
1116            link2 = hyperlink.HyperLinkCtrl(self, wx.ID_ANY, link2Url, URL="http://"+link2Url)
1117            link2.AutoBrowse(True)
1118        else:
1119            link = wx.StaticText(self, -1, linkUrl, style=wx.ALIGN_CENTER)
1120            link2 = wx.StaticText(self, -1, link2Url, style=wx.ALIGN_CENTER)
1121
1122        text = wx.StaticText(self, -1, contentText, style=wx.ALIGN_CENTER)
1123        text2 = wx.StaticText(self, -1, link2Text, style=wx.ALIGN_CENTER)
1124       
1125
1126        sizer = wx.BoxSizer(wx.VERTICAL)
1127        sizer.AddSpacer((20, 20))
1128        sizer.Add(title, 0, wx.ALIGN_CENTER | wx.RIGHT | wx.LEFT, border=15)
1129        sizer.Add(text, 0, wx.ALIGN_CENTER)
1130        sizer.Add(link, 0, wx.ALIGN_CENTER)
1131        sizer.AddSpacer((15,15))
1132        sizer.Add(text2, 0, wx.ALIGN_CENTER)
1133        sizer.Add(link2, 0, wx.ALIGN_CENTER)
1134        sizer.AddSpacer((15,15))
1135        sizer.Add(okBtn, 0, wx.ALIGN_CENTER)
1136        sizer.AddSpacer((5,5))
1137        self.SetSizer(sizer)
1138        self.Fit()
1139        self.ShowModal()
1140        self.Destroy()
1141               
1142
1143
1144
1145
1146############################################################################
1147#
1148#  CLASS: SAGEui
1149
1150#  DESCRIPTION: This is a starting point for wx. It extends wx.App and
1151#               creates the SAGEuiFrame to place the canvases in. It also displays
1152#               the initial dialogs for the User profile and SAGE connection.
1153#
1154#  DATE:        October 2004
1155#
1156############################################################################
1157
1158class SAGEui(wx.App):
1159    def __init__(self, usersServerIP, usersServerPort, verbose, autologinMachine, loadState):
1160        self.usersServerIP = usersServerIP
1161        self.usersServerPort = usersServerPort
1162        self.autologinMachine = autologinMachine
1163        self.loadState = loadState
1164       
1165        if verbose:
1166            wx.App.__init__(self, redirect=False)
1167        else:
1168            try:
1169                wx.App.__init__(self, redirect=True, filename=LOG_FILE)
1170            except IOError:
1171                print "\nError: Could not redirect output to a log file. Possibly because of file permissions."
1172                print "Instead, output will be printed in the console"
1173                wx.App.__init__(self, redirect=False)
1174
1175    def Skip( self, evt ):
1176        pass
1177
1178    def OnInit(self):
1179        wx.Log_SetActiveTarget(wx.LogStderr())
1180        self.SetAssertMode(assertMode)
1181        socket.setdefaulttimeout(2)
1182   
1183        # initialize network communication with:
1184        # sageGate...   the connection to SAGE
1185        # usersClient...the connection to UsersServer
1186        # usersData...  the datastructure used in conjunction with usersClient
1187        usersData = UsersDatastructure()
1188        setUsersData(usersData) #store it in a global scope
1189        sageGate = SageGate()
1190        usersClient = UsersClient()
1191
1192        # initialize the dialog and show it. If it returns False, the user pressed quit
1193        # otherwise the connection to SAGE was successful and the username was accepted
1194        # so show the frame and continue with execution
1195        cd = ConnectionDialog(sageGate, usersClient, self.usersServerIP, usersServerPort = self.usersServerPort, autologinMachine=self.autologinMachine)
1196        if cd.ShowDialog():       
1197            title = usersData.GetMyUsername() + " @ " + cd.GetMachine().GetName()
1198            self.frame = SAGEuiFrame(sageGate, usersClient, cd.GetMachine().GetId(), self.loadState, title)       
1199            self.SetTopWindow(self.frame)
1200        else:
1201            usersClient.Disconnect()
1202            sys.exit(0)
1203                         
1204        return True
1205
1206
1207
1208
1209############################################################################
1210#
1211# Main entry point for the application
1212#
1213############################################################################
1214
1215### sets up the parser for the command line options
1216def get_commandline_options():
1217    parser = optparse.OptionParser()
1218
1219    h = "if set, prints output to console, otherwise to ~/.sageConfig/sageui/output_log.txt"
1220    parser.add_option("-v", "--verbose", action="store_true", help=h, dest="verbose", default=False)
1221
1222    h = "which sage server / connection manager to use (default is sage.sl.startap.net)"
1223    parser.add_option("-s", "--server", dest="server", help=h, default="sage.sl.startap.net")
1224
1225    h = "change the port number of the sage server (default is 15558)"
1226    parser.add_option("-p", "--port", help=h, type="int", dest="port", default=15558)
1227
1228    h = "override which application launcher to use (by default it looks for one on the same machine as sage master. Specify as machine:port)"
1229    parser.add_option("-l", "--launcher", dest="launcher", help=h, default="")
1230
1231    h = "try autologin to this sage name (what fsManager reports to connection manager from fsManager.conf )"
1232    parser.add_option("-a", "--autologin", dest="autologin", help=h, default=None)
1233
1234    h = "upon startup load this saved state (write saved state name from saved-states directory)"
1235    parser.add_option("-o", "--load_state", dest="load_state", help=h, default=None)
1236
1237    h = "perform autosave?"
1238    parser.add_option("-t", "--autosave", action="store_true", help=h, dest="autosave", default=False)
1239
1240    return parser.parse_args()
1241
1242
1243
1244def main(argv):
1245    os.chdir(sys.path[0])  # change to the folder where script is running
1246    global autosave
1247    verbose = False
1248    usersServerIP = "74.114.99.36"
1249    usersServerPort = 15558
1250   
1251    # parse the command line params
1252    (options, args) = get_commandline_options()
1253    verbose = options.verbose
1254    usersServerPort = options.port
1255    usersServerIP = options.server
1256    appLauncher = options.launcher
1257    autologinMachine = options.autologin
1258    loadState = options.load_state
1259    autosave = options.autosave
1260   
1261    # set the overridden app launcher
1262    if appLauncher != "":
1263        setAppLauncher(appLauncher)
1264       
1265    # set the global variable for the SAGE SERVER
1266    setSAGEServer(usersServerIP)
1267   
1268    # print some information about the system currently running
1269    print "\nCurrently running:\n--------------------------"
1270    print "SAGE UI version: ", VERSION
1271    print "Python version:  ", string.split(sys.version, "(", 1)[0]
1272    print "wxPython version: "+str(wx.VERSION[0])+"."+str(wx.VERSION[1])+"."+str(wx.VERSION[2])+"."+str(wx.VERSION[3])+"\n" 
1273
1274    # read all the preferences
1275    import preferences as prefs
1276    prefs.readAllPreferences()
1277
1278    app = SAGEui(usersServerIP, usersServerPort, verbose, autologinMachine, loadState)
1279    app.MainLoop()
1280   
1281   
1282
1283
1284if __name__ == '__main__':
1285    import sys, os
1286    main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
1287
1288
1289   
1290   
1291
1292
Note: See TracBrowser for help on using the repository browser.