Exemple #1
0
 def linkActivated(self, cmd):
     if cmd == 'resolve':
         dlg = resolve.ResolveDialog(self.repo, self)
         dlg.exec_()
         self.checkResolve()
     elif cmd == 'commit':
         dlg = commit.CommitDialog(self.repo, [], {}, self)
         dlg.finished.connect(dlg.deleteLater)
         dlg.exec_()
         self.destcsinfo.update(self.repo['.'])
         self.checkStatus()
     elif cmd == 'discard':
         labels = [(QMessageBox.Yes, _('&Discard')),
                   (QMessageBox.No, _('Cancel'))]
         if not qtlib.QuestionMsgBox(_('Confirm Discard'),
                  _('Discard outstanding changes to working directory?'),
                  labels=labels, parent=self):
             return
         def finished(ret):
             self.repo.decrementBusyCount()
             if ret == 0:
                 self.checkStatus()
         cmdline = ['update', '--clean', '--repository', self.repo.root,
                    '--rev', '.']
         self.runner = cmdui.Runner(True, self)
         self.runner.commandFinished.connect(finished)
         self.repo.incrementBusyCount()
         self.runner.run(cmdline)
Exemple #2
0
 def _showexceptiondialog(self):
     from tortoisehg.hgqt.bugreport import BugReport, ExceptionMsgBox
     opts = {}
     opts['cmd'] = ' '.join(sys.argv[1:])
     opts['error'] = ''.join(''.join(traceback.format_exception(*args))
                             for args in self.errors)
     etype, evalue = self.errors[0][:2]
     if (len(set(e[0] for e in self.errors)) == 1
             and etype in self._recoverableexc):
         opts['values'] = evalue
         errstr = self._recoverableexc[etype]
         if etype is error.Abort and evalue.hint:
             errstr = u''.join(
                 [errstr, u'<br><b>',
                  _('hint:'), u'</b> %(arg1)s'])
             opts['values'] = [str(evalue), evalue.hint]
         dlg = ExceptionMsgBox(hglib.tounicode(str(evalue)),
                               hglib.tounicode(errstr),
                               opts,
                               parent=self._mainapp.activeWindow())
     elif etype is KeyboardInterrupt:
         if qtlib.QuestionMsgBox(
                 hglib.tounicode(_('Keyboard interrupt')),
                 hglib.tounicode(_('Close this application?'))):
             QApplication.quit()
         else:
             self.errors = []
             return
     else:
         dlg = BugReport(opts, parent=self._mainapp.activeWindow())
     dlg.exec_()
Exemple #3
0
 def reject(self):
     if os.path.exists(self.repo.join('rebasestate')):
         main = _('Exiting with an unfinished rebase is not recommended.')
         text = _('Consider aborting the rebase first.')
         labels = ((QMessageBox.Yes, _('&Exit')), (QMessageBox.No,
                                                   _('Cancel')))
         if not qtlib.QuestionMsgBox(
                 _('Confirm Exit'), main, text, labels=labels, parent=self):
             return
     super(RebaseDialog, self).reject()
Exemple #4
0
    def init(self):
        dest = self.getPath()

        if dest == '':
            qtlib.ErrorMsgBox(_('Error executing init'),
                              _('Destination path is empty'),
                              _('Please enter the directory path'))
            self.dest_edit.setFocus()
            return False

        dest = os.path.normpath(dest)
        self.dest_edit.setText(hglib.tounicode(dest))
        udest = self.dest_edit.text()

        if not os.path.exists(dest):
            p = dest
            l = 0
            while not os.path.exists(p):
                l += 1
                p, t = os.path.split(p)
                if not t:
                    break  # already root path
            if l > 1:
                res = qtlib.QuestionMsgBox(
                    _('Init'),
                    _('Are you sure about adding the new repository '
                      '%d extra levels deep?') % l,
                    _('Path exists up to:\n%s\nand you asked for:\n%s') %
                    (p, udest),
                    defaultbutton=QMessageBox.No)
                if not res:
                    self.dest_edit.setFocus()
                    return
            try:
                # create the folder, just like Hg would
                os.makedirs(dest)
            except:
                qtlib.ErrorMsgBox(_('Error executing init'),
                                  _('Cannot create folder %s') % udest)
                return False

        _ui = ui.ui()

        # dotencode is the new default repo format in Mercurial 1.7
        if self.make_pre_1_7_chk.isChecked():
            _ui.setconfig('format', 'dotencode', 'False')

        try:
            # create the new repo
            hg.repository(_ui, dest, create=1)
        except error.RepoError, inst:
            qtlib.ErrorMsgBox(_('Error executing init'),
                              _('Unable to create new repository'),
                              hglib.tounicode(str(inst)))
            return False
