]>
Commit | Line | Data |
---|---|---|
6f1a3f9c RD |
1 | #---------------------------------------------------------------------------- |
2 | # Name: SVNService.py | |
3 | # Purpose: Subversion Service for pydocview | |
4 | # | |
5 | # Author: Morgan Hua | |
6 | # | |
7 | # Created: 5/13/05 | |
8 | # CVS-ID: $Id$ | |
9 | # Copyright: (c) 2005 ActiveGrid, Inc. | |
10 | # License: wxWindows License | |
11 | #---------------------------------------------------------------------------- | |
12 | ||
13 | import wx | |
26ee3a06 | 14 | import os |
6f1a3f9c RD |
15 | import os.path |
16 | import ProjectEditor | |
17 | import MessageService | |
18 | ||
19 | import sys # for errors | |
20 | import traceback # for errors | |
21 | ||
22 | try: | |
23 | import pysvn # python-subversion integration | |
24 | SVN_INSTALLED = True | |
25 | except ImportError: | |
26 | SVN_INSTALLED = False | |
27 | ||
28 | _ = wx.GetTranslation | |
29 | ||
30 | ||
31 | #---------------------------------------------------------------------------- | |
32 | # Constants | |
33 | #---------------------------------------------------------------------------- | |
34 | SVN_CONFIG_DIR = "SVNConfigDir" | |
26ee3a06 | 35 | SVN_REPOSITORY_URL = "SVNRepositoryURLs" |
6f1a3f9c RD |
36 | |
37 | SPACE = 10 | |
38 | HALF_SPACE = 5 | |
39 | ||
40 | ||
41 | #---------------------------------------------------------------------------- | |
42 | # Classes | |
43 | #---------------------------------------------------------------------------- | |
44 | ||
45 | class SVNService(wx.lib.pydocview.DocService): | |
26ee3a06 | 46 | SVN_UPDATE_ALL_ID = wx.NewId() |
6f1a3f9c RD |
47 | SVN_UPDATE_ID = wx.NewId() |
48 | SVN_CHECKIN_ID = wx.NewId() | |
26ee3a06 | 49 | SVN_CHECKIN_ALL_ID = wx.NewId() |
6f1a3f9c RD |
50 | SVN_CHECKOUT_ID = wx.NewId() |
51 | SVN_REVERT_ID = wx.NewId() | |
52 | SVN_ADD_ID = wx.NewId() | |
53 | SVN_DELETE_ID = wx.NewId() | |
26ee3a06 | 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] |
6f1a3f9c RD |
55 | |
56 | ||
57 | def __init__(self): | |
58 | self._defaultURL = "svn://" | |
59 | ||
60 | global SVN_INSTALLED | |
61 | if SVN_INSTALLED: | |
62 | config = wx.ConfigBase_Get() | |
26ee3a06 | 63 | |
6f1a3f9c | 64 | configDir = config.Read(SVN_CONFIG_DIR, "") |
6f1a3f9c RD |
65 | self._client = pysvn.Client(configDir) |
66 | try: | |
67 | self._defaultURL = self._client.info('.').url | |
68 | except: | |
69 | pass | |
26ee3a06 | 70 | |
6f1a3f9c RD |
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 | |
79 | ||
80 | #---------------------------------------------------------------------------- | |
81 | # pysvn.Client() Callback Methods | |
82 | #---------------------------------------------------------------------------- | |
83 | ||
84 | def IfCancel(self): | |
85 | """ return True if user wants to cancel current command """ | |
86 | return False | |
87 | ||
88 | ||
89 | def UpdateStatus(self, eventDict): | |
90 | messageService = wx.GetApp().GetService(MessageService.MessageService) | |
91 | messageService.ShowWindow() | |
92 | ||
93 | view = messageService.GetView() | |
94 | view.AddLines(_("%s %s\n") % (eventDict['action'], eventDict['path'])) | |
95 | ||
96 | ||
97 | def GetLogMessage(self): | |
98 | dlg = wx.TextEntryDialog(wx.GetApp().GetTopWindow(), | |
99 | _("Comment"), | |
100 | _("SVN Log Message")) | |
101 | ||
102 | if dlg.ShowModal() == wx.ID_OK: | |
103 | retcode = True | |
104 | message = dlg.GetValue() | |
105 | else: | |
106 | retcode = False | |
107 | message = _("Cancel Action") | |
108 | ||
109 | dlg.Destroy() | |
110 | ||
111 | return retcode, message | |
112 | ||
113 | ||
114 | def GetLogin(self, realm, username, maySave): | |
115 | dlg = wx.Dialog(wx.GetApp().GetTopWindow(), -1, _("SVN Login")) | |
116 | ||
117 | sizer = wx.FlexGridSizer(cols = 2, hgap = 5, vgap = 5) | |
118 | sizer.Add(wx.StaticText(dlg, -1, _("Username:")), 0, wx.ALIGN_CENTER_VERTICAL) | |
119 | usernameTxt = wx.TextCtrl(dlg, -1, username, size = (200, -1)) | |
120 | sizer.Add(usernameTxt, 0, wx.ALIGN_CENTER_VERTICAL) | |
121 | sizer.Add(wx.StaticText(dlg, -1, _("Password:")), 0, wx.ALIGN_CENTER_VERTICAL) | |
122 | passwordTxt = wx.TextCtrl(dlg, -1, size=(200, -1), style=wx.TE_PASSWORD) | |
123 | sizer.Add(passwordTxt, 0, wx.ALIGN_CENTER_VERTICAL) | |
124 | ||
125 | savePasswordCheckbox = wx.CheckBox(dlg, -1, _("Remember Username and Password")) | |
126 | if not maySave: | |
127 | savePasswordCheckbox.Enable(False) | |
128 | ||
129 | buttonSizer = wx.BoxSizer(wx.HORIZONTAL) | |
130 | okBtn = wx.Button(dlg, wx.ID_OK) | |
131 | okBtn.SetDefault() | |
132 | buttonSizer.Add(okBtn, 0, wx.RIGHT, HALF_SPACE) | |
133 | buttonSizer.Add(wx.Button(dlg, wx.ID_CANCEL), 0) | |
134 | ||
135 | contentSizer = wx.BoxSizer(wx.VERTICAL) | |
136 | contentSizer.Add(sizer, 0, wx.LEFT|wx.TOP|wx.RIGHT, SPACE) | |
137 | contentSizer.Add(savePasswordCheckbox, 0, wx.TOP|wx.LEFT|wx.BOTTOM, SPACE) | |
138 | contentSizer.Add(buttonSizer, 0, wx.ALL|wx.ALIGN_RIGHT, SPACE) | |
139 | ||
140 | dlg.SetSizer(contentSizer) | |
141 | dlg.Fit() | |
142 | dlg.Layout() | |
143 | ||
144 | if dlg.ShowModal() == wx.ID_OK: | |
145 | retcode = True | |
146 | username = usernameTxt.GetValue().strip() | |
147 | password = passwordTxt.GetValue() | |
148 | save = savePasswordCheckBox.IsChecked() | |
149 | else: | |
150 | retcode = False | |
151 | username = None | |
152 | password = None | |
153 | save = False | |
154 | ||
155 | dlg.Destroy() | |
156 | return retcode, username, password, save | |
157 | ||
158 | ||
159 | def SSLServerPrompt(self): | |
160 | """ Not implemented, as per pysvn documentation """ | |
161 | return | |
162 | ||
163 | ||
164 | def GetSSLServerTrust(self, trustDict): | |
165 | dlg = wx.Dialog(wx.GetApp().GetTopWindow(), -1, _("SSL Server Certificate")) | |
166 | ||
167 | sizer = wx.FlexGridSizer(cols = 2, hgap = 5, vgap = 5) | |
168 | for k in ['hostname', 'valid_from', 'valid_to', 'issuer_dname', 'realm']: | |
169 | if trustDict.has_key(k): | |
170 | sizer.Add(wx.StaticText(dlg, -1, "%s:" % k), 0, wx.ALIGN_CENTER_VERTICAL) | |
171 | sizer.Add(wx.StaticText(dlg, -1, "%s" % trustDict[k]), 0, wx.ALIGN_CENTER_VERTICAL) | |
172 | ||
173 | box = wx.StaticBoxSizer(wx.StaticBox(dlg, -1, _("Certificate Info")), wx.VERTICAL) | |
174 | box.Add(sizer, 0, wx.EXPAND) | |
175 | ||
176 | certRadio = wx.RadioBox(dlg, -1, _("Certificate"), choices=[_("Accept Always"), _("Accept Once"), _("Reject")], majorDimension=1, style=wx.RA_SPECIFY_COLS) | |
177 | ||
178 | buttonSizer = wx.BoxSizer(wx.HORIZONTAL) | |
179 | okBtn = wx.Button(dlg, wx.ID_OK) | |
180 | okBtn.SetDefault() | |
181 | buttonSizer.Add(okBtn, 0, wx.RIGHT, HALF_SPACE) | |
182 | buttonSizer.Add(wx.Button(dlg, wx.ID_CANCEL), 0) | |
183 | ||
184 | contentSizer = wx.BoxSizer(wx.VERTICAL) | |
185 | contentSizer.Add(box, 0, wx.TOP|wx.LEFT|wx.RIGHT|wx.EXPAND, SPACE) | |
186 | contentSizer.Add(certRadio, 0, wx.TOP|wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.EXPAND, SPACE) | |
187 | contentSizer.Add(buttonSizer, 0, wx.ALL|wx.ALIGN_RIGHT, SPACE) | |
188 | ||
189 | dlg.SetSizer(contentSizer) | |
190 | dlg.Fit() | |
191 | dlg.Layout() | |
192 | ||
193 | # default values for reject | |
194 | retcode = False | |
195 | acceptedFailures = 0 | |
196 | save = False | |
197 | ||
198 | if dlg.ShowModal() == wx.ID_OK: | |
199 | cert = certRadio.GetStringSelection() | |
200 | if cert == _("Accept Always"): | |
201 | retcode = True | |
202 | acceptedFailures = trustDict.get('failures') | |
203 | save = True | |
204 | elif cert == _("Accept Once"): | |
205 | retcode = True | |
206 | acceptedFailures = trustDict.get('failures') | |
207 | save = False | |
208 | ||
209 | return retcode, acceptedFailures, save | |
210 | ||
211 | ||
212 | def SSLClientPassword(self, realm, maySave): | |
213 | dlg = wx.Dialog(wx.GetApp().GetTopWindow(), -1, _("SSL Client Certificate Login")) | |
214 | ||
215 | sizer = wx.FlexGridSizer(cols = 2, hgap = 5, vgap = 5) | |
216 | sizer.Add(wx.StaticText(dlg, -1, _("Realm:")), 0, wx.ALIGN_CENTER_VERTICAL) | |
217 | sizer.Add(wx.StaticText(dlg, -1, realm), 0, wx.ALIGN_CENTER_VERTICAL) | |
218 | sizer.Add(wx.StaticText(dlg, -1, _("Password:")), 0, wx.ALIGN_CENTER_VERTICAL) | |
219 | passwordTxt = wx.TextCtrl(dlg, -1, size=(200, -1), style=wx.TE_PASSWORD) | |
220 | sizer.Add(passwordTxt, 0, wx.ALIGN_CENTER_VERTICAL) | |
221 | ||
222 | savePasswordCheckbox = wx.CheckBox(dlg, -1, _("Remember Password")) | |
223 | if not maySave: | |
224 | savePasswordCheckbox.Enable(False) | |
225 | ||
226 | buttonSizer = wx.BoxSizer(wx.HORIZONTAL) | |
227 | okBtn = wx.Button(dlg, wx.ID_OK) | |
228 | okBtn.SetDefault() | |
229 | buttonSizer.Add(okBtn, 0, wx.RIGHT, HALF_SPACE) | |
230 | buttonSizer.Add(wx.Button(dlg, wx.ID_CANCEL), 0) | |
231 | ||
232 | contentSizer = wx.BoxSizer(wx.VERTICAL) | |
233 | contentSizer.Add(sizer, 0, wx.LEFT|wx.TOP|wx.RIGHT, SPACE) | |
234 | contentSizer.Add(savePasswordCheckbox, 0, wx.TOP|wx.LEFT|wx.BOTTOM, SPACE) | |
235 | contentSizer.Add(buttonSizer, 0, wx.ALL|wx.ALIGN_RIGHT, SPACE) | |
236 | ||
237 | dlg.SetSizer(contentSizer) | |
238 | dlg.Fit() | |
239 | dlg.Layout() | |
240 | ||
241 | if dlg.ShowModal() == wx.ID_OK: | |
242 | retcode = True | |
243 | password = passwordTxt.GetValue() | |
244 | save = savePasswordCheckBox.IsChecked() | |
245 | else: | |
246 | retcode = False | |
247 | password = None | |
248 | save = False | |
249 | ||
250 | dlg.Destroy() | |
251 | return retcode, password, save | |
252 | ||
253 | ||
254 | def SSLClientCert(self): | |
255 | dlg = wx.FileDialog(wx.GetApp().GetTopWindow(), | |
256 | message="Choose certificate", defaultDir=os.getcwd(), | |
257 | style=wx.OPEN|wx.CHANGE_DIR | |
258 | ) | |
259 | ||
260 | if dlg.ShowModal() == wx.ID_OK: | |
261 | retcode = True | |
262 | certfile = dlg.GetPath() | |
263 | else: | |
264 | retcode = False | |
265 | certfile = None | |
266 | ||
267 | dlg.Destroy() | |
268 | return retcode, certfile | |
269 | ||
270 | ||
271 | ||
272 | #---------------------------------------------------------------------------- | |
273 | # Service Methods | |
274 | #---------------------------------------------------------------------------- | |
275 | ||
276 | def InstallControls(self, frame, menuBar = None, toolBar = None, statusBar = None, document = None): | |
277 | menu = menuBar.GetMenu(menuBar.FindMenu(_("Project"))) | |
278 | ||
279 | menu.AppendSeparator() | |
280 | ||
26ee3a06 RD |
281 | wx.EVT_MENU(frame, SVNService.SVN_UPDATE_ALL_ID, self.ProcessEvent) |
282 | wx.EVT_UPDATE_UI(frame, SVNService.SVN_UPDATE_ALL_ID, self.ProcessUpdateUIEvent) | |
283 | menu.Append(SVNService.SVN_UPDATE_ALL_ID, _("SVN Update All in Project"), _("Update all files in a project from Subversion")) | |
284 | wx.EVT_MENU(frame, SVNService.SVN_CHECKIN_ALL_ID, self.ProcessEvent) | |
285 | wx.EVT_UPDATE_UI(frame, SVNService.SVN_CHECKIN_ALL_ID, self.ProcessUpdateUIEvent) | |
286 | menu.Append(SVNService.SVN_CHECKIN_ALL_ID, _("SVN Commit All in Project..."), _("Commit all files changes in a project to Subversion")) | |
6f1a3f9c RD |
287 | wx.EVT_MENU(frame, SVNService.SVN_UPDATE_ID, self.ProcessEvent) |
288 | wx.EVT_UPDATE_UI(frame, SVNService.SVN_UPDATE_ID, self.ProcessUpdateUIEvent) | |
289 | menu.Append(SVNService.SVN_UPDATE_ID, _("SVN Update"), _("Update file from Subversion")) | |
290 | wx.EVT_MENU(frame, SVNService.SVN_CHECKIN_ID, self.ProcessEvent) | |
291 | wx.EVT_UPDATE_UI(frame, SVNService.SVN_CHECKIN_ID, self.ProcessUpdateUIEvent) | |
292 | menu.Append(SVNService.SVN_CHECKIN_ID, _("SVN Commit..."), _("Commit file changes to Subversion")) | |
293 | wx.EVT_MENU(frame, SVNService.SVN_CHECKOUT_ID, self.ProcessEvent) | |
294 | wx.EVT_UPDATE_UI(frame, SVNService.SVN_CHECKOUT_ID, self.ProcessUpdateUIEvent) | |
295 | menu.Append(SVNService.SVN_CHECKOUT_ID, _("SVN Checkout..."), _("Checkout file from Subversion")) | |
296 | wx.EVT_MENU(frame, SVNService.SVN_REVERT_ID, self.ProcessEvent) | |
297 | wx.EVT_UPDATE_UI(frame, SVNService.SVN_REVERT_ID, self.ProcessUpdateUIEvent) | |
298 | menu.Append(SVNService.SVN_REVERT_ID, _("SVN Revert"), _("Revert file from Subversion")) | |
299 | ||
300 | menu.AppendSeparator() | |
301 | ||
302 | wx.EVT_MENU(frame, SVNService.SVN_ADD_ID, self.ProcessEvent) | |
303 | wx.EVT_UPDATE_UI(frame, SVNService.SVN_ADD_ID, self.ProcessUpdateUIEvent) | |
304 | menu.Append(SVNService.SVN_ADD_ID, _("SVN Add"), _("Add file to Subversion")) | |
305 | wx.EVT_MENU(frame, SVNService.SVN_DELETE_ID, self.ProcessEvent) | |
306 | wx.EVT_UPDATE_UI(frame, SVNService.SVN_DELETE_ID, self.ProcessUpdateUIEvent) | |
307 | menu.Append(SVNService.SVN_DELETE_ID, _("SVN Delete"), _("Delete file from Subversion")) | |
308 | ||
309 | ||
310 | def ProcessEvent(self, event): | |
311 | ||
312 | id = event.GetId() | |
313 | ||
314 | if not SVN_INSTALLED: | |
315 | if id in SVNService.SVN_COMMAND_LIST: | |
316 | wx.MessageBox(_("pysvn not found. Please install pysvn"), _("Python Subversion")) | |
317 | return True | |
318 | return False | |
319 | ||
320 | ||
321 | if id == SVNService.SVN_UPDATE_ID: | |
6f1a3f9c | 322 | wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT)) |
26ee3a06 RD |
323 | |
324 | filenames = self.GetCurrentDocuments()[:] | |
325 | filenames.sort(self.BasenameCaseInsensitiveCompare) | |
6f1a3f9c RD |
326 | |
327 | messageService = wx.GetApp().GetService(MessageService.MessageService) | |
328 | messageService.ShowWindow() | |
329 | ||
330 | view = messageService.GetView() | |
331 | view.ClearLines() | |
332 | view.AddLines(_("SVN Update:\n")) | |
333 | ||
334 | for filename in filenames: | |
335 | view.AddLines("%s\n" % filename) | |
336 | try: | |
337 | status = self._client.update(filename) | |
338 | ||
339 | if status.number > 0: | |
340 | view.AddLines(_("Updated to revision %s\n") % status.number) | |
341 | ||
342 | openDocs = wx.GetApp().GetDocumentManager().GetDocuments() | |
343 | for doc in openDocs: | |
344 | if doc.GetFilename() == filename: | |
345 | yesNoMsg = wx.MessageDialog(wx.GetApp().GetTopWindow(), | |
346 | _("Updated file '%s' is currently open. Close it?") % os.path.basename(filename), | |
347 | _("Close File"), | |
348 | wx.YES_NO|wx.ICON_QUESTION) | |
349 | if yesNoMsg.ShowModal() == wx.ID_YES: | |
350 | doc.DeleteAllViews() | |
351 | break | |
352 | else: | |
353 | view.AddLines(_("Update failed.\n")) | |
354 | ||
355 | except pysvn.ClientError, e: | |
356 | view.AddLines("%s\n" % str(e)) | |
357 | wx.MessageBox(str(e), _("SVN Update"), wx.OK | wx.ICON_EXCLAMATION) | |
358 | except: | |
359 | extype, ex, tb = sys.exc_info() | |
360 | view.AddLines("Update failed: (%s) %s\n" % (extype, str(ex))) | |
361 | for line in traceback.format_tb(tb): | |
362 | view.AddLines(line) | |
363 | ||
364 | wx.MessageBox(_("Update failed."), _("SVN Update"), wx.OK | wx.ICON_EXCLAMATION) | |
365 | ||
366 | wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) | |
367 | ||
368 | return True | |
26ee3a06 RD |
369 | |
370 | elif id == SVNService.SVN_UPDATE_ALL_ID: | |
371 | wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT)) | |
372 | ||
373 | messageService = wx.GetApp().GetService(MessageService.MessageService) | |
374 | messageService.ShowWindow() | |
375 | ||
376 | view = messageService.GetView() | |
377 | view.ClearLines() | |
378 | view.AddLines(_("SVN Update:\n")) | |
379 | ||
380 | projects = self.GetCurrentProjects() | |
381 | for project in projects: | |
382 | openDocs = wx.GetApp().GetDocumentManager().GetDocuments() | |
383 | for doc in openDocs: | |
384 | if doc.GetFilename() == project: | |
385 | filenames = doc.GetFiles()[:] # make a copy and sort it. | |
386 | filenames.sort(self.BasenameCaseInsensitiveCompare) | |
387 | ||
388 | for filename in filenames: | |
389 | view.AddLines("%s\n" % filename) | |
390 | try: | |
391 | status = self._client.update(filename) | |
392 | ||
393 | if status.number > 0: | |
394 | view.AddLines(_("Updated to revision %s\n") % status.number) | |
395 | ||
396 | openDocs = wx.GetApp().GetDocumentManager().GetDocuments() | |
397 | for doc in openDocs: | |
398 | if doc.GetFilename() == filename: | |
399 | yesNoMsg = wx.MessageDialog(wx.GetApp().GetTopWindow(), | |
400 | _("Updated file '%s' is currently open. Close it?") % os.path.basename(filename), | |
401 | _("Close File"), | |
402 | wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION) | |
403 | status = yesNoMsg.ShowModal() | |
404 | if status == wx.ID_YES: | |
405 | doc.DeleteAllViews() | |
406 | elif status == wx.ID_NO: | |
407 | pass | |
408 | else: # elif status == wx.CANCEL: | |
409 | wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) | |
410 | return True | |
411 | break | |
412 | else: | |
413 | view.AddLines(_("Update failed.\n")) | |
414 | ||
415 | except pysvn.ClientError, e: | |
416 | view.AddLines("%s\n" % str(e)) | |
417 | wx.MessageBox(str(e), _("SVN Update"), wx.OK | wx.ICON_EXCLAMATION) | |
418 | except: | |
419 | extype, ex, tb = sys.exc_info() | |
420 | view.AddLines("Update failed: (%s) %s\n" % (extype, str(ex))) | |
421 | for line in traceback.format_tb(tb): | |
422 | view.AddLines(line) | |
423 | ||
424 | wx.MessageBox(_("Update failed."), _("SVN Update"), wx.OK | wx.ICON_EXCLAMATION) | |
425 | ||
426 | wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) | |
427 | return True | |
428 | ||
429 | elif id == SVNService.SVN_CHECKIN_ALL_ID: | |
430 | filenames = [] | |
431 | projects = self.GetCurrentProjects() | |
432 | for project in projects: | |
433 | openDocs = wx.GetApp().GetDocumentManager().GetDocuments() | |
434 | for doc in openDocs: | |
435 | if doc.GetFilename() == project: | |
436 | for filename in doc.GetFiles(): | |
437 | if filename not in filenames: | |
438 | filenames.append(filename) | |
439 | filenames.sort(self.BasenameCaseInsensitiveCompare) | |
440 | ||
441 | # ask user if dirty files should be saved first | |
442 | openDocs = wx.GetApp().GetDocumentManager().GetDocuments() | |
443 | for filename in filenames: | |
444 | for doc in openDocs: | |
445 | if doc.GetFilename() == filename and doc.IsModified(): | |
446 | yesNoMsg = wx.MessageDialog(wx.GetApp().GetTopWindow(), | |
447 | _("'%s' has unsaved modifications. Save it before commit?") % os.path.basename(filename), | |
448 | _("SVN Commit"), | |
449 | wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION) | |
450 | status = yesNoMsg.ShowModal() | |
451 | if status == wx.ID_YES: | |
452 | doc.Save() | |
453 | elif status == wx.ID_NO: | |
454 | pass | |
455 | else: # elif status == wx.CANCEL: | |
456 | return True | |
457 | break | |
458 | ||
459 | shortFilenames = [] | |
460 | for i, filename in enumerate(filenames): | |
461 | shortFilename = os.path.basename(filename) | |
462 | shortFilenames.append(shortFilename) | |
463 | ||
464 | dlg = wx.Dialog(wx.GetApp().GetTopWindow(), -1, _("SVN Commit")) | |
465 | ||
466 | sizer = wx.BoxSizer(wx.VERTICAL) | |
467 | sizer.Add(wx.StaticText(dlg, -1, _("Comment:")), 0, wx.ALIGN_CENTER_VERTICAL) | |
468 | commentText = wx.TextCtrl(dlg, -1, size=(250,-1), style=wx.TE_MULTILINE) | |
469 | sizer.Add(commentText, 1, wx.EXPAND|wx.TOP, HALF_SPACE) | |
470 | ||
471 | sizer.Add(wx.StaticText(dlg, -1, _("Files:")), 0, wx.ALIGN_CENTER_VERTICAL|wx.TOP, SPACE) | |
472 | fileList = wx.CheckListBox(dlg, -1, choices = shortFilenames) | |
473 | for i in range(fileList.GetCount()): | |
474 | fileList.Check(i, True) | |
475 | sizer.Add(fileList, 0, wx.EXPAND|wx.TOP, HALF_SPACE) | |
476 | ||
477 | buttonSizer = wx.BoxSizer(wx.HORIZONTAL) | |
478 | okBtn = wx.Button(dlg, wx.ID_OK) | |
479 | okBtn.SetDefault() | |
480 | buttonSizer.Add(okBtn, 0, wx.RIGHT, HALF_SPACE) | |
481 | buttonSizer.Add(wx.Button(dlg, wx.ID_CANCEL), 0) | |
482 | ||
483 | contentSizer = wx.BoxSizer(wx.VERTICAL) | |
484 | contentSizer.Add(sizer, 0, wx.ALL, SPACE) | |
485 | contentSizer.Add(buttonSizer, 0, wx.ALL|wx.ALIGN_RIGHT, SPACE) | |
486 | ||
487 | dlg.SetSizer(contentSizer) | |
488 | dlg.Fit() | |
489 | dlg.Layout() | |
490 | ||
491 | if dlg.ShowModal() == wx.ID_OK: | |
492 | wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT)) | |
493 | ||
494 | messageService = wx.GetApp().GetService(MessageService.MessageService) | |
495 | messageService.ShowWindow() | |
496 | ||
497 | view = messageService.GetView() | |
498 | view.ClearLines() | |
499 | view.AddLines(_("SVN Commit:\n")) | |
500 | ||
501 | try: | |
502 | selFilenames = [] | |
503 | for i in range(fileList.GetCount()): | |
504 | if fileList.IsChecked(i): | |
505 | selFilenames.append(filenames[i]) | |
506 | view.AddLines("%s\n" % filenames[i]) | |
507 | ||
508 | if len(selFilenames): | |
509 | comment = commentText.GetValue() | |
510 | status = self._client.checkin(selFilenames, comment) | |
511 | ||
512 | if status is None: | |
513 | view.AddLines(_("Nothing to commit.\n")) | |
514 | elif status.number > 0: | |
515 | view.AddLines(_("Committed as revision %s.\n") % status.number) | |
516 | else: | |
517 | view.AddLines(_("Commit failed.\n")) | |
518 | ||
519 | except pysvn.ClientError, e: | |
520 | view.AddLines("%s\n" % str(e)) | |
521 | wx.MessageBox(str(e), _("SVN Commit"), wx.OK | wx.ICON_EXCLAMATION) | |
522 | except: | |
523 | extype, ex, tb = sys.exc_info() | |
524 | view.AddLines("Commit failed: (%s) %s\n" % (extype, str(ex))) | |
525 | for line in traceback.format_tb(tb): | |
526 | view.AddLines(line) | |
527 | wx.MessageBox(_("Commit failed."), _("SVN Commit"), wx.OK | wx.ICON_EXCLAMATION) | |
528 | ||
529 | wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) | |
530 | dlg.Destroy() | |
531 | return True | |
532 | ||
6f1a3f9c RD |
533 | |
534 | elif id == SVNService.SVN_CHECKIN_ID: | |
26ee3a06 RD |
535 | filenames = self.GetCurrentDocuments()[:] |
536 | filenames.sort(self.BasenameCaseInsensitiveCompare) | |
6f1a3f9c RD |
537 | |
538 | # ask user if dirty files should be saved first | |
539 | openDocs = wx.GetApp().GetDocumentManager().GetDocuments() | |
540 | for filename in filenames: | |
541 | for doc in openDocs: | |
542 | if doc.GetFilename() == filename and doc.IsModified(): | |
543 | yesNoMsg = wx.MessageDialog(wx.GetApp().GetTopWindow(), | |
544 | _("'%s' has unsaved modifications. Save it before commit?") % os.path.basename(filename), | |
545 | _("SVN Commit"), | |
546 | wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION) | |
547 | status = yesNoMsg.ShowModal() | |
548 | if status == wx.ID_YES: | |
549 | doc.Save() | |
550 | elif status == wx.ID_NO: | |
551 | pass | |
552 | else: # elif status == wx.CANCEL: | |
553 | return True | |
554 | break | |
555 | ||
556 | shortFilenames = [] | |
557 | for i, filename in enumerate(filenames): | |
558 | shortFilename = os.path.basename(filename) | |
559 | shortFilenames.append(shortFilename) | |
560 | ||
561 | dlg = wx.Dialog(wx.GetApp().GetTopWindow(), -1, _("SVN Commit")) | |
562 | ||
563 | sizer = wx.BoxSizer(wx.VERTICAL) | |
564 | sizer.Add(wx.StaticText(dlg, -1, _("Comment:")), 0, wx.ALIGN_CENTER_VERTICAL) | |
565 | commentText = wx.TextCtrl(dlg, -1, size=(250,-1), style=wx.TE_MULTILINE) | |
566 | sizer.Add(commentText, 1, wx.EXPAND|wx.TOP, HALF_SPACE) | |
567 | ||
568 | sizer.Add(wx.StaticText(dlg, -1, _("Files:")), 0, wx.ALIGN_CENTER_VERTICAL|wx.TOP, SPACE) | |
569 | fileList = wx.CheckListBox(dlg, -1, choices = shortFilenames) | |
570 | for i in range(fileList.GetCount()): | |
571 | fileList.Check(i, True) | |
572 | sizer.Add(fileList, 0, wx.EXPAND|wx.TOP, HALF_SPACE) | |
573 | ||
574 | buttonSizer = wx.BoxSizer(wx.HORIZONTAL) | |
575 | okBtn = wx.Button(dlg, wx.ID_OK) | |
576 | okBtn.SetDefault() | |
577 | buttonSizer.Add(okBtn, 0, wx.RIGHT, HALF_SPACE) | |
578 | buttonSizer.Add(wx.Button(dlg, wx.ID_CANCEL), 0) | |
579 | ||
580 | contentSizer = wx.BoxSizer(wx.VERTICAL) | |
581 | contentSizer.Add(sizer, 0, wx.ALL, SPACE) | |
582 | contentSizer.Add(buttonSizer, 0, wx.ALL|wx.ALIGN_RIGHT, SPACE) | |
583 | ||
584 | dlg.SetSizer(contentSizer) | |
585 | dlg.Fit() | |
586 | dlg.Layout() | |
587 | ||
588 | if dlg.ShowModal() == wx.ID_OK: | |
589 | wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT)) | |
590 | ||
591 | messageService = wx.GetApp().GetService(MessageService.MessageService) | |
592 | messageService.ShowWindow() | |
593 | ||
594 | view = messageService.GetView() | |
595 | view.ClearLines() | |
596 | view.AddLines(_("SVN Commit:\n")) | |
597 | ||
598 | try: | |
599 | selFilenames = [] | |
600 | for i in range(fileList.GetCount()): | |
601 | if fileList.IsChecked(i): | |
602 | selFilenames.append(filenames[i]) | |
603 | view.AddLines("%s\n" % filenames[i]) | |
604 | ||
605 | if len(selFilenames): | |
606 | comment = commentText.GetValue() | |
607 | status = self._client.checkin(selFilenames, comment) | |
608 | ||
609 | if status is None: | |
610 | view.AddLines(_("Nothing to commit.\n")) | |
611 | elif status.number > 0: | |
612 | view.AddLines(_("Committed as revision %s.\n") % status.number) | |
613 | else: | |
614 | view.AddLines(_("Commit failed.\n")) | |
615 | ||
616 | except pysvn.ClientError, e: | |
617 | view.AddLines("%s\n" % str(e)) | |
618 | wx.MessageBox(str(e), _("SVN Commit"), wx.OK | wx.ICON_EXCLAMATION) | |
619 | except: | |
620 | extype, ex, tb = sys.exc_info() | |
621 | view.AddLines("Commit failed: (%s) %s\n" % (extype, str(ex))) | |
622 | for line in traceback.format_tb(tb): | |
623 | view.AddLines(line) | |
624 | wx.MessageBox(_("Commit failed."), _("SVN Commit"), wx.OK | wx.ICON_EXCLAMATION) | |
625 | ||
626 | wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) | |
627 | dlg.Destroy() | |
628 | return True | |
629 | ||
630 | elif id == SVNService.SVN_CHECKOUT_ID: | |
631 | config = wx.ConfigBase_Get() | |
632 | svnUrl = config.Read(SVN_REPOSITORY_URL, self._defaultURL) | |
633 | ||
634 | dlg = wx.Dialog(wx.GetApp().GetTopWindow(), -1, _("SVN Checkout")) | |
635 | ||
636 | gridSizer = wx.FlexGridSizer(cols = 2, hgap = 5, vgap = 5) | |
637 | gridSizer.Add(wx.StaticText(dlg, -1, _("Repository URL:")), 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.TOP, HALF_SPACE) | |
26ee3a06 RD |
638 | svnUrlList = ReadSvnUrlList() |
639 | svnURLCombobox = wx.ComboBox(dlg, -1, size=(200, -1), choices=svnUrlList, style=wx.CB_DROPDOWN) | |
640 | if len(svnUrlList): | |
641 | svnURLCombobox.SetToolTipString(svnUrlList[0]) | |
642 | svnURLCombobox.SetStringSelection(svnUrlList[0]) | |
643 | else: | |
644 | svnURLCombobox.SetToolTipString(_("Set Repository URL")) | |
645 | gridSizer.Add(svnURLCombobox, 0) | |
6f1a3f9c RD |
646 | |
647 | gridSizer.Add(wx.StaticText(dlg, -1, _("Checkout to dir:")), 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.TOP, HALF_SPACE) | |
648 | localPath = wx.TextCtrl(dlg, -1, size = (200, -1)) | |
649 | localPath.SetToolTipString(_("Path in local file system where files will be located.")) | |
650 | findDirButton = wx.Button(dlg, -1, _("Browse...")) | |
651 | ||
652 | def OnBrowseButton(event): | |
653 | dirDlg = wx.DirDialog(wx.GetApp().GetTopWindow(), _("Choose a directory:"), style=wx.DD_DEFAULT_STYLE) | |
654 | dir = localPath.GetValue() | |
655 | if len(dir): | |
656 | dirDlg.SetPath(dir) | |
657 | if dirDlg.ShowModal() == wx.ID_OK: | |
658 | localPath.SetValue(dirDlg.GetPath()) | |
659 | localPath.SetToolTipString(localPath.GetValue()) | |
660 | localPath.SetInsertionPointEnd() | |
661 | ||
662 | dirDlg.Destroy() | |
663 | wx.EVT_BUTTON(findDirButton, -1, OnBrowseButton) | |
664 | ||
665 | sizer = wx.BoxSizer(wx.HORIZONTAL) | |
666 | sizer.Add(localPath, 1, wx.EXPAND) | |
667 | sizer.Add(findDirButton, 0, wx.LEFT, HALF_SPACE) | |
668 | gridSizer.Add(sizer, 0) | |
669 | ||
670 | buttonSizer = wx.BoxSizer(wx.HORIZONTAL) | |
671 | okBtn = wx.Button(dlg, wx.ID_OK) | |
672 | okBtn.SetDefault() | |
673 | buttonSizer.Add(okBtn, 0, wx.RIGHT, HALF_SPACE) | |
674 | buttonSizer.Add(wx.Button(dlg, wx.ID_CANCEL), 0) | |
675 | ||
676 | contentSizer = wx.BoxSizer(wx.VERTICAL) | |
677 | contentSizer.Add(gridSizer, 0, wx.ALL, SPACE) | |
678 | contentSizer.Add(buttonSizer, 0, wx.ALL|wx.ALIGN_RIGHT, SPACE) | |
679 | ||
680 | dlg.SetSizer(contentSizer) | |
681 | dlg.Fit() | |
682 | dlg.Layout() | |
683 | ||
684 | if dlg.ShowModal() == wx.ID_OK: | |
685 | wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT)) | |
26ee3a06 RD |
686 | |
687 | WriteSvnUrlList(svnURLCombobox) | |
6f1a3f9c RD |
688 | |
689 | messageService = wx.GetApp().GetService(MessageService.MessageService) | |
690 | messageService.ShowWindow() | |
691 | ||
692 | view = messageService.GetView() | |
693 | view.ClearLines() | |
694 | view.AddLines(_("SVN Checkout:\n")) | |
695 | ||
26ee3a06 | 696 | svnUrl = svnURLCombobox.GetValue() |
6f1a3f9c RD |
697 | toLocation = localPath.GetValue() |
698 | try: | |
699 | self._client.checkout(svnUrl, toLocation) | |
700 | view.AddLines(_("Checkout completed.\n")) | |
701 | except pysvn.ClientError, e: | |
702 | view.AddLines(_("Checkout failed. %s\n") % str(e)) | |
703 | wx.MessageBox(_("Checkout failed. %s") % str(e), _("SVN Checkout"), wx.OK | wx.ICON_EXCLAMATION) | |
704 | except: | |
705 | extype, ex, tb = sys.exc_info() | |
706 | view.AddLines("Checkout failed: (%s) %s\n" % (extype, str(ex))) | |
707 | for line in traceback.format_tb(tb): | |
708 | view.AddLines(line) | |
709 | wx.MessageBox(_("Checkout failed."), _("SVN Checkout"), wx.OK | wx.ICON_EXCLAMATION) | |
710 | ||
711 | wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) | |
712 | dlg.Destroy() | |
713 | return True | |
714 | ||
715 | elif id == SVNService.SVN_REVERT_ID: | |
716 | wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT)) | |
717 | ||
718 | filenames = self.GetCurrentDocuments() | |
719 | ||
720 | messageService = wx.GetApp().GetService(MessageService.MessageService) | |
721 | messageService.ShowWindow() | |
722 | ||
723 | view = messageService.GetView() | |
724 | view.ClearLines() | |
725 | view.AddLines(_("SVN Revert:\n")) | |
726 | for filename in filenames: | |
727 | view.AddLines("%s\n" % filename) | |
728 | ||
729 | try: | |
730 | self._client.revert(filenames) | |
731 | view.AddLines(_("Revert completed.\n")) | |
732 | ||
733 | openDocs = wx.GetApp().GetDocumentManager().GetDocuments() | |
734 | for doc in openDocs[:]: # need to make a copy of the list otherwise ordinality changes as we close the files | |
735 | if doc.GetFilename() in filenames: | |
736 | yesNoMsg = wx.MessageDialog(wx.GetApp().GetTopWindow(), | |
737 | _("Reverted file '%s' is currently open. Close it?") % os.path.basename(doc.GetFilename()), | |
738 | _("Close File"), | |
739 | wx.YES_NO|wx.ICON_QUESTION) | |
740 | if yesNoMsg.ShowModal() == wx.ID_YES: | |
741 | doc.DeleteAllViews() | |
742 | ||
743 | except pysvn.ClientError, e: | |
744 | view.AddLines("%s\n" % str(e)) | |
745 | wx.MessageBox(str(e), _("SVN Revert"), wx.OK | wx.ICON_EXCLAMATION) | |
746 | except: | |
747 | extype, ex, tb = sys.exc_info() | |
748 | view.AddLines("Revert failed: (%s) %s\n" % (extype, str(ex))) | |
749 | for line in traceback.format_tb(tb): | |
750 | view.AddLines(line) | |
751 | wx.MessageBox(_("Revert failed."), _("SVN Revert"), wx.OK | wx.ICON_EXCLAMATION) | |
752 | ||
753 | wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) | |
754 | return True | |
755 | ||
756 | elif id == SVNService.SVN_ADD_ID: | |
757 | wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT)) | |
758 | ||
759 | filenames = self.GetCurrentDocuments() | |
760 | ||
761 | messageService = wx.GetApp().GetService(MessageService.MessageService) | |
762 | messageService.ShowWindow() | |
763 | ||
764 | view = messageService.GetView() | |
765 | view.ClearLines() | |
766 | view.AddLines(_("SVN Add:\n")) | |
767 | for filename in filenames: | |
768 | view.AddLines("%s\n" % filename) | |
769 | ||
770 | try: | |
771 | self._client.add(filenames) | |
772 | view.AddLines(_("Add completed.\n")) | |
773 | except pysvn.ClientError, e: | |
774 | view.AddLines("%s\n" % str(e)) | |
775 | wx.MessageBox(str(e), _("SVN Add"), wx.OK | wx.ICON_EXCLAMATION) | |
776 | except: | |
777 | extype, ex, tb = sys.exc_info() | |
778 | view.AddLines("Add failed: (%s) %s\n" % (extype, str(ex))) | |
779 | for line in traceback.format_tb(tb): | |
780 | view.AddLines(line) | |
781 | wx.MessageBox(_("Add failed."), _("SVN Add"), wx.OK | wx.ICON_EXCLAMATION) | |
782 | ||
783 | wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) | |
784 | return True | |
785 | ||
786 | elif id == SVNService.SVN_DELETE_ID: | |
787 | wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT)) | |
788 | ||
789 | filenames = self.GetCurrentDocuments() | |
790 | ||
791 | messageService = wx.GetApp().GetService(MessageService.MessageService) | |
792 | messageService.ShowWindow() | |
793 | ||
794 | view = messageService.GetView() | |
795 | view.ClearLines() | |
796 | view.AddLines(_("SVN Delete:\n")) | |
797 | for filename in filenames: | |
798 | view.AddLines("%s\n" % filename) | |
799 | ||
800 | try: | |
801 | self._client.remove(filenames) | |
802 | view.AddLines(_("Delete completed.\n")) | |
803 | except pysvn.ClientError, e: | |
804 | view.AddLines("%s\n" % str(e)) | |
805 | wx.MessageBox(str(e), _("SVN Delete"), wx.OK | wx.ICON_EXCLAMATION) | |
806 | except: | |
807 | extype, ex, tb = sys.exc_info() | |
808 | view.AddLines("Delete failed: (%s) %s\n" % (extype, str(ex))) | |
809 | for line in traceback.format_tb(tb): | |
810 | view.AddLines(line) | |
811 | wx.MessageBox(_("Delete failed."), _("SVN Delete"), wx.OK | wx.ICON_EXCLAMATION) | |
812 | ||
813 | wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) | |
814 | return True | |
815 | ||
816 | return False | |
817 | ||
818 | ||
819 | def ProcessUpdateUIEvent(self, event): | |
820 | id = event.GetId() | |
821 | ||
822 | if id in [SVNService.SVN_UPDATE_ID, | |
823 | SVNService.SVN_CHECKIN_ID, | |
824 | SVNService.SVN_REVERT_ID, | |
825 | SVNService.SVN_ADD_ID, | |
826 | SVNService.SVN_DELETE_ID]: | |
827 | if self.GetCurrentDocuments(): | |
828 | event.Enable(True) | |
829 | else: | |
830 | event.Enable(False) | |
831 | return True | |
832 | ||
833 | elif id == SVNService.SVN_CHECKOUT_ID: | |
834 | event.Enable(True) | |
835 | return True | |
836 | ||
26ee3a06 RD |
837 | elif (id == SVNService.SVN_UPDATE_ALL_ID |
838 | or id == SVNService.SVN_CHECKIN_ALL_ID): | |
839 | if self.GetCurrentProjects(): | |
840 | event.Enable(True) | |
841 | else: | |
842 | event.Enable(False) | |
843 | return True | |
844 | ||
6f1a3f9c RD |
845 | return False |
846 | ||
847 | ||
26ee3a06 RD |
848 | def GetCurrentProjects(self): |
849 | projectService = wx.GetApp().GetService(ProjectEditor.ProjectService) | |
850 | if projectService: | |
851 | projView = projectService.GetView() | |
852 | ||
853 | if projView.HasFocus(): | |
854 | filenames = projView.GetSelectedProjects() | |
855 | if len(filenames): | |
856 | return filenames | |
857 | else: | |
858 | return None | |
859 | return None | |
860 | ||
861 | ||
6f1a3f9c RD |
862 | def GetCurrentDocuments(self): |
863 | ||
864 | projectService = wx.GetApp().GetService(ProjectEditor.ProjectService) | |
865 | if projectService: | |
866 | projView = projectService.GetView() | |
867 | ||
868 | if projView.HasFocus(): | |
869 | filenames = projView.GetSelectedFiles() | |
870 | if len(filenames): | |
871 | return filenames | |
872 | else: | |
873 | return None | |
874 | ||
875 | doc = wx.GetApp().GetTopWindow().GetDocumentManager().GetCurrentDocument() | |
876 | if doc: | |
877 | filenames = [doc.GetFilename()] | |
878 | else: | |
879 | filenames = None | |
880 | ||
881 | return filenames | |
882 | ||
883 | ||
26ee3a06 RD |
884 | def BasenameCaseInsensitiveCompare(self, s1, s2): |
885 | s1L = os.path.basename(s1).lower() | |
886 | s2L = os.path.basename(s2).lower() | |
887 | if s1L == s2L: | |
888 | return 0 | |
889 | elif s1L < s2L: | |
890 | return -1 | |
891 | else: | |
892 | return 1 | |
893 | ||
894 | ||
6f1a3f9c RD |
895 | class SVNOptionsPanel(wx.Panel): |
896 | ||
897 | ||
898 | def __init__(self, parent, id): | |
899 | wx.Panel.__init__(self, parent, id) | |
900 | ||
901 | config = wx.ConfigBase_Get() | |
6f1a3f9c RD |
902 | configDir = config.Read(SVN_CONFIG_DIR, "") |
903 | ||
904 | borderSizer = wx.BoxSizer(wx.VERTICAL) | |
905 | sizer = wx.FlexGridSizer(cols = 2, hgap = 5, vgap = 5) | |
906 | ||
907 | sizer.Add(wx.StaticText(self, -1, _("SVN Config Dir:")), 0, wx.ALIGN_CENTER_VERTICAL) | |
908 | ||
909 | self._svnConfigDir = wx.TextCtrl(self, -1, configDir, size = (200, -1)) | |
910 | if configDir == "": | |
911 | self._svnConfigDir.SetToolTipString(_("Path Subversion configuration directory.")) | |
912 | else: | |
913 | self._svnConfigDir.SetToolTipString(configDir) | |
914 | ||
915 | findDirButton = wx.Button(self, -1, _("Browse...")) | |
916 | ||
917 | def OnBrowseButton(event): | |
918 | dirDlg = wx.DirDialog(self, _("Choose a directory:"), style=wx.DD_DEFAULT_STYLE) | |
919 | dir = self._svnConfigDir.GetValue() | |
920 | if len(dir): | |
921 | dirDlg.SetPath(dir) | |
922 | if dirDlg.ShowModal() == wx.ID_OK: | |
923 | self._svnConfigDir.SetValue(dirDlg.GetPath()) | |
924 | self._svnConfigDir.SetToolTipString(self._svnConfigDir.GetValue()) | |
925 | self._svnConfigDir.SetInsertionPointEnd() | |
926 | ||
927 | dirDlg.Destroy() | |
928 | wx.EVT_BUTTON(findDirButton, -1, OnBrowseButton) | |
929 | ||
930 | hsizer = wx.BoxSizer(wx.HORIZONTAL) | |
931 | hsizer.Add(self._svnConfigDir, 1, wx.EXPAND) | |
932 | hsizer.Add(findDirButton, 0, wx.LEFT, HALF_SPACE) | |
933 | sizer.Add(hsizer, 0) | |
934 | ||
26ee3a06 RD |
935 | |
936 | svnUrlList = ReadSvnUrlList() | |
6f1a3f9c | 937 | sizer.Add(wx.StaticText(self, -1, _("SVN URL:")), 0, wx.ALIGN_CENTER_VERTICAL) |
26ee3a06 RD |
938 | self._svnURLCombobox = wx.ComboBox(self, -1, size=(200, -1), choices=svnUrlList, style=wx.CB_DROPDOWN) |
939 | if len(svnUrlList): | |
940 | self._svnURLCombobox.SetToolTipString(svnUrlList[0]) | |
941 | self._svnURLCombobox.SetStringSelection(svnUrlList[0]) | |
942 | else: | |
943 | self._svnURLCombobox.SetToolTipString(_("Set Repository URL")) | |
944 | sizer.Add(self._svnURLCombobox, 0) | |
945 | ||
946 | ||
947 | sizer.Add(wx.StaticText(self, -1, _("SVN_SSH:")), 0, wx.ALIGN_CENTER_VERTICAL) | |
948 | svnSSH = os.getenv("SVN_SSH") | |
949 | if not svnSSH or svnSSH == "": | |
950 | self._svnSSH = wx.TextCtrl(self, -1, size = (200, -1)) | |
951 | else: | |
952 | self._svnSSH = wx.TextCtrl(self, -1, svnSSH, size = (200, -1)) | |
953 | self._svnSSH.SetToolTipString(_("Override SVN_SSH environment variable temporarily.")) | |
954 | ||
955 | findSSHButton = wx.Button(self, -1, _("Browse...")) | |
956 | ||
957 | def OnBrowseFileButton(event): | |
958 | dirDlg = wx.FileDialog(self, _("Choose a file:"), style=wx.OPEN|wx.CHANGE_DIR) | |
959 | if dirDlg.ShowModal() == wx.ID_OK: | |
960 | self._svnSSH.SetValue(dirDlg.GetPath()) | |
961 | self._svnSSH.SetToolTipString(self._svnSSH.GetValue()) | |
962 | self._svnSSH.SetInsertionPointEnd() | |
963 | dirDlg.Destroy() | |
964 | wx.EVT_BUTTON(findSSHButton, -1, OnBrowseFileButton) | |
965 | ||
966 | hsizer = wx.BoxSizer(wx.HORIZONTAL) | |
967 | hsizer.Add(self._svnSSH, 1, wx.EXPAND) | |
968 | hsizer.Add(findSSHButton, 0, wx.LEFT, HALF_SPACE) | |
969 | sizer.Add(hsizer, 0) | |
970 | ||
6f1a3f9c RD |
971 | |
972 | borderSizer.Add(sizer, 0, wx.ALL, SPACE) | |
973 | self.SetSizer(borderSizer) | |
974 | self.Layout() | |
975 | parent.AddPage(self, _("SVN")) | |
976 | ||
977 | ||
978 | def OnOK(self, optionsDialog): | |
979 | config = wx.ConfigBase_Get() | |
26ee3a06 | 980 | |
6f1a3f9c | 981 | config.Write(SVN_CONFIG_DIR, self._svnConfigDir.GetValue()) |
26ee3a06 RD |
982 | |
983 | WriteSvnUrlList(self._svnURLCombobox) | |
984 | ||
985 | os.environ["SVN_SSH"] = self._svnSSH.GetValue() | |
986 | ||
987 | ||
988 | def ReadSvnUrlList(): | |
989 | """ Read in list of SNV repository URLs. First in list is the last one path used. """ | |
990 | config = wx.ConfigBase_Get() | |
991 | urlStringList = config.Read(SVN_REPOSITORY_URL) | |
992 | if len(urlStringList): | |
993 | urlList = eval(urlStringList) | |
994 | else: | |
995 | urlList = [] | |
996 | if len(urlList) == 0: | |
997 | svnService = wx.GetApp().GetService(SVNService) | |
998 | if svnService and hasattr(svnService, "_defaultURL"): | |
999 | urlList.append(svnService._defaultURL) | |
1000 | return urlList | |
1001 | ||
1002 | ||
1003 | def WriteSvnUrlList(comboBox): | |
1004 | """ Save out list of SVN repository URLs from combobox. Put on top the current selection. Only save out first 10 from the list """ | |
1005 | urlList = [] | |
1006 | ||
1007 | url = comboBox.GetValue() | |
1008 | if len(url): | |
1009 | urlList.append(url) | |
1010 | ||
1011 | for i in range(min(comboBox.GetCount(), 10)): | |
1012 | url = comboBox.GetString(i) | |
1013 | if url not in urlList: | |
1014 | urlList.append(url) | |
1015 | ||
1016 | config = wx.ConfigBase_Get() | |
1017 | config.Write(SVN_REPOSITORY_URL, urlList.__repr__()) | |
1018 | ||
6f1a3f9c | 1019 |