1 #---------------------------------------------------------------------------- 
   3 # Purpose:      Subversion Service for pydocview 
   9 # Copyright:    (c) 2005 ActiveGrid, Inc. 
  10 # License:      wxWindows License 
  11 #---------------------------------------------------------------------------- 
  19 import sys        
# for errors 
  20 import traceback  
# for errors 
  23     import pysvn  
# python-subversion integration 
  31 #---------------------------------------------------------------------------- 
  33 #---------------------------------------------------------------------------- 
  34 SVN_CONFIG_DIR 
= "SVNConfigDir" 
  35 SVN_REPOSITORY_URL 
= "SVNRepositoryURLs" 
  41 #---------------------------------------------------------------------------- 
  43 #---------------------------------------------------------------------------- 
  45 class SVNService(wx
.lib
.pydocview
.DocService
): 
  46     SVN_UPDATE_ALL_ID 
= wx
.NewId() 
  47     SVN_UPDATE_ID 
= wx
.NewId() 
  48     SVN_CHECKIN_ID 
= wx
.NewId() 
  49     SVN_CHECKIN_ALL_ID 
= wx
.NewId() 
  50     SVN_CHECKOUT_ID 
= wx
.NewId() 
  51     SVN_REVERT_ID 
= wx
.NewId() 
  52     SVN_ADD_ID 
= wx
.NewId() 
  53     SVN_DELETE_ID 
= wx
.NewId() 
  54     SVN_COMMAND_LIST 
= [SVN_UPDATE_ALL_ID
, SVN_CHECKIN_ALL_ID
, SVN_UPDATE_ID
, SVN_CHECKIN_ID
, SVN_CHECKOUT_ID
, SVN_REVERT_ID
, SVN_ADD_ID
, SVN_DELETE_ID
] 
  58         self
._defaultURL 
= "svn://" 
  62             config 
= wx
.ConfigBase_Get() 
  64             configDir 
= config
.Read(SVN_CONFIG_DIR
, "") 
  65             self
._client 
= pysvn
.Client(configDir
) 
  67                 self
._defaultURL 
= self
._client
.info('.').url
 
  71             self
._client
.callback_cancel 
= self
.IfCancel
 
  72             self
._client
.callback_notify 
= self
.UpdateStatus
 
  73             self
._client
.callback_get_log_message 
= self
.GetLogMessage
 
  74             self
._client
.callback_get_login 
= self
.GetLogin
 
  75             self
._client
.callback_ssl_server_trust_prompt 
= self
.GetSSLServerTrust
 
  76             self
._client
.callback_ssl_client_cert_password_prompt 
= self
.SSLClientPassword
 
  77             self
._client
.callback_ssl_client_cert_prompt 
= self
.SSLClientCert
 
  78             self
._client
.callback_ssl_server_prompt 
= self
.SSLServerPrompt
 
  80     #---------------------------------------------------------------------------- 
  81     # pysvn.Client() Callback Methods 
  82     #---------------------------------------------------------------------------- 
  85         """ return True if user wants to cancel current command """ 
  89     def UpdateStatus(self
, eventDict
): 
  90         messageService 
= wx
.GetApp().GetService(MessageService
.MessageService
) 
  91         messageService
.ShowWindow() 
  93         view 
= messageService
.GetView() 
  94         view
.AddLines(_("%s %s\n") % (eventDict
['action'], eventDict
['path'])) 
  97     def GetLogMessage(self
): 
  98         dlg 
= wx
.TextEntryDialog(wx
.GetApp().GetTopWindow(), 
 100                 _("SVN Log Message")) 
 103         if dlg
.ShowModal() == wx
.ID_OK
: 
 105             message 
= dlg
.GetValue() 
 108             message 
= _("Cancel Action") 
 112         return retcode
, message
 
 115     def GetLogin(self
, realm
, username
, maySave
): 
 116         dlg 
= wx
.Dialog(wx
.GetApp().GetTopWindow(), -1, _("SVN Login")) 
 118         sizer 
= wx
.FlexGridSizer(cols 
= 2, hgap 
= 5, vgap 
= 5) 
 119         sizer
.Add(wx
.StaticText(dlg
, -1, _("Username:")), 0, wx
.ALIGN_CENTER_VERTICAL
) 
 120         usernameTxt 
= wx
.TextCtrl(dlg
, -1, username
, size 
= (200, -1)) 
 121         sizer
.Add(usernameTxt
, 0, wx
.ALIGN_CENTER_VERTICAL
) 
 122         sizer
.Add(wx
.StaticText(dlg
, -1, _("Password:")), 0, wx
.ALIGN_CENTER_VERTICAL
) 
 123         passwordTxt 
= wx
.TextCtrl(dlg
, -1, size
=(200, -1), style
=wx
.TE_PASSWORD
) 
 124         sizer
.Add(passwordTxt
, 0, wx
.ALIGN_CENTER_VERTICAL
) 
 126         savePasswordCheckbox 
= wx
.CheckBox(dlg
, -1, _("Remember Username and Password")) 
 128             savePasswordCheckbox
.Enable(False) 
 130         buttonSizer 
= wx
.BoxSizer(wx
.HORIZONTAL
) 
 131         okBtn 
= wx
.Button(dlg
, wx
.ID_OK
) 
 133         buttonSizer
.Add(okBtn
, 0, wx
.RIGHT
, HALF_SPACE
) 
 134         buttonSizer
.Add(wx
.Button(dlg
, wx
.ID_CANCEL
), 0) 
 136         contentSizer 
= wx
.BoxSizer(wx
.VERTICAL
) 
 137         contentSizer
.Add(sizer
, 0, wx
.LEFT|wx
.TOP|wx
.RIGHT
, SPACE
) 
 138         contentSizer
.Add(savePasswordCheckbox
, 0, wx
.TOP|wx
.LEFT|wx
.BOTTOM
, SPACE
) 
 139         contentSizer
.Add(buttonSizer
, 0, wx
.ALL|wx
.ALIGN_RIGHT
, SPACE
) 
 141         dlg
.SetSizer(contentSizer
) 
 146         if dlg
.ShowModal() == wx
.ID_OK
: 
 148             username 