Exemple #5
0
    def rename(self):
        """execute the rename"""

        # check inputs
        src = self.get_src()
        dest = self.get_dest()
        if not os.path.exists(src):
            qtlib.WarningMsgBox(self.msgTitle, _('Source does not exists.'))
            return
        fullsrc = os.path.abspath(src)
        if not fullsrc.startswith(self.repo.root):
            qtlib.ErrorMsgBox(self.errTitle,
                    _('The source must be within the repository tree.'))
            return
        fulldest = os.path.abspath(dest)
        if not fulldest.startswith(self.repo.root):
            qtlib.ErrorMsgBox(self.errTitle,
                    _('The destination must be within the repository tree.'))
            return
        if src == dest:
            qtlib.ErrorMsgBox(self.errTitle,
                    _('Please give a destination that differs from the source'))
            return
        if (os.path.isfile(dest) and not self.isCaseFoldingOnWin()):
            res = qtlib.QuestionMsgBox(self.msgTitle, '<p>%s</p><p>%s</p>' %
                    (_('Destination file already exists.'),
                    _('Are you sure you want to overwrite it ?')),
                    defaultbutton=QMessageBox.No)
            if not res:
                return

        cmdline = self.compose_command(src, dest)
        self.show_command(cmdline)
        if self.isCaseFoldingOnWin():
            # We do the rename ourselves if it's a pure casefolding
            # action on Windows. Because there is no way to make Hg
            # do 'hg mv foo Foo' correctly there.
            if self.copy_chk.isChecked():
                qtlib.ErrorMsgBox(self.errTitle,
                        _('Cannot do a pure casefolding copy on Windows'))
                return
            else:
                try:
                    targetdir = os.path.dirname(fulldest)
                    if not os.path.isdir(targetdir):
                        os.makedirs(targetdir)
                    os.rename(fullsrc, fulldest)
                except (OSError, IOError), inst:
                    if self.copy_chk.isChecked():
                        txt = _('The following error was caught while copying:')
                    else:
                        txt = _('The following error was caught while renaming:')
                    qtlib.ErrorMsgBox(self.errTitle, txt,
                            hglib.tounicode(str(inst)))
                    return
Exemple #6
0
 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
Exemple #7
0
 def deleteShelfB(self):
     shelf = self.currentPatchB()
     ushelf = hglib.tounicode(os.path.basename(shelf))
     if not qtlib.QuestionMsgBox(_('Are you sure?'),
                                 _('Delete shelf file %s?') % ushelf):
         return
     try:
         os.unlink(shelf)
         self.showMessage(_('Shelf deleted'))
     except EnvironmentError, e:
         self.showMessage(hglib.tounicode(str(e)))
Exemple #8
0
 def clearShelfB(self):
     shelf = self.currentPatchB()
     ushelf = hglib.tounicode(os.path.basename(shelf))
     if not qtlib.QuestionMsgBox(_('Are you sure?'),
                             _('Clear contents of shelf file %s?') % ushelf):
         return
     try:
         f = open(shelf, "w")
         f.close()
         self.showMessage(_('Shelf cleared'))
     except EnvironmentError, e:
         self.showMessage(hglib.tounicode(str(e)))
Exemple #9
0
 def reject(self):
     s = QSettings()
     s.setValue('resolve/geom', self.saveGeometry())
     if self.utree.model().rowCount() > 0:
         main = _('Exit without finishing resolve?')
         text = _('Unresolved conflicts remain. Are you sure?')
         labels = ((QMessageBox.Yes, _('E&xit')),
                   (QMessageBox.No, _('Cancel')))
         if not qtlib.QuestionMsgBox(_('Confirm Exit'), main, text,
                             labels=labels, parent=self):
             return
     super(ResolveDialog, self).reject()
Exemple #10
0
 def qqueueActivate(self):
     uq = self.ql.item(self.ql.currentRow()).text()
     q = hglib.fromunicode(uq)
     if q == self.repo.thgactivemqname:
         return
     if qtlib.QuestionMsgBox(
             _('Confirm patch queue switch'),
             _("Do you really want to activate patch queue '%s' ?") % uq,
             parent=self,
             defaultbutton=QMessageBox.No):
         opts = [q]
         self.qqueueCommand(opts)
Exemple #11
0
 def reject(self):
     if self.th and self.th.isRunning():
         return
     if os.path.exists(self._graftstatefile):
         main = _('Exiting with an unfinished graft is not recommended.')
         text = _('Consider aborting the graft first.')
         labels = ((QMessageBox.Yes, _('&Exit')),
                   (QMessageBox.No, _('Cancel')))
         if not qtlib.QuestionMsgBox(_('Confirm Exit'), main, text,
                                     labels=labels, parent=self):
             return
     super(GraftDialog, self).reject()
