1# topic.py - Topic dialog for TortoiseHg 2# 3# Copyright 2010 Michal De Wildt <michael.dewildt@gmail.com> 4# 5# This software may be used and distributed according to the terms of the 6# GNU General Public License version 2, incorporated herein by reference. 7 8from __future__ import absolute_import 9 10from mercurial import error 11 12from .qtcore import ( 13 Qt, 14 pyqtSlot, 15) 16from .qtgui import ( 17 QComboBox, 18 QDialog, 19 QDialogButtonBox, 20 QFontMetrics, 21 QFormLayout, 22 QFrame, 23 QLabel, 24 QLayout, 25 QSizePolicy, 26 QVBoxLayout, 27 QWidget, 28) 29 30from mercurial import ( 31 pycompat, 32) 33 34from ..util import hglib 35from ..util.obsoleteutil import first_known_successors 36from ..util.i18n import _ 37from . import ( 38 cmdcore, 39 qtlib, 40) 41 42class TopicDialog(QDialog): 43 44 def __init__(self, repoagent, rev, parent=None): 45 super(TopicDialog, self).__init__(parent) 46 self.setWindowFlags(self.windowFlags() & 47 ~Qt.WindowContextHelpButtonHint) 48 self._repoagent = repoagent 49 repo = repoagent.rawRepo() 50 self._cmdsession = cmdcore.nullCmdSession() 51 self.rev = rev 52 53 # base layout box 54 base = QVBoxLayout() 55 base.setSpacing(0) 56 base.setContentsMargins(*(0,)*4) 57 base.setSizeConstraint(QLayout.SetMinAndMaxSize) 58 self.setLayout(base) 59 60 # main layout grid 61 formwidget = QWidget(self) 62 formwidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) 63 form = QFormLayout(fieldGrowthPolicy=QFormLayout.AllNonFixedFieldsGrow) 64 formwidget.setLayout(form) 65 base.addWidget(formwidget) 66 67 self.revLabel = QLabel() # text is set in self.revUpdated() 68 form.addRow(_('Revision:'), self.revLabel) 69 70 # topic combo 71 self.topicsCombo = QComboBox() 72 self.topicsCombo.setEditable(True) 73 self.topicsCombo.setMinimumContentsLength(30) # cut long name 74 self.topicsCombo.currentIndexChanged.connect(self.topicTextChanged) 75 self.topicsCombo.editTextChanged.connect(self.topicTextChanged) 76 qtlib.allowCaseChangingInput(self.topicsCombo) 77 form.addRow(_('Topic:'), self.topicsCombo) 78 79 # bottom buttons 80 BB = QDialogButtonBox 81 bbox = QDialogButtonBox() 82 self.setBtn = bbox.addButton(_('&Set'), BB.ActionRole) 83 self.clearBtn = bbox.addButton(_('&Clear'), BB.ActionRole) 84 bbox.addButton(BB.Close) 85 bbox.rejected.connect(self.reject) 86 form.addRow(bbox) 87 88 self.setBtn.clicked.connect(self.set_topic) 89 self.clearBtn.clicked.connect(self.clear_topic) 90 91 # horizontal separator 92 self.sep = QFrame() 93 self.sep.setFrameShadow(QFrame.Sunken) 94 self.sep.setFrameShape(QFrame.HLine) 95 self.layout().addWidget(self.sep) 96 97 # status line 98 self.status = qtlib.StatusLabel() 99 self.status.setContentsMargins(4, 2, 4, 4) 100 self.layout().addWidget(self.status) 101 self._finishmsg = None 102 103 # dialog setting 104 self.setWindowTitle(_('Topic - %s') % repoagent.displayName()) 105 self.setWindowIcon(qtlib.geticon('hg-topics')) 106 107 # prepare to show 108 self.clear_status() 109 self.revUpdated() 110 self.refresh() 111 self._repoagent.repositoryChanged.connect(self.refresh) 112 self.topicsCombo.setFocus() 113 self.topicTextChanged() 114 115 def revUpdated(self): 116 if self.rev is None: 117 hasunicodestar = QFontMetrics(self.font()).inFont(u'\u2605') 118 if hasunicodestar: 119 # The Unicode symbol is a black star: 120 revText = u'\u2605 ' + _('Working Directory') + u' \u2605' 121 else: 122 revText = '*** ' + _('Working Directory') + ' ***' 123 else: 124 revText = '%d (%s)' % (self.rev, self.repo[self.rev]) 125 self.revLabel.setText(revText) 126 self.topicsCombo.setEditText(self._current_topic) 127 128 @property 129 def repo(self): 130 return self._repoagent.rawRepo() 131 132 @pyqtSlot() 133 def refresh(self): 134 """Update drop-down list if repo changed.""" 135 cur = self.topicsCombo.currentText() 136 self.topicsCombo.clear() 137 self.topicsCombo.addItems(sorted(map(hglib.tounicode, 138 self.repo.topics))) 139 self.topicsCombo.setEditText(cur) 140 141 @pyqtSlot() 142 def topicTextChanged(self): 143 topic = self.topicsCombo.currentText() 144 self.setBtn.setEnabled(bool(topic)) 145 146 @property 147 def _current_topic(self): 148 return hglib.tounicode(self.repo[self.rev].topic()) 149 150 def setTopicName(self, name): 151 self.topicsCombo.setEditText(name) 152 153 def set_status(self, text, icon=None): 154 self.status.setVisible(True) 155 self.sep.setVisible(True) 156 self.status.set_status(text, icon) 157 158 def clear_status(self): 159 self.status.setHidden(True) 160 self.sep.setHidden(True) 161 162 def _runTopic(self, *args, **opts): 163 self._finishmsg = opts.pop('finishmsg') 164 cmdline = hglib.buildcmdargs('topic', *args, **opts) 165 self._cmdsession = sess = self._repoagent.runCommand(cmdline, self) 166 sess.commandFinished.connect(self._onTopicFinished) 167 168 @pyqtSlot(int) 169 def _onTopicFinished(self, ret): 170 if ret == 0: 171 self.set_status(self._finishmsg, True) 172 else: 173 self.set_status(self._cmdsession.errorString(), False) 174 repo = self.repo.unfiltered() 175 ctx = repo[self.rev] 176 if ctx.extinct(): 177 changes = [x for x in first_known_successors(ctx)] 178 if changes: 179 self.rev = changes[0].rev() 180 self.revUpdated() 181 182 @pyqtSlot() 183 def set_topic(self): 184 topic = pycompat.unicode(self.topicsCombo.currentText()) 185 finishmsg = _("Set topic to '%s'") % topic 186 self._runTopic(topic, rev=self.rev, finishmsg=finishmsg) 187 188 @pyqtSlot() 189 def clear_topic(self): 190 finishmsg = _("Cleared current topic '%s'") % self._current_topic 191 self._runTopic(rev=self.rev, clear=True, finishmsg=finishmsg) 192