= usernameTxt
.GetValue().strip() 
 149             password 
= passwordTxt
.GetValue() 
 150             save 
= savePasswordCheckbox
.IsChecked() 
 158         return retcode
, username
, password
, save
 
 161     def SSLServerPrompt(self
): 
 162         """ Not implemented, as per pysvn documentation """ 
 166     def GetSSLServerTrust(self
, trustDict
): 
 167         dlg 
= wx
.Dialog(wx
.GetApp().GetTopWindow(), -1, _("SSL Server Certificate")) 
 169         sizer 
= wx
.FlexGridSizer(cols 
= 2, hgap 
= 5, vgap 
= 5) 
 170         for k 
in ['hostname', 'valid_from', 'valid_to', 'issuer_dname', 'realm']: 
 171             if trustDict
.has_key(k
): 
 172                 sizer
.Add(wx
.StaticText(dlg
, -1, "%s:" % k
), 0, wx
.ALIGN_CENTER_VERTICAL
) 
 173                 sizer
.Add(wx
.StaticText(dlg
, -1, "%s"  % trustDict
[k
]), 0, wx
.ALIGN_CENTER_VERTICAL
) 
 175         box 
= wx
.StaticBoxSizer(wx
.StaticBox(dlg
, -1, _("Certificate Info")), wx
.VERTICAL
) 
 176         box
.Add(sizer
, 0, wx
.EXPAND
) 
 178         certRadio 
= wx
.RadioBox(dlg
, -1, _("Certificate"), choices
=[_("Accept Always"), _("Accept Once"), _("Reject")], majorDimension
=1, style
=wx
.RA_SPECIFY_COLS
) 
 180         buttonSizer 
= wx
.BoxSizer(wx
.HORIZONTAL
) 
 181         okBtn 
= wx
.Button(dlg
, wx
.ID_OK
) 
 183         buttonSizer
.Add(okBtn
, 0, wx
.RIGHT
, HALF_SPACE
) 
 184         buttonSizer
.Add(wx
.Button(dlg
, wx
.ID_CANCEL
), 0) 
 186         contentSizer 
= wx
.BoxSizer(wx
.VERTICAL
) 
 187         contentSizer
.Add(box
, 0, wx
.TOP|wx
.LEFT|wx
.RIGHT|wx
.EXPAND
, SPACE
) 
 188         contentSizer
.Add(certRadio
, 0, wx
.TOP|wx
.LEFT|wx
.RIGHT|wx
.BOTTOM|wx
.EXPAND
, SPACE
) 
 189         contentSizer
.Add(buttonSizer
, 0, wx
.ALL|wx
.ALIGN_RIGHT
, SPACE
) 
 191         dlg
.SetSizer(contentSizer
) 
 195         # default values for reject 
 201         if dlg
.ShowModal() == wx
.ID_OK
: 
 202             cert 
= certRadio
.GetStringSelection() 
 203             if cert 
== _("Accept Always"): 
 205                 acceptedFailures 
= trustDict
.get('failures') 
 207             elif cert 
== _("Accept Once"): 
 209                 acceptedFailures 
= trustDict
.get('failures') 
 213         return retcode
, acceptedFailures
, save
 
 216     def SSLClientPassword(self
, realm
, maySave
): 
 217         dlg 
= wx
.Dialog(wx
.GetApp().GetTopWindow(), -1, _("SSL Client Certificate Login")) 
 219         sizer 
= wx
.FlexGridSizer(cols 
= 2, hgap 
= 5, vgap 
= 5) 
 220         sizer
.Add(wx
.StaticText(dlg
, -1, _("Realm:")), 0, wx
.ALIGN_CENTER_VERTICAL
) 
 221         sizer
.Add(wx
.StaticText(dlg
, -1, realm
), 0, wx
.ALIGN_CENTER_VERTICAL
) 
 222         sizer
.Add(wx
.StaticText(dlg
, -1, _("Password:")), 0, wx
.ALIGN_CENTER_VERTICAL
) 
 223         passwordTxt 
= wx
.TextCtrl(dlg
, -1, size
=(200, -1), style
=wx
.TE_PASSWORD
) 
 224         sizer
.Add(passwordTxt
, 0, wx
.ALIGN_CENTER_VERTICAL
) 
 226         savePasswordCheckbox 
= wx
.CheckBox(dlg
, -1, _("Remember Password")) 
 228             savePasswordCheckbox
.Enable(False) 
 230         buttonSizer 
= wx
.BoxSizer(wx
.HORIZONTAL
) 
 231         okBtn 
= wx
.Button(dlg
, wx
.ID_OK
) 
 233         buttonSizer
.Add(okBtn
, 0, wx
.RIGHT
, HALF_SPACE
) 
 234         buttonSizer
.Add(wx
.Button(dlg
, wx
.ID_CANCEL
), 0) 
 236         contentSizer 
= wx
.BoxSizer(wx
.VERTICAL
) 
 237         contentSizer
.Add(sizer
, 0, wx
.LEFT|wx
.TOP|wx
.RIGHT
, SPACE
) 
 238         contentSizer
.Add(savePasswordCheckbox
, 0, wx
.TOP|wx
.LEFT|wx
.BOTTOM
, SPACE
) 
 239         contentSizer
.Add(buttonSizer
, 0, wx
.ALL|wx
.ALIGN_RIGHT
, SPACE
) 
 241         dlg
.SetSizer(contentSizer
) 
 246         if dlg
.ShowModal() == wx
.ID_OK
: 
 248             password 
= passwordTxt
.GetValue() 
 249             save 
= savePasswordCheckbox
.IsChecked() 
 256         return retcode
, password
, save
 
 259     def SSLClientCert(self
): 
 260         dlg 