Exemple #12
0
    def archive(self):
        # verify input
        type = self.get_selected_archive_type()['type']
        dest = unicode(self.dest_edit.text())
        if os.path.exists(dest):
            if type == 'files':
                if os.path.isfile(dest):
                    qtlib.WarningMsgBox(_('Duplicate Name'),
                            _('The destination "%s" already exists as '
                              'a file!') % dest)
                    return False
                elif os.listdir(dest):
                    if not qtlib.QuestionMsgBox(_('Confirm Overwrite'),
                                 _('The directory "%s" is not empty!\n\n'
                                   'Do you want to overwrite it?') % dest,
                                 parent=self):
                        return False
            else:
                if os.path.isfile(dest):
                    if not qtlib.QuestionMsgBox(_('Confirm Overwrite'),
                                 _('The file "%s" already exists!\n\n'
                                   'Do you want to overwrite it?') % dest,
                                 parent=self):
                        return False
                else:
                    qtlib.WarningMsgBox(_('Duplicate Name'),
                          _('The destination "%s" already exists as '
                            'a folder!') % dest)
                    return False

        # prepare command line
        cmdline = self.compose_command(hglib.fromunicode(dest), type)

        if self.files_in_rev_chk.isChecked():
            self.savedcwd = os.getcwd()
            os.chdir(self.repo.root)

        # start archiving
        self.cmd.run(cmdline)
Exemple #13
0
 def qqueueDelete(self):
     uq = self.ql.item(self.ql.currentRow()).text()
     q = hglib.fromunicode(uq)
     if q == 'patches':
         return
     if qtlib.QuestionMsgBox(
             _('Confirm patch queue delete'),
             _("Do you really want to delete patch queue '%s' ?") % uq,
             parent=self,
             defaultbutton=QMessageBox.No):
         opts = ['--delete', q]
         self.needsRefresh = True
         self.qqueueCommand(opts)
Exemple #14
0
 def clearShelfA(self):
     if self.comboa.currentIndex() == 0:
         if not qtlib.QuestionMsgBox(_('Are you sure?'),
                                     _('Revert all working copy changes?')):
             return
         try:
             self.repo.ui.quiet = True
             commands.revert(self.repo.ui, self.repo, all=True)
             self.repo.ui.quiet = False
         except (EnvironmentError, error.Abort), e:
             self.showMessage(hglib.tounicode(str(e)))
             self.refreshCombos()
         return
Exemple #15
0
 def canExit(self):
     if len(self.repo.parents()) == 2:
         main = _('Do you want to exit?')
         text = _('To finish merging, you must commit '
                  'the working directory.\n\n'
                  'To cancel the merge you can update to one '
                  'of the merge parent revisions.')
         labels = ((QMessageBox.Yes, _('&Exit')), (QMessageBox.No,
                                                   _('Cancel')))
         if not qtlib.QuestionMsgBox(
                 _('Confirm Exit'), main, text, labels=labels, parent=self):
             return False
     return True
Exemple #16
0
 def checkGuardsOrComments():
     cont = True
     for p in self.repo.mq.fullseries:
         if '#' in p:
             cont = qtlib.QuestionMsgBox(
                 'Confirm qreorder',
                 _('<p>ATTENTION!<br>'
                   'Guard or comment found.<br>'
                   'Reordering patches will destroy them.<br>'
                   '<br>Continue?</p>'),
                 parent=self,
                 defaultbutton=QMessageBox.No)
             break
     return cont
Exemple #17
0
def checkForRejects(repo, rawoutput, parent=None):
    """Parse output of qpush/qpop to resolve hunk failure manually"""
    rejre = re.compile('saving rejects to file (.*).rej')
    for m in rejre.finditer(rawoutput):
        wfile = m.groups()[0]
        if not os.path.exists(repo.wjoin(wfile)):
            continue
        ufile = hglib.tounicode(wfile)
        if qtlib.QuestionMsgBox(_('Manually resolve rejected chunks?'),
                                _('%s had rejected chunks, edit patched '
                                  'file together with rejects?') % ufile,
                                parent=parent):
            dlg = rejects.RejectsDialog(repo.wjoin(wfile), parent)
            dlg.exec_()
Exemple #18
0
    def strip(self):
        # Note that we have discussed that --hidden should only be passed to
        # mercurial commands when hidden revisions are shown.
        # However in the case of strip we can always pass it --hidden safely,
        # since strip will always strip all the descendants of a revision.
        # Thus in this case --hidden will just let us choose a hidden revision
        # as the base revision to strip.
        cmdline = [
            'strip', '--repository', self.repo.root, '--verbose', '--hidden'
        ]
        rev = hglib.fromunicode(self.rev_combo.currentText())
        if not rev:
            return
        cmdline.append(rev)

        if self.discard_chk.isChecked():
            cmdline.append('--force')
        else:
            try:
                node = self.repo[rev]
            except (error.LookupError, error.RepoLookupError, error.RepoError):
                return

            def isclean():
                """return whether WD is changed"""
                wc = self.repo[None]
                return not (wc.modified() or wc.added() or wc.removed())

            if not isclean():
                main = _("Detected uncommitted local changes.")
                text = _("Do you want to discard them and continue?")
                labels = ((QMessageBox.Yes, _('&Yes (--force)')),
                          (QMessageBox.No, _('&No')))
                if qtlib.QuestionMsgBox(_('Confirm Strip'),
                                        main,
                                        text,
                                        labels=labels,
                                        parent=self):
                    cmdline.append('--force')
                else:
                    return

        # backup options
        if self.nobackup_chk.isChecked():
            cmdline.append('--nobackup')

        # start the strip
        self.repo.incrementBusyCount()
        self.cmd.run(cmdline)
