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