= wx
.FileDialog(wx
.GetApp().GetTopWindow(), 
 261             message
="Choose certificate", 
 262             style
=wx
.OPEN|wx
.FILE_MUST_EXIST|wx
.CHANGE_DIR
 
 265         # dlg.CenterOnParent()  # wxBug: caused crash with wx.FileDialog 
 266         if dlg
.ShowModal() == wx
.ID_OK
: 
 268             certfile 
= dlg
.GetPath() 
 274         return retcode
, certfile
 
 278     #---------------------------------------------------------------------------- 
 280     #---------------------------------------------------------------------------- 
 282     def InstallControls(self
, frame
, menuBar 
= None, toolBar 
= None, statusBar 
= None, document 
= None): 
 283         menu 
= menuBar
.GetMenu(menuBar
.FindMenu(_("Project"))) 
 285         menu
.AppendSeparator() 
 287         wx
.EVT_MENU(frame
, SVNService
.SVN_UPDATE_ALL_ID
, self
.ProcessEvent
) 
 288         wx
.EVT_UPDATE_UI(frame
, SVNService
.SVN_UPDATE_ALL_ID
, self
.ProcessUpdateUIEvent
) 
 289         menu
.Append(SVNService
.SVN_UPDATE_ALL_ID
, _("SVN Update All in Project"), _("Update all files in a project from Subversion")) 
 290         wx
.EVT_MENU(frame
, SVNService
.SVN_CHECKIN_ALL_ID
, self
.ProcessEvent
) 
 291         wx
.EVT_UPDATE_UI(frame
, SVNService
.SVN_CHECKIN_ALL_ID
, self
.ProcessUpdateUIEvent
) 
 292         menu
.Append(SVNService
.SVN_CHECKIN_ALL_ID
, _("SVN Commit All in Project..."), _("Commit all files changes in a project to Subversion")) 
 293         wx
.EVT_MENU(frame
, SVNService
.SVN_UPDATE_ID
, self
.ProcessEvent
) 
 294         wx
.EVT_UPDATE_UI(frame
, SVNService
.SVN_UPDATE_ID
, self
.ProcessUpdateUIEvent
) 
 295         menu
.Append(SVNService
.SVN_UPDATE_ID
, _("SVN Update"), _("Update file from Subversion")) 
 296         wx
.EVT_MENU(frame
, SVNService
.SVN_CHECKIN_ID
, self
.ProcessEvent
) 
 297         wx
.EVT_UPDATE_UI(frame
, SVNService
.SVN_CHECKIN_ID
, self
.ProcessUpdateUIEvent
) 
 298         menu
.Append(SVNService
.SVN_CHECKIN_ID
, _("SVN Commit..."), _("Commit file changes to Subversion")) 
 299         wx
.EVT_MENU(frame
, SVNService
.SVN_CHECKOUT_ID
, self
.ProcessEvent
) 
 300         wx
.EVT_UPDATE_UI(frame
, SVNService
.SVN_CHECKOUT_ID
, self
.ProcessUpdateUIEvent
) 
 301         menu
.Append(SVNService
.SVN_CHECKOUT_ID
, _("SVN Checkout..."), _("Checkout file from Subversion")) 
 302         wx
.EVT_MENU(frame
, SVNService
.SVN_REVERT_ID
, self
.ProcessEvent
) 
 303         wx
.EVT_UPDATE_UI(frame
, SVNService
.SVN_REVERT_ID
, self
.ProcessUpdateUIEvent
) 
 304         menu
.Append(SVNService
.SVN_REVERT_ID
, _("SVN Revert"), _("Revert file from Subversion")) 
 306         menu
.AppendSeparator() 
 308         wx
.EVT_MENU(frame
, SVNService
.SVN_ADD_ID
, self
.ProcessEvent
) 
 309         wx
.EVT_UPDATE_UI(frame
, SVNService
.SVN_ADD_ID
, self
.ProcessUpdateUIEvent
) 
 310         menu
.Append(SVNService
.SVN_ADD_ID
, _("SVN Add"), _("Add file to Subversion")) 
 311         wx
.EVT_MENU(frame
, SVNService
.SVN_DELETE_ID
, self
.ProcessEvent
) 
 312         wx
.EVT_UPDATE_UI(frame
, SVNService
.SVN_DELETE_ID
, self
.ProcessUpdateUIEvent
) 
 313         menu
.Append(SVNService
.SVN_DELETE_ID
, _("SVN Delete"), _("Delete file from Subversion")) 
 316     def ProcessEvent(self
, event
): 
 320         if not SVN_INSTALLED
: 
 321             if id in SVNService
.SVN_COMMAND_LIST
: 
 322                 wx
.MessageBox(_("pysvn not found.  Please install pysvn"), _("Python Subversion")) 
 327         if id == SVNService
.SVN_UPDATE_ID
: 
 328             wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_WAIT
)) 
 330             filenames 
= self
.GetCurrentDocuments() 
 332                 filenames 
= filenames
[:] 
 333                 filenames
.sort(self
.BasenameCaseInsensitiveCompare
) 
 335                 folderPath 
= self
.GetCurrentFolder() 
 337                     filenames 
= [folderPath
] 
 339             messageService 
= wx
.GetApp().GetService(MessageService
.MessageService
) 
 340             messageService
.ShowWindow() 
 342             view 
= messageService
.GetView() 
 344             view
.AddLines(_("SVN Update:\n")) 
 346             for filename 
in filenames
: 
 347                 view
.AddLines("%s\n" % filename
) 
 349                     status 
= self
._client
.update(filename
) 
 351                     if status
.number 
> 0: 
 352                         view
.AddLines(_("Updated to revision %s\n") % status
.number
) 
 354                         openDocs 
= wx
.GetApp().GetDocumentManager().GetDocuments() 
 356                             if doc
.GetFilename() == filename
: 
 357                                 yesNoMsg 
= wx
.MessageDialog(wx
.GetApp().GetTopWindow(), 
 358                                                          _("Updated file '%s' is currently open.  Close it?") % os
.path
.basename(filename
), 
 360                                                          wx
.YES_NO|wx
.ICON_QUESTION
) 
 361                                 yesNoMsg
.CenterOnParent() 
 362                                 status 
= yesNoMsg
.ShowModal() 
 364                                 if status 
== wx
.ID_YES
: 
 368                         view
.AddLines(_("Update failed.\n")) 
 370                 except pysvn
.ClientError
, e
: 
 371                     view
.AddLines("%s\n" % str(e
)) 
 372                     wx
