Changeset deb9afd9eccd…
Parent d95a6e8bd22c…
by
Changes to one file · Browse files at deb9afd9eccd Showing diff from parent d95a6e8bd22c Diff from another changeset...
|
|
@@ -1,14 +1,12 @@ # merge.py - Merge dialog for TortoiseHg
#
# Copyright 2010 Yuki KODAMA <endflow.net@gmail.com>
+# Copyright 2011 Steve Borho <steve@borho.org>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2, incorporated herein by reference.
-from PyQt4.QtCore import *
-from PyQt4.QtGui import *
-
-from mercurial import error
+from mercurial import hg, error
from mercurial import merge as mergemod
from tortoisehg.util import hglib
@@ -16,34 +14,40 @@from tortoisehg.hgqt import qtlib, csinfo, i18n, cmdui, status, commit, resolve
from tortoisehg.hgqt import qscilib, thgrepo
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+
keep = i18n.keepgettext()
-MERGE_PAGE = 0
-COMMIT_PAGE = 1
-RESULT_PAGE = 2
+SUMMARY_PAGE = 0
+MERGE_PAGE = 1
+COMMIT_PAGE = 2
+RESULT_PAGE = 3
+
+MARGINS = (8, 0, 0, 0)
class MergeDialog(QWizard):
- def __init__(self, other, repo, parent):
+ def __init__(self, otherrev, repo, parent):
super(MergeDialog, self).__init__(parent)
f = self.windowFlags()
self.setWindowFlags(f & ~Qt.WindowContextHelpButtonHint)
self.repo = repo
- self.other = str(other)
- self.local = str(self.repo['.'].rev())
+ self.otherrev = str(otherrev)
+ self.localrev = str(self.repo['.'].rev())
self.setWindowTitle(_('Merge - %s') % self.repo.displayname)
self.setWindowIcon(qtlib.geticon('hg-merge'))
- self.setMinimumSize(600, 528)
- self.setOption(QWizard.DisabledBackButtonOnLastPage, True)
self.setOption(QWizard.HelpButtonOnRight, False)
- self.setDefaultProperty('QComboBox', 'currentText', 'editTextChanged()')
+ self.setOption(QWizard.IndependentPages, True)
# set pages
- self.setPage(MERGE_PAGE, MergePage(self))
- self.setPage(COMMIT_PAGE, CommitPage(self))
- self.setPage(RESULT_PAGE, ResultPage(self))
+ self.setPage(SUMMARY_PAGE, SummaryPage(repo, self))
+ self.setPage(MERGE_PAGE, MergePage(repo, self))
+ self.setPage(COMMIT_PAGE, CommitPage(repo, self))
+ self.setPage(RESULT_PAGE, ResultPage(repo, self))
+ self.currentIdChanged.connect(self.pageChanged)
repo.repositoryChanged.connect(self.repositoryChanged)
repo.configChanged.connect(self.configChanged)
@@ -54,42 +58,27 @@ def configChanged(self):
self.currentPage().configChanged()
+ def pageChanged(self, id):
+ if id != -1:
+ self.currentPage().currentPage()
+
def reject(self):
- page = self.currentPage()
- if hasattr(page, 'need_cleanup') and page.need_cleanup():
- main = _('Do you want to exit?')
- text = _('To finish merging, you need to commit '
- 'the working directory.')
- labels = ((QMessageBox.Yes, _('&Exit')),
- (QMessageBox.No, _('Cancel')))
- if not qtlib.QuestionMsgBox(_('Confirm Exit'), main, text,
- labels=labels, parent=self):
- return
- page.reject()
- super(MergeDialog, self).reject()
+ if self.currentPage().canExit():
+ super(MergeDialog, self).reject()
-MAIN_PANE = 0
-PERFORM_PANE = 1
class BasePage(QWizardPage):
+ def __init__(self, repo, parent):
+ super(BasePage, self).__init__(parent)
+ self.repo = repo
- def __init__(self, parent=None):
- super(BasePage, self).__init__(parent)
- self.nextEnabled = True
- self.done = False
+ def validatePage(self):
+ 'user pressed NEXT button, can we proceed?'
+ return True
- def switch_pane(self, pane):
- self.setup_buttons(pane)
- self.layout().setCurrentIndex(pane)
- if pane == MAIN_PANE:
- self.ready()
- elif pane == PERFORM_PANE:
- self.cmd.core.clearOutput()
- self.perform()
- else:
- raise 'unknown pane: %s' % pane
-
- ### Override Method ###
+ def isComplete(self):
+ 'should NEXT button be sensitive?'
+ return True
def repositoryChanged(self):
'repository has detected a change to changelog or parents'
@@ -99,125 +88,39 @@ 'repository has detected a change to config files'
pass
- def reject(self):
+ def currentPage(self):
pass
+ def canExit(self):
+ if len(self.repo.parents()) == 2:
+ main = _('Do you want to exit?')
+ text = _('To finish merging, you need to commit '
+ 'the working directory.')
+ labels = ((QMessageBox.Yes, _('&Exit')),
+ (QMessageBox.No, _('Cancel')))
+ if not qtlib.QuestionMsgBox(_('Confirm Exit'), main, text,
+ labels=labels, parent=self):
+ return False
+ return True
+
+class SummaryPage(BasePage):
+
+ def __init__(self, repo, parent):
+ super(SummaryPage, self).__init__(repo, parent)
+ self.clean = None
+ self.th = None
+
+ ### Override Methods ###
+
def initializePage(self):
if self.layout():
return
+ self.setTitle(_('Preparation'))
+ self.setSubTitle(_('Verify merge targets and ensure your working '
+ 'directory is clean.'))
+ self.setLayout(QVBoxLayout())
- stack = QStackedLayout()
- self.setLayout(stack)
-
- def wrap(layout):
- widget = QWidget()
- widget.setLayout(layout)
- return widget
-
- # main pane
- fpane = self.get_pane()
- num = stack.addWidget(wrap(fpane))
- assert num == MAIN_PANE
-
- # perform pane
- ppane = QVBoxLayout()
- ppane.addSpacing(4)
- self.cmd = cmdui.Widget(True, True, self)
- self.cmd.setShowOutput(True)
- self.cmd.commandFinished.connect(self.command_finished)
- self.cmd.commandCanceling.connect(self.command_canceling)
- ppane.addWidget(self.cmd)
- num = stack.addWidget(wrap(ppane))
- assert num == PERFORM_PANE
-
- def setVisible(self, visible):
- super(BasePage, self).setVisible(visible)
- if visible:
- self.switch_pane(MAIN_PANE)
-
- def validatePage(self):
- #When the user first clicks on the "Next" button ("Merge"/"Commit")
- #After any validation via overloading validatePage(),
- #we switch to the perform pane
- if self.layout().currentIndex() == MAIN_PANE:
- self.switch_pane(PERFORM_PANE)
- return False
-
- #When the perform pane is done, it'll call this again
- return self.can_continue()
-
- ### Method to be overridden ###
-
- def get_pane(self):
- return QVBoxLayout()
-
- def get_perform_label(self):
- return None
-
- def setup_buttons(self, pane):
- if pane == MAIN_PANE:
- label = self.get_perform_label()
- if label:
- self.wizard().setButtonText(QWizard.NextButton, label);
- self.nextEnabled = True
- else:
- self.nextEnabled = False
- self.wizard().setOption(QWizard.HaveHelpButton, False)
- self.wizard().setOption(QWizard.HaveCustomButton1, False)
- self.wizard().setOption(QWizard.NoCancelButton, False)
- elif pane == PERFORM_PANE:
- button = QPushButton(_('Cancel'))
- self.wizard().setButton(QWizard.CustomButton1, button)
- self.wizard().setOption(QWizard.HaveCustomButton1, True)
- button.clicked.connect(self.cancel_clicked)
- self.nextEnabled = False
- self.wizard().setOption(QWizard.NoCancelButton, True)
- else:
- raise 'unknown pane: %s' % pane
-
- def ready(self):
- pass
-
- def perform(self):
- pass
-
- def cancel(self):
- self.cmd.cancel()
-
- def can_continue(self):
- return self.done
-
- def need_cleanup(self):
- return False
-
- ### Signal Handlers ###
-
- def cancel_clicked(self):
- self.cancel()
-
- def command_finished(self, ret):
- pass
-
- def command_canceling(self):
- pass
-
-MARGINS = (8, 0, 0, 0)
-
-class MergePage(BasePage):
-
- def __init__(self, parent=None):
- super(MergePage, self).__init__(parent)
-
- self.clean = None
- self.undo = False
- self.th = None
-
- ### Override Methods ###
-
- def get_pane(self):
- repo = self.wizard().repo
- box = QVBoxLayout()
-
+ repo = self.repo
contents = ('ishead',) + csinfo.PANEL_DEFAULT
style = csinfo.panelstyle(contents=contents)
def markup_func(widget, item, value):
@@ -230,36 +133,31 @@
## merge target
other_sep = qtlib.LabeledSeparator(_('Merge from (other revision)'))
- box.addWidget(other_sep)
+ self.layout().addWidget(other_sep)
try:
- other_info = create(self.wizard().other)
- other_info.setContentsMargins(5, 0, 0, 0)
- box.addWidget(other_info)
- self.other_info = other_info
+ otherCsInfo = create(self.wizard().otherrev)
except error.RepoLookupError:
qtlib.InfoMsgBox(_('Unable to merge'),
_('Merge revision not specified or not found'))
QTimer.singleShot(0, self.wizard().close)
+ self.layout().addWidget(otherCsInfo)
+ self.otherCsInfo = otherCsInfo
## current revision
- box.addSpacing(6)
local_sep = qtlib.LabeledSeparator(_('Merge to (working directory)'))
- box.addWidget(local_sep)
- local_info = create(self.wizard().local)
- local_info.setContentsMargins(5, 0, 0, 0)
- box.addWidget(local_info)
- self.local_info = local_info
+ self.layout().addWidget(local_sep)
+ localCsInfo = create(self.wizard().localrev)
+ self.layout().addWidget(localCsInfo)
+ self.localCsInfo = localCsInfo
## working directory status
- box.addSpacing(6)
wd_sep = qtlib.LabeledSeparator(_('Working directory status'))
- box.addWidget(wd_sep)
+ self.layout().addWidget(wd_sep)
self.groups = qtlib.WidgetGroups()
wdbox = QHBoxLayout()
- wdbox.setContentsMargins(*MARGINS)
- box.addLayout(wdbox)
+ self.layout().addLayout(wdbox)
self.wd_status = qtlib.StatusLabel()
self.wd_status.set_status(_('Checking...'))
wdbox.addWidget(self.wd_status)
@@ -268,34 +166,28 @@ wd_prog.setTextVisible(False)
self.groups.add(wd_prog, 'prog')
wdbox.addWidget(wd_prog, 1)
- wd_detail = QLabel(_('<a href="view">View changes...</a>'))
- wd_detail.linkActivated.connect(self.link_activated)
- self.groups.add(wd_detail, 'detail')
- wdbox.addWidget(wd_detail)
- wdbox.addSpacing(4)
wd_merged = QLabel(_('The working directory is already <b>merged</b>. '
'<a href="skip"><b>Continue</b></a> or '
'<a href="discard"><b>discard</b></a> existing '
'merge.'))
- wd_merged.setContentsMargins(*MARGINS)
- wd_merged.linkActivated.connect(self.link_activated)
+ wd_merged.linkActivated.connect(self.onLinkActivated)
+ wd_merged.setWordWrap(True)
self.groups.add(wd_merged, 'merged')
- box.addWidget(wd_merged)
+ self.layout().addWidget(wd_merged)
text = _('Before merging, you must <a href="commit"><b>commit</b></a>, '
'<a href="shelve"><b>shelve</b></a> to patch, '
'or <a href="discard"><b>discard</b></a> changes.')
wd_text = QLabel(text)
- wd_text.setContentsMargins(*MARGINS)
- wd_text.linkActivated.connect(self.link_activated)
+ wd_text.setWordWrap(True)
+ wd_text.linkActivated.connect(self.onLinkActivated)
self.wd_text = wd_text
self.groups.add(wd_text, 'dirty')
- box.addWidget(wd_text)
+ self.layout().addWidget(wd_text)
wdbox = QHBoxLayout()
- wdbox.setContentsMargins(*MARGINS)
- box.addLayout(wdbox)
+ self.layout().addLayout(wdbox)
wd_alt = QLabel(_('Or use:'))
self.groups.add(wd_alt, 'dirty')
wdbox.addWidget(wd_alt)
@@ -305,25 +197,18 @@ self.registerField('force', force_chk)
self.groups.add(force_chk, 'dirty')
wdbox.addWidget(force_chk)
- wdbox.addStretch(0)
-
- box.addSpacing(6)
### options
expander = qtlib.ExpanderLabel(_('Options'), False)
- expander.expanded.connect(self.show_options)
- box.addWidget(expander)
+ expander.expanded.connect(self.toggleShowOptions)
+ self.layout().addWidget(expander)
self.expander = expander
- optbox = QVBoxLayout()
- optbox.setSpacing(6)
- box.addLayout(optbox)
-
### discard option
discard_chk = QCheckBox(_('Discard all changes from merge target '
'(other) revision'))
self.registerField('discard', discard_chk)
- optbox.addWidget(discard_chk)
+ self.layout().addWidget(discard_chk)
self.discard_chk = discard_chk
## auto-resolve
@@ -332,129 +217,95 @@ autoresolve_chk.setChecked(
repo.ui.configbool('tortoisehg', 'autoresolve', False))
self.registerField('autoresolve', autoresolve_chk)
- optbox.addWidget(autoresolve_chk)
+ self.layout().addWidget(autoresolve_chk)
self.autoresolve_chk = autoresolve_chk
- box.addStretch(0)
-
- return box
-
- def get_perform_label(self):
- return _('&Merge')
-
- def ready(self):
- self.done = False
self.setTitle(_('Merge another revision to the working directory'))
self.groups.set_visible(False, 'dirty')
self.groups.set_visible(False, 'merged')
- self.groups.set_visible(False, 'detail')
- self.show_options(self.expander.is_expanded())
- self.check_status()
+ self.toggleShowOptions(self.expander.is_expanded())
- if self.undo:
- self.link_activated('discard:noconfirm')
- self.undo = False
+ def isComplete(self):
+ 'should Next button be sensitive?'
+ return self.clean or self.field('force').toBool()
def validatePage(self):
- #If we haven't already done the action, pop up a confirmation for
- #dummy merge.
- if not self.done and self.field('discard').toBool():
+ 'validate that we can continue with the merge'
+ if self.field('discard').toBool():
labels = [(QMessageBox.Yes, _('&Discard')),
(QMessageBox.No, _('Cancel'))]
if not qtlib.QuestionMsgBox(_('Confirm Discard Changes'),
_('The changes from revision %s and all unmerged parents '
'will be discarded.\n\n'
'Are you sure this is what you want to do?')
- % (self.other_info.get_data('revid')),
+ % (self.otherCsInfo.get_data('revid')),
labels=labels, parent=self):
return False
+ return super(SummaryPage, self).validatePage();
- return super(MergePage, self).validatePage();
+ ## custom methods ##
- def perform(self):
- self.setTitle(_('Merging...'))
- self.setSubTitle(_('All conflicting files will be marked unresolved.'))
-
- if self.field('discard').toBool():
- # '.' is safer than self.localrev, in case the user has
- # pulled a fast one on us and updated from the CLI
- cmdline = ['--repository', self.wizard().repo.root,
- 'debugsetparents', '.', self.wizard().other]
- else:
- cmdline = ['--repository', self.wizard().repo.root, 'merge']
- if self.field('force').toBool():
- cmdline.append('--force')
- tool = self.field('autoresolve').toBool() and 'merge' or 'fail'
- cmdline += ['--tool=internal:' + tool]
- cmdline.append(self.wizard().other)
- self.cmd.run(cmdline)
-
- def cancel(self):
- main = _('Cancel merge and discard changes?')
- # Does this restart "resolved" files too?
- text = _('Discard local changes and restart merge?')
- labels = ((QMessageBox.Yes, _('&Discard')),
- (QMessageBox.No, _('Cancel')))
- if qtlib.QuestionMsgBox(_('Confirm Clean Up'), main, text,
- labels=labels, parent=self):
- o = self.cmd.outputLog
- o.appendLog(_('Canceling merge...\n'), 'control')
- o.appendLog(_('(Please close any running merge tools)\n'), 'control')
- self.cmd.cancel()
-
- def isComplete(self):
- if not self.nextEnabled:
- return False
- if self.clean:
- return True
- return self.field('force').toBool()
-
- ### Signal Handlers ###
-
- def command_finished(self, ret):
- repo = self.wizard().repo
- if ret in (0, 1):
- repo.incrementBusyCount()
- repo.decrementBusyCount()
- self.done = True
- self.wizard().next()
- else:
- qtlib.InfoMsgBox(_('Merge failed'), _('Returning to first page'))
- self.link_activated('discard:noconfirm')
- self.switch_pane(MAIN_PANE)
+ def toggleShowOptions(self, visible):
+ self.discard_chk.setShown(visible)
+ self.autoresolve_chk.setShown(visible)
def repositoryChanged(self):
'repository has detected a change to changelog or parents'
- pctx = self.wizard().repo['.']
- self.local_info.update(pctx)
- self.wizard().local = str(pctx.rev())
+ pctx = self.repo['.']
+ self.localCsInfo.update(pctx)
+ self.wizard().localrev = str(pctx.rev())
- def reject(self):
- if self.th is not None and not self.th.isFinished():
+ def canExit(self):
+ 'can merge tool be closed?'
+ if self.th is not None and self.th.isRunning():
self.th.cancel()
self.th.wait()
+ return True
- def show_options(self, visible):
- self.discard_chk.setShown(visible)
- self.autoresolve_chk.setShown(visible)
+ def currentPage(self):
+ self.refresh()
- def command_canceling(self):
- self.wizard().button(QWizard.CustomButton1).setDisabled(True)
+ def refresh(self):
+ if self.th is None:
+ self.th = CheckThread(self.repo, self)
+ self.th.finished.connect(self.threadFinished)
+ if self.th.isRunning():
+ return
+ self.groups.set_visible(True, 'prog')
+ self.th.start()
- def link_activated(self, cmd):
- cmd = str(cmd)
- repo = self.wizard().repo
+ def threadFinished(self):
+ self.groups.set_visible(False, 'prog')
+ if self.th.canceled:
+ return
+ dirty, parents = self.th.results
+ self.clean = not dirty
+ if dirty:
+ self.groups.set_visible(parents == 2, 'merged')
+ self.groups.set_visible(parents == 1, 'dirty')
+ self.wd_status.set_status(_('<b>Uncommitted local changes '
+ 'are detected</b>'), 'thg-warning')
+ else:
+ self.groups.set_visible(False, 'dirty')
+ self.groups.set_visible(False, 'merged')
+ self.wd_status.set_status(_('Clean'), True)
+ self.completeChanged.emit()
+
+ @pyqtSlot(QString)
+ def onLinkActivated(self, cmd):
+ cmd = hglib.fromunicode(cmd)
+ repo = self.repo
if cmd == 'commit':
dlg = commit.CommitDialog([], dict(root=repo.root), self)
dlg.finished.connect(dlg.deleteLater)
dlg.exec_()
- self.check_status()
+ self.refresh()
elif cmd == 'shelve':
from tortoisehg.hgqt import shelve
dlg = shelve.ShelveDialog(repo, self.wizard())
dlg.finished.connect(dlg.deleteLater)
dlg.exec_()
- self.check_status()
+ self.refresh()
elif cmd.startswith('discard'):
if cmd != 'discard:noconfirm':
labels = [(QMessageBox.Yes, _('&Discard')),
@@ -465,108 +316,112 @@ return
def finished(ret):
repo.decrementBusyCount()
- if ret == 0:
- self.check_status()
+ self.refresh()
cmdline = ['update', '--clean', '--repository', repo.root,
'--rev', '.']
self.runner = cmdui.Runner(True, self)
self.runner.commandFinished.connect(finished)
repo.incrementBusyCount()
self.runner.run(cmdline)
- elif cmd.startswith('rename:'):
- patch = cmd[7:]
- name, ok = QInputDialog.getText(self, _('Rename Patch'),
- _('Input a new patch name:'), text=patch)
- if not ok or name == patch:
- return
- oldpatch = hglib.fromunicode(patch)
- newpatch = hglib.fromunicode(name)
- def finished(ret):
- repo.decrementBusyCount()
- if ret == 0:
- text = _('The patch <b>%(old)s</b> is renamed to <b>'
- '%(new)s</b>. <a href="rename:%(new)s"><b>'
- 'Rename</b></a> again?')
- self.wd_text.setText(text % dict(old=patch, new=name))
- self.runner = cmdui.Runner(True, self)
- self.runner.commandFinished.connect(finished)
- repo.incrementBusyCount()
- self.runner.run(['qrename', '--repository', repo.root,
- oldpatch, newpatch])
elif cmd == 'view':
dlg = status.StatusDialog([], {}, repo.root, self)
dlg.exec_()
- self.check_status()
+ self.refresh()
elif cmd == 'skip':
- self.done = True
self.wizard().next()
else:
- raise 'unknown command: %s' % str(cmd)
+ raise 'unknown command: %s' % cmd
- ### Private Methods ###
- def check_status(self, callback=None):
- repo = self.wizard().repo
- class CheckThread(QThread):
- def __init__(self, parent):
- QThread.__init__(self, parent)
- self.results = (False, 1)
- self.canceled = False
+class MergePage(BasePage):
+ # TODO: add a checkbox on this page to automatically continue
- def run(self):
- unresolved = False
- for root, path, status in thgrepo.recursiveMergeStatus(repo):
- if self.canceled:
- return
- if status == 'u':
- unresolved = True
- break
- wctx = repo[None]
- dirty = bool(wctx.dirty()) or unresolved
- self.results = (dirty, len(wctx.parents()))
+ def __init__(self, repo, parent):
+ super(MergePage, self).__init__(repo, parent)
+ self.mergecomplete = False
- def cancel(self):
- self.canceled = True
+ self.setTitle(_('Merging...'))
+ self.setSubTitle(_('All conflicting files will be marked unresolved.'))
+ self.setLayout(QVBoxLayout())
- def completed():
- if self.th.canceled:
- return
- self.th.wait()
- dirty, parents = self.th.results
- self.clean = not dirty
- self.groups.set_visible(False, 'prog')
- self.groups.set_visible(dirty, 'detail')
- if dirty:
- self.groups.set_visible(parents == 2, 'merged')
- self.groups.set_visible(parents == 1, 'dirty')
- self.wd_status.set_status(_('<b>Uncommitted local changes '
- 'are detected</b>'), 'thg-warning')
+ self.cmd = cmdui.Widget(True, False, self)
+ self.cmd.commandFinished.connect(self.onCommandFinished)
+ self.cmd.setShowOutput(True)
+ self.layout().addWidget(self.cmd)
+
+ self.reslabel = QLabel()
+ self.reslabel.linkActivated.connect(self.onLinkActivated)
+ self.layout().addWidget(self.reslabel)
+
+ def currentPage(self):
+ if self.field('discard').toBool():
+ # '.' is safer than self.localrev, in case the user has
+ # pulled a fast one on us and updated from the CLI
+ cmdline = ['--repository', self.repo.root, 'debugsetparents',
+ '.', self.wizard().otherrev]
+ else:
+ cmdline = ['--repository', self.repo.root, 'merge']
+ if self.field('force').toBool():
+ cmdline.append('--force')
+ tool = self.field('autoresolve').toBool() and 'merge' or 'fail'
+ cmdline += ['--tool=internal:' + tool]
+ cmdline.append(self.wizard().otherrev)
+
+ if len(self.repo.parents()) == 1:
+ self.repo.incrementBusyCount()
+ self.cmd.core.clearOutput()
+ self.cmd.run(cmdline)
+ else:
+ self.mergecomplete = True
+ self.completeChanged.emit()
+
+ def isComplete(self):
+ 'should Next button be sensitive?'
+ if not self.mergecomplete:
+ return False
+ count = 0
+ for root, path, status in thgrepo.recursiveMergeStatus(self.repo):
+ if status == 'u':
+ count += 1
+ if count:
+ if self.field('autoresolve').toBool():
+ # if autoresolve is enabled, we know these were real conflicts
+ self.reslabel.setText(_('%d files have <b>merge conflicts</b> '
+ 'that must be <a href="resolve">'
+ '<b>resolved</b></a>') % count)
else:
- self.groups.set_visible(False, 'dirty')
- self.groups.set_visible(False, 'merged')
- self.wd_status.set_status(_('Clean'), True)
+ # else give a calmer indication of conflicts
+ self.reslabel.setText(_('%d files were modified on both '
+ 'branches and must be <a href="resolve">'
+ '<b>resolved</b></a>') % count)
+ return False
+ else:
+ self.reslabel.setText(_('No merge conflicts, ready to commit'))
+ return True
+
+ def onCommandFinished(self, ret):
+ self.repo.decrementBusyCount()
+ if ret in (0, 1):
+ self.mergecomplete = True
+ self.completeChanged.emit()
+
+ @pyqtSlot(QString)
+ def onLinkActivated(self, cmd):
+ if cmd == 'resolve':
+ dlg = resolve.ResolveDialog(self.repo, self)
+ dlg.finished.connect(dlg.deleteLater)
+ dlg.exec_()
self.completeChanged.emit()
- if callable(callback):
- callback()
- self.th = CheckThread(self)
- self.th.finished.connect(completed)
- self.th.start()
class CommitPage(BasePage):
- def __init__(self, parent=None):
- super(CommitPage, self).__init__(parent)
+ def __init__(self, repo, parent):
+ super(CommitPage, self).__init__(repo, parent)
- ### Override Methods ###
-
- def get_pane(self):
- repo = self.wizard().repo
- box = QVBoxLayout()
-
- self.reslabel = QLabel()
- self.reslabel.linkActivated.connect(self.link_activated)
- box.addWidget(self.reslabel)
+ self.setTitle(_('Commit merge results'))
+ self.setLayout(QVBoxLayout())
+ self.setCommitPage(True)
# csinfo
def label_func(widget, item, ctx):
@@ -614,28 +469,29 @@ style = csinfo.panelstyle(contents=contents, margin=6)
# merged files
- box.addSpacing(12)
rev_sep = qtlib.LabeledSeparator(_('Working Directory (merged)'))
- box.addWidget(rev_sep)
- rev_info = csinfo.create(repo, None, style, custom=custom,
- withupdate=True)
- page = self.wizard().page(MERGE_PAGE)
- rev_info.linkActivated.connect(page.link_activated)
- box.addWidget(rev_info)
+ self.layout().addWidget(rev_sep)
+ mergeCsInfo = csinfo.create(repo, None, style, custom=custom,
+ withupdate=True)
+ mergeCsInfo.linkActivated.connect(self.onLinkActivated)
+ self.layout().addWidget(mergeCsInfo)
# commit message area
msg_sep = qtlib.LabeledSeparator(_('Commit message'))
- box.addWidget(msg_sep)
- msg_text = commit.MessageEntry(self)
- msg_text.installEventFilter(qscilib.KeyPressInterceptor(self))
- msg_text.refresh(repo)
- msg_text.loadSettings(QSettings(), 'merge/message')
- engmsg = repo.ui.configbool('tortoisehg', 'engmsg', False)
- msgset = keep._('Merge ')
- msg_text.setText(engmsg and msgset['id'] or msgset['str'])
- msg_text.textChanged.connect(self.completeChanged)
- self.msg_text = msg_text
- box.addWidget(msg_text)
+ self.layout().addWidget(msg_sep)
+ msgEntry = commit.MessageEntry(self)
+ msgEntry.installEventFilter(qscilib.KeyPressInterceptor(self))
+ msgEntry.refresh(repo)
+ msgEntry.loadSettings(QSettings(), 'merge/message')
+
+ msgEntry.textChanged.connect(self.completeChanged)
+ self.layout().addWidget(msgEntry)
+ self.msgEntry = msgEntry
+
+ self.cmd = cmdui.Widget(True, False, self)
+ self.cmd.commandFinished.connect(self.onCommandFinished)
+ self.cmd.setShowOutput(False)
+ self.layout().addWidget(self.cmd)
def tryperform():
if self.isComplete():
@@ -644,121 +500,90 @@ actionEnter.setShortcuts([Qt.CTRL+Qt.Key_Return, Qt.CTRL+Qt.Key_Enter])
actionEnter.triggered.connect(tryperform)
self.addAction(actionEnter)
- return box
- def link_activated(self, cmd):
- if cmd == 'resolve':
- dlg = resolve.ResolveDialog(self.wizard().repo, self)
- dlg.finished.connect(dlg.deleteLater)
+ def currentPage(self):
+ # TODO: add other branch name, when appropriate
+ engmsg = self.repo.ui.configbool('tortoisehg', 'engmsg', False)
+ msgset = keep._('Merge ')
+ self.msgEntry.setText(engmsg and msgset['id'] or msgset['str'])
+ self.msgEntry.moveCursorToEnd()
+
+ @pyqtSlot(QString)
+ def onLinkActivated(self, cmd):
+ if cmd == 'view':
+ dlg = status.StatusDialog([], {}, self.repo.root, self)
dlg.exec_()
- self.completeChanged.emit()
+ self.refresh()
- def get_perform_label(self):
- return _('&Commit')
+ def isComplete(self):
+ return len(self.repo.parents()) == 2 and len(self.msgEntry.text()) > 0
- def setup_buttons(self, pane):
- super(CommitPage, self).setup_buttons(pane)
+ def validatePage(self):
+ if len(self.repo.parents()) == 1:
+ # commit succeeded, repositoryChanged() called wizard().next()
+ return True
+ if self.cmd.core.running():
+ return False
- if pane == MAIN_PANE:
- undo = QPushButton(_('Undo'))
- undo.clicked.connect(self.wizard().back)
- self.wizard().setButton(QWizard.HelpButton, undo)
- self.wizard().setOption(QWizard.HaveHelpButton, True)
- elif pane == PERFORM_PANE:
- self.wizard().setOption(QWizard.HaveHelpButton, False)
- else:
- raise 'unknown pane: %s' % pane
-
- def ready(self):
- self.setTitle(_('Commit merged files'))
- self.msg_text.moveCursorToEnd()
-
- def perform(self):
self.setTitle(_('Committing...'))
self.setSubTitle(_('Please wait while committing merged files.'))
- # merges must be committed without specifying file list
- message = hglib.fromunicode(self.msg_text.text())
+ message = hglib.fromunicode(self.msgEntry.text())
cmdline = ['commit', '--verbose', '--message', message,
- '--repository', self.wizard().repo.root]
- self.wizard().repo.incrementBusyCount()
+ '--repository', self.repo.root]
+ self.repo.incrementBusyCount()
+ self.cmd.setShowOutput(True)
self.cmd.run(cmdline)
-
- def isComplete(self):
- if not self.nextEnabled:
- return False
- repo = self.wizard().repo
- for root, path, status in thgrepo.recursiveMergeStatus(repo):
- if status == 'u':
- self.reslabel.setText(_('There were <b>merge conflicts</b> '
- 'that must be <a href="resolve">'
- '<b>resolved</b></a>'))
- return False
- else:
- self.reslabel.setText(_('No merge conflicts, ready to commit'))
- return len(self.msg_text.text()) > 0
-
- def need_cleanup(self):
- return len(self.wizard().repo.parents()) == 2
+ self.msgEntry.saveSettings(QSettings(), 'merge/message')
+ return False
def repositoryChanged(self):
'repository has detected a change to changelog or parents'
- if self.done:
- return
- if len(self.wizard().repo.parents()) == 1:
- self.wizard().restart()
+ if len(self.repo.parents()) == 1:
+ self.wizard().next()
- ### Private Method ###
+ def onCommandFinished(self, ret):
+ self.repo.decrementBusyCount()
+ self.completeChanged.emit()
- def undo(self):
- page = self.wizard().page(MERGE_PAGE)
- page.undo = True
+class ResultPage(BasePage):
+ # TODO: Add a checkbox on this page to make it optional
- ### Signal Handlers ###
+ def __init__(self, repo, parent):
+ super(ResultPage, self).__init__(repo, parent)
+ self.setTitle(_('Finished'))
+ self.setFinalPage(True)
- def command_finished(self, ret):
- if ret == 0:
- self.done = True
- self.wizard().repo.decrementBusyCount()
- self.msg_text.saveSettings(QSettings(), 'merge/message')
- self.wizard().next()
- else:
- self.wizard().repo.decrementBusyCount()
+ self.setLayout(QVBoxLayout())
+ merge_sep = qtlib.LabeledSeparator(_('Merge changeset'))
+ self.layout().addWidget(merge_sep)
+ merge_info = csinfo.create(self.repo, 'tip', withupdate=True)
+ self.layout().addWidget(merge_info)
+ self.layout().addStretch(1)
- def command_canceling(self):
- page = self.wizard().page(MERGE_PAGE)
- page.undo = True
-class ResultPage(QWizardPage):
+class CheckThread(QThread):
+ def __init__(self, repo, parent):
+ QThread.__init__(self, parent)
+ self.repo = hg.repository(repo.ui, repo.root)
+ self.results = (False, 1)
+ self.canceled = False
- def __init__(self, parent=None):
- super(ResultPage, self).__init__(parent)
+ def run(self):
+ self.repo.dirstate.invalidate()
+ unresolved = False
+ for root, path, status in thgrepo.recursiveMergeStatus(self.repo):
+ if self.canceled:
+ return
+ if status == 'u':
+ unresolved = True
+ break
+ wctx = self.repo[None]
+ dirty = bool(wctx.dirty()) or unresolved
+ self.results = (dirty, len(wctx.parents()))
- self.setTitle(_('Finished'))
-
- ### Override Method ###
-
- def reject(self):
- pass
-
- def repositoryChanged(self):
- 'repository has detected a change to changelog or parents'
- pass
-
- def initializePage(self):
- box = QVBoxLayout()
- self.setLayout(box)
-
- # merge changeset
- merge_sep = qtlib.LabeledSeparator(_('Merge changeset'))
- box.addWidget(merge_sep)
- merge_info = csinfo.create(self.wizard().repo, 'tip', withupdate=True)
- box.addWidget(merge_info)
- box.addStretch(0)
-
- self.wizard().setOption(QWizard.HaveHelpButton, False)
- self.wizard().setOption(QWizard.NoCancelButton, True)
- self.wizard().setOption(QWizard.HaveCustomButton1, False)
+ def cancel(self):
+ self.canceled = True
def run(ui, *pats, **opts):
from tortoisehg.util import paths
|
Loading...