1 #---------------------------------------------------------------------------- 
   3 # Purpose:      Subversion Service for pydocview 
   9 # Copyright:    (c) 2005 ActiveGrid, Inc. 
  10 # License:      wxWindows License 
  11 #---------------------------------------------------------------------------- 
  18 import sys        
# for errors 
  19 import traceback  
# for errors 
  22     import pysvn  
# python-subversion integration 
  30 #---------------------------------------------------------------------------- 
  32 #---------------------------------------------------------------------------- 
  33 SVN_CONFIG_DIR 
= "SVNConfigDir" 
  34 SVN_REPOSITORY_URL 
= "SVNRepositoryURL" 
  40 #---------------------------------------------------------------------------- 
  42 #---------------------------------------------------------------------------- 
  44 class SVNService(wx
.lib
.pydocview
.DocService
): 
  45     SVN_UPDATE_ID 
= wx
.NewId() 
  46     SVN_CHECKIN_ID 
= wx
.NewId() 
  47     SVN_CHECKOUT_ID 
= wx
.NewId() 
  48     SVN_REVERT_ID 
= wx
.NewId() 
  49     SVN_ADD_ID 
= wx
.NewId() 
  50     SVN_DELETE_ID 
= wx
.NewId() 
  51     SVN_COMMAND_LIST 
= [SVN_UPDATE_ID
, SVN_CHECKIN_ID
, SVN_CHECKOUT_ID
, SVN_REVERT_ID
, SVN_ADD_ID
, SVN_DELETE_ID
] 
  55         self
._defaultURL 
= "svn://" 
  59             config 
= wx
.ConfigBase_Get() 
  60             configDir 
= config
.Read(SVN_CONFIG_DIR
, "") 
  62             self
._client 
= pysvn
.Client(configDir
) 
  64                 self
._defaultURL 
= self
._client
.info('.').url
 
  67             self
._client
.callback_cancel 
= self
.IfCancel
 
  68             self
._client
.callback_notify 
= self
.UpdateStatus
 
  69             self
._client
.callback_get_log_message 
= self
.GetLogMessage
 
  70             self
._client
.callback_get_login 
= self
.GetLogin
 
  71             self
._client
.callback_ssl_server_trust_prompt 
= self
.GetSSLServerTrust
 
  72             self
._client
.callback_ssl_client_cert_password_prompt 
= self
.SSLClientPassword
 
  73             self
._client
.callback_ssl_client_cert_prompt 
= self
.SSLClientCert
 
  74             self
._client
.callback_ssl_server_prompt 
= self
.SSLServerPrompt
 
  76     #---------------------------------------------------------------------------- 
  77     # pysvn.Client() Callback Methods 
  78     #---------------------------------------------------------------------------- 
  81         """ return True if user wants to cancel current command """ 
  85     def UpdateStatus(self
, eventDict
): 
  86         messageService 
= wx
.GetApp().GetService(MessageService
.MessageService
) 
  87         messageService
.ShowWindow() 
  89         view 
= messageService
.GetView() 
  90         view
.AddLines(_("%s %s\n") % (eventDict
['action'], eventDict
['path'])) 
  93     def GetLogMessage(self
): 
  94         dlg 