.MessageBox(str(e
), _("SVN Update"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 374                     extype
, ex
, tb 
= sys
.exc_info() 
 375                     view
.AddLines("Update failed: (%s) %s\n" % (extype
, str(ex
))) 
 376                     for line 
in traceback
.format_tb(tb
): 
 379                     wx
.MessageBox(_("Update failed."), _("SVN Update"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 381             wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_DEFAULT
)) 
 385         elif id == SVNService
.SVN_UPDATE_ALL_ID
: 
 386             wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_WAIT
)) 
 388             messageService 
= wx
.GetApp().GetService(MessageService
.MessageService
) 
 389             messageService
.ShowWindow() 
 391             view 
= messageService
.GetView() 
 393             view
.AddLines(_("SVN Update:\n")) 
 395             project 
= self
.GetCurrentProject() 
 397                 openDocs 
= wx
.GetApp().GetDocumentManager().GetDocuments() 
 399                     if doc
.GetFilename() == project
: 
 400                         filenames 
= doc
.GetFiles()[:]  # make a copy and sort it. 
 401                         filenames
.sort(self
.BasenameCaseInsensitiveCompare
) 
 403                         for filename 
in filenames
: 
 404                             view
.AddLines("%s\n" % filename
) 
 406                                 status 
= self
._client
.update(filename
) 
 408                                 if status
.number 
> 0: 
 409                                     view
.AddLines(_("Updated to revision %s\n") % status
.number
) 
 411                                     openDocs 
= wx
.GetApp().GetDocumentManager().GetDocuments() 
 413                                         if doc
.GetFilename() == filename
: 
 414                                             yesNoMsg 
= wx
.MessageDialog(wx
.GetApp().GetTopWindow(), 
 415                                                                      _("Updated file '%s' is currently open.  Close it?") % os
.path
.basename(filename
), 
 417                                                                      wx
.YES_NO|wx
.CANCEL|wx
.ICON_QUESTION
) 
 418                                             yesNoMsg
.CenterOnParent() 
 419                                             status 
= yesNoMsg
.ShowModal() 
 421                                             if status 
== wx
.ID_YES
: 
 423                                             elif status 
== wx
.ID_NO
: 
 425                                             else: # elif status == wx.CANCEL: 
 426                                                 wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_DEFAULT
)) 
 430                                     view
.AddLines(_("Update failed.\n")) 
 432                             except pysvn
.ClientError
, e
: 
 433                                 view
.AddLines("%s\n" % str(e
)) 
 434                                 wx
.MessageBox(str(e
), _("SVN Update"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 436                                 extype
, ex
, tb 
= sys
.exc_info() 
 437                                 view
.AddLines("Update failed: (%s) %s\n" % (extype
, str(ex
))) 
 438                                 for line 
in traceback
.format_tb(tb
): 
 441                                 wx
.MessageBox(_("Update failed."), _("SVN Update"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 443             wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_DEFAULT
)) 
 446         elif id == SVNService
.SVN_CHECKIN_ALL_ID
: 
 448             project 
= self
.GetCurrentProject() 
 450                 openDocs 
= wx
.GetApp().GetDocumentManager().GetDocuments() 
 452                     if doc
.GetFilename() == project
: 
 453                         for filename 
in doc
.GetFiles(): 
 454                             if filename 
not in filenames
: 
 455                                 filenames
.append(filename
) 
 456             filenames
.sort(self
.BasenameCaseInsensitiveCompare
) 
 458             # ask user if dirty files should be saved first 
 459             openDocs 
= wx
.GetApp().GetDocumentManager().GetDocuments() 
 460             for filename 
in filenames
: 
 462                     if doc
.GetFilename() == filename 
and doc
.IsModified(): 
 463                         yesNoMsg 
= wx
.MessageDialog(wx
.GetApp().GetTopWindow(), 
 464                                                  _("'%s' has unsaved modifications.  Save it before commit?") % os
.path
.basename(filename
), 
 466                                                  wx
.YES_NO|wx
.CANCEL|wx
.ICON_QUESTION
) 
 467                         yesNoMsg
.CenterOnParent() 
 468                         status 
= yesNoMsg
.ShowModal() 
 470                         if status 
== wx
.ID_YES
: 
 472                         elif status 
== wx
.ID_NO
: 
 474                         else: # elif status == wx.CANCEL: 
 479             for i
, filename 
in enumerate(filenames
): 
 480                 shortFilename 
= os
.path
.basename(filename
) 
 481                 shortFilenames
.append(shortFilename
) 
 483             dlg 
= wx
.Dialog(wx
.GetApp().GetTopWindow(), -1, _("SVN Commit")) 
 485             sizer 
= wx
.BoxSizer(wx
.VERTICAL
) 
 486             sizer
.Add(wx
.StaticText(dlg
, -1, _("Comment:")), 0, wx
.ALIGN_CENTER_VERTICAL
) 
 487             commentText 
= wx
.TextCtrl(dlg
, -1, size
=(250,-1), style
=wx
.TE_MULTILINE
) 
 488             sizer
.Add(commentText
, 1, wx
.EXPAND|wx
.TOP
, HALF_SPACE
) 
 490             sizer
.Add(wx
.StaticText(dlg
, -1, _("Files:")), 0, wx
.ALIGN_CENTER_VERTICAL|wx
.TOP
, SPACE
) 
 491             fileList 
= wx
.CheckListBox(dlg
, -1, choices 
= shortFilenames
) 
 492             for i 
in range(fileList
.GetCount()): 
 493                 fileList
.Check(i
, True) 
 494             sizer
.Add(fileList
, 0, wx
.EXPAND|wx
.TOP
, HALF_SPACE
) 
 496             buttonSizer 
= wx
.StdDialogButtonSizer() 
 497             okBtn 
= wx
.Button(dlg
, wx
.ID_OK
) 
 499             buttonSizer
.AddButton(okBtn
) 
 500             buttonSizer
.AddButton(wx
.Button(dlg
, wx
.ID_CANCEL
)) 
 501             buttonSizer
.Realize() 
 503             contentSizer 
= wx
.BoxSizer(wx
.VERTICAL
) 
 504             contentSizer
.Add(sizer
, 0, wx
.ALL
, SPACE
) 
 505             contentSizer
.Add(buttonSizer
, 0, wx
.ALL|wx
.ALIGN_RIGHT
, SPACE
) 
 507             dlg
.SetSizer(contentSizer
) 
 512             if dlg
.ShowModal() == wx
.ID_OK
: 
 513                 wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_WAIT
)) 
 515                 messageService 
