Changeset 6192aa5ad61c…
Parent 0fd1168e9dcd…
by
Changes to 4 files · Browse files at 6192aa5ad61c Showing diff from parent 0fd1168e9dcd Diff from another changeset...
@@ -112,6 +112,8 @@ self.showAtRev),
('update', _('Update to rev...'), None, None, None,
self.updateToRev),
+ ('tag', _('Tag to rev...'), None, None, None,
+ self.tagToRev),
]
return a
@@ -140,9 +142,12 @@ def updateToRev(self):
self.emit(SIGNAL('updateToRevision'), self.current_rev)
+ def tagToRev(self):
+ self.emit(SIGNAL('tagToRevision'), self.current_rev)
+
def contextMenuEvent(self, event):
menu = QtGui.QMenu(self)
- for act in ['update', 'manifest', None, 'back', 'forward']:
+ for act in ['update', 'manifest', 'tag', None, 'back', 'forward']:
if act:
menu.addAction(self._actions[act])
else:
|
@@ -21,6 +21,7 @@ from tortoisehg.hgqt.qtlib import geticon
from tortoisehg.hgqt.repomodel import HgRepoListModel
from tortoisehg.hgqt.update import UpdateDialog
+from tortoisehg.hgqt.tag import TagDialog
from tortoisehg.hgqt import cmdui
from tortoisehg.hgqt.config import HgConfig
from tortoisehg.hgqt.manifestdialog import ManifestDialog
@@ -187,6 +188,7 @@ connect(view, SIGNAL('revisionSelected'), self.revision_selected)
connect(view, SIGNAL('revisionActivated'), self.revision_activated)
connect(view, SIGNAL('updateToRevision'), self.updateToRevision)
+ connect(view, SIGNAL('tagToRevision'), self.tagToRevision)
#self.attachQuickBar(view.goto_toolbar)
gotoaction = view.goto_toolbar.toggleViewAction()
gotoaction.setIcon(geticon('goto'))
@@ -227,6 +229,15 @@ dlg.quitsignal.connect(quit)
dlg.show()
+ def tagToRevision(self, rev):
+ saved = self.setScanForRepoChanges(False)
+ dlg = TagDialog(self.repo, rev=str(rev), parent=self)
+ def invalidated():
+ self.reload()
+ self.setScanForRepoChanges(saved)
+ dlg.repoInvalidated.connect(invalidated) # TODO: implement something less drastic than a full reload
+ dlg.show()
+
def revision_selected(self, rev):
if self.repomodel.graph:
ctx = self.repomodel.repo.changectx(rev)
|
@@ -377,6 +377,11 @@ from tortoisehg.hgqt.status import run
qtrun(run, ui, *pats, **opts)
+def tag(ui, *pats, **opts):
+ """clone tool"""
+ from tortoisehg.hgqt.tag import run
+ qtrun(run, ui, *pats, **opts)
+
def test(ui, *pats, **opts):
"""test arbitrary widgets"""
from tortoisehg.hgqt.chunkselect import run
@@ -691,6 +696,14 @@ [('c', 'clean', False, _('show files without changes')),
('i', 'ignored', False, _('show ignored files'))],
_('thg status [OPTIONS] [FILE]')),
+ "^tag":
+ (tag,
+ [('f', 'force', None, _('replace existing tag')),
+ ('l', 'local', None, _('make the tag local')),
+ ('r', 'rev', '', _('revision to tag')),
+ ('', 'remove', None, _('remove a tag')),
+ ('m', 'message', '', _('use <text> as commit message')),],
+ _('thg tag [-f] [-l] [-m TEXT] [-r REV] [NAME]')),
"test": (test, [], _('thg test')),
"help": (help_, [], _('thg help [COMMAND]')),
"^update|checkout|co":
|
|
|
@@ -0,0 +1,331 @@ + # tag.py - Tag dialog for TortoiseHg
+#
+# Copyright 2010 Yuki KODAMA <endflow.net@gmail.com>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2, incorporated herein by reference.
+
+import os
+import traceback
+
+from PyQt4.QtCore import Qt, pyqtSignal
+from PyQt4.QtGui import QDialog, QDialogButtonBox, QVBoxLayout, QHBoxLayout
+from PyQt4.QtGui import QComboBox, QLabel, QLayout, QCheckBox, QGridLayout
+from PyQt4.QtGui import QLineEdit, QFrame
+
+from mercurial import hg, ui, error
+
+from tortoisehg.util import hglib, paths, i18n
+from tortoisehg.hgqt.qtlib import getpixmap
+from tortoisehg.hgqt.i18n import _
+from tortoisehg.hgqt import cmdui, qtlib
+
+keep = i18n.keepgettext()
+
+class TagDialog(QDialog):
+
+ repoInvalidated = pyqtSignal()
+
+ def __init__(self, repo=None, tag='', rev='tip', parent=None, opts=None):
+ super(TagDialog, self).__init__(parent)
+ self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
+
+ self.ui = ui.ui()
+ if repo:
+ self.repo = repo
+ else:
+ root = paths.find_root()
+ if root:
+ self.repo = hg.repository(self.ui, path=root)
+ else:
+ raise 'not repository'
+
+ if not tag and rev and rev != 'tip':
+ bmarks = hglib.get_repo_bookmarks(self.repo)
+ for t in self.repo.nodetags(self.repo[rev].node()):
+ if t != 'tip' \
+ and ((not bmarks) or (bmarks and t not in bmarks)):
+ tag = t
+ break
+ else:
+ tag = ''
+
+ # base layout box
+ base = QVBoxLayout()
+ base.setSpacing(0)
+ base.setContentsMargins(*(0,)*4)
+
+ # main layout box
+ box = QVBoxLayout()
+ box.setSpacing(6)
+ box.setContentsMargins(*(6,)*4)
+ base.addLayout(box)
+
+ ## main layout grid
+ grid = QGridLayout()
+ grid.setSpacing(6)
+ box.addLayout(grid)
+
+ ### tag combo
+ self.tag_combo = QComboBox()
+ self.tag_combo.setEditable(True)
+ self.tag_combo.setMinimumWidth(180)
+ self.tag_combo.setEditText(tag)
+ self.tag_combo.editTextChanged.connect(self.tag_changed)
+ grid.addWidget(QLabel(_('Tag:')), 0, 0)
+ grid.addWidget(self.tag_combo, 0, 1)
+
+ ### revision input
+ self.initial_rev = rev
+ self.rev_text = QLineEdit()
+ self.rev_text.setMaximumWidth(100)
+ self.rev_text.setText(rev)
+ self.rev_text.textEdited.connect(lambda s: self.update_sensitives())
+ grid.addWidget(QLabel(_('Revision:')), 1, 0)
+ grid.addWidget(self.rev_text, 1, 1)
+
+ ### options
+ expander = qtlib.ExpanderLabel(_('Options'), False)
+ expander.expanded.connect(self.show_options)
+ grid.addWidget(expander, 2, 0, 1, 2, Qt.AlignLeft | Qt.AlignTop)
+
+ optbox = QVBoxLayout()
+ optbox.setSpacing(6)
+ grid.addLayout(optbox, 3, 0, 1, 2)
+
+ hbox = QHBoxLayout()
+ hbox.setSpacing(0)
+ optbox.addLayout(hbox)
+
+ self.local_chk = QCheckBox(_('Local tag'))
+ self.local_chk.toggled.connect(self.local_toggled)
+ self.replace_chk = QCheckBox(_('Replace existing tag (-f/--force)'))
+ self.replace_chk.toggled.connect(lambda b: self.update_sensitives())
+ optbox.addWidget(self.local_chk)
+ optbox.addWidget(self.replace_chk)
+
+ self.eng_chk = QCheckBox(_('Use English commit message'))
+ engmsg = self.ui.configbool('tortoisehg', 'engmsg', False)
+ self.eng_chk.setChecked(engmsg)
+ optbox.addWidget(self.eng_chk)
+
+ self.custom_chk = QCheckBox(_('Use custom commit message:'))
+ self.custom_chk.toggled.connect(
+ lambda e: self.toggle_enabled(e, self.custom_text))
+ self.custom_text = QLineEdit()
+ optbox.addWidget(self.custom_chk)
+ optbox.addWidget(self.custom_text)
+
+ ## bottom buttons
+ buttons = QDialogButtonBox()
+ self.close_btn = buttons.addButton(QDialogButtonBox.Close)
+ self.close_btn.clicked.connect(self.reject)
+ self.add_btn = buttons.addButton(_('&Add'),
+ QDialogButtonBox.ActionRole)
+ self.add_btn.clicked.connect(self.add_tag)
+ self.remove_btn = buttons.addButton(_('&Remove'),
+ QDialogButtonBox.ActionRole)
+ self.remove_btn.clicked.connect(self.remove_tag)
+ box.addWidget(buttons)
+
+ ## horizontal separator
+ self.sep = QFrame()
+ self.sep.setFrameShadow(QFrame.Sunken)
+ self.sep.setFrameShape(QFrame.HLine)
+ base.addWidget(self.sep)
+
+ ## status line
+ self.status = qtlib.StatusLabel()
+ self.status.setContentsMargins(4, 2, 4, 4)
+ base.addWidget(self.status)
+
+ # dialog setting
+ self.setLayout(base)
+ self.layout().setSizeConstraint(QLayout.SetFixedSize)
+ reponame = hglib.get_reponame(self.repo)
+ self.setWindowTitle(_('Tag - %s') % hglib.tounicode(reponame))
+
+ # prepare to show
+ self.custom_text.setDisabled(True)
+ self.clear_statue()
+ self.update_tagcombo(clear=False)
+ self.update_sensitives(affectlocal=True)
+ self.show_options(False)
+ self.tag_combo.setFocus()
+
+ self.replace_chk.setChecked(bool(opts['force']))
+ self.local_chk.setChecked(bool(opts['local']))
+ if not opts['local'] and opts['message']:
+ self.custom_chk.setChecked(True)
+ self.custom_text.setText(opts['message'])
+
+ ### Private Methods ###
+
+ def update_tagcombo(self, clear=True):
+ """ update display on dialog with recent repo data """
+ self.repo.invalidate()
+ tag_name = self.tag_combo.currentText()
+ self.tag_combo.clear()
+
+ # add tags to drop-down list
+ tags = list(self.repo.tags())
+ tags.sort()
+ tags.reverse()
+ for tag in tags:
+ if tag == 'tip':
+ continue
+ self.tag_combo.addItem(hglib.tounicode(tag))
+ self.tag_combo.clearEditText()
+
+ # restore tag name
+ if not clear and tag_name:
+ self.tag_combo.setEditText(tag_name)
+
+ def update_sensitives(self, affectlocal=False):
+ """ update bottom button sensitives based on rev and tag """
+ tag = self.tag_combo.currentText()
+ rev = self.rev_text.text()
+ if not rev or not tag:
+ self.add_btn.setDisabled(True)
+ self.remove_btn.setDisabled(True)
+ return
+
+ # check if valid revision
+ try:
+ self.repo[hglib.fromunicode(rev)]
+ except (error.LookupError, error.RepoLookupError, error.RepoError):
+ self.add_btn.setDisabled(True)
+ self.remove_btn.setDisabled(True)
+ return
+
+ # check tag existence
+ force = self.replace_chk.isChecked()
+ is_exist = hglib.fromunicode(tag) in self.repo.tags()
+ self.add_btn.setEnabled(not is_exist or force)
+ self.remove_btn.setEnabled(is_exist)
+
+ # check if local
+ is_local = self.repo.tagtype(hglib.fromunicode(tag))
+ if affectlocal and is_local is not None:
+ self.local_chk.setChecked(is_local == 'local')
+ self.update_revision()
+
+ def update_revision(self):
+ """ update revision entry based on tag """
+ tagmap = self.repo.tags()
+ tag = self.tag_combo.currentText()
+ replace = self.replace_chk.isChecked()
+ if not tag or hglib.fromunicode(tag) not in tagmap or replace:
+ if self.initial_rev:
+ self.rev_text.setText(self.initial_rev)
+ return
+
+ node = tagmap[hglib.fromunicode(tag)]
+ ctx = self.repo[node]
+ self.rev_text.setText(unicode(ctx.rev()))
+
+ def show_options(self, visible):
+ self.local_chk.setVisible(visible)
+ self.replace_chk.setVisible(visible)
+ self.eng_chk.setVisible(visible)
+ self.custom_chk.setVisible(visible)
+ self.custom_text.setVisible(visible)
+
+ def set_status(self, text, icon=None):
+ self.status.setShown(True)
+ self.sep.setShown(True)
+ self.status.set_status(text, icon)
+
+ def clear_statue(self):
+ self.status.setHidden(True)
+ self.sep.setHidden(True)
+
+ def add_tag(self):
+ local = self.local_chk.isChecked()
+ name = self.tag_combo.currentText()
+ lname = hglib.fromunicode(name)
+ rev = hglib.fromunicode(self.rev_text.text())
+ force = self.replace_chk.isChecked()
+ english = self.eng_chk.isChecked()
+ message = hglib.fromunicode(self.custom_text.text())
+
+ try:
+ # tagging
+ if lname in self.repo.tags() and not force:
+ raise util.Abort(_("Tag '%s' already exist") % name)
+ ctx = self.repo[rev]
+ node = ctx.node()
+ if not message:
+ msgset = keep._('Added tag %s for changeset %s')
+ message = (english and msgset['id'] or msgset['str']) \
+ % (name, str(ctx))
+ self.repo.tag(lname, node, message, local, None, None)
+
+ # update UI
+ self.set_status(_("Tag '%s' has been added") % name, True)
+ self.update_tagcombo()
+ self.close_btn.setFocus()
+ self.repoInvalidated.emit()
+
+ except:
+ self.set_status(_('Error in tagging'), False)
+ print traceback.format_exc()
+
+ def remove_tag(self):
+ local = self.local_chk.isChecked()
+ name = self.tag_combo.currentText()
+ lname = hglib.fromunicode(name)
+ english = self.eng_chk.isChecked()
+ message = hglib.fromunicode(self.custom_text.text())
+
+ try:
+ # tagging
+ tagtype = self.repo.tagtype(lname)
+ if local:
+ if tagtype != 'local':
+ raise util.Abort(_('tag \'%s\' is not a local tag') % lname)
+ else:
+ if tagtype != 'global':
+ raise util.Abort(_('tag \'%s\' is not a global tag') % lname)
+ if not message:
+ msgset = keep._('Removed tag %s')
+ message = (english and msgset['id'] or msgset['str']) % name
+ node = self.repo[-1].node()
+ self.repo.tag(lname, node, message, local, None, None)
+
+ # update UI
+ self.set_status(_("Tag '%s' has been removed") % name, True)
+ self.update_tagcombo()
+ self.close_btn.setFocus()
+ self.repoInvalidated.emit()
+
+ except:
+ self.set_status(_('Error in tagging'), False)
+ print traceback.format_exc()
+
+ ### Signal Handlers ###
+
+ def local_toggled(self, checked):
+ self.eng_chk.setEnabled(not checked)
+ self.custom_chk.setEnabled(not checked)
+ custom = self.custom_chk.isChecked()
+ self.custom_text.setEnabled(not checked and custom)
+
+ def tag_changed(self, combo):
+ self.update_revision()
+ self.update_sensitives(True)
+
+ def toggle_enabled(self, checked, target):
+ target.setEnabled(checked)
+ if checked:
+ target.setFocus()
+
+def run(ui, *pats, **opts):
+ kargs = {}
+ tag = len(pats) > 0 and pats[0] or None
+ if tag:
+ kargs['tag'] = tag
+ rev = opts.get('rev')
+ if rev:
+ kargs['rev'] = rev
+ return TagDialog(opts=opts, **kargs)
|
Loading...