= wx
.TextEntryDialog(wx
.GetApp().GetTopWindow(), 
  98         if dlg
.ShowModal() == wx
.ID_OK
: 
 100             message 
= dlg
.GetValue() 
 103             message 
= _("Cancel Action") 
 107         return retcode
, message
 
 110     def GetLogin(self
, realm
, username
, maySave
): 
 111         dlg 
= wx
.Dialog(wx
.GetApp().GetTopWindow(), -1, _("SVN Login")) 
 113         sizer 
= wx
.FlexGridSizer(cols 
= 2, hgap 
= 5, vgap 
= 5) 
 114         sizer
.Add(wx
.StaticText(dlg
, -1, _("Username:")), 0, wx
.ALIGN_CENTER_VERTICAL
) 
 115         usernameTxt 
= wx
.TextCtrl(dlg
, -1, username
, size 
= (200, -1)) 
 116         sizer
.Add(usernameTxt
, 0, wx
.ALIGN_CENTER_VERTICAL
) 
 117         sizer
.Add(wx
.StaticText(dlg
, -1, _("Password:")), 0, wx
.ALIGN_CENTER_VERTICAL
) 
 118         passwordTxt 
= wx
.TextCtrl(dlg
, -1, size
=(200, -1), style
=wx
.TE_PASSWORD
) 
 119         sizer
.Add(passwordTxt
, 0, wx
.ALIGN_CENTER_VERTICAL
) 
 121         savePasswordCheckbox 
= wx
.CheckBox(dlg
, -1, _("Remember Username and Password")) 
 123             savePasswordCheckbox
.Enable(False) 
 125         buttonSizer 
= wx
.BoxSizer(wx
.HORIZONTAL
) 
 126         okBtn 
= wx
.Button(dlg
, wx
.ID_OK
) 
 128         buttonSizer
.Add(okBtn
, 0, wx
.RIGHT
, HALF_SPACE
) 
 129         buttonSizer
.Add(wx
.Button(dlg
, wx
.ID_CANCEL
), 0) 
 131         contentSizer 
= wx
.BoxSizer(wx
.VERTICAL
) 
 132         contentSizer
.Add(sizer
, 0, wx
.LEFT|wx
.TOP|wx
.RIGHT
, SPACE
) 
 133         contentSizer
.Add(savePasswordCheckbox
, 0, wx
.TOP|wx
.LEFT|wx
.BOTTOM
, SPACE
) 
 134         contentSizer
.Add(buttonSizer
, 0, wx
.ALL|wx
.ALIGN_RIGHT
, SPACE
) 
 136         dlg
.SetSizer(contentSizer
) 
 140         if dlg
.ShowModal() == wx
.ID_OK
: 
 142             username 
= usernameTxt
.GetValue().strip() 
 143             password 
= passwordTxt
.GetValue() 
 144             save 
= savePasswordCheckBox
.IsChecked() 
 152         return retcode
, username
, password
, save
 
 155     def SSLServerPrompt(self
): 
 156         """ Not implemented, as per pysvn documentation """ 
 160     def GetSSLServerTrust(self
, trustDict
): 
 161         dlg 
= wx
.Dialog(wx
.GetApp().GetTopWindow(), -1, _("SSL Server Certificate")) 
 163         sizer 
= wx
.FlexGridSizer(cols 
= 2, hgap 
= 5, vgap 
= 5) 
 164         for k 
in ['hostname', 'valid_from', 'valid_to', 'issuer_dname', 'realm']: 
 165             if trustDict
.has_key(k
): 
 166                 sizer
.Add(wx
.StaticText(dlg
, -1, "%s:" % k
), 0, wx
.ALIGN_CENTER_VERTICAL
) 
 167                 sizer
.Add(wx
.StaticText(dlg
, -1, "%s"  % trustDict
[k
]), 0, wx
.ALIGN_CENTER_VERTICAL
) 
 169         box 
= wx
.StaticBoxSizer(wx
.StaticBox(dlg
, -1, _("Certificate Info")), wx
.VERTICAL
) 
 170         box
.Add(sizer
, 0, wx
.EXPAND
) 
 172         certRadio 
= wx
.RadioBox(dlg
, -1, _("Certificate"), choices
=[_("Accept Always"), _("Accept Once"), _("Reject")], majorDimension
=1, style
=wx
.RA_SPECIFY_COLS
) 
 174         buttonSizer 
= wx
.BoxSizer(wx
.HORIZONTAL
) 
 175         okBtn 
= wx
.Button(dlg
, wx
.ID_OK
) 
 177         buttonSizer
.Add(okBtn
, 0, wx
.RIGHT
, HALF_SPACE
) 
 178         buttonSizer
.Add(wx
.Button(dlg
, wx
.ID_CANCEL
), 0) 
 180         contentSizer 
= wx
.BoxSizer(wx
.VERTICAL
) 
 181         contentSizer
.Add(box
, 0, wx
.TOP|wx
.LEFT|wx
.RIGHT|wx
.EXPAND
, SPACE
) 
 182         contentSizer
.Add(certRadio
, 0, wx
.TOP|wx
.LEFT|wx
.RIGHT|wx
.BOTTOM|wx
.EXPAND
, SPACE
) 
 183         contentSizer
.Add(buttonSizer
, 0, wx
.ALL|wx
.ALIGN_RIGHT
, SPACE
) 
 185         dlg
.SetSizer(contentSizer
) 
 189         # default values for reject 
 194         if dlg
.ShowModal() == wx
.ID_OK
: 
 195             cert 
= certRadio
.GetStringSelection() 
 196             if cert 
== _("Accept Always"): 
 198                 acceptedFailures 
= trustDict
.get('failures') 
 200             elif cert 
== _("Accept Once"): 
 202                 acceptedFailures 
= trustDict
.get('failures') 
 205         return retcode
, acceptedFailures
, save
 
 208     def SSLClientPassword(self
, realm
, maySave
): 
 209         dlg 
= wx
.Dialog(wx
.GetApp().GetTopWindow(), -1, _("SSL Client Certificate Login")) 
 211         sizer 
= wx
.FlexGridSizer(cols 
= 2, hgap 
= 5, vgap 
= 5) 
 212         sizer
.Add(wx
.StaticText(dlg
, -1, _("Realm:")), 0, wx
.ALIGN_CENTER_VERTICAL
) 
 213         sizer
.Add(wx
.StaticText(dlg
, -1, realm
), 0, wx
.ALIGN_CENTER_VERTICAL
) 
 214         sizer
.Add(wx
.StaticText(dlg
, -1, _("Password:")), 0, wx
.ALIGN_CENTER_VERTICAL
) 
 215         passwordTxt 
= wx
.TextCtrl(dlg
, -1, size
=(200, -1), style
=wx
.TE_PASSWORD
) 
 216         sizer
.Add(passwordTxt
, 0, wx
.ALIGN_CENTER_VERTICAL
) 
 218         savePasswordCheckbox 
= wx
.CheckBox(dlg
, -1, _("Remember Password")) 
 220             savePasswordCheckbox
.Enable(False) 
 222         buttonSizer 
= wx
.BoxSizer(wx
.HORIZONTAL
) 
 223         okBtn 
= wx
.Button(dlg
, wx
.ID_OK
) 
 225         buttonSizer
.Add(okBtn
, 0, wx
.RIGHT
, HALF_SPACE
) 
 226         buttonSizer
.Add(wx
.Button(dlg
, wx
.ID_CANCEL
), 0) 
 228         contentSizer 
= wx
.BoxSizer(wx
.VERTICAL
) 
 229         contentSizer
.Add(sizer
, 0, wx
.LEFT|wx
.TOP|wx
.RIGHT
, SPACE
) 
 230         contentSizer
.Add(savePasswordCheckbox
, 0, wx
.TOP|wx
.LEFT|wx
.BOTTOM
, SPACE
) 
 231         contentSizer
.Add(buttonSizer
, 0, wx
.ALL|wx
.ALIGN_RIGHT
, SPACE
) 
 233         dlg
.SetSizer(contentSizer
) 
 237         if dlg
.ShowModal() == wx
.ID_OK
: 
 239             password 
= passwordTxt
.GetValue() 
 240             save 
= savePasswordCheckBox
.IsChecked() 
 247         return retcode
, password
, save
 
 250     def SSLClientCert(self
): 
 251         dlg 
= wx
.FileDialog(wx
.GetApp().GetTopWindow(), 
 252             message
="Choose certificate", defaultDir
=os
.getcwd(),  
 253             style
=wx
.OPEN|wx
.CHANGE_DIR
 
 256         if dlg
.ShowModal() == wx
.ID_OK
: 
 258             certfile 
= dlg
.GetPath() 
 264         return retcode
, certfile
 
 268     #---------------------------------------------------------------------------- 
 270     #---------------------------------------------------------------------------- 
 272     def InstallControls(self
, frame
, menuBar 
= None, toolBar 
= None, statusBar 
= None, document 
= None): 
 273         menu 
= menuBar
.GetMenu(menuBar
.FindMenu(_("Project"))) 
 275         menu
.AppendSeparator() 
 277         wx
.EVT_MENU(frame
, SVNService
.SVN_UPDATE_ID
, self
.ProcessEvent
) 
 278         wx
.EVT_UPDATE_UI(frame
, SVNService
.SVN_UPDATE_ID
, self
.ProcessUpdateUIEvent
) 
 279         menu
.Append(SVNService
.SVN_UPDATE_ID
, _("SVN Update"), _("Update file from Subversion")) 
 280         wx
.EVT_MENU(frame
, SVNService
.SVN_CHECKIN_ID
, self
.ProcessEvent
) 
 281         wx
.EVT_UPDATE_UI(frame
, SVNService
.SVN_CHECKIN_ID
, self
.ProcessUpdateUIEvent
) 
 282         menu
.Append(SVNService
.SVN_CHECKIN_ID
, _("SVN Commit..."), _("Commit file changes to Subversion")) 
 283         wx
.EVT_MENU(frame
, SVNService
.SVN_CHECKOUT_ID
, self
.ProcessEvent
) 
 284         wx
.EVT_UPDATE_UI(frame
, SVNService
.SVN_CHECKOUT_ID
, self
.ProcessUpdateUIEvent
) 
 285         menu
.Append(SVNService
.SVN_CHECKOUT_ID
, _("SVN Checkout..."), _("Checkout file from Subversion")) 
 286         wx
.EVT_MENU(frame
, SVNService
.SVN_REVERT_ID
, self
.ProcessEvent
) 
 287         wx
.EVT_UPDATE_UI(frame
, SVNService
.SVN_REVERT_ID
, self
.ProcessUpdateUIEvent
) 
 288         menu
.Append(SVNService
.SVN_REVERT_ID
, _("SVN Revert"), _("Revert file from Subversion")) 
 290         menu
.AppendSeparator() 
 292         wx
.EVT_MENU(frame
, SVNService
.SVN_ADD_ID
, self
.ProcessEvent
) 
 293         wx
.EVT_UPDATE_UI(frame
, SVNService
.SVN_ADD_ID
, self
.ProcessUpdateUIEvent
) 
 294         menu
.Append(SVNService
.SVN_ADD_ID
, _("SVN Add"), _("Add file to Subversion")) 
 295         wx
.EVT_MENU(frame
, SVNService
.SVN_DELETE_ID
, self
.ProcessEvent
) 
 296         wx
.EVT_UPDATE_UI(frame
, SVNService
.SVN_DELETE_ID
, self
.ProcessUpdateUIEvent
) 
 297         menu
.Append(SVNService
.SVN_DELETE_ID
, _("SVN Delete"), _("Delete file from Subversion")) 
 300     def ProcessEvent(self
, event
): 
 304         if not SVN_INSTALLED
: 
 305             if id in SVNService
.SVN_COMMAND_LIST
: 
 306                 wx
.MessageBox(_("pysvn not found.  Please install pysvn"), _("Python Subversion")) 
 311         if id == SVNService
.SVN_UPDATE_ID
: 
 312             filenames 
= self
.GetCurrentDocuments() 
 314             wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_WAIT
)) 
 316             messageService 