= wx
.GetApp().GetService(MessageService
.MessageService
) 
 516                 messageService
.ShowWindow() 
 518                 view 
= messageService
.GetView() 
 520                 view
.AddLines(_("SVN Commit:\n")) 
 524                     for i 
in range(fileList
.GetCount()): 
 525                         if fileList
.IsChecked(i
): 
 526                             selFilenames
.append(filenames
[i
]) 
 527                             view
.AddLines("%s\n" % filenames
[i
]) 
 529                     if len(selFilenames
): 
 530                         comment 
= commentText
.GetValue() 
 531                         status 
= self
._client
.checkin(selFilenames
, comment
) 
 534                             view
.AddLines(_("Nothing to commit.\n")) 
 535                         elif status
.number 
> 0: 
 536                             view
.AddLines(_("Committed as revision %s.\n") % status
.number
) 
 538                             view
.AddLines(_("Commit failed.\n")) 
 540                 except pysvn
.ClientError
, e
: 
 541                     view
.AddLines("%s\n" % str(e
)) 
 542                     wx
.MessageBox(str(e
), _("SVN Commit"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 544                     extype
, ex
, tb 
= sys
.exc_info() 
 545                     view
.AddLines("Commit failed: (%s) %s\n" % (extype
, str(ex
))) 
 546                     for line 
in traceback
.format_tb(tb
): 
 548                     wx
.MessageBox(_("Commit failed."), _("SVN Commit"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 550                 wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_DEFAULT
)) 
 555         elif id == SVNService
.SVN_CHECKIN_ID
: 
 556             filenames 
= self
.GetCurrentDocuments()[:] 
 557             filenames
.sort(self
.BasenameCaseInsensitiveCompare
)             
 559             # ask user if dirty files should be saved first 
 560             openDocs 
= wx
.GetApp().GetDocumentManager().GetDocuments() 
 561             for filename 
in filenames
: 
 563                     if doc
.GetFilename() == filename 
and doc
.IsModified(): 
 564                         yesNoMsg 
= wx
.MessageDialog(wx
.GetApp().GetTopWindow(), 
 565                                                  _("'%s' has unsaved modifications.  Save it before commit?") % os
.path
.basename(filename
), 
 567                                                  wx
.YES_NO|wx
.CANCEL|wx
.ICON_QUESTION
) 
 568                         yesNoMsg
.CenterOnParent() 
 569                         status 
= yesNoMsg
.ShowModal() 
 571                         if status 
== wx
.ID_YES
: 
 573                         elif status 
== wx
.ID_NO
: 
 575                         else: # elif status == wx.CANCEL: 
 580             for i
, filename 
in enumerate(filenames
): 
 581                 shortFilename 
= os
.path
.basename(filename
) 
 582                 shortFilenames
.append(shortFilename
) 
 584             dlg 
= wx
.Dialog(wx
.GetApp().GetTopWindow(), -1, _("SVN Commit")) 
 586             sizer 
= wx
.BoxSizer(wx
.VERTICAL
) 
 587             sizer
.Add(wx
.StaticText(dlg
, -1, _("Comment:")), 0, wx
.ALIGN_CENTER_VERTICAL
) 
 588             commentText 
= wx
.TextCtrl(dlg
, -1, size
=(250,-1), style
=wx
.TE_MULTILINE
) 
 589             sizer
.Add(commentText
, 1, wx
.EXPAND|wx
.TOP
, HALF_SPACE
) 
 591             sizer
.Add(wx
.StaticText(dlg
, -1, _("Files:")), 0, wx
.ALIGN_CENTER_VERTICAL|wx
.TOP
, SPACE
) 
 592             fileList 
= wx
.CheckListBox(dlg
, -1, choices 
= shortFilenames
) 
 593             for i 
in range(fileList
.GetCount()): 
 594                 fileList
.Check(i
, True) 
 595             sizer
.Add(fileList
, 0, wx
.EXPAND|wx
.TOP
, HALF_SPACE
) 
 597             buttonSizer 
= wx
.StdDialogButtonSizer() 
 598             okBtn 
= wx
.Button(dlg
, wx
.ID_OK
) 
 600             buttonSizer
.AddButton(okBtn
) 
 601             buttonSizer
.AddButton(wx
.Button(dlg
, wx
.ID_CANCEL
)) 
 602             buttonSizer
.Realize() 
 604             contentSizer 
= wx
.BoxSizer(wx
.VERTICAL
) 
 605             contentSizer
.Add(sizer
, 0, wx
.ALL
, SPACE
) 
 606             contentSizer
.Add(buttonSizer
, 0, wx
.ALL|wx
.ALIGN_RIGHT
, SPACE
) 
 608             dlg
.SetSizer(contentSizer
) 
 613             if dlg
.ShowModal() == wx
.ID_OK
: 
 614                 wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_WAIT
)) 
 616                 messageService 
= wx
.GetApp().GetService(MessageService
.MessageService
) 
 617                 messageService
.ShowWindow() 
 619                 view 
= messageService
.GetView() 
 621                 view
.AddLines(_("SVN Commit:\n")) 
 625                     for i 
in range(fileList
.GetCount()): 
 626                         if fileList
.IsChecked(i
): 
 627                             selFilenames
.append(filenames
[i
]) 
 628                             view
.AddLines("%s\n" % filenames
[i
]) 
 630                     if len(selFilenames
): 
 631                         comment 
= commentText
.GetValue() 
 632                         status 
= self
._client
.checkin(selFilenames
, comment
) 
 635                             view
.AddLines(_("Nothing to commit.\n")) 
 636                         elif status
.number 
> 0: 
 637                             view
.AddLines(_("Committed as revision %s.\n") % status
.number
) 
 639                             view
.AddLines(_("Commit failed.\n")) 
 641                 except pysvn
.ClientError
, e
: 
 642                     view
.AddLines("%s\n" % str(e
)) 
 643                     wx