Exemple #19
0
 def qqueuePurge(self):
     uq = self.ql.item(self.ql.currentRow()).text()
     q = hglib.fromunicode(uq)
     if q == 'patches':
         return
     if qtlib.QuestionMsgBox(
             _('Confirm patch queue purge'),
             _("<p>This will also erase the patchfiles on disk!</p>"
               "<p>Do you really want to purge patch queue '%s' ?</p>") %
             uq,
             parent=self,
             defaultbutton=QMessageBox.No):
         opts = ['--purge', q]
         self.needsRefresh = True
         self.qqueueCommand(opts)
Exemple #20
0
 def validatePage(self):
     '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.otherCsInfo.get_data('revid')),
                 labels=labels,
                 parent=self):
             return False
     return super(SummaryPage, self).validatePage()
Exemple #21
0
 def checkForRejects(self, ret):
     if ret is 0:
         self.refreshStatus()
         return
     rejre = re.compile('saving rejects to file (.*).rej')
     for m in rejre.finditer(self.cmd.core.rawoutput()):
         wfile = m.groups()[0]
         if not os.path.exists(self.repo.wjoin(wfile)):
             continue
         ufile = hglib.tounicode(wfile)
         if qtlib.QuestionMsgBox(_('Manually resolve rejected chunks?'),
                                 _('%s had rejected chunks, edit patched '
                                   'file together with rejects?') % ufile,
                                 parent=self):
             dlg = rejects.RejectsDialog(self.repo.wjoin(wfile), self)
             dlg.exec_()
     self.refreshStatus()
Exemple #22
0
    def onLinkActivated(self, cmd):
        cmd = hglib.fromunicode(cmd)
        repo = self.repo
        if cmd == 'commit':
            from tortoisehg.hgqt import commit
            dlg = commit.CommitDialog(repo, [], {}, self)
            dlg.finished.connect(dlg.deleteLater)
            dlg.exec_()
            self.refresh()
        elif cmd == 'shelve':
            from tortoisehg.hgqt import shelve
            dlg = shelve.ShelveDialog(repo, self.wizard())
            dlg.finished.connect(dlg.deleteLater)
            dlg.exec_()
            self.refresh()
        elif cmd.startswith('discard'):
            if cmd != 'discard:noconfirm':
                labels = [(QMessageBox.Yes, _('&Discard')),
                          (QMessageBox.No, _('Cancel'))]
                if not qtlib.QuestionMsgBox(
                        _('Confirm Discard'),
                        _('Discard outstanding changes to working directory?'),
                        labels=labels,
                        parent=self):
                    return

            def finished(ret):
                repo.decrementBusyCount()
                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 == 'view':
            dlg = status.StatusDialog(repo, [], {}, self)
            dlg.exec_()
            self.refresh()
        elif cmd == 'skip':
            self.wizard().next()
        else:
            raise 'unknown command: %s' % cmd
Exemple #23
0
 def eng_toggled(checked):
     if self.isComplete():
         oldmsg = self.msgEntry.text()
         if self.wizard().backoutmergeparentrev:
             msgset = i18n.keepgettext()._(
                 'Backed out merge changeset: ')
         else:
             msgset = i18n.keepgettext()._('Backed out changeset: ')
         msg = checked and msgset['id'] or msgset['str']
         if oldmsg and oldmsg != msg:
             if not qtlib.QuestionMsgBox(
                     _('Confirm Discard Message'),
                     _('Discard current backout message?'),
                     parent=self):
                 self.engChk.blockSignals(True)
                 self.engChk.setChecked(not checked)
                 self.engChk.blockSignals(False)
                 return
         self.msgEntry.setText(msg +
                               str(self.repo[self.wizard().backoutrev]))
         self.msgEntry.moveCursorToEnd()
 def removeSelected(self):
     'remove selected repository'
     s = self.selitem
     item = s.internalPointer()
     if 'remove' not in item.menulist():  # check capability
         return
     if not item.okToDelete():
         labels = [(QMessageBox.Yes, _('&Delete')),
                   (QMessageBox.No, _('Cancel'))]
         if not qtlib.QuestionMsgBox(
                 _('Confirm Delete'),
                 _("Delete Group '%s' and all its entries?") % item.name,
                 labels=labels,
                 parent=self):
             return
     m = self.model()
     row = s.row()
     parent = s.parent()
     m.removeRows(row, 1, parent)
     self.selectionChanged(None, None)
     self.updateSettingsFile.emit()