= wx
.GetApp().GetService(MessageService
.MessageService
) 
 317             messageService
.ShowWindow() 
 319             view 
= messageService
.GetView() 
 321             view
.AddLines(_("SVN Update:\n")) 
 323             for filename 
in filenames
: 
 324                 view
.AddLines("%s\n" % filename
) 
 326                     status 
= self
._client
.update(filename
) 
 328                     if status
.number 
> 0: 
 329                         view
.AddLines(_("Updated to revision %s\n") % status
.number
) 
 331                         openDocs 
= wx
.GetApp().GetDocumentManager().GetDocuments() 
 333                             if doc
.GetFilename() == filename
: 
 334                                 yesNoMsg 
= wx
.MessageDialog(wx
.GetApp().GetTopWindow(), 
 335                                                          _("Updated file '%s' is currently open.  Close it?") % os
.path
.basename(filename
), 
 337                                                          wx
.YES_NO|wx
.ICON_QUESTION
) 
 338                                 if yesNoMsg
.ShowModal() == wx
.ID_YES
: 
 342                         view
.AddLines(_("Update failed.\n")) 
 344                 except pysvn
.ClientError
, e
: 
 345                     view
.AddLines("%s\n" % str(e
)) 
 346                     wx
.MessageBox(str(e
), _("SVN Update"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 348                     extype
, ex
, tb 
= sys
.exc_info() 
 349                     view
.AddLines("Update failed: (%s) %s\n" % (extype
, str(ex
))) 
 350                     for line 
in traceback
.format_tb(tb
): 
 353                     wx
.MessageBox(_("Update failed."), _("SVN Update"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 355             wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_DEFAULT
)) 
 359         elif id == SVNService
.SVN_CHECKIN_ID
: 
 360             filenames 
= self
.GetCurrentDocuments() 
 362             # ask user if dirty files should be saved first 
 363             openDocs 
= wx
.GetApp().GetDocumentManager().GetDocuments() 
 364             for filename 
in filenames
: 
 366                     if doc
.GetFilename() == filename 
and doc
.IsModified(): 
 367                         yesNoMsg 
= wx
.MessageDialog(wx
.GetApp().GetTopWindow(), 
 368                                                  _("'%s' has unsaved modifications.  Save it before commit?") % os
.path
.basename(filename
), 
 370                                                  wx
.YES_NO|wx
.CANCEL|wx
.ICON_QUESTION
) 
 371                         status 
= yesNoMsg
.ShowModal() 
 372                         if status 
== wx
.ID_YES
: 
 374                         elif status 
== wx
.ID_NO
: 
 376                         else: # elif status == wx.CANCEL: 
 381             for i
, filename 
in enumerate(filenames
): 
 382                 shortFilename 
= os
.path
.basename(filename
) 
 383                 shortFilenames
.append(shortFilename
) 
 385             dlg 
= wx
.Dialog(wx
.GetApp().GetTopWindow(), -1, _("SVN Commit")) 
 387             sizer 
= wx
.BoxSizer(wx
.VERTICAL
) 
 388             sizer
.Add(wx
.StaticText(dlg
, -1, _("Comment:")), 0, wx
.ALIGN_CENTER_VERTICAL
) 
 389             commentText 
= wx
.TextCtrl(dlg
, -1, size
=(250,-1), style
=wx
.TE_MULTILINE
) 
 390             sizer
.Add(commentText
, 1, wx
.EXPAND|wx
.TOP
, HALF_SPACE
) 
 392             sizer
.Add(wx
.StaticText(dlg
, -1, _("Files:")), 0, wx
.ALIGN_CENTER_VERTICAL|wx
.TOP
, SPACE
) 
 393             fileList 
= wx
.CheckListBox(dlg
, -1, choices 
= shortFilenames
) 
 394             for i 
in range(fileList
.GetCount()): 
 395                 fileList
.Check(i
, True) 
 396             sizer
.Add(fileList
, 0, wx
.EXPAND|wx
.TOP
, HALF_SPACE
) 
 398             buttonSizer 
= wx
.BoxSizer(wx
.HORIZONTAL
) 
 399             okBtn 
= wx
.Button(dlg
, wx
.ID_OK
) 
 401             buttonSizer
.Add(okBtn
, 0, wx
.RIGHT
, HALF_SPACE
) 
 402             buttonSizer
.Add(wx
.Button(dlg
, wx
.ID_CANCEL
), 0) 
 404             contentSizer 
= wx
.BoxSizer(wx
.VERTICAL
) 
 405             contentSizer
.Add(sizer
, 0, wx
.ALL
, SPACE
) 
 406             contentSizer
.Add(buttonSizer
, 0, wx
.ALL|wx
.ALIGN_RIGHT
, SPACE
) 
 408             dlg
.SetSizer(contentSizer
) 
 412             if dlg
.ShowModal() == wx
.ID_OK
: 
 413                 wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_WAIT
)) 
 415                 messageService 