.MessageBox(str(e
), _("SVN Commit"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 645                     extype
, ex
, tb 
= sys
.exc_info() 
 646                     view
.AddLines("Commit failed: (%s) %s\n" % (extype
, str(ex
))) 
 647                     for line 
in traceback
.format_tb(tb
): 
 649                     wx
.MessageBox(_("Commit failed."), _("SVN Commit"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 651                 wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_DEFAULT
)) 
 655         elif id == SVNService
.SVN_CHECKOUT_ID
: 
 656             config 
= wx
.ConfigBase_Get() 
 657             svnUrl 
= config
.Read(SVN_REPOSITORY_URL
, self
._defaultURL
) 
 659             dlg 
= wx
.Dialog(wx
.GetApp().GetTopWindow(), -1, _("SVN Checkout")) 
 661             gridSizer 
= wx
.FlexGridSizer(cols 
= 2, hgap 
= 5, vgap 
= 5) 
 662             gridSizer
.Add(wx
.StaticText(dlg
, -1, _("Repository URL:")), 0, wx
.ALIGN_CENTER_VERTICAL|wx
.RIGHT|wx
.TOP
, HALF_SPACE
) 
 663             svnUrlList 
= ReadSvnUrlList() 
 664             svnURLCombobox 
= wx
.ComboBox(dlg
, -1, size
=(200, -1), choices
=svnUrlList
, style
=wx
.CB_DROPDOWN
) 
 666                 svnURLCombobox
.SetToolTipString(svnUrlList
[0]) 
 667                 svnURLCombobox
.SetStringSelection(svnUrlList
[0]) 
 669                 svnURLCombobox
.SetToolTipString(_("Set Repository URL")) 
 670             gridSizer
.Add(svnURLCombobox
, 0) 
 672             gridSizer
.Add(wx
.StaticText(dlg
, -1, _("Checkout to dir:")), 0, wx
.ALIGN_CENTER_VERTICAL|wx
.RIGHT|wx
.TOP
, HALF_SPACE
) 
 673             localPath 
= wx
.TextCtrl(dlg
, -1, size 
= (200, -1)) 
 674             localPath
.SetToolTipString(_("Path in local file system where files will be located.")) 
 675             findDirButton 
= wx
.Button(dlg
, -1, _("Browse...")) 
 677             def OnBrowseButton(event
): 
 678                 dirDlg 
= wx
.DirDialog(wx
.GetApp().GetTopWindow(), _("Choose a directory:"), style
=wx
.DD_DEFAULT_STYLE
) 
 679                 dir = localPath
.GetValue() 
 682                 dirDlg
.CenterOnParent() 
 683                 if dirDlg
.ShowModal() == wx
.ID_OK
: 
 684                     localPath
.SetValue(dirDlg
.GetPath()) 
 685                     localPath
.SetToolTipString(localPath
.GetValue()) 
 686                     localPath
.SetInsertionPointEnd() 
 688             wx
.EVT_BUTTON(findDirButton
, -1, OnBrowseButton
) 
 690             sizer 
= wx
.BoxSizer(wx
.HORIZONTAL
) 
 691             sizer
.Add(localPath
, 1, wx
.EXPAND
) 
 692             sizer
.Add(findDirButton
, 0, wx
.LEFT
, HALF_SPACE
) 
 693             gridSizer
.Add(sizer
, 0) 
 695             buttonSizer 
= wx
.StdDialogButtonSizer() 
 696             okBtn 
= wx
.Button(dlg
, wx
.ID_OK
) 
 698             buttonSizer
.AddButton(okBtn
) 
 699             buttonSizer
.AddButton(wx
.Button(dlg
, wx
.ID_CANCEL
)) 
 700             buttonSizer
.Realize() 
 702             contentSizer 
= wx
.BoxSizer(wx
.VERTICAL
) 
 703             contentSizer
.Add(gridSizer
, 0, wx
.ALL
, SPACE
) 
 704             contentSizer
.Add(buttonSizer
, 0, wx
.ALL|wx
.ALIGN_RIGHT
, SPACE
) 
 706             dlg
.SetSizer(contentSizer
) 
 711             if dlg
.ShowModal() == wx
.ID_OK
: 
 712                 wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_WAIT
)) 
 714                 WriteSvnUrlList(svnURLCombobox
) 
 716                 messageService 
= wx
.GetApp().GetService(MessageService
.MessageService
) 
 717                 messageService
.ShowWindow() 
 719                 view 
= messageService
.GetView() 
 721                 view
.AddLines(_("SVN Checkout:\n")) 
 723                 svnUrl 
= svnURLCombobox
.GetValue() 
 724                 toLocation 
= localPath
.GetValue() 
 726                     self
._client
.checkout(svnUrl
, toLocation
) 
 727                     view
.AddLines(_("Checkout completed.\n")) 
 728                 except pysvn
.ClientError
, e
: 
 729                     view
.AddLines(_("Checkout failed.  %s\n") % str(e
)) 
 730                     wx
.MessageBox(_("Checkout failed.  %s") % str(e
), _("SVN Checkout"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 732                     extype
, ex
, tb 
= sys
.exc_info() 
 733                     view
.AddLines("Checkout failed: (%s) %s\n" % (extype
, str(ex
))) 
 734                     for line 
in traceback
.format_tb(tb
): 
 736                     wx
.MessageBox(_("Checkout failed."), _("SVN Checkout"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 738                 wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_DEFAULT
)) 
 742         elif id == SVNService
.SVN_REVERT_ID
: 
 743             wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_WAIT
)) 
 745             filenames 
= self
.GetCurrentDocuments() 
 747             messageService 
= wx
.GetApp().GetService(MessageService
.MessageService
) 
 748             messageService
.ShowWindow() 
 750             view 
= messageService
.GetView() 
 752             view
.AddLines(_("SVN Revert:\n")) 
 753             for filename 
in filenames
: 
 754                 view
.AddLines("%s\n" % filename
) 
 757                 self
._client
.revert(filenames
) 
 758                 view
.AddLines(_("Revert completed.\n")) 
 760                 openDocs 
= wx
.GetApp().GetDocumentManager().GetDocuments() 
 761                 for doc 