Exemple #25
0
    def rename(self):
        """execute the rename"""

        # check inputs
        src = self.get_src()
        dest = self.get_dest()
        if not os.path.exists(src):
            qtlib.WarningMsgBox(self.msgTitle, _('Source does not exists.'))
            return
        fullsrc = os.path.abspath(src)
        if not fullsrc.startswith(self.repo.root):
            qtlib.ErrorMsgBox(self.errTitle,
                    _('The source must be within the repository tree.'))
            return
        fulldest = os.path.abspath(dest)
        if not fulldest.startswith(self.repo.root):
            qtlib.ErrorMsgBox(self.errTitle,
                    _('The destination must be within the repository tree.'))
            return
        if src == dest:
            qtlib.ErrorMsgBox(self.errTitle,
                    _('Please give a destination that differs from the source'))
            return
        if (os.path.isfile(dest) and not self.isCaseFoldingOnWin()):
            res = qtlib.QuestionMsgBox(self.msgTitle, '<p>%s</p><p>%s</p>' %
                    (_('Destination file already exists.'),
                    _('Are you sure you want to overwrite it ?')),
                    defaultbutton=QMessageBox.No)
            if not res:
                return
        if self.isCaseFoldingOnWin() and self.copy_chk.isChecked():
            qtlib.ErrorMsgBox(self.errTitle,
                _('Cannot do a pure casefolding copy on Windows'))
            return

        cmdline = self.compose_command(src, dest)
        self.show_command(cmdline)
        self.cmd.run(cmdline)
Exemple #26
0
 def newHook(self):
     td = HookConfigDialog(self)
     res = td.exec_()
     if res:
         hooktype, command, hookname = td.value()
         # Does the new hook already exist?
         hooks = self.value()
         if hooktype in hooks:
             existingcommand = hooks[hooktype].get(hookname, None)
             if existingcommand is not None:
                 if existingcommand == command:
                     # The command already exists "as is"!
                     return
                 if not qtlib.QuestionMsgBox(
                         _('Replace existing hook?'),
                         _('There is an existing %s.%s hook.\n\n'
                           'Do you want to replace it?') %
                     (hooktype, hookname),
                         parent=self):
                     return
                 # Delete existing matching hooks in reverse order
                 # (otherwise the row numbers will be wrong after the first
                 # deletion)
                 for r in reversed(
                         self.findHooks(hooktype=hooktype,
                                        hookname=hookname)):
                     self.deleteHook(r)
         self.hooktable.setSortingEnabled(False)
         row = self.hooktable.rowCount()
         self.hooktable.insertRow(row)
         for c, text in enumerate((hooktype, hookname, command)):
             self.hooktable.setItem(row, c, QTableWidgetItem(text))
         # Make the hook column not editable (a dialog is used to edit it)
         itemhook = self.hooktable.item(row, 0)
         itemhook.setFlags(itemhook.flags() & ~Qt.ItemIsEditable)
         self.hooktable.setSortingEnabled(True)
         self.hooktable.resizeColumnsToContents()
         self.updatebuttons()