= wx
.GetApp().GetService(MessageService
.MessageService
) 
 416                 messageService
.ShowWindow() 
 418                 view 
= messageService
.GetView() 
 420                 view
.AddLines(_("SVN Commit:\n")) 
 424                     for i 
in range(fileList
.GetCount()): 
 425                         if fileList
.IsChecked(i
): 
 426                             selFilenames
.append(filenames
[i
]) 
 427                             view
.AddLines("%s\n" % filenames
[i
]) 
 429                     if len(selFilenames
): 
 430                         comment 
= commentText
.GetValue() 
 431                         status 
= self
._client
.checkin(selFilenames
, comment
) 
 434                             view
.AddLines(_("Nothing to commit.\n")) 
 435                         elif status
.number 
> 0: 
 436                             view
.AddLines(_("Committed as revision %s.\n") % status
.number
) 
 438                             view
.AddLines(_("Commit failed.\n")) 
 440                 except pysvn
.ClientError
, e
: 
 441                     view
.AddLines("%s\n" % str(e
)) 
 442                     wx
.MessageBox(str(e
), _("SVN Commit"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 444                     extype
, ex
, tb 
= sys
.exc_info() 
 445                     view
.AddLines("Commit failed: (%s) %s\n" % (extype
, str(ex
))) 
 446                     for line 
in traceback
.format_tb(tb
): 
 448                     wx
.MessageBox(_("Commit failed."), _("SVN Commit"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 450                 wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_DEFAULT
)) 
 454         elif id == SVNService
.SVN_CHECKOUT_ID
: 
 455             config 
= wx
.ConfigBase_Get() 
 456             svnUrl 
= config
.Read(SVN_REPOSITORY_URL
, self
._defaultURL
) 
 458             dlg 
= wx
.Dialog(wx
.GetApp().GetTopWindow(), -1, _("SVN Checkout")) 
 460             gridSizer 
= wx
.FlexGridSizer(cols 
= 2, hgap 
= 5, vgap 
= 5) 
 461             gridSizer
.Add(wx
.StaticText(dlg
, -1, _("Repository URL:")), 0, wx
.ALIGN_CENTER_VERTICAL|wx
.RIGHT|wx
.TOP
, HALF_SPACE
) 
 462             svnURLText 
= wx
.TextCtrl(dlg
, -1, svnUrl
, size 
= (200, -1)) 
 463             svnURLText
.SetToolTipString(svnUrl
) 
 464             gridSizer
.Add(svnURLText
, 0) 
 466             gridSizer
.Add(wx
.StaticText(dlg
, -1, _("Checkout to dir:")), 0, wx
.ALIGN_CENTER_VERTICAL|wx
.RIGHT|wx
.TOP
, HALF_SPACE
) 
 467             localPath 
= wx
.TextCtrl(dlg
, -1, size 
= (200, -1)) 
 468             localPath
.SetToolTipString(_("Path in local file system where files will be located.")) 
 469             findDirButton 
= wx
.Button(dlg
, -1, _("Browse...")) 
 471             def OnBrowseButton(event
): 
 472                 dirDlg 
= wx
.DirDialog(wx
.GetApp().GetTopWindow(), _("Choose a directory:"), style
=wx
.DD_DEFAULT_STYLE
) 
 473                 dir = localPath
.GetValue() 
 476                 if dirDlg
.ShowModal() == wx
.ID_OK
: 
 477                     localPath
.SetValue(dirDlg
.GetPath()) 
 478                     localPath
.SetToolTipString(localPath
.GetValue()) 
 479                     localPath
.SetInsertionPointEnd() 
 482             wx
.EVT_BUTTON(findDirButton
, -1, OnBrowseButton
) 
 484             sizer 
= wx
.BoxSizer(wx
.HORIZONTAL
) 
 485             sizer
.Add(localPath
, 1, wx
.EXPAND
) 
 486             sizer
.Add(findDirButton
, 0, wx
.LEFT
, HALF_SPACE
) 
 487             gridSizer
.Add(sizer
, 0) 
 489             buttonSizer 
= wx
.BoxSizer(wx
.HORIZONTAL
) 
 490             okBtn 
= wx
.Button(dlg
, wx
.ID_OK
) 
 492             buttonSizer
.Add(okBtn
, 0, wx
.RIGHT
, HALF_SPACE
) 
 493             buttonSizer
.Add(wx
.Button(dlg
, wx
.ID_CANCEL
), 0) 
 495             contentSizer 
= wx
.BoxSizer(wx
.VERTICAL
) 
 496             contentSizer
.Add(gridSizer
, 0, wx
.ALL
, SPACE
) 
 497             contentSizer
.Add(buttonSizer
, 0, wx
.ALL|wx
.ALIGN_RIGHT
, SPACE
) 
 499             dlg
.SetSizer(contentSizer
) 
 503             if dlg
.ShowModal() == wx
.ID_OK
: 
 504                 wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_WAIT
)) 
 506                 messageService 