in openDocs
[:]:   # need to make a copy of the list otherwise ordinality changes as we close the files 
 762                     if doc
.GetFilename() in filenames
: 
 763                         yesNoMsg 
= wx
.MessageDialog(wx
.GetApp().GetTopWindow(), 
 764                                                  _("Reverted file '%s' is currently open.  Close it?") % os
.path
.basename(doc
.GetFilename()), 
 766                                                  wx
.YES_NO|wx
.ICON_QUESTION
) 
 767                         yesNoMsg
.CenterOnParent() 
 768                         status 
= yesNoMsg
.ShowModal() 
 770                         if status 
== wx
.ID_YES
: 
 773             except pysvn
.ClientError
, e
: 
 774                 view
.AddLines("%s\n" % str(e
)) 
 775                 wx
.MessageBox(str(e
), _("SVN Revert"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 777                 extype
, ex
, tb 
= sys
.exc_info() 
 778                 view
.AddLines("Revert failed: (%s) %s\n" % (extype
, str(ex
))) 
 779                 for line 
in traceback
.format_tb(tb
): 
 781                 wx
.MessageBox(_("Revert failed."), _("SVN Revert"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 783             wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_DEFAULT
)) 
 786         elif id == SVNService
.SVN_ADD_ID
: 
 787             wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_WAIT
)) 
 789             filenames 
= self
.GetCurrentDocuments() 
 791             messageService 
= wx
.GetApp().GetService(MessageService
.MessageService
) 
 792             messageService
.ShowWindow() 
 794             view 
= messageService
.GetView() 
 796             view
.AddLines(_("SVN Add:\n")) 
 797             for filename 
in filenames
: 
 798                 view
.AddLines("%s\n" % filename
) 
 801                 self
._client
.add(filenames
) 
 802                 view
.AddLines(_("Add completed.\n")) 
 803             except pysvn
.ClientError
, e
: 
 804                 view
.AddLines("%s\n" % str(e
)) 
 805                 wx
.MessageBox(str(e
), _("SVN Add"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 807                 extype
, ex
, tb 
= sys
.exc_info() 
 808                 view
.AddLines("Add failed: (%s) %s\n" % (extype
, str(ex
))) 
 809                 for line 
in traceback
.format_tb(tb
): 
 811                 wx
.MessageBox(_("Add failed."), _("SVN Add"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 813             wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_DEFAULT
)) 
 816         elif id == SVNService
.SVN_DELETE_ID
: 
 817             wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_WAIT
)) 
 819             filenames 
= self
.GetCurrentDocuments() 
 821             messageService 
= wx
.GetApp().GetService(MessageService
.MessageService
) 
 822             messageService
.ShowWindow() 
 824             view 
= messageService
.GetView() 
 826             view
.AddLines(_("SVN Delete:\n")) 
 827             for filename 
in filenames
: 
 828                 view
.AddLines("%s\n" % filename
) 
 831                 self
._client
.remove(filenames
) 
 832                 view
.AddLines(_("Delete completed.\n")) 
 833             except pysvn
.ClientError
, e
: 
 834                 view
.AddLines("%s\n" % str(e
)) 
 835                 wx
