src/eric7/VCS/VersionControl.py

branch
eric7
changeset 9209
b99e7fd55fd3
parent 8943
23f9c7b9e18e
child 9221
bf71ee032bb4
equal deleted inserted replaced
9208:3fc8dfeb6ebe 9209:b99e7fd55fd3
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2002 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing an abstract base class to be subclassed by all specific
8 VCS interfaces.
9 """
10
11 import contextlib
12 import json
13 import os
14
15 from PyQt6.QtCore import (
16 QObject, QThread, QMutex, QProcess, Qt, pyqtSignal, QCoreApplication,
17 QLockFile
18 )
19 from PyQt6.QtWidgets import QApplication
20
21 from EricWidgets import EricMessageBox
22 from EricWidgets.EricApplication import ericApp
23
24 import Preferences
25
26
27 class VersionControl(QObject):
28 """
29 Class implementing an abstract base class to be subclassed by all specific
30 VCS interfaces.
31
32 It defines the vcs interface to be implemented by subclasses
33 and the common methods.
34
35 @signal committed() emitted after the commit action has completed
36 @signal vcsStatusMonitorData(list of str) emitted to update the VCS status
37 @signal vcsStatusMonitorAllData(dict) emitted to signal all VCS status
38 (key is project relative file name, value is status)
39 @signal vcsStatusMonitorStatus(str, str) emitted to signal the status of
40 the monitoring thread (ok, nok, op, off) and a status message
41 @signal vcsStatusMonitorInfo(str) emitted to signal some info of the
42 monitoring thread
43 @signal vcsStatusChanged() emitted to indicate a change of the overall
44 VCS status
45 """
46 committed = pyqtSignal()
47 vcsStatusMonitorData = pyqtSignal(list)
48 vcsStatusMonitorAllData = pyqtSignal(dict)
49 vcsStatusMonitorStatus = pyqtSignal(str, str)
50 vcsStatusMonitorInfo = pyqtSignal(str)
51 vcsStatusChanged = pyqtSignal()
52
53 canBeCommitted = 1 # Indicates that a file/directory is in the vcs.
54 canBeAdded = 2 # Indicates that a file/directory is not in vcs.
55
56 commitHistoryLock = "commitHistory.lock"
57 commitHistoryData = "commitHistory.json"
58
59 def __init__(self, parent=None, name=None):
60 """
61 Constructor
62
63 @param parent parent widget (QWidget)
64 @param name name of this object (string)
65 """
66 super().__init__(parent)
67 if name:
68 self.setObjectName(name)
69 self.defaultOptions = {
70 'global': [''],
71 'commit': [''],
72 'checkout': [''],
73 'update': [''],
74 'add': [''],
75 'remove': [''],
76 'diff': [''],
77 'log': [''],
78 'history': [''],
79 'status': [''],
80 'tag': [''],
81 'export': ['']
82 }
83 self.interestingDataKeys = []
84 self.options = {}
85 self.otherData = {}
86 self.canDetectBinaries = True
87
88 self.statusMonitorThread = None
89 self.vcsExecutionMutex = QMutex()
90
91 def vcsShutdown(self):
92 """
93 Public method used to shutdown the vcs interface.
94
95 @exception RuntimeError to indicate that this method must be
96 implemented by a subclass
97 """
98 raise RuntimeError('Not implemented')
99
100 def vcsExists(self):
101 """
102 Public method used to test for the presence of the vcs.
103
104 @return tuple of flag indicating the existence and a string
105 giving an error message in case of failure
106 @exception RuntimeError to indicate that this method must be
107 implemented by a subclass
108 """
109 raise RuntimeError('Not implemented')
110
111 return (False, "")
112
113 def vcsInit(self, vcsDir, noDialog=False):
114 """
115 Public method used to initialize the vcs.
116
117 @param vcsDir name of the VCS directory (string)
118 @param noDialog flag indicating quiet operations (boolean)
119 @return flag indicating success (boolean)
120 @exception RuntimeError to indicate that this method must be
121 implemented by a subclass
122 """
123 raise RuntimeError('Not implemented')
124
125 return False
126
127 def vcsConvertProject(self, vcsDataDict, project, addAll=True):
128 """
129 Public method to convert an uncontrolled project to a version
130 controlled project.
131
132 @param vcsDataDict dictionary of data required for the conversion
133 @type dict
134 @param project reference to the project object
135 @type Project
136 @param addAll flag indicating to add all files to the repository
137 @type bool
138 @exception RuntimeError to indicate that this method must be
139 implemented by a subclass
140 """
141 raise RuntimeError('Not implemented')
142
143 def vcsImport(self, vcsDataDict, projectDir, noDialog=False, addAll=True):
144 """
145 Public method used to import the project into the vcs.
146
147 @param vcsDataDict dictionary of data required for the import
148 @type dict
149 @param projectDir project directory (string)
150 @type str
151 @param noDialog flag indicating quiet operations
152 @type bool
153 @param addAll flag indicating to add all files to the repository
154 @type bool
155 @return tuple containing a flag indicating an execution without errors
156 and a flag indicating the version control status
157 @rtype tuple of (bool, bool)
158 @exception RuntimeError to indicate that this method must be
159 implemented by a subclass
160 """
161 raise RuntimeError('Not implemented')
162
163 return (False, False)
164
165 def vcsCheckout(self, vcsDataDict, projectDir, noDialog=False):
166 """
167 Public method used to check the project out of the vcs.
168
169 @param vcsDataDict dictionary of data required for the checkout
170 @param projectDir project directory to create (string)
171 @param noDialog flag indicating quiet operations
172 @return flag indicating an execution without errors (boolean)
173 @exception RuntimeError to indicate that this method must be
174 implemented by a subclass
175 """
176 raise RuntimeError('Not implemented')
177
178 return False
179
180 def vcsExport(self, vcsDataDict, projectDir):
181 """
182 Public method used to export a directory from the vcs.
183
184 @param vcsDataDict dictionary of data required for the export
185 @param projectDir project directory to create (string)
186 @return flag indicating an execution without errors (boolean)
187 @exception RuntimeError to indicate that this method must be
188 implemented by a subclass
189 """
190 raise RuntimeError('Not implemented')
191
192 return False
193
194 def vcsCommit(self, name, message, noDialog=False):
195 """
196 Public method used to make the change of a file/directory permanent in
197 the vcs.
198
199 @param name file/directory name to be committed (string)
200 @param message message for this operation (string)
201 @param noDialog flag indicating quiet operations (boolean)
202 @return flag indicating success (boolean)
203 @exception RuntimeError to indicate that this method must be
204 implemented by a subclass
205 """
206 raise RuntimeError('Not implemented')
207
208 return False
209
210 def vcsCommitMessages(self):
211 """
212 Public method to get the list of saved commit messages.
213
214 @return list of saved commit messages
215 @rtype list of str
216 @exception RuntimeError to indicate that this method must be
217 implemented by a subclass
218 """
219 raise RuntimeError('Not implemented')
220
221 return []
222
223 def _vcsProjectCommitMessages(self):
224 """
225 Protected method to get the list of saved commit messages.
226
227 @return list of saved commit messages
228 @rtype list of str
229 """
230 messages = []
231 if Preferences.getVCS("PerProjectCommitHistory"):
232 projectMgmtDir = (
233 ericApp().getObject("Project").getProjectManagementDir()
234 )
235 with contextlib.suppress(OSError, json.JSONDecodeError):
236 with open(os.path.join(projectMgmtDir,
237 VersionControl.commitHistoryData),
238 "r") as f:
239 jsonString = f.read()
240 messages = json.loads(jsonString)
241
242 return messages
243
244 def vcsAddCommitMessage(self, message):
245 """
246 Public method to add a commit message to the list of saved messages.
247
248 @param message message to be added
249 @type str
250 @exception RuntimeError to indicate that this method must be
251 implemented by a subclass
252 """
253 raise RuntimeError('Not implemented')
254
255 def _vcsAddProjectCommitMessage(self, message):
256 """
257 Protected method to add a commit message to the list of project
258 specific saved messages.
259
260 @param message message to be added
261 @type str
262 @return flag indicating success
263 @rtype bool
264 """
265 if Preferences.getVCS("PerProjectCommitHistory"):
266 projectMgmtDir = (
267 ericApp().getObject("Project").getProjectManagementDir()
268 )
269 lockFile = QLockFile(
270 os.path.join(projectMgmtDir, VersionControl.commitHistoryLock))
271 if lockFile.lock():
272 noMessages = Preferences.getVCS("CommitMessages")
273 messages = self.vcsCommitMessages()
274 if message in messages:
275 messages.remove(message)
276 messages.insert(0, message)
277 del messages[noMessages:]
278
279 with contextlib.suppress(TypeError, OSError):
280 jsonString = json.dumps(messages, indent=2)
281 with open(os.path.join(projectMgmtDir,
282 VersionControl.commitHistoryData),
283 "w") as f:
284 f.write(jsonString)
285 lockFile.unlock()
286 return True
287
288 return False
289
290 def vcsClearCommitMessages(self):
291 """
292 Public method to clear the list of saved messages.
293
294 @exception RuntimeError to indicate that this method must be
295 implemented by a subclass
296 """
297 raise RuntimeError('Not implemented')
298
299 def _vcsClearProjectCommitMessages(self):
300 """
301 Protected method to clear the list of project specific saved messages.
302
303 @return flag indicating success
304 @rtype bool
305 """
306 if Preferences.getVCS("PerProjectCommitHistory"):
307 projectMgmtDir = (
308 ericApp().getObject("Project").getProjectManagementDir()
309 )
310 lockFile = QLockFile(
311 os.path.join(projectMgmtDir, VersionControl.commitHistoryLock))
312 if lockFile.lock():
313 with contextlib.suppress(TypeError, OSError):
314 jsonString = json.dumps([], indent=2)
315 with open(os.path.join(projectMgmtDir,
316 VersionControl.commitHistoryData),
317 "w") as f:
318 f.write(jsonString)
319 lockFile.unlock()
320 return True
321
322 return False
323
324 def vcsUpdate(self, name, noDialog=False):
325 """
326 Public method used to update a file/directory in the vcs.
327
328 @param name file/directory name to be updated (string)
329 @param noDialog flag indicating quiet operations (boolean)
330 @return flag indicating, that the update contained an add
331 or delete (boolean)
332 @exception RuntimeError to indicate that this method must be
333 implemented by a subclass
334 """
335 raise RuntimeError('Not implemented')
336
337 return False
338
339 def vcsAdd(self, name, isDir=False, noDialog=False):
340 """
341 Public method used to add a file/directory in the vcs.
342
343 @param name file/directory name to be added (string)
344 @param isDir flag indicating name is a directory (boolean)
345 @param noDialog flag indicating quiet operations (boolean)
346 @exception RuntimeError to indicate that this method must be
347 implemented by a subclass
348 """
349 raise RuntimeError('Not implemented')
350
351 def vcsAddBinary(self, name, isDir=False):
352 """
353 Public method used to add a file/directory in binary mode in the vcs.
354
355 @param name file/directory name to be added (string)
356 @param isDir flag indicating name is a directory (boolean)
357 @exception RuntimeError to indicate that this method must be
358 implemented by a subclass
359 """
360 raise RuntimeError('Not implemented')
361
362 def vcsAddTree(self, path):
363 """
364 Public method to add a directory tree rooted at path in the vcs.
365
366 @param path root directory of the tree to be added (string)
367 @exception RuntimeError to indicate that this method must be
368 implemented by a subclass
369 """
370 raise RuntimeError('Not implemented')
371
372 def vcsRemove(self, name, project=False, noDialog=False):
373 """
374 Public method used to add a file/directory in the vcs.
375
376 @param name file/directory name to be removed (string)
377 @param project flag indicating deletion of a project tree (boolean)
378 @param noDialog flag indicating quiet operations
379 @return flag indicating success (boolean)
380 @exception RuntimeError to indicate that this method must be
381 implemented by a subclass
382 """
383 raise RuntimeError('Not implemented')
384
385 return False
386
387 def vcsMove(self, name, project, target=None, noDialog=False):
388 """
389 Public method used to move a file/directory.
390
391 @param name file/directory name to be moved (string)
392 @param project reference to the project object
393 @param target new name of the file/directory (string)
394 @param noDialog flag indicating quiet operations
395 @return flag indicating successfull operation (boolean)
396 @exception RuntimeError to indicate that this method must be
397 implemented by a subclass
398 """
399 raise RuntimeError('Not implemented')
400
401 return False
402
403 def vcsLogBrowser(self, name, isFile=False):
404 """
405 Public method used to view the log of a file/directory in the vcs
406 with a log browser dialog.
407
408 @param name file/directory name to show the log for (string)
409 @param isFile flag indicating log for a file is to be shown
410 (boolean)
411 @exception RuntimeError to indicate that this method must be
412 implemented by a subclass
413 """
414 raise RuntimeError('Not implemented')
415
416 def vcsDiff(self, name):
417 """
418 Public method used to view the diff of a file/directory in the vcs.
419
420 @param name file/directory name to be diffed (string)
421 @exception RuntimeError to indicate that this method must be
422 implemented by a subclass
423 """
424 raise RuntimeError('Not implemented')
425
426 def vcsSbsDiff(self, name, extended=False, revisions=None):
427 """
428 Public method used to view the difference of a file to the Mercurial
429 repository side-by-side.
430
431 @param name file name to be diffed
432 @type str
433 @param extended flag indicating the extended variant
434 @type bool
435 @param revisions tuple of two revisions
436 @type tuple of two str
437 @exception RuntimeError to indicate that this method must be
438 implemented by a subclass
439 """
440 raise RuntimeError('Not implemented')
441
442 def vcsStatus(self, name):
443 """
444 Public method used to view the status of a file/directory in the vcs.
445
446 @param name file/directory name to show the status for (string)
447 @exception RuntimeError to indicate that this method must be
448 implemented by a subclass
449 """
450 raise RuntimeError('Not implemented')
451
452 def vcsTag(self, name):
453 """
454 Public method used to set the tag of a file/directory in the vcs.
455
456 @param name file/directory name to be tagged (string)
457 @exception RuntimeError to indicate that this method must be
458 implemented by a subclass
459 """
460 raise RuntimeError('Not implemented')
461
462 def vcsRevert(self, name):
463 """
464 Public method used to revert changes made to a file/directory.
465
466 @param name file/directory name to be reverted
467 @type str
468 @return flag indicating, that the update contained an add
469 or delete
470 @rtype bool
471 @exception RuntimeError to indicate that this method must be
472 implemented by a subclass
473 """
474 raise RuntimeError('Not implemented')
475
476 return False
477
478 def vcsForget(self, name):
479 """
480 Public method used to remove a file from the repository.
481
482 @param name file/directory name to be removed
483 @type str or list of str
484 @exception RuntimeError to indicate that this method must be
485 implemented by a subclass
486 """
487 raise RuntimeError('Not implemented')
488
489 def vcsSwitch(self, name):
490 """
491 Public method used to switch a directory to a different tag/branch.
492
493 @param name directory name to be switched (string)
494 @return flag indicating, that the switch contained an add
495 or delete (boolean)
496 @exception RuntimeError to indicate that this method must be
497 implemented by a subclass
498 """
499 raise RuntimeError('Not implemented')
500
501 return False
502
503 def vcsMerge(self, name):
504 """
505 Public method used to merge a tag/branch into the local project.
506
507 @param name file/directory name to be merged (string)
508 @exception RuntimeError to indicate that this method must be
509 implemented by a subclass
510 """
511 raise RuntimeError('Not implemented')
512
513 def vcsRegisteredState(self, name):
514 """
515 Public method used to get the registered state of a file in the vcs.
516
517 @param name filename to check (string)
518 @return a combination of canBeCommited and canBeAdded or
519 0 in order to signal an error
520 @exception RuntimeError to indicate that this method must be
521 implemented by a subclass
522 """
523 raise RuntimeError('Not implemented')
524
525 return 0
526
527 def vcsAllRegisteredStates(self, names, dname):
528 """
529 Public method used to get the registered states of a number of files
530 in the vcs.
531
532 @param names dictionary with all filenames to be checked as keys
533 @param dname directory to check in (string)
534 @return the received dictionary completed with a combination of
535 canBeCommited and canBeAdded or None in order to signal an error
536 @exception RuntimeError to indicate that this method must be
537 implemented by a subclass
538 """
539 raise RuntimeError('Not implemented')
540
541 return {}
542
543 def vcsName(self):
544 """
545 Public method returning the name of the vcs.
546
547 @return name of the vcs (string)
548 @exception RuntimeError to indicate that this method must be
549 implemented by a subclass
550 """
551 raise RuntimeError('Not implemented')
552
553 return ""
554
555 def vcsCleanup(self, name):
556 """
557 Public method used to cleanup the local copy.
558
559 @param name directory name to be cleaned up (string)
560 @exception RuntimeError to indicate that this method must be
561 implemented by a subclass
562 """
563 raise RuntimeError('Not implemented')
564
565 def vcsCommandLine(self, name):
566 """
567 Public method used to execute arbitrary vcs commands.
568
569 @param name directory name of the working directory (string)
570 @exception RuntimeError to indicate that this method must be
571 implemented by a subclass
572 """
573 raise RuntimeError('Not implemented')
574
575 def vcsOptionsDialog(self, project, archive, editable=False, parent=None):
576 """
577 Public method to get a dialog to enter repository info.
578
579 @param project reference to the project object
580 @param archive name of the project in the repository (string)
581 @param editable flag indicating that the project name is editable
582 (boolean)
583 @param parent parent widget (QWidget)
584 @exception RuntimeError to indicate that this method must be
585 implemented by a subclass
586 """
587 raise RuntimeError('Not implemented')
588
589 def vcsNewProjectOptionsDialog(self, parent=None):
590 """
591 Public method to get a dialog to enter repository info for getting a
592 new project.
593
594 @param parent parent widget (QWidget)
595 @exception RuntimeError to indicate that this method must be
596 implemented by a subclass
597 """
598 raise RuntimeError('Not implemented')
599
600 def vcsRepositoryInfos(self, ppath):
601 """
602 Public method to retrieve information about the repository.
603
604 @param ppath local path to get the repository infos (string)
605 @return string with ready formated info for display (string)
606 @exception RuntimeError to indicate that this method must be
607 implemented by a subclass
608 """
609 raise RuntimeError('Not implemented')
610
611 return ""
612
613 def vcsGetProjectBrowserHelper(self, browser, project,
614 isTranslationsBrowser=False):
615 """
616 Public method to instanciate a helper object for the different
617 project browsers.
618
619 @param browser reference to the project browser object
620 @param project reference to the project object
621 @param isTranslationsBrowser flag indicating, the helper is requested
622 for the translations browser (this needs some special treatment)
623 @return the project browser helper object
624 @exception RuntimeError to indicate that this method must be
625 implemented by a subclass
626 """
627 raise RuntimeError('Not implemented')
628
629 return None # __IGNORE_WARNING_M831__
630
631 def vcsGetProjectHelper(self, project):
632 """
633 Public method to instanciate a helper object for the project.
634
635 @param project reference to the project object
636 @return the project helper object
637 @exception RuntimeError to indicate that this method must be
638 implemented by a subclass
639 """
640 raise RuntimeError('Not implemented')
641
642 return None # __IGNORE_WARNING_M831__
643
644 #####################################################################
645 ## methods above need to be implemented by a subclass
646 #####################################################################
647
648 def clearStatusCache(self):
649 """
650 Public method to clear the status cache.
651 """
652 pass
653
654 def vcsInitConfig(self, project):
655 """
656 Public method to initialize the VCS configuration.
657
658 This method could ensure, that certain files or directories are
659 exclude from being version controlled.
660
661 @param project reference to the project (Project)
662 """
663 pass
664
665 def vcsSupportCommandOptions(self):
666 """
667 Public method to signal the support of user settable command options.
668
669 @return flag indicating the support of user settable command options
670 (boolean)
671 """
672 return True
673
674 def vcsSetOptions(self, options):
675 """
676 Public method used to set the options for the vcs.
677
678 @param options a dictionary of option strings with keys as
679 defined by the default options
680 """
681 if self.vcsSupportCommandOptions():
682 for key in options:
683 with contextlib.suppress(KeyError):
684 self.options[key] = options[key]
685
686 def vcsGetOptions(self):
687 """
688 Public method used to retrieve the options of the vcs.
689
690 @return a dictionary of option strings that can be passed to
691 vcsSetOptions.
692 """
693 if self.vcsSupportCommandOptions():
694 return self.options
695 else:
696 return self.defaultOptions
697
698 def vcsSetOtherData(self, data):
699 """
700 Public method used to set vcs specific data.
701
702 @param data a dictionary of vcs specific data
703 """
704 for key in data:
705 with contextlib.suppress(KeyError):
706 self.otherData[key] = data[key]
707
708 def vcsGetOtherData(self):
709 """
710 Public method used to retrieve vcs specific data.
711
712 @return a dictionary of vcs specific data
713 """
714 return self.otherData
715
716 def vcsSetData(self, key, value):
717 """
718 Public method used to set an entry in the otherData dictionary.
719
720 @param key the key of the data (string)
721 @param value the value of the data
722 """
723 if key in self.interestingDataKeys:
724 self.otherData[key] = value
725
726 def vcsSetDataFromDict(self, dictionary):
727 """
728 Public method used to set entries in the otherData dictionary.
729
730 @param dictionary dictionary to pick entries from
731 """
732 for key in self.interestingDataKeys:
733 if key in dictionary:
734 self.otherData[key] = dictionary[key]
735
736 def vcsResolved(self, name):
737 """
738 Public method used to resolve conflicts of a file/directory.
739
740 @param name file/directory name to be resolved
741 @type str
742 """
743 # default implementation just refreshes the status
744 self.checkVCSStatus()
745
746 #####################################################################
747 ## below are some utility methods
748 #####################################################################
749
750 def startSynchronizedProcess(self, proc, program, arguments,
751 workingDir=None):
752 """
753 Public method to start a synchroneous process.
754
755 This method starts a process and waits
756 for its end while still serving the Qt event loop.
757
758 @param proc process to start (QProcess)
759 @param program path of the executable to start (string)
760 @param arguments list of arguments for the process (list of strings)
761 @param workingDir working directory for the process (string)
762 @return flag indicating normal exit (boolean)
763 """
764 if proc is None:
765 return False
766
767 if workingDir:
768 proc.setWorkingDirectory(workingDir)
769 proc.start(program, arguments)
770 procStarted = proc.waitForStarted(5000)
771 if not procStarted:
772 EricMessageBox.critical(
773 None,
774 QCoreApplication.translate(
775 "VersionControl", 'Process Generation Error'),
776 QCoreApplication.translate(
777 "VersionControl",
778 'The process {0} could not be started. '
779 'Ensure, that it is in the search path.'
780 ).format(program))
781 return False
782 else:
783 while proc.state() == QProcess.ProcessState.Running:
784 QThread.msleep(300)
785 QApplication.processEvents()
786 return (
787 (proc.exitStatus() == QProcess.ExitStatus.NormalExit) and
788 (proc.exitCode() == 0)
789 )
790
791 def splitPath(self, name):
792 """
793 Public method splitting name into a directory part and a file part.
794
795 @param name path name (string)
796 @return a tuple of 2 strings (dirname, filename).
797 """
798 if os.path.isdir(name):
799 dn = os.path.abspath(name)
800 fn = "."
801 else:
802 dn, fn = os.path.split(name)
803 return (dn, fn)
804
805 def splitPathList(self, names):
806 """
807 Public method splitting the list of names into a common directory part
808 and a file list.
809
810 @param names list of paths (list of strings)
811 @return a tuple of string and list of strings (dirname, filenamelist)
812 """
813 dname = os.path.commonprefix(names)
814 if dname:
815 if not dname.endswith(os.sep):
816 dname = os.path.dirname(dname) + os.sep
817 fnames = [n.replace(dname, '') for n in names]
818 dname = os.path.dirname(dname)
819 return (dname, fnames)
820 else:
821 return ("/", names)
822
823 def addArguments(self, args, argslist):
824 """
825 Public method to add an argument list to the already present
826 arguments.
827
828 @param args current arguments list (list of strings)
829 @param argslist list of arguments (list of strings)
830 """
831 for arg in argslist:
832 if arg != '':
833 args.append(arg)
834
835 ###########################################################################
836 ## VCS status monitor thread related methods
837 ###########################################################################
838
839 def __statusMonitorStatus(self, status, statusMsg):
840 """
841 Private slot to receive the status monitor status.
842
843 It simply re-emits the received status.
844
845 @param status status of the monitoring thread
846 @type str (one of ok, nok or off)
847 @param statusMsg explanotory text for the signaled status
848 @type str
849 """
850 self.vcsStatusMonitorStatus.emit(status, statusMsg)
851 QCoreApplication.processEvents()
852
853 def __statusMonitorData(self, statusList):
854 """
855 Private method to receive the status monitor data update.
856
857 It simply re-emits the received status list.
858
859 @param statusList list of status records
860 @type list of str
861 """
862 self.vcsStatusMonitorData.emit(statusList)
863 QCoreApplication.processEvents()
864
865 def __statusMonitorAllData(self, statusDict):
866 """
867 Private method to receive all status monitor data.
868
869 It simply re-emits the received status list.
870
871 @param statusDict dictionary of status records
872 @type dict
873 """
874 self.vcsStatusMonitorAllData.emit(statusDict)
875 QCoreApplication.processEvents()
876
877 def __statusMonitorInfo(self, info):
878 """
879 Private slot to receive the status monitor info message.
880
881 It simply re-emits the received info message.
882
883 @param info received info message
884 @type str
885 """
886 self.vcsStatusMonitorInfo.emit(info)
887 QCoreApplication.processEvents()
888
889 def startStatusMonitor(self, project):
890 """
891 Public method to start the VCS status monitor thread.
892
893 @param project reference to the project object
894 @return reference to the monitor thread (QThread)
895 """
896 vcsStatusMonitorInterval = (
897 project.pudata["VCSSTATUSMONITORINTERVAL"]
898 if project.pudata["VCSSTATUSMONITORINTERVAL"] else
899 Preferences.getVCS("StatusMonitorInterval")
900 )
901 if vcsStatusMonitorInterval > 0:
902 self.statusMonitorThread = self._createStatusMonitorThread(
903 vcsStatusMonitorInterval, project)
904 if self.statusMonitorThread is not None:
905 self.statusMonitorThread.vcsStatusMonitorData.connect(
906 self.__statusMonitorData,
907 Qt.ConnectionType.QueuedConnection)
908 self.statusMonitorThread.vcsStatusMonitorAllData.connect(
909 self.__statusMonitorAllData,
910 Qt.ConnectionType.QueuedConnection)
911 self.statusMonitorThread.vcsStatusMonitorStatus.connect(
912 self.__statusMonitorStatus,
913 Qt.ConnectionType.QueuedConnection)
914 self.statusMonitorThread.vcsStatusMonitorInfo.connect(
915 self.__statusMonitorInfo,
916 Qt.ConnectionType.QueuedConnection)
917 self.statusMonitorThread.setAutoUpdate(
918 Preferences.getVCS("AutoUpdate"))
919 self.statusMonitorThread.start()
920 else:
921 self.statusMonitorThread = None
922 return self.statusMonitorThread
923
924 def stopStatusMonitor(self):
925 """
926 Public method to stop the VCS status monitor thread.
927 """
928 if self.statusMonitorThread is not None:
929 self.__statusMonitorData(["--RESET--"])
930 self.statusMonitorThread.vcsStatusMonitorData.disconnect(
931 self.__statusMonitorData)
932 self.statusMonitorThread.vcsStatusMonitorAllData.disconnect(
933 self.__statusMonitorAllData)
934 self.statusMonitorThread.vcsStatusMonitorStatus.disconnect(
935 self.__statusMonitorStatus)
936 self.statusMonitorThread.vcsStatusMonitorInfo.disconnect(
937 self.__statusMonitorInfo)
938 self.statusMonitorThread.stop()
939 self.statusMonitorThread.wait(10000)
940 if not self.statusMonitorThread.isFinished():
941 self.statusMonitorThread.terminate()
942 self.statusMonitorThread.wait(10000)
943 self.statusMonitorThread = None
944 self.__statusMonitorStatus(
945 "off",
946 QCoreApplication.translate(
947 "VersionControl",
948 "Repository status checking is switched off"))
949 self.__statusMonitorInfo("")
950
951 def setStatusMonitorInterval(self, interval, project):
952 """
953 Public method to change the monitor interval.
954
955 @param interval new interval in seconds (integer)
956 @param project reference to the project object
957 """
958 if self.statusMonitorThread is not None:
959 if interval == 0:
960 self.stopStatusMonitor()
961 else:
962 self.statusMonitorThread.setInterval(interval)
963 else:
964 self.startStatusMonitor(project)
965
966 def getStatusMonitorInterval(self):
967 """
968 Public method to get the monitor interval.
969
970 @return interval in seconds (integer)
971 """
972 if self.statusMonitorThread is not None:
973 return self.statusMonitorThread.getInterval()
974 else:
975 return 0
976
977 def setStatusMonitorAutoUpdate(self, auto):
978 """
979 Public method to enable the auto update function.
980
981 @param auto status of the auto update function (boolean)
982 """
983 if self.statusMonitorThread is not None:
984 self.statusMonitorThread.setAutoUpdate(auto)
985
986 def getStatusMonitorAutoUpdate(self):
987 """
988 Public method to retrieve the status of the auto update function.
989
990 @return status of the auto update function (boolean)
991 """
992 if self.statusMonitorThread is not None:
993 return self.statusMonitorThread.getAutoUpdate()
994 else:
995 return False
996
997 def checkVCSStatus(self):
998 """
999 Public method to wake up the VCS status monitor thread.
1000 """
1001 self.vcsStatusChanged.emit()
1002
1003 if self.statusMonitorThread is not None:
1004 self.statusMonitorThread.checkStatus()
1005
1006 def clearStatusMonitorCachedState(self, name):
1007 """
1008 Public method to clear the cached VCS state of a file/directory.
1009
1010 @param name name of the entry to be cleared (string)
1011 """
1012 if self.statusMonitorThread is not None:
1013 self.statusMonitorThread.clearCachedState(name)
1014
1015 def _createStatusMonitorThread(self, interval, project):
1016 """
1017 Protected method to create an instance of the VCS status monitor
1018 thread.
1019
1020 Note: This method should be overwritten in subclasses in order to
1021 support VCS status monitoring.
1022
1023 @param interval check interval for the monitor thread in seconds
1024 (integer)
1025 @param project reference to the project object
1026 @return reference to the monitor thread (QThread)
1027 """
1028 return None # __IGNORE_WARNING_M831__

eric ide

mercurial