Plugins/VcsPlugins/vcsPySvn/SvnStatusDialog.py

changeset 889
65585df1d52c
parent 791
9ec2ac20e54e
child 917
746c54b643eb
child 1271
1e22e0168561
equal deleted inserted replaced
888:16cecff8614d 889:65585df1d52c
2 2
3 # Copyright (c) 2003 - 2011 Detlev Offenbach <detlev@die-offenbachs.de> 3 # Copyright (c) 2003 - 2011 Detlev Offenbach <detlev@die-offenbachs.de>
4 # 4 #
5 5
6 """ 6 """
7 Module implementing a dialog to show the output of the svn status command process. 7 Module implementing a dialog to show the output of the svn status command
8 process.
8 """ 9 """
9 10
10 import os 11 import os
11 12
12 import pysvn 13 import pysvn
23 24
24 import Preferences 25 import Preferences
25 26
26 class SvnStatusDialog(QWidget, SvnDialogMixin, Ui_SvnStatusDialog): 27 class SvnStatusDialog(QWidget, SvnDialogMixin, Ui_SvnStatusDialog):
27 """ 28 """
28 Class implementing a dialog to show the output of the svn status command process. 29 Class implementing a dialog to show the output of the svn status command
30 process.
29 """ 31 """
30 def __init__(self, vcs, parent = None): 32 def __init__(self, vcs, parent = None):
31 """ 33 """
32 Constructor 34 Constructor
33 35
39 SvnDialogMixin.__init__(self) 41 SvnDialogMixin.__init__(self)
40 42
41 self.__changelistColumn = 0 43 self.__changelistColumn = 0
42 self.__statusColumn = 1 44 self.__statusColumn = 1
43 self.__propStatusColumn = 2 45 self.__propStatusColumn = 2
46 self.__lockedColumn = 3
47 self.__historyColumn = 4
48 self.__switchedColumn = 5
44 self.__lockinfoColumn = 6 49 self.__lockinfoColumn = 6
50 self.__upToDateColumn = 7
45 self.__pathColumn = 11 51 self.__pathColumn = 11
46 self.__lastColumn = self.statusList.columnCount() 52 self.__lastColumn = self.statusList.columnCount()
47 53
48 self.refreshButton = \ 54 self.refreshButton = \
49 self.buttonBox.addButton(self.trUtf8("Refresh"), QDialogButtonBox.ActionRole) 55 self.buttonBox.addButton(self.trUtf8("Refresh"),
50 self.refreshButton.setToolTip(self.trUtf8("Press to refresh the status display")) 56 QDialogButtonBox.ActionRole)
57 self.refreshButton.setToolTip(
58 self.trUtf8("Press to refresh the status display"))
51 self.refreshButton.setEnabled(False) 59 self.refreshButton.setEnabled(False)
52 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False) 60 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False)
53 self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True) 61 self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
54 62
55 self.vcs = vcs 63 self.vcs = vcs
56 self.vcs.committed.connect(self.__committed) 64 self.vcs.committed.connect(self.__committed)
57 65
58 self.statusList.headerItem().setText(self.__lastColumn, "") 66 self.statusList.headerItem().setText(self.__lastColumn, "")
59 self.statusList.header().setSortIndicator(self.__pathColumn, Qt.AscendingOrder) 67 self.statusList.header().setSortIndicator(self.__pathColumn,
68 Qt.AscendingOrder)
60 if pysvn.svn_version < (1, 5, 0) or pysvn.version < (1, 6, 0): 69 if pysvn.svn_version < (1, 5, 0) or pysvn.version < (1, 6, 0):
61 self.statusList.header().hideSection(self.__changelistColumn) 70 self.statusList.header().hideSection(self.__changelistColumn)
62 71
63 self.menuactions = [] 72 self.menuactions = []
64 self.menu = QMenu() 73 self.menu = QMenu()
72 if pysvn.svn_version >= (1, 5, 0) and pysvn.version >= (1, 6, 0): 81 if pysvn.svn_version >= (1, 5, 0) and pysvn.version >= (1, 6, 0):
73 self.menu.addSeparator() 82 self.menu.addSeparator()
74 self.menuactions.append(self.menu.addAction( 83 self.menuactions.append(self.menu.addAction(
75 self.trUtf8("Add to Changelist"), self.__addToChangelist)) 84 self.trUtf8("Add to Changelist"), self.__addToChangelist))
76 self.menuactions.append(self.menu.addAction( 85 self.menuactions.append(self.menu.addAction(
77 self.trUtf8("Remove from Changelist"), self.__removeFromChangelist)) 86 self.trUtf8("Remove from Changelist"),
87 self.__removeFromChangelist))
78 if self.vcs.versionStr >= '1.2.0': 88 if self.vcs.versionStr >= '1.2.0':
79 self.menu.addSeparator() 89 self.menu.addSeparator()
80 self.menuactions.append(self.menu.addAction(self.trUtf8("Lock"), 90 self.menuactions.append(self.menu.addAction(self.trUtf8("Lock"),
81 self.__lock)) 91 self.__lock))
82 self.menuactions.append(self.menu.addAction(self.trUtf8("Unlock"), 92 self.menuactions.append(self.menu.addAction(self.trUtf8("Unlock"),
83 self.__unlock)) 93 self.__unlock))
84 self.menuactions.append(self.menu.addAction(self.trUtf8("Break lock"), 94 self.menuactions.append(self.menu.addAction(
95 self.trUtf8("Break lock"),
85 self.__breakLock)) 96 self.__breakLock))
86 self.menuactions.append(self.menu.addAction(self.trUtf8("Steal lock"), 97 self.menuactions.append(self.menu.addAction(
98 self.trUtf8("Steal lock"),
87 self.__stealLock)) 99 self.__stealLock))
88 self.menu.addSeparator() 100 self.menu.addSeparator()
89 self.menuactions.append(self.menu.addAction(self.trUtf8("Adjust column sizes"), 101 self.menuactions.append(self.menu.addAction(
102 self.trUtf8("Adjust column sizes"),
90 self.__resizeColumns)) 103 self.__resizeColumns))
91 for act in self.menuactions: 104 for act in self.menuactions:
92 act.setEnabled(False) 105 act.setEnabled(False)
93 106
94 self.statusList.setContextMenuPolicy(Qt.CustomContextMenu) 107 self.statusList.setContextMenuPolicy(Qt.CustomContextMenu)
95 self.statusList.customContextMenuRequested.connect(self.__showContextMenu) 108 self.statusList.customContextMenuRequested.connect(
109 self.__showContextMenu)
96 110
97 self.modifiedIndicators = [ 111 self.modifiedIndicators = [
98 self.trUtf8(svnStatusMap[pysvn.wc_status_kind.added]), 112 self.trUtf8(svnStatusMap[pysvn.wc_status_kind.added]),
99 self.trUtf8(svnStatusMap[pysvn.wc_status_kind.deleted]), 113 self.trUtf8(svnStatusMap[pysvn.wc_status_kind.deleted]),
100 self.trUtf8(svnStatusMap[pysvn.wc_status_kind.modified]) 114 self.trUtf8(svnStatusMap[pysvn.wc_status_kind.modified])
153 Private method to resize the list columns. 167 Private method to resize the list columns.
154 """ 168 """
155 self.statusList.header().resizeSections(QHeaderView.ResizeToContents) 169 self.statusList.header().resizeSections(QHeaderView.ResizeToContents)
156 self.statusList.header().setStretchLastSection(True) 170 self.statusList.header().setStretchLastSection(True)
157 171
158 def __generateItem(self, changelist, status, propStatus, locked, history, switched, 172 def __generateItem(self, changelist, status, propStatus, locked, history,
159 lockinfo, uptodate, revision, change, author, path): 173 switched, lockinfo, uptodate, revision, change, author,
174 path):
160 """ 175 """
161 Private method to generate a status item in the status list. 176 Private method to generate a status item in the status list.
162 177
163 @param changelist name of the changelist (string) 178 @param changelist name of the changelist (string)
164 @param status text status (pysvn.wc_status_kind) 179 @param status text status (pysvn.wc_status_kind)
228 opts = self.vcs.options['global'] + self.vcs.options['status'] 243 opts = self.vcs.options['global'] + self.vcs.options['status']
229 verbose = "--verbose" in opts 244 verbose = "--verbose" in opts
230 recurse = "--non-recursive" not in opts 245 recurse = "--non-recursive" not in opts
231 update = "--show-updates" in opts 246 update = "--show-updates" in opts
232 247
248 hidePropertyStatusColumn = True
249 hideLockColumns = True
250 hideUpToDateColumn = True
251 hideHistoryColumn = True
252 hideSwitchedColumn = True
253
233 locker = QMutexLocker(self.vcs.vcsExecutionMutex) 254 locker = QMutexLocker(self.vcs.vcsExecutionMutex)
234 cwd = os.getcwd() 255 cwd = os.getcwd()
235 os.chdir(self.dname) 256 os.chdir(self.dname)
236 try: 257 try:
237 for name in fnames: 258 for name in fnames:
240 if hasattr(self.client, 'get_changelist'): 261 if hasattr(self.client, 'get_changelist'):
241 if recurse: 262 if recurse:
242 depth = pysvn.depth.infinity 263 depth = pysvn.depth.infinity
243 else: 264 else:
244 depth = pysvn.depth.immediate 265 depth = pysvn.depth.immediate
245 changelists = self.client.get_changelist(name, depth = depth) 266 changelists = self.client.get_changelist(name, depth=depth)
246 for entry in changelists: 267 for entry in changelists:
247 changelistsDict[entry[0]] = entry[1] 268 changelistsDict[entry[0]] = entry[1]
248 self.statusList.setColumnHidden(self.__changelistColumn, 269 self.statusList.setColumnHidden(self.__changelistColumn,
249 len(changelistsDict) == 0) 270 len(changelistsDict) == 0)
250 271
251 # step 2: determine status of files 272 # step 2: determine status of files
252 allFiles = self.client.status(name, recurse = recurse, get_all = verbose, 273 allFiles = self.client.status(name, recurse = recurse,
253 ignore = True, update = update) 274 get_all=verbose, ignore=True,
275 update = update)
254 counter = 0 276 counter = 0
255 for file in allFiles: 277 for file in allFiles:
256 uptodate = True 278 uptodate = True
257 if file.repos_text_status != pysvn.wc_status_kind.none: 279 if file.repos_text_status != pysvn.wc_status_kind.none:
258 uptodate = uptodate and file.repos_text_status == file.text_status 280 uptodate = uptodate and \
281 file.repos_text_status == file.text_status
259 if file.repos_prop_status != pysvn.wc_status_kind.none: 282 if file.repos_prop_status != pysvn.wc_status_kind.none:
260 uptodate = uptodate and file.repos_prop_status == file.prop_status 283 uptodate = uptodate and \
284 file.repos_prop_status == file.prop_status
261 285
262 lockState = " " 286 lockState = " "
263 if file.entry is not None and \ 287 if file.entry is not None and \
264 hasattr(file.entry, 'lock_token') and \ 288 hasattr(file.entry, 'lock_token') and \
265 file.entry.lock_token is not None: 289 file.entry.lock_token is not None:
267 if hasattr(file, 'repos_lock') and update: 291 if hasattr(file, 'repos_lock') and update:
268 if lockState == "L" and file.repos_lock is None: 292 if lockState == "L" and file.repos_lock is None:
269 lockState = "B" 293 lockState = "B"
270 elif lockState == " " and file.repos_lock is not None: 294 elif lockState == " " and file.repos_lock is not None:
271 lockState = "O" 295 lockState = "O"
272 elif lockState == "L" and file.repos_lock is not None and \ 296 elif lockState == "L" and \
297 file.repos_lock is not None and \
273 file.entry.lock_token != file.repos_lock["token"]: 298 file.entry.lock_token != file.repos_lock["token"]:
274 lockState = "S" 299 lockState = "S"
275 300
276 if file.path in changelistsDict: 301 if file.path in changelistsDict:
277 changelist = changelistsDict[file.path] 302 changelist = changelistsDict[file.path]
278 else: 303 else:
279 changelist = "" 304 changelist = ""
305
306 hidePropertyStatusColumn = hidePropertyStatusColumn and \
307 file.prop_status in [
308 pysvn.wc_status_kind.none,
309 pysvn.wc_status_kind.normal
310 ]
311 hideLockColumns = hideLockColumns and \
312 not file.is_locked and lockState == " "
313 hideUpToDateColumn = hideUpToDateColumn and uptodate
314 hideHistoryColumn = hideHistoryColumn and \
315 not file.is_copied
316 hideSwitchedColumn = hideSwitchedColumn and \
317 not file.is_switched
280 318
281 self.__generateItem( 319 self.__generateItem(
282 changelist, 320 changelist,
283 file.text_status, 321 file.text_status,
284 file.prop_status, 322 file.prop_status,
300 break 338 break
301 if self._clientCancelCallback(): 339 if self._clientCancelCallback():
302 break 340 break
303 except pysvn.ClientError as e: 341 except pysvn.ClientError as e:
304 self.__showError(e.args[0]+'\n') 342 self.__showError(e.args[0]+'\n')
343
344 self.statusList.setColumnHidden(self.__propStatusColumn,
345 hidePropertyStatusColumn)
346 self.statusList.setColumnHidden(self.__lockedColumn,
347 hideLockColumns)
348 self.statusList.setColumnHidden(self.__lockinfoColumn,
349 hideLockColumns)
350 self.statusList.setColumnHidden(self.__upToDateColumn,
351 hideUpToDateColumn)
352 self.statusList.setColumnHidden(self.__historyColumn,
353 hideHistoryColumn)
354 self.statusList.setColumnHidden(self.__switchedColumn,
355 hideSwitchedColumn)
356
305 locker.unlock() 357 locker.unlock()
306 self.__finish() 358 self.__finish()
307 os.chdir(cwd) 359 os.chdir(cwd)
308 360
309 def __finish(self): 361 def __finish(self):
310 """ 362 """
311 Private slot called when the process finished or the user pressed the button. 363 Private slot called when the process finished or the user pressed
364 the button.
312 """ 365 """
313 QApplication.restoreOverrideCursor() 366 QApplication.restoreOverrideCursor()
314 367
315 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True) 368 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
316 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False) 369 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
367 """ 420 """
368 self.errorGroup.show() 421 self.errorGroup.show()
369 self.errors.insertPlainText(msg) 422 self.errors.insertPlainText(msg)
370 self.errors.ensureCursorVisible() 423 self.errors.ensureCursorVisible()
371 424
372 ############################################################################ 425 ###########################################################################
373 ## Context menu handling methods 426 ## Context menu handling methods
374 ############################################################################ 427 ###########################################################################
375 428
376 def __showContextMenu(self, coord): 429 def __showContextMenu(self, coord):
377 """ 430 """
378 Protected slot to show the context menu of the status list. 431 Protected slot to show the context menu of the status list.
379 432
388 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) \ 441 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) \
389 for itm in self.__getModifiedItems()] 442 for itm in self.__getModifiedItems()]
390 if not names: 443 if not names:
391 E5MessageBox.information(self, 444 E5MessageBox.information(self,
392 self.trUtf8("Commit"), 445 self.trUtf8("Commit"),
393 self.trUtf8("""There are no uncommitted changes available/selected.""")) 446 self.trUtf8("""There are no uncommitted changes"""
447 """ available/selected."""))
394 return 448 return
395 449
396 if Preferences.getVCS("AutoSaveFiles"): 450 if Preferences.getVCS("AutoSaveFiles"):
397 vm = e5App().getObject("ViewManager") 451 vm = e5App().getObject("ViewManager")
398 for name in names: 452 for name in names:
414 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) \ 468 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) \
415 for itm in self.__getUnversionedItems()] 469 for itm in self.__getUnversionedItems()]
416 if not names: 470 if not names:
417 E5MessageBox.information(self, 471 E5MessageBox.information(self,
418 self.trUtf8("Add"), 472 self.trUtf8("Add"),
419 self.trUtf8("""There are no unversioned entries available/selected.""")) 473 self.trUtf8("""There are no unversioned entries"""
474 """ available/selected."""))
420 return 475 return
421 476
422 self.vcs.vcsAdd(names) 477 self.vcs.vcsAdd(names)
423 self.on_refreshButton_clicked() 478 self.on_refreshButton_clicked()
424 479
434 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) \ 489 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) \
435 for itm in self.__getModifiedItems()] 490 for itm in self.__getModifiedItems()]
436 if not names: 491 if not names:
437 E5MessageBox.information(self, 492 E5MessageBox.information(self,
438 self.trUtf8("Revert"), 493 self.trUtf8("Revert"),
439 self.trUtf8("""There are no uncommitted changes available/selected.""")) 494 self.trUtf8("""There are no uncommitted changes"""
495 """ available/selected."""))
440 return 496 return
441 497
442 self.vcs.vcsRevert(names) 498 self.vcs.vcsRevert(names)
443 self.on_refreshButton_clicked() 499 self.on_refreshButton_clicked()
444 500
454 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) \ 510 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) \
455 for itm in self.__getLockActionItems(self.unlockedIndicators)] 511 for itm in self.__getLockActionItems(self.unlockedIndicators)]
456 if not names: 512 if not names:
457 E5MessageBox.information(self, 513 E5MessageBox.information(self,
458 self.trUtf8("Lock"), 514 self.trUtf8("Lock"),
459 self.trUtf8("""There are no unlocked files available/selected.""")) 515 self.trUtf8("""There are no unlocked files"""
516 """ available/selected."""))
460 return 517 return
461 518
462 self.vcs.svnLock(names, parent = self) 519 self.vcs.svnLock(names, parent = self)
463 self.on_refreshButton_clicked() 520 self.on_refreshButton_clicked()
464 521
469 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) \ 526 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) \
470 for itm in self.__getLockActionItems(self.lockedIndicators)] 527 for itm in self.__getLockActionItems(self.lockedIndicators)]
471 if not names: 528 if not names:
472 E5MessageBox.information(self, 529 E5MessageBox.information(self,
473 self.trUtf8("Unlock"), 530 self.trUtf8("Unlock"),
474 self.trUtf8("""There are no locked files available/selected.""")) 531 self.trUtf8("""There are no locked files"""
532 """ available/selected."""))
475 return 533 return
476 534
477 self.vcs.svnUnlock(names, parent = self) 535 self.vcs.svnUnlock(names, parent = self)
478 self.on_refreshButton_clicked() 536 self.on_refreshButton_clicked()
479 537
480 def __breakLock(self): 538 def __breakLock(self):
481 """ 539 """
482 Private slot to handle the Break Lock context menu entry. 540 Private slot to handle the Break Lock context menu entry.
483 """ 541 """
484 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) \ 542 names = [os.path.join(self.dname, itm.text(self.__pathColumn))
485 for itm in self.__getLockActionItems(self.stealBreakLockIndicators)] 543 for itm in self.__getLockActionItems(
544 self.stealBreakLockIndicators)]
486 if not names: 545 if not names:
487 E5MessageBox.information(self, 546 E5MessageBox.information(self,
488 self.trUtf8("Break Lock"), 547 self.trUtf8("Break Lock"),
489 self.trUtf8("""There are no locked files available/selected.""")) 548 self.trUtf8("""There are no locked files"""
549 """ available/selected."""))
490 return 550 return
491 551
492 self.vcs.svnUnlock(names, parent = self, breakIt = True) 552 self.vcs.svnUnlock(names, parent = self, breakIt = True)
493 self.on_refreshButton_clicked() 553 self.on_refreshButton_clicked()
494 554
495 def __stealLock(self): 555 def __stealLock(self):
496 """ 556 """
497 Private slot to handle the Break Lock context menu entry. 557 Private slot to handle the Break Lock context menu entry.
498 """ 558 """
499 names = [os.path.join(self.dname, itm.text(self.__pathColumn)) \ 559 names = [os.path.join(self.dname, itm.text(self.__pathColumn))
500 for itm in self.__getLockActionItems(self.stealBreakLockIndicators)] 560 for itm in self.__getLockActionItems(
561 self.stealBreakLockIndicators)]
501 if not names: 562 if not names:
502 E5MessageBox.information(self, 563 E5MessageBox.information(self,
503 self.trUtf8("Steal Lock"), 564 self.trUtf8("Steal Lock"),
504 self.trUtf8("""There are no locked files available/selected.""")) 565 self.trUtf8("""There are no locked files"""
566 """ available/selected."""))
505 return 567 return
506 568
507 self.vcs.svnLock(names, parent=self, stealIt=True) 569 self.vcs.svnLock(names, parent=self, stealIt=True)
508 self.on_refreshButton_clicked() 570 self.on_refreshButton_clicked()
509 571
533 for itm in self.__getChangelistItems()] 595 for itm in self.__getChangelistItems()]
534 if not names: 596 if not names:
535 E5MessageBox.information(self, 597 E5MessageBox.information(self,
536 self.trUtf8("Remove from Changelist"), 598 self.trUtf8("Remove from Changelist"),
537 self.trUtf8( 599 self.trUtf8(
538 """There are no files available/selected belonging to a changelist.""" 600 """There are no files available/selected belonging"""
601 """ to a changelist."""
539 ) 602 )
540 ) 603 )
541 return 604 return
542 self.vcs.svnRemoveFromChangelist(names) 605 self.vcs.svnRemoveFromChangelist(names)
543 self.on_refreshButton_clicked() 606 self.on_refreshButton_clicked()
555 modifiedItems.append(itm) 618 modifiedItems.append(itm)
556 return modifiedItems 619 return modifiedItems
557 620
558 def __getUnversionedItems(self): 621 def __getUnversionedItems(self):
559 """ 622 """
560 Private method to retrieve all entries, that have an unversioned status. 623 Private method to retrieve all entries, that have an
624 unversioned status.
561 625
562 @return list of all items with an unversioned status 626 @return list of all items with an unversioned status
563 """ 627 """
564 unversionedItems = [] 628 unversionedItems = []
565 for itm in self.statusList.selectedItems(): 629 for itm in self.statusList.selectedItems():
579 lockitems.append(itm) 643 lockitems.append(itm)
580 return lockitems 644 return lockitems
581 645
582 def __getChangelistItems(self): 646 def __getChangelistItems(self):
583 """ 647 """
584 Private method to retrieve all entries, that are members of a changelist. 648 Private method to retrieve all entries, that are members of
649 a changelist.
585 650
586 @return list of all items belonging to a changelist 651 @return list of all items belonging to a changelist
587 """ 652 """
588 clitems = [] 653 clitems = []
589 for itm in self.statusList.selectedItems(): 654 for itm in self.statusList.selectedItems():
591 clitems.append(itm) 656 clitems.append(itm)
592 return clitems 657 return clitems
593 658
594 def __getNonChangelistItems(self): 659 def __getNonChangelistItems(self):
595 """ 660 """
596 Private method to retrieve all entries, that are not members of a changelist. 661 Private method to retrieve all entries, that are not members of
662 a changelist.
597 663
598 @return list of all items not belonging to a changelist 664 @return list of all items not belonging to a changelist
599 """ 665 """
600 clitems = [] 666 clitems = []
601 for itm in self.statusList.selectedItems(): 667 for itm in self.statusList.selectedItems():

eric ide

mercurial