Exemple #27
0
    def update(self):
        self.saveSettings()
        cmdline = ['update', '--repository', self.repo.root]
        if self.verbose_chk.isChecked():
            cmdline += ['--verbose']
        cmdline += [
            '--config', 'ui.merge=internal:' +
            (self.autoresolve_chk.isChecked() and 'merge' or 'fail')
        ]
        rev = hglib.fromunicode(self.rev_combo.currentText())

        activatebookmarkmode = self.repo.ui.config('tortoisehg',
                                                   'activatebookmarks',
                                                   'prompt')
        if activatebookmarkmode != 'never':
            bookmarks = self.repo[rev].bookmarks()
            if bookmarks and rev not in bookmarks:
                # The revision that we are updating into has bookmarks,
                # but the user did not refer to the revision by one of them
                # (probably used a revision number or hash)
                # Ask the user if it wants to update to one of these bookmarks
                # instead
                selectedbookmark = None
                if len(bookmarks) == 1:
                    if activatebookmarkmode == 'auto':
                        activatebookmark = True
                    else:
                        activatebookmark = qtlib.QuestionMsgBox(
                            _('Activate bookmark?'),
                            _('The selected revision (%s) has a bookmark on it '
                            'called "<i>%s</i>".<p>Do you want to activate it?'
                            '<br></b><i>You can disable this prompt by configuring '
                            'Settings/Workbench/Activate Bookmarks</i>') \
                            % (hglib.tounicode(rev), bookmarks[0]))
                    if activatebookmark:
                        selectedbookmark = bookmarks[0]
                else:
                    # Even in auto mode, when there is more than one bookmark
                    # we must ask the user which one must be activated
                    selectedbookmark = qtlib.ChoicePrompt(
                        _('Activate bookmark?'),
                        _('The selected revision (<i>%s</i>) has <i>%d</i> '
                        'bookmarks on it.<p>Select the bookmark that you want '
                        'to activate and click <i>OK</i>.<p>Click <i>Cancel</i> '
                        'if you don\'t want to activate any of them.<p>'
                        '<p><i>You can disable this prompt by configuring '
                        'Settings/Workbench/Activate Bookmarks</i><p>') \
                        % (hglib.tounicode(rev), len(bookmarks)),
                        self, bookmarks, self.repo._bookmarkcurrent).run()
                if selectedbookmark:
                    rev = selectedbookmark
                elif self.repo[rev] == self.repo[self.repo._bookmarkcurrent]:
                    deactivatebookmark = qtlib.QuestionMsgBox(
                        _('Deactivate current bookmark?'),
                        _('Do you really want to deactivate the <i>%s</i> '
                          'bookmark?') % self.repo._bookmarkcurrent)
                    if deactivatebookmark:
                        cmdline = ['bookmark', '--repository', self.repo.root]
                        if self.verbose_chk.isChecked():
                            cmdline += ['--verbose']
                        cmdline += ['-i', self.repo._bookmarkcurrent]
                        self.repo.incrementBusyCount()
                        self.cmd.run(cmdline)
                    return

        cmdline.append('--rev')
        cmdline.append(rev)

        if self.discard_chk.isChecked():
            cmdline.append('--clean')
        else:
            cur = self.repo['.']
            try:
                node = self.repo[rev]
            except (error.LookupError, error.RepoLookupError, error.RepoError):
                return

            def isclean():
                '''whether WD is changed'''
                try:
                    wc = self.repo[None]
                    if wc.modified() or wc.added() or wc.removed():
                        return False
                    for s in wc.substate:
                        if wc.sub(s).dirty():
                            return False
                except EnvironmentError:
                    return False
                return True

            def ismergedchange():
                '''whether the local changes are merged (have 2 parents)'''
                wc = self.repo[None]
                return len(wc.parents()) == 2

            def iscrossbranch(p1, p2):
                '''whether p1 -> p2 crosses branch'''
                pa = p1.ancestor(p2)
                return p1.branch() != p2.branch() or (p1 != pa and p2 != pa)

            def islocalmerge(p1, p2, clean=None):
                if clean is None:
                    clean = isclean()
                pa = p1.ancestor(p2)
                return not clean and (p1 == pa or p2 == pa)

            def confirmupdate(clean=None):
                if clean is None:
                    clean = isclean()

                msg = _('Detected uncommitted local changes in working tree.\n'
                        'Please select to continue:\n')
                data = {
                    'discard':
                    (_('&Discard'),
                     _('Discard - discard local changes, no backup')),
                    'shelve': (_('&Shelve'),
                               _('Shelve - move local changes to a patch')),
                    'merge': (_('&Merge'),
                              _('Merge - allow to merge with local changes')),
                }

                opts = ['discard']
                if not ismergedchange():
                    opts.append('shelve')
                if islocalmerge(cur, node, clean):
                    opts.append('merge')

                dlg = QMessageBox(QMessageBox.Question, _('Confirm Update'),
                                  '', QMessageBox.Cancel, self)
                buttonnames = {}
                for name in opts:
                    label, desc = data[name]
                    msg += '\n'
                    msg += desc
                    btn = dlg.addButton(label, QMessageBox.ActionRole)
                    buttonnames[btn] = name
                dlg.setDefaultButton(QMessageBox.Cancel)
                dlg.setText(msg)
                dlg.exec_()
                clicked = buttonnames.get(dlg.clickedButton())
                return clicked

            # If merge-by-default, we want to merge whenever possible,
            # without prompting user (similar to command-line behavior)
            defaultmerge = self.merge_chk.isChecked()
            clean = isclean()
            if clean:
                cmdline.append('--check')
            elif not (defaultmerge and islocalmerge(cur, node, clean)):
                clicked = confirmupdate(clean)
                if clicked == 'discard':
                    cmdline.append('--clean')
                elif clicked == 'shelve':
                    from tortoisehg.hgqt import shelve
                    dlg = shelve.ShelveDialog(self._repoagent, self)
                    dlg.finished.connect(dlg.deleteLater)
                    dlg.exec_()
                    return
                elif clicked == 'merge':
                    pass  # no args
                else:
                    return

        # start updating
        self.repo.incrementBusyCount()
        self.cmd.run(cmdline)