= wx
.GetApp().GetService(MessageService
.MessageService
) 
 507                 messageService
.ShowWindow() 
 509                 view 
= messageService
.GetView() 
 511                 view
.AddLines(_("SVN Checkout:\n")) 
 513                 svnUrl 
= svnURLText
.GetValue() 
 514                 toLocation 
= localPath
.GetValue() 
 516                     self
._client
.checkout(svnUrl
, toLocation
) 
 517                     view
.AddLines(_("Checkout completed.\n")) 
 518                 except pysvn
.ClientError
, e
: 
 519                     view
.AddLines(_("Checkout failed.  %s\n") % str(e
)) 
 520                     wx
.MessageBox(_("Checkout failed.  %s") % str(e
), _("SVN Checkout"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 522                     extype
, ex
, tb 
= sys
.exc_info() 
 523                     view
.AddLines("Checkout failed: (%s) %s\n" % (extype
, str(ex
))) 
 524                     for line 
in traceback
.format_tb(tb
): 
 526                     wx
.MessageBox(_("Checkout failed."), _("SVN Checkout"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 528                 wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_DEFAULT
)) 
 532         elif id == SVNService
.SVN_REVERT_ID
: 
 533             wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_WAIT
)) 
 535             filenames 
= self
.GetCurrentDocuments() 
 537             messageService 
