2 from PyQt4
import QtCore
3 from PyQt4
import QtGui
4 from PyQt4
.QtCore
import SIGNAL
8 from cola
import gitcfg
9 from cola
import gitcmds
11 from cola
import qtutils
12 from cola
import signals
13 from cola
.views
import revselect
14 from cola
.views
import standard
17 def install_command_wrapper(parent
):
18 cmd_wrapper
= ActionCommandWrapper(parent
)
19 cola
.factory().add_command_wrapper(cmd_wrapper
)
22 def get_config_actions():
23 cfg
= gitcfg
.instance()
24 names
= cfg
.get_guitool_names()
28 def run_command(parent
, title
, command
):
29 """Show a command widget"""
31 view
= GitCommandWidget(parent
)
32 view
.setWindowModality(QtCore
.Qt
.ApplicationModal
)
33 view
.set_command(command
)
34 view
.setWindowTitle(title
)
36 qtutils
.center_on_screen(view
)
41 return (view
.exitstatus
, view
.out
, view
.err
)
44 class GitCommandWidget(standard
.StandardDialog
):
45 """Nice TextView that reads the output of a command syncronously"""
46 # Keep us in scope otherwise PyQt kills the widget
47 def __init__(self
, parent
=None):
48 standard
.StandardDialog
.__init
__(self
, parent
=parent
)
51 # Construct the process
52 self
.proc
= QtCore
.QProcess(self
)
57 self
._layout
= QtGui
.QVBoxLayout(self
)
58 self
._layout
.setContentsMargins(3, 3, 3, 3)
60 # Create the text browser
61 self
.output_text
= QtGui
.QTextBrowser(self
)
62 self
.output_text
.setAcceptDrops(False)
63 self
.output_text
.setTabChangesFocus(True)
64 self
.output_text
.setUndoRedoEnabled(False)
65 self
.output_text
.setReadOnly(True)
66 self
.output_text
.setAcceptRichText(False)
68 self
._layout
.addWidget(self
.output_text
)
70 # Create abort / close buttons
71 self
.button_abort
= QtGui
.QPushButton(self
)
72 self
.button_abort
.setText(self
.tr('Abort'))
73 self
.button_close
= QtGui
.QPushButton(self
)
74 self
.button_close
.setText(self
.tr('Close'))
76 # Put them in a horizontal layout at the bottom.
77 self
.button_box
= QtGui
.QDialogButtonBox(self
)
78 self
.button_box
.addButton(self
.button_abort
, QtGui
.QDialogButtonBox
.RejectRole
)
79 self
.button_box
.addButton(self
.button_close
, QtGui
.QDialogButtonBox
.AcceptRole
)
80 self
._layout
.addWidget(self
.button_box
)
82 # Connect the signals to the process
83 self
.connect(self
.proc
, SIGNAL('readyReadStandardOutput()'), self
.readOutput
)
84 self
.connect(self
.proc
, SIGNAL('readyReadStandardError()'), self
.readErrors
)
85 self
.connect(self
.proc
, SIGNAL('finished(int)'), self
.finishProc
)
86 self
.connect(self
.proc
, SIGNAL('stateChanged(QProcess::ProcessState)'), self
.stateChanged
)
88 # Connect the signlas to the buttons
89 self
.connect(self
.button_abort
, SIGNAL('clicked()'), self
.abortProc
)
90 self
.connect(self
.button_close
, SIGNAL('clicked()'), self
.close
)
91 # Start with abort disabled - will be enabled when the process is run.
92 self
.button_abort
.setEnabled(False)
94 def set_command(self
, command
):
95 self
.command
= command
98 """Runs the process"""
99 self
.proc
.start(self
.command
[0], QtCore
.QStringList(self
.command
[1:]))
101 def readOutput(self
):
102 rawbytes
= self
.proc
.readAllStandardOutput()
107 self
.append_text(data
)
109 def readErrors(self
):
110 rawbytes
= self
.proc
.readAllStandardError()
115 self
.append_text(data
)
117 def append_text(self
, txt
):
118 cursor
= self
.output_text
.textCursor()
119 cursor
.movePosition(cursor
.End
)
120 cursor
.insertText(core
.decode(txt
))
121 cursor
.movePosition(cursor
.End
)
122 self
.output_text
.setTextCursor(cursor
)
125 if self
.proc
.state() != QtCore
.QProcess
.NotRunning
:
126 # Terminate seems to do nothing in windows
127 self
.proc
.terminate()
129 QtCore
.QTimer
.singleShot(1000, self
.proc
, QtCore
.SLOT('kill()'))
131 def closeEvent(self
, event
):
132 if self
.proc
.state() != QtCore
.QProcess
.NotRunning
:
133 # The process is still running, make sure we really want to abort.
134 reply
= QtGui
.QMessageBox
.question(self
, 'Message',
135 self
.tr('Abort process?'),
136 QtGui
.QMessageBox
.Yes
, QtGui
.QMessageBox
.No
)
137 if reply
== QtGui
.QMessageBox
.Yes
:
145 def stateChanged(self
, newstate
):
146 # State of process has changed - change the abort button state.
147 if newstate
== QtCore
.QProcess
.NotRunning
:
148 self
.button_abort
.setEnabled(False)
150 self
.button_abort
.setEnabled(True)
152 def finishProc(self
, status
):
153 self
.exitstatus
= status
156 class ActionCommandWrapper(object):
157 def __init__(self
, parent
):
160 signals
.run_config_action
: self
._run
_config
_action
,
161 signals
.run_command
: self
._run
_command
,
164 def _run_command(self
, title
, cmd
):
165 return run_command(self
.parent
, title
, cmd
)
167 def _run_config_action(self
, name
, opts
):
168 dlg
= ActionDialog(self
.parent
, name
, opts
)
170 if dlg
.exec_() != QtGui
.QDialog
.Accepted
:
172 rev
= unicode(dlg
.revision())
174 opts
['revision'] = rev
175 args
= unicode(dlg
.args())
181 class ActionDialog(standard
.StandardDialog
):
182 def __init__(self
, parent
, name
, opts
):
183 standard
.StandardDialog
.__init
__(self
, parent
)
187 self
.layt
= QtGui
.QVBoxLayout()
188 self
.layt
.setMargin(10)
189 self
.setLayout(self
.layt
)
191 title
= opts
.get('title')
193 self
.setWindowTitle(os
.path
.expandvars(title
))
195 self
.prompt
= QtGui
.QLabel()
197 prompt
= opts
.get('prompt')
199 self
.prompt
.setText(os
.path
.expandvars(prompt
))
200 self
.layt
.addWidget(self
.prompt
)
203 self
.argslabel
= QtGui
.QLabel()
204 if 'argprompt' not in opts
or opts
.get('argprompt') is True:
205 argprompt
= qtutils
.tr('Arguments')
207 argprompt
= opts
.get('argprompt')
209 self
.argslabel
.setText(argprompt
)
211 self
.argstxt
= QtGui
.QLineEdit()
212 self
.argslayt
= QtGui
.QHBoxLayout()
213 self
.argslayt
.addWidget(self
.argslabel
)
214 self
.argslayt
.addWidget(self
.argstxt
)
215 self
.layt
.addLayout(self
.argslayt
)
217 if not self
.opts
.get('argprompt'):
218 self
.argslabel
.setMinimumSize(1, 1)
219 self
.argstxt
.setMinimumSize(1, 1)
221 self
.argslabel
.hide()
224 ('Local Branch', gitcmds
.branch_list(remote
=False)),
225 ('Tracking Branch', gitcmds
.branch_list(remote
=True)),
226 ('Tag', gitcmds
.tag_list()),
229 if 'revprompt' not in opts
or opts
.get('revprompt') is True:
230 revprompt
= qtutils
.tr('Revision')
232 revprompt
= opts
.get('revprompt')
233 self
.revselect
= revselect
.RevisionSelector(self
, revs
=revs
)
234 self
.revselect
.set_revision_label(revprompt
)
235 self
.layt
.addWidget(self
.revselect
)
237 if not opts
.get('revprompt'):
238 self
.revselect
.hide()
241 self
.btnlayt
= QtGui
.QHBoxLayout()
242 self
.btnspacer
= QtGui
.QSpacerItem(1, 1,
243 QtGui
.QSizePolicy
.MinimumExpanding
,
244 QtGui
.QSizePolicy
.Minimum
)
245 self
.btnlayt
.addItem(self
.btnspacer
)
246 self
.closebtn
= qt
.create_button(self
.tr('Close'), self
.btnlayt
)
247 self
.runbtn
= qt
.create_button(self
.tr('Run'), self
.btnlayt
)
248 self
.runbtn
.setDefault(True)
249 self
.layt
.addLayout(self
.btnlayt
)
251 self
.connect(self
.closebtn
, SIGNAL('clicked()'), self
.reject
)
252 self
.connect(self
.runbtn
, SIGNAL('clicked()'), self
.accept
)
254 # Widen the dialog by default
255 self
.resize(666, self
.height())
258 return self
.revselect
.revision()
261 return self
.argstxt
.text()