Exemple #28
0
class ChunksWidget(QWidget):

    linkActivated = pyqtSignal(QString)
    showMessage = pyqtSignal(QString)
    chunksSelected = pyqtSignal(bool)
    fileSelected = pyqtSignal(bool)
    fileModelEmpty = pyqtSignal(bool)
    fileModified = pyqtSignal()

    contextmenu = None

    def __init__(self, repo, parent, multiselectable):
        QWidget.__init__(self, parent)

        self.repo = repo
        self.multiselectable = multiselectable
        self.currentFile = None

        layout = QVBoxLayout(self)
        layout.setSpacing(0)
        layout.setMargin(0)
        layout.setContentsMargins(2, 2, 2, 2)
        self.setLayout(layout)

        self.splitter = QSplitter(self)
        self.splitter.setOrientation(Qt.Vertical)
        self.splitter.setChildrenCollapsible(False)
        self.layout().addWidget(self.splitter)

        self.filelist = filelistview.HgFileListView(repo, self,
                                                    multiselectable)
        self.filelistmodel = filelistmodel.HgFileListModel(self)
        self.filelist.setModel(self.filelistmodel)
        self.filelist.setContextMenuPolicy(Qt.CustomContextMenu)
        self.filelist.customContextMenuRequested.connect(self.menuRequest)
        self.filelist.doubleClicked.connect(self.vdiff)

        self.fileListFrame = QFrame(self.splitter)
        self.fileListFrame.setFrameShape(QFrame.NoFrame)
        vbox = QVBoxLayout()
        vbox.setSpacing(0)
        vbox.setMargin(0)
        vbox.addWidget(self.filelist)
        self.fileListFrame.setLayout(vbox)

        self.diffbrowse = DiffBrowser(self.splitter)
        self.diffbrowse.setFont(qtlib.getfont('fontdiff').font())
        self.diffbrowse.showMessage.connect(self.showMessage)
        self.diffbrowse.linkActivated.connect(self.linkActivated)
        self.diffbrowse.chunksSelected.connect(self.chunksSelected)

        self.filelist.fileSelected.connect(self.displayFile)
        self.filelist.clearDisplay.connect(self.diffbrowse.clearDisplay)

        self.splitter.setStretchFactor(0, 0)
        self.splitter.setStretchFactor(1, 3)
        self.timerevent = self.startTimer(500)

        self._actions = {}
        for name, desc, icon, key, tip, cb in [
            ('diff', _('Visual Diff'), 'visualdiff', 'Ctrl+D',
             _('View file changes in external diff tool'), self.vdiff),
            ('edit', _('Edit Local'), 'edit-file', 'Shift+Ctrl+L',
             _('Edit current file in working copy'), self.editCurrentFile),
            ('revert', _('Revert to Revision'), 'hg-revert', 'Shift+Ctrl+R',
             _('Revert file(s) to contents at this revision'),
             self.revertfile),
        ]:
            act = QAction(desc, self)
            if icon:
                act.setIcon(qtlib.geticon(icon))
            if key:
                act.setShortcut(key)
            if tip:
                act.setStatusTip(tip)
            if cb:
                act.triggered.connect(cb)
            self._actions[name] = act
            self.addAction(act)

    @pyqtSlot(QPoint)
    def menuRequest(self, point):
        actionlist = ['diff', 'edit', 'revert']
        if not self.contextmenu:
            menu = QMenu(self)
            for act in actionlist:
                menu.addAction(self._actions[act])
            self.contextmenu = menu
        self.contextmenu.exec_(self.filelist.viewport().mapToGlobal(point))

    def vdiff(self):
        filenames = self.getSelectedFiles()
        if len(filenames) == 0:
            return
        opts = {'change': self.ctx.rev()}
        dlg = visdiff.visualdiff(self.repo.ui, self.repo, filenames, opts)
        if dlg:
            dlg.exec_()

    def revertfile(self):
        filenames = self.getSelectedFiles()
        if len(filenames) == 0:
            return
        rev = self.ctx.rev()
        if rev is None:
            rev = self.ctx.p1().rev()
        dlg = revert.RevertDialog(self.repo, filenames, rev, self)
        dlg.exec_()
        dlg.deleteLater()

    def timerEvent(self, event):
        'Periodic poll of currently displayed patch or working file'
        if not hasattr(self, 'filelist'):
            return
        ctx = self.ctx
        if ctx is None:
            return
        if isinstance(ctx, patchctx):
            path = ctx._path
            mtime = ctx._mtime
        elif self.currentFile:
            path = self.repo.wjoin(self.currentFile)
            mtime = self.mtime
        else:
            return
        try:
            if os.path.exists(path):
                newmtime = os.path.getmtime(path)
                if mtime != newmtime:
                    self.mtime = newmtime
                    self.refresh()
        except EnvironmentError:
            pass

    def runPatcher(self, fp, wfile, updatestate):
        ui = self.repo.ui.copy()

        class warncapt(ui.__class__):
            def warn(self, msg, *args, **opts):
                self.write(msg)

        ui.__class__ = warncapt

        ok = True
        repo = self.repo
        ui.pushbuffer()
        try:
            eolmode = ui.config('patch', 'eol', 'strict')
            if eolmode.lower() not in patch.eolmodes:
                eolmode = 'strict'
            else:
                eolmode = eolmode.lower()
            # 'updatestate' flag has no effect since hg 1.9
            try:
                ret = patch.internalpatch(ui,
                                          repo,
                                          fp,
                                          1,
                                          files=None,
                                          eolmode=eolmode,
                                          similarity=0)
            except ValueError:
                ret = -1
            if ret < 0:
                ok = False
                self.showMessage.emit(_('Patch failed to apply'))
        except (patch.PatchError, EnvironmentError), err:
            ok = False
            self.showMessage.emit(hglib.tounicode(str(err)))
        rejfilere = re.compile(r'\b%s\.rej\b' % re.escape(wfile))
        for line in ui.popbuffer().splitlines():
            if rejfilere.search(line):
                if qtlib.QuestionMsgBox(_('Manually resolve rejected chunks?'),
                                        hglib.tounicode(line) + u'<br><br>' +
                                        _('Edit patched file and rejects?'),
                                        parent=self):
                    from tortoisehg.hgqt import rejects
                    dlg = rejects.RejectsDialog(repo.wjoin(wfile), self)
                    if dlg.exec_() == QDialog.Accepted:
                        ok = True
                    break
        return ok