= wx
.GetApp().GetService(MessageService
.MessageService
) 
 538             messageService
.ShowWindow() 
 540             view 
= messageService
.GetView() 
 542             view
.AddLines(_("SVN Revert:\n")) 
 543             for filename 
in filenames
: 
 544                 view
.AddLines("%s\n" % filename
) 
 547                 self
._client
.revert(filenames
) 
 548                 view
.AddLines(_("Revert completed.\n")) 
 550                 openDocs 
= wx
.GetApp().GetDocumentManager().GetDocuments() 
 551                 for doc 
in openDocs
[:]:   # need to make a copy of the list otherwise ordinality changes as we close the files 
 552                     if doc
.GetFilename() in filenames
: 
 553                         yesNoMsg 
= wx
.MessageDialog(wx
.GetApp().GetTopWindow(), 
 554                                                  _("Reverted file '%s' is currently open.  Close it?") % os
.path
.basename(doc
.GetFilename()), 
 556                                                  wx
.YES_NO|wx
.ICON_QUESTION
) 
 557                         if yesNoMsg
.ShowModal() == wx
.ID_YES
: 
 560             except pysvn
.ClientError
, e
: 
 561                 view
.AddLines("%s\n" % str(e
)) 
 562                 wx
.MessageBox(str(e
), _("SVN Revert"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 564                 extype
, ex
, tb 
= sys
.exc_info() 
 565                 view
.AddLines("Revert failed: (%s) %s\n" % (extype
, str(ex
))) 
 566                 for line 
in traceback
.format_tb(tb
): 
 568                 wx
.MessageBox(_("Revert failed."), _("SVN Revert"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 570             wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_DEFAULT
)) 
 573         elif id == SVNService
.SVN_ADD_ID
: 
 574             wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_WAIT
)) 
 576             filenames 
= self
.GetCurrentDocuments() 
 578             messageService 
= wx
.GetApp().GetService(MessageService
.MessageService
) 
 579             messageService
.ShowWindow() 
 581             view 
= messageService
.GetView() 
 583             view
.AddLines(_("SVN Add:\n")) 
 584             for filename 
in filenames
: 
 585                 view
.AddLines("%s\n" % filename
) 
 588                 self
._client
.add(filenames
) 
 589                 view
.AddLines(_("Add completed.\n")) 
 590             except pysvn
.ClientError
, e
: 
 591                 view
.AddLines("%s\n" % str(e
)) 
 592                 wx
.MessageBox(str(e
), _("SVN Add"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 594                 extype
, ex
, tb 
= sys
.exc_info() 
 595                 view
.AddLines("Add failed: (%s) %s\n" % (extype
, str(ex
))) 
 596                 for line 
in traceback
.format_tb(tb
): 
 598                 wx
.MessageBox(_("Add failed."), _("SVN Add"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 600             wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_DEFAULT
)) 
 603         elif id == SVNService
.SVN_DELETE_ID
: 
 604             wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_WAIT
)) 
 606             filenames 
= self
.GetCurrentDocuments() 
 608             messageService 
= wx
.GetApp().GetService(MessageService
.MessageService
) 
 609             messageService
.ShowWindow() 
 611             view 
= messageService
.GetView() 
 613             view
.AddLines(_("SVN Delete:\n")) 
 614             for filename 
in filenames
: 
 615                 view
.AddLines("%s\n" % filename
) 
 618                 self
._client
.remove(filenames
) 
 619                 view
.AddLines(_("Delete completed.\n")) 
 620             except pysvn
.ClientError
, e
: 
 621                 view
.AddLines("%s\n" % str(e
)) 
 622                 wx