.MessageBox(str(e
), _("SVN Delete"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 837                 extype
, ex
, tb 
= sys
.exc_info() 
 838                 view
.AddLines("Delete failed: (%s) %s\n" % (extype
, str(ex
))) 
 839                 for line 
in traceback
.format_tb(tb
): 
 841                 wx
.MessageBox(_("Delete failed."), _("SVN Delete"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 843             wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_DEFAULT
)) 
 849     def ProcessUpdateUIEvent(self
, event
): 
 852         if id in [SVNService
.SVN_CHECKIN_ID
, 
 853                   SVNService
.SVN_REVERT_ID
, 
 854                   SVNService
.SVN_ADD_ID
, 
 855                   SVNService
.SVN_DELETE_ID
]: 
 856             if self
.GetCurrentDocuments(): 
 862         elif id == SVNService
.SVN_UPDATE_ID
: 
 863             if self
.GetCurrentDocuments() or self
.GetCurrentFolder(): 
 869         elif id == SVNService
.SVN_CHECKOUT_ID
: 
 873         elif (id == SVNService
.SVN_UPDATE_ALL_ID
 
 874         or id == SVNService
.SVN_CHECKIN_ALL_ID
): 
 875             if self
.GetCurrentProject(): 
 884     def GetCurrentProject(self
): 
 885         projectService 
= wx
.GetApp().GetService(ProjectEditor
.ProjectService
) 
 887             projView 
= projectService
.GetView() 
 888             return projView
.GetSelectedProject() 
 892     def GetCurrentDocuments(self
): 
 893         projectService 
= wx
.GetApp().GetService(ProjectEditor
.ProjectService
) 
 895             projView 
= projectService
.GetView() 
 897             if projView
.FilesHasFocus(): 
 898                 filenames 
= projView
.GetSelectedFiles() 
 904         doc 
= wx
.GetApp().GetTopWindow().GetDocumentManager().GetCurrentDocument() 
 906             filenames 
= [doc
.GetFilename()] 
 913     def GetCurrentFolder(self
): 
 914         projectService 
= wx
.GetApp().GetService(ProjectEditor
.ProjectService
) 
 916             projView 
= projectService
.GetView() 
 918             if projView
.FilesHasFocus(): 
 919                 folderPath 
= projView
.GetSelectedPhysicalFolder() 
 926     def BasenameCaseInsensitiveCompare(self
, s1
, s2
): 
 927         s1L 
= os
.path
.basename(s1
).lower() 
 928         s2L 
= os
.path
.basename(s2
).lower() 
 937 class SVNOptionsPanel(wx
.Panel
): 
 940     def __init__(self
, parent
, id): 
 941         wx
.Panel
.__init
__(self
, parent
, id) 
 943         config 
= wx
.ConfigBase_Get() 
 944         configDir 
= config
.Read(SVN_CONFIG_DIR
, "") 
 946         borderSizer 
= wx
.BoxSizer(wx
.VERTICAL
) 
 947         sizer 
= wx
.FlexGridSizer(cols 
= 2, hgap 
= 5, vgap 
= 5) 
 948         sizer
.AddGrowableCol(1, 1) 
 950         sizer
.Add(wx
.StaticText(self
, -1, _("SVN Config Dir:")), 0, wx
.ALIGN_CENTER_VERTICAL
) 
 952         self
._svnConfigDir 
= wx
.TextCtrl(self
, -1, configDir
, size 
= (200, -1)) 
 954             self
._svnConfigDir
.SetToolTipString(_("Path Subversion configuration directory.")) 
 956             self
._svnConfigDir
.SetToolTipString(configDir
) 
 958         findDirButton 
= wx
.Button(self
, -1, _("Browse...")) 
 960         def OnBrowseButton(event
): 
 961             dirDlg 
= wx
.DirDialog(self
, _("Choose a directory:"), style
=wx
.DD_DEFAULT_STYLE
) 
 962             dir = self
._svnConfigDir
.GetValue() 
 965             dirDlg
.CenterOnParent() 
 966             if dirDlg
.ShowModal() == wx
.ID_OK
: 
 967                 self
._svnConfigDir
.SetValue(dirDlg
.GetPath()) 
 968                 self
._svnConfigDir
.SetToolTipString(self
._svnConfigDir
.GetValue()) 
 969                 self
._svnConfigDir
.SetInsertionPointEnd() 
 971         wx
.EVT_BUTTON(findDirButton
, -1, OnBrowseButton
) 
 973         hsizer 
= wx
.BoxSizer(wx
.HORIZONTAL
) 
 974         hsizer
.Add(self
._svnConfigDir
, 1, wx
.EXPAND
) 
 975         hsizer
.Add(findDirButton
, 0, wx
.LEFT
, HALF_SPACE
) 
 976         sizer
.Add(hsizer
, 0, wx
.EXPAND
) 
 979         svnUrlList 
= ReadSvnUrlList() 
 980         sizer
.Add(wx
.StaticText(self
, -1, _("SVN URL:")), 0, wx
.ALIGN_CENTER_VERTICAL
) 
 981         self
._svnURLCombobox 
= wx
.ComboBox(self
, -1, size
=(200, -1), choices
=svnUrlList
, style
=wx
.CB_DROPDOWN
) 
 983             self
._svnURLCombobox
.SetToolTipString(svnUrlList
[0]) 
 984             self
._svnURLCombobox
.SetStringSelection(svnUrlList
[0]) 
 986             self
._svnURLCombobox
.SetToolTipString(_("Set Repository URL")) 
 987         sizer
.Add(self
._svnURLCombobox
, 0, wx
.EXPAND
) 
 990         sizer
.Add(wx
.StaticText(self
, -1, _("SVN_SSH:")), 0, wx
.ALIGN_CENTER_VERTICAL
) 
 991         svnSSH 
= os
.getenv("SVN_SSH") 
 992         if not svnSSH 
or svnSSH 
== "": 
 993             self
._svnSSH 
= wx
.TextCtrl(self
, -1, size 
= (200, -1)) 
 995             self
._svnSSH 
= wx
.TextCtrl(self
, -1, svnSSH
, size 
= (200, -1)) 
 996         self
._svnSSH
.SetToolTipString(_("Override SVN_SSH environment variable temporarily.")) 
 998         findSSHButton 
= wx
.Button(self
, -1, _("Browse...")) 
1000         def OnBrowseFileButton(event
): 
1001             dirDlg 
= wx
.FileDialog(self
, _("Choose a file:"), style
=wx
.OPEN|wx
.CHANGE_DIR
) 
1002             # dirDlg.CenterOnParent()  # wxBug: caused crash with wx.FileDialog 
1003             if dirDlg
.ShowModal() == wx
.ID_OK
: 
1004                 self
._svnSSH
.SetValue(dirDlg
.GetPath()) 
1005                 self
._svnSSH
.SetToolTipString(self
._svnSSH
.GetValue()) 
1006                 self
._svnSSH
.SetInsertionPointEnd() 
1008         wx
.EVT_BUTTON(findSSHButton
, -1, OnBrowseFileButton
) 
1010         hsizer 
= wx
.BoxSizer(wx
.HORIZONTAL
) 
1011         hsizer
.Add(self
._svnSSH
, 1, wx
.EXPAND
) 
1012         hsizer
.Add(findSSHButton
, 0, wx
.LEFT
, HALF_SPACE
) 
1013         sizer
.Add(hsizer
, 0, wx
.EXPAND
) 
1016         borderSizer
.Add(sizer
, 0, wx
.ALL|wx
.EXPAND
, SPACE
) 
1017         self
.SetSizer(borderSizer
) 
1019         parent
.AddPage(self
, _("SVN")) 
1026     def OnOK(self
, optionsDialog
): 
1027         config 
= wx
.ConfigBase_Get() 
1029         config
.Write(SVN_CONFIG_DIR
, self
._svnConfigDir
.GetValue()) 
1031         WriteSvnUrlList(self
._svnURLCombobox
) 
1033         os
.environ
["SVN_SSH"] = self
._svnSSH
.GetValue() 
1036 def ReadSvnUrlList(): 
1037     """ Read in list of SNV repository URLs.  First in list is the last one path used. """ 
1038     config 
= wx
.ConfigBase_Get() 
1039     urlStringList 
= config
.Read(SVN_REPOSITORY_URL
) 
1040     if len(urlStringList
): 
1041         urlList 
= eval(urlStringList
) 
1044     if len(urlList
) == 0: 
1045         svnService 
= wx
.GetApp().GetService(SVNService
) 
1046         if svnService 
and hasattr(svnService
, "_defaultURL"): 
1047             urlList
.append(svnService
._defaultURL
) 
1051 def WriteSvnUrlList(comboBox
): 
1052     """ Save out list of SVN repository URLs from combobox.  Put on top the current selection.  Only save out first 10 from the list """ 
1055     url 
= comboBox
.GetValue() 
1059     for i 
in range(min(comboBox
.GetCount(), 10)): 
1060         url 
= comboBox
.GetString(i
) 
1061         if url 
not in urlList
: 
1064     config 
= wx
.ConfigBase_Get() 
1065     config
.Write(SVN_REPOSITORY_URL
, urlList
.__repr
__())