Exemple #29
0
 def deleteSelectedChunks(self):
     'delete currently selected chunks'
     repo = self.repo
     chunks = self.diffbrowse.curchunks
     dchunks = [c for c in chunks[1:] if c.selected]
     if not dchunks:
         self.showMessage.emit(_('No deletable chunks'))
         return
     ctx = self.ctx
     kchunks = [c for c in chunks[1:] if not c.selected]
     revertall = False
     if not kchunks:
         if isinstance(ctx, patchctx):
             revertmsg = _('Completely remove file from patch?')
         else:
             revertmsg = _('Revert all file changes?')
         revertall = qtlib.QuestionMsgBox(_('No chunks remain'), revertmsg)
     if isinstance(ctx, patchctx):
         repo.thgbackup(ctx._path)
         fp = util.atomictempfile(ctx._path, 'wb')
         buf = cStringIO.StringIO()
         try:
             if ctx._ph.comments:
                 buf.write('\n'.join(ctx._ph.comments))
                 buf.write('\n\n')
             needsnewline = False
             for wfile in ctx._fileorder:
                 if wfile == self.currentFile:
                     if revertall:
                         continue
                     chunks[0].write(buf)
                     for chunk in kchunks:
                         chunk.write(buf)
                 else:
                     if buf.tell() and buf.getvalue()[-1] != '\n':
                         buf.write('\n')
                     for chunk in ctx._files[wfile]:
                         chunk.write(buf)
             fp.write(buf.getvalue())
             fp.close()
         finally:
             del fp
         ctx.invalidate()
         self.fileModified.emit()
     else:
         path = repo.wjoin(self.currentFile)
         if not os.path.exists(path):
             self.showMessage.emit(_('file has been deleted, refresh'))
             return
         if self.mtime != os.path.getmtime(path):
             self.showMessage.emit(_('file has been modified, refresh'))
             return
         repo.thgbackup(path)
         if revertall:
             commands.revert(repo.ui, repo, path, no_backup=True)
         else:
             wlock = repo.wlock()
             try:
                 # atomictemp can preserve file permission
                 wf = repo.wopener(self.currentFile, 'wb', atomictemp=True)
                 wf.write(self.diffbrowse.origcontents)
                 wf.close()
                 fp = cStringIO.StringIO()
                 chunks[0].write(fp)
                 for c in kchunks:
                     c.write(fp)
                 fp.seek(0)
                 self.runPatcher(fp, self.currentFile, False)
             finally:
                 wlock.release()
         self.fileModified.emit()
Exemple #30
0
        if self.comboa.currentIndex() == 0:
            if not qtlib.QuestionMsgBox(_('Are you sure?'),
                                        _('Revert all working copy changes?')):
                return
            try:
                self.repo.ui.quiet = True
                commands.revert(self.repo.ui, self.repo, all=True)
                self.repo.ui.quiet = False
            except (EnvironmentError, error.Abort), e:
                self.showMessage(hglib.tounicode(str(e)))
                self.refreshCombos()
            return
        shelf = self.currentPatchA()
        ushelf = hglib.tounicode(os.path.basename(shelf))
        if not qtlib.QuestionMsgBox(
                _('Are you sure?'),
                _('Clear contents of shelf file %s?') % ushelf):
            return
        try:
            f = open(shelf, "w")
            f.close()
            self.showMessage(_('Shelf cleared'))
        except EnvironmentError, e:
            self.showMessage(hglib.tounicode(str(e)))
        self.refreshCombos()

    @pyqtSlot()
    def deleteShelfB(self):
        shelf = self.currentPatchB()
        ushelf = hglib.tounicode(os.path.basename(shelf))
        if not qtlib.QuestionMsgBox(_('Are you sure?'),