.MessageBox(str(e
), _("SVN Delete"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 624                 extype
, ex
, tb 
= sys
.exc_info() 
 625                 view
.AddLines("Delete failed: (%s) %s\n" % (extype
, str(ex
))) 
 626                 for line 
in traceback
.format_tb(tb
): 
 628                 wx
.MessageBox(_("Delete failed."), _("SVN Delete"), wx
.OK | wx
.ICON_EXCLAMATION
) 
 630             wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_DEFAULT
)) 
 636     def ProcessUpdateUIEvent(self
, event
): 
 639         if id in [SVNService
.SVN_UPDATE_ID
, 
 640                   SVNService
.SVN_CHECKIN_ID
, 
 641                   SVNService
.SVN_REVERT_ID
, 
 642                   SVNService
.SVN_ADD_ID
, 
 643                   SVNService
.SVN_DELETE_ID
]: 
 644             if self
.GetCurrentDocuments(): 
 650         elif id == SVNService
.SVN_CHECKOUT_ID
: 
 657     def GetCurrentDocuments(self
): 
 659         projectService 
= wx
.GetApp().GetService(ProjectEditor
.ProjectService
) 
 661             projView 
= projectService
.GetView() 
 663             if projView
.HasFocus(): 
 664                 filenames 
= projView
.GetSelectedFiles() 
 670         doc 
= wx
.GetApp().GetTopWindow().GetDocumentManager().GetCurrentDocument() 
 672             filenames 
= [doc
.GetFilename()] 
 679 class SVNOptionsPanel(wx
.Panel
): 
 682     def __init__(self
, parent
, id): 
 683         wx
.Panel
.__init
__(self
, parent
, id) 
 685         config 
= wx
.ConfigBase_Get() 
 686         svnService 
= wx
.GetApp().GetService(SVNService
) 
 687         svnUrl 
= config
.Read(SVN_REPOSITORY_URL
, svnService
._defaultURL
) 
 688         configDir 
= config
.Read(SVN_CONFIG_DIR
, "") 
 690         borderSizer 
= wx
.BoxSizer(wx
.VERTICAL
) 
 691         sizer 
= wx
.FlexGridSizer(cols 
= 2, hgap 
= 5, vgap 
= 5) 
 693         sizer
.Add(wx
.StaticText(self
, -1, _("SVN Config Dir:")), 0, wx
.ALIGN_CENTER_VERTICAL
) 
 695         self
._svnConfigDir 
= wx
.TextCtrl(self
, -1, configDir
, size 
= (200, -1)) 
 697             self
._svnConfigDir
.SetToolTipString(_("Path Subversion configuration directory.")) 
 699             self
._svnConfigDir
.SetToolTipString(configDir
) 
 701         findDirButton 
= wx
.Button(self
, -1, _("Browse...")) 
 703         def OnBrowseButton(event
): 
 704             dirDlg 
= wx
.DirDialog(self
, _("Choose a directory:"), style
=wx
.DD_DEFAULT_STYLE
) 
 705             dir = self
._svnConfigDir
.GetValue() 
 708             if dirDlg
.ShowModal() == wx
.ID_OK
: 
 709                 self
._svnConfigDir
.SetValue(dirDlg
.GetPath()) 
 710                 self
._svnConfigDir
.SetToolTipString(self
._svnConfigDir
.GetValue()) 
 711                 self
._svnConfigDir
.SetInsertionPointEnd() 
 714         wx
.EVT_BUTTON(findDirButton
, -1, OnBrowseButton
) 
 716         hsizer 
= wx
.BoxSizer(wx
.HORIZONTAL
) 
 717         hsizer
.Add(self
._svnConfigDir
, 1, wx
.EXPAND
) 
 718         hsizer
.Add(findDirButton
, 0, wx
.LEFT
, HALF_SPACE
) 
 721         sizer
.Add(wx
.StaticText(self
, -1, _("SVN URL:")), 0, wx
.ALIGN_CENTER_VERTICAL
) 
 722         self
._svnURLText 
= wx
.TextCtrl(self
, -1, svnUrl
, size 
= (200, -1)) 
 723         self
._svnURLText
.SetToolTipString(svnUrl
) 
 724         sizer
.Add(self
._svnURLText
, 0) 
 726         borderSizer
.Add(sizer
, 0, wx
.ALL
, SPACE
) 
 727         self
.SetSizer(borderSizer
) 
 729         parent
.AddPage(self
, _("SVN")) 
 732     def OnOK(self
, optionsDialog
): 
 733         config 
= wx
.ConfigBase_Get() 
 734         config
.Write(SVN_CONFIG_DIR
, self
._svnConfigDir
.GetValue()) 
 735         config
.Write(SVN_REPOSITORY_URL
, self
._svnURLText
.GetValue())