|
# status.py - working copy browser
#
# Copyright 2010 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.
import os
from mercurial import ui, hg, util, patch, cmdutil, error, mdiff
from mercurial import context, merge, commands, subrepo
from tortoisehg.hgqt import qtlib, htmlui, chunkselect, wctxactions, visdiff
from tortoisehg.util import paths, hglib
from tortoisehg.util.util import xml_escape
from tortoisehg.hgqt.i18n import _
from PyQt4.QtCore import *
from PyQt4.QtGui import *
# This widget can be used as the basis of the commit tool or any other
# working copy browser.
# Technical Debt
# We need a real icon set for file status types
# Thread rowSelected, connect to an external progress bar
# Chunk selection, tri-state checkboxes for commit
# Maybe, Maybe Not
# Investigate folding/nesting of files
# Toolbar
# double-click visual diffs
COL_PATH = 0
COL_STATUS = 1
COL_MERGE_STATE = 2
COL_PATH_DISPLAY = 3
COL_EXTENSION = 4
COL_SIZE = 5
_colors = {}
class StatusWidget(QWidget):
'''Working copy status widget
SIGNALS:
loadBegin() - for progress bar
loadComplete() - for progress bar
errorMessage(QString) - for status bar
titleTextChanged(QString) - for window title
'''
loadBegin = pyqtSignal()
loadComplete = pyqtSignal()
def __init__(self, pats, opts, root=None, parent=None):
QWidget.__init__(self, parent)
root = paths.find_root(root)
assert(root)
self.repo = hg.repository(ui.ui(), path=root)
self.wctx = self.repo[None]
self.opts = dict(modified=True, added=True, removed=True, deleted=True,
unknown=True, clean=False, ignored=False, subrepo=True)
self.opts.update(opts)
self.pats = pats
self.ms = {}
self.curRow = None
self.patchecked = {}
self.refreshing = None
# determine the user configured status colors
# (in the future, we could support full rich-text tags)
qtlib.configstyles(self.repo.ui)
labels = [(stat, val.uilabel) for stat, val in statusTypes.items()]
labels.extend([('r', 'resolve.resolved'), ('u', 'resolve.unresolved')])
for stat, label in labels:
effect = qtlib.geteffect(label)
for e in effect.split(';'):
if e.startswith('color:'):
_colors[stat] = QColor(e[7:])
break
SP = QSizePolicy
split = QSplitter(Qt.Horizontal)
layout = QVBoxLayout()
layout.setMargin(0)
layout.addWidget(split)
self.setLayout(layout)
vbox = QVBoxLayout()
vbox.setMargin(0)
frame = QFrame(split)
sp = SP(SP.Expanding, SP.Expanding)
sp.setHorizontalStretch(0)
sp.setVerticalStretch(0)
frame.setSizePolicy(sp)
frame.setLayout(vbox)
hbox = QHBoxLayout()
hbox.setContentsMargins (5, 0, 0, 0)
lbl = QLabel(_('Filter:'))
le = QLineEdit()
pb = QPushButton(_('MAR!?IC')) # needs a better label
hbox.addWidget(lbl)
hbox.addWidget(le)
hbox.addWidget(pb)
tv = WctxFileTree(self.repo)
vbox.addLayout(hbox)
vbox.addWidget(tv)
split.addWidget(frame)
if self.pats:
def clearPattern():
self.pats = []
self.refreshWctx()
cpb.setVisible(False)
self.emit(SIGNAL('titleTextChanged'), QString(self.getTitle()))
cpb = QPushButton(_('Remove filter, show root'))
vbox.addWidget(cpb)
cpb.clicked.connect(clearPattern)
self.countlbl = QLabel()
hcbox = QHBoxLayout()
vbox.addLayout(hcbox)
hcbox.addSpacing(6)
hcbox.addWidget(self.countlbl)
self.connect(tv, SIGNAL('clicked(QModelIndex)'), self.rowSelected)
self.connect(tv, SIGNAL('menuAction()'), self.refreshWctx)
tv.setItemsExpandable(False)
tv.setRootIsDecorated(False)
tv.sortByColumn(COL_PATH_DISPLAY)
def setButtonText():
text = ''
for stat in StatusType.preferredOrder:
name = statusTypes[stat].name
if self.opts[name]:
text += stat
pb.setText(text)
def statusTypeTrigger(isChecked):
txt = hglib.fromunicode(self.sender().text())
self.opts[txt[2:]] = isChecked
self.refreshWctx()
setButtonText()
menu = QMenu()
for stat in StatusType.preferredOrder:
val = statusTypes[stat]
a = menu.addAction('%s %s' % (stat, val.name))
a.setCheckable(True)
a.setChecked(self.opts[val.name])
a.triggered.connect(statusTypeTrigger)
pb.setMenu(menu)
setButtonText()
pb.storeref = menu
self.tv = tv
self.le = le
# Diff panel side of splitter
vbox = QVBoxLayout()
vbox.setSpacing(0)
vbox.setContentsMargins(0, 0, 0, 0)
docf = QFrame(split)
sp = SP(SP.Expanding, SP.Expanding)
sp.setHorizontalStretch(1)
sp.setVerticalStretch(0)
docf.setSizePolicy(sp)
docf.setLayout(vbox)
self.docf = docf
hbox = QHBoxLayout()
hbox.setContentsMargins (0, 0, 0, 0)
self.fnamelabel = QLabel()
self.fnamelabel.setContextMenuPolicy(Qt.CustomContextMenu)
self.connect(self.fnamelabel,
SIGNAL('customContextMenuRequested(const QPoint &)'),
self.customContextMenuRequested)
hbox.addWidget(self.fnamelabel)
hbox.addStretch()
self.override = QCheckBox()
self.override.hide()
self.override.setText(_('Show Contents'))
self.override.setCheckable(True)
self.override.toggled.connect(self.refreshDiff)
hbox.addWidget(self.override)
hbox.addSpacing(6)
self.te = QTextBrowser()
self.te.setOpenLinks(False)
self.connect(self.te, SIGNAL('anchorClicked(QUrl)'), self.teLinkClicked)
self.te.document().setDefaultStyleSheet(qtlib.thgstylesheet)
self.te.setReadOnly(True)
self.te.setLineWrapMode(QTextEdit.NoWrap)
vbox.addLayout(hbox)
vbox.addWidget(self.te, 1)
self.split = split
self.diffvbox = vbox
QTimer.singleShot(0, self.refreshWctx)
def teLinkClicked(self, url):
self.override.setChecked(True)
def getTitle(self):
if self.pats:
return hglib.tounicode(_('%s - status (selection filtered)') %
hglib.get_reponame(self.repo))
else:
return hglib.tounicode(_('%s - status') %
hglib.get_reponame(self.repo))
def restoreState(self, data):
return self.split.restoreState(data)
def saveState(self):
return self.split.saveState()
def customContextMenuRequested(self, point):
'menu request for filename label'
if self.curRow is None:
return
point = self.fnamelabel.mapToGlobal(point)
path, status, mst, u = self.curRow
selrows = [(set(status+mst.lower()), path), ]
action = wctxactions.wctxactions(self, point, self.repo, selrows)
if action:
self.emit(SIGNAL('menuAction()'))
def keyPressEvent(self, event):
if event.key() == Qt.Key_F5:
self.te.clear()
self.refreshWctx()
else:
return super(StatusWidget, self).keyPressEvent(event)
def refreshWctx(self):
if self.refreshing:
return
self.te.clear()
self.fnamelabel.clear()
self.curRow = None
self.override.setChecked(False)
self.override.setEnabled(False)
# store selected paths or current path
model = self.tv.model()
if model:
sp = [model.getRow(i)[COL_PATH] for i in self.tv.selectedRows()]
if not sp:
index = self.tv.selectionModel().currentIndex()
if index.isValid():
sp = [model.getRow(index)[COL_PATH]]
else:
sp = None
self.sp = sp
self.loadBegin.emit()
self.refreshing = StatusThread(self.repo, self.pats, self.opts)
self.connect(self.refreshing, SIGNAL('finished'), self.reloadComplete)
# re-emit error messages from this object
self.connect(self.refreshing, SIGNAL('errorMessage'),
lambda msg: self.emit(SIGNAL('errorMessage'), msg))
self.refreshing.start()
def reloadComplete(self, wctx, patchecked):
self.ms = merge.mergestate(self.repo)
self.wctx = wctx
self.patchecked = patchecked.copy()
self.updateModel()
self.loadComplete.emit()
self.refreshing.wait()
self.refreshing = None
def updateModel(self):
self.tv.setSortingEnabled(False)
if self.tv.model():
checked = self.tv.model().getChecked()
else:
checked = self.patchecked
if self.pats and not self.patchecked:
qtlib.WarningMsgBox(_('No appropriate files'),
_('No files found for this operation'),
parent=self)
tm = WctxModel(self.wctx, self.ms, self.opts, checked)
self.tv.setModel(tm)
self.tv.setSortingEnabled(True)
self.tv.setColumnHidden(COL_PATH, self.isMerge())
self.tv.setColumnHidden(COL_MERGE_STATE, not tm.anyMerge())
for col in xrange(COL_SIZE):
self.tv.resizeColumnToContents(col)
self.connect(self.tv, SIGNAL('activated(QModelIndex)'), tm.toggleRow)
self.connect(self.tv, SIGNAL('pressed(QModelIndex)'), tm.pressedRow)
self.connect(self.le, SIGNAL('textEdited(QString)'), tm.setFilter)
self.connect(tm, SIGNAL('checkToggled()'), self.updateCheckCount)
self.updateCheckCount()
# reset selection, or select first row
selmodel = self.tv.selectionModel()
flags = QItemSelectionModel.Select | QItemSelectionModel.Rows
if self.sp:
first = None
for i, row in enumerate(tm.getAllRows()):
if row[COL_PATH] in self.sp:
index = tm.index(i, 0)
selmodel.select(index, flags)
if not first: first = index
else:
first = tm.index(0, 0)
selmodel.select(first, flags)
if first and first.isValid():
self.rowSelected(first)
def updateCheckCount(self):
text = _('Checkmarked file count: %d') % len(self.getChecked())
self.countlbl.setText(text)
def isMerge(self):
return bool(self.wctx.p2())
def getChecked(self, types=None):
model = self.tv.model()
if model:
checked = model.getChecked()
if types is None:
return [f for f, v in checked.iteritems() if v]
else:
files = []
for row in model.getAllRows():
path, status, mst, upath, ext, sz = row
if status in types and checked[path]:
files.append(path)
return files
else:
return []
def rowSelected(self, index):
'Connected to treeview "clicked" signal'
self.curRow = None
self.override.setChecked(False)
self.curRow = index.model().getRow(index)
self.refreshDiff()
def refreshDiff(self):
if self.curRow is None:
return
path, status, mst, upath, ext, sz = self.curRow
wfile = util.pconvert(path)
self.fnamelabel.setText(statusMessage(status, mst, upath))
showanyway = self.override.isChecked()
hu = htmlui.htmlui()
show = ' (<a href="cmd:show">%s</a>)' % _('show anyway')
if status in '?I':
if showanyway:
# Read untracked file contents from working directory
try:
diff = open(self.repo.wjoin(wfile), 'r').read()
except EnvironmentError, e:
diff = '<b>%s</b>' % str(e)
if '\0' in diff:
diff = _('<b>Contents are binary, not previewable</b>')
self.te.setHtml(diff)
else:
diff = '<pre>%s</pre>' % xml_escape(diff)
self.te.setHtml(diff)
else:
diff = _('<b>Not displayed</b>') + show
self.te.setHtml(diff)
return
elif status in '!C':
if showanyway:
# Read file contents from parent revision
ctx = self.repo['.']
diff = ctx.filectx(wfile).data()
if '\0' in diff:
diff = _('<b>Contents are binary, not previewable</b>')
self.te.setHtml(diff)
else:
diff = '<pre>%s</pre>' % xml_escape(diff)
self.te.setHtml(diff)
else:
diff = _('<b>Not displayed</b>') + show
self.te.setHtml(diff)
return
elif status in 'S':
if showanyway:
try:
sroot = self.repo.wjoin(path)
srepo = hg.repository(hu, path=sroot)
srev = self.wctx.substate.get(path, subrepo.nullstate)[1]
sactual = srepo['.'].hex()
commands.status(hu, srepo)
out = [hu.getdata()[0]]
if srev != sactual:
out.append('<b>')
out.append(_('revision changed from:'))
out.append('</b><br>')
opts = {'date':None, 'user':None, 'rev':[srev]}
commands.log(hu, srepo, **opts)
out.append(hu.getdata()[0])
out.append('<b>')
out.append(_('to:'))
out.append('</b><br>')
opts['rev'] = [sactual]
commands.log(hu, srepo, **opts)
out.append(hu.getdata()[0])
diff = ''.join(out)
except error.RepoError:
diff = _('<b>Not an hg subrepo, not previewable</b>')
else:
diff = _('<b>Subrepository status not displayed</b>') + show
self.te.setHtml(diff)
return
warnings = chunkselect.check_max_diff(self.wctx, wfile)
if warnings and not showanyway:
text = '<b>Diffs not displayed: %s</b>' % warnings[1] + show
self.te.setHtml(text)
return
self.override.setChecked(True)
# Generate diffs to first parent
m = cmdutil.matchfiles(self.repo, [wfile])
try:
for s, l in qtlib.difflabel(self.wctx.diff, match=m, git=True):
hu.write(s, label=l)
except (IOError, error.RepoError, error.LookupError, util.Abort), e:
err = hglib.tounicode(str(e))
self.emit(SIGNAL('errorMessage'), QString(err))
return
o, e = hu.getdata()
diff = o or _('<em>No displayable differences</em>')
if self.isMerge():
header = _('===== Diff to first parent %d:%s =====\n') % (
self.wctx.p1().rev(), str(self.wctx.p1()))
header = '<h3>' + header + '</h3></br>'
text = header + diff
else:
self.te.setHtml(diff)
return
# Generate diffs to second parent
try:
for s, l in qtlib.difflabel(self.wctx.diff, self.wctx.p2(),
match=m, git=True):
hu.write(s, label=l)
except (IOError, error.RepoError, error.LookupError, util.Abort), e:
err = hglib.tounicode(str(e))
self.emit(SIGNAL('errorMessage'), QString(err))
return
text += '</br><h3>'
text += _('===== Diff to second parent %d:%s =====\n') % (
self.wctx.p2().rev(), str(self.wctx.p2()))
text += '</h3></br>'
o, e = hu.getdata()
diff = o or _('<em>No displayable differences</em>')
self.te.setHtml(text + diff)
class StatusThread(QThread):
'''Background thread for generating a workingctx'''
def __init__(self, repo, pats, opts, parent=None):
super(StatusThread, self).__init__()
self.repo = repo
self.pats = pats
self.opts = opts
def run(self):
hglib.invalidaterepo(self.repo)
extract = lambda x, y: dict(zip(x, map(y.get, x)))
stopts = extract(('unknown', 'ignored', 'clean'), self.opts)
patchecked = {}
try:
if self.pats:
m = cmdutil.match(self.repo, self.pats)
status = self.repo.status(match=m, **stopts)
# Record all matched files as initially checked
for i, stat in enumerate(StatusType.preferredOrder):
if stat == 'S':
continue
val = statusTypes[stat]
if self.opts[val.name]:
d = dict([(fn, True) for fn in status[i]])
patchecked.update(d)
wctx = context.workingctx(self.repo, changes=status)
else:
wctx = self.repo[None]
wctx.status(**stopts)
except (OSError, IOError, util.Abort), e:
err = hglib.tounicode(str(e))
self.emit(SIGNAL('errorMessage'), QString(err))
try:
wctx.dirtySubrepos = []
for s in wctx.substate:
if wctx.sub(s).dirty():
wctx.dirtySubrepos.append(s)
except (OSError, IOError, util.Abort,
error.RepoLookupError, error.ConfigError), e:
err = hglib.tounicode(str(e))
self.emit(SIGNAL('errorMessage'), QString(err))
self.emit(SIGNAL('finished'), wctx, patchecked)
class WctxFileTree(QTreeView):
def __init__(self, repo, parent=None):
QTreeView.__init__(self, parent)
self.repo = repo
self.setSelectionMode(QTreeView.ExtendedSelection)
self.setContextMenuPolicy(Qt.CustomContextMenu)
self.connect(self, SIGNAL('customContextMenuRequested(const QPoint &)'),
self.customContextMenuRequested)
def keyPressEvent(self, event):
if event.key() == 32:
for index in self.selectedRows():
self.model().toggleRow(index)
if event.key() == Qt.Key_D and event.modifiers() == Qt.ControlModifier:
selfiles = []
for index in self.selectedRows():
selfiles.append(self.model().getRow(index)[COL_PATH])
visdiff.visualdiff(self.repo.ui, self.repo, selfiles, {})
else:
return super(WctxFileTree, self).keyPressEvent(event)
def dragObject(self):
urls = []
for index in self.selectedRows():
path = self.model().getRow(index)[COL_PATH]
u = QUrl()
u.setPath('file://' + os.path.join(self.repo.root, path))
urls.append(u)
if urls:
d = QDrag(self)
m = QMimeData()
m.setUrls(urls)
d.setMimeData(m)
d.start(Qt.CopyAction)
def mousePressEvent(self, event):
self.pressPos = event.pos()
self.pressTime = QTime.currentTime()
return QTreeView.mousePressEvent(self, event)
def mouseMoveEvent(self, event):
d = event.pos() - self.pressPos
if d.manhattanLength() < QApplication.startDragDistance():
return QTreeView.mouseMoveEvent(self, event)
elapsed = self.pressTime.msecsTo(QTime.currentTime())
if elapsed < QApplication.startDragTime():
return QTreeView.mouseMoveEvent(self, event)
self.dragObject()
return QTreeView.mouseMoveEvent(self, event)
def customContextMenuRequested(self, point):
selrows = []
for index in self.selectedRows():
path, status, mst, u, ext, sz = self.model().getRow(index)
selrows.append((set(status+mst.lower()), path))
point = self.mapToGlobal(point)
action = wctxactions.wctxactions(self, point, self.repo, selrows)
if action:
self.emit(SIGNAL('menuAction()'))
def selectedRows(self):
return self.selectionModel().selectedRows()
class WctxModel(QAbstractTableModel):
def __init__(self, wctx, ms, opts, checked, parent=None):
QAbstractTableModel.__init__(self, parent)
rows = []
def mkrow(fname, st):
ext, sizek = '', ''
try:
mst = fname in ms and ms[fname].upper() or ""
name, ext = os.path.splitext(fname)
sizebytes = wctx[fname].size()
sizek = (sizebytes + 1023) // 1024
except EnvironmentError:
pass
return [fname, st, mst, hglib.tounicode(fname), ext[1:], sizek]
if opts['modified']:
for m in wctx.modified():
checked[m] = checked.get(m, True)
rows.append(mkrow(m, 'M'))
if opts['added']:
for a in wctx.added():
checked[a] = checked.get(a, True)
rows.append(mkrow(a, 'A'))
if opts['removed']:
for r in wctx.removed():
mst = r in ms and ms[r].upper() or ""
checked[r] = checked.get(r, True)
rows.append(mkrow(r, 'R'))
if opts['deleted']:
for d in wctx.deleted():
mst = d in ms and ms[d].upper() or ""
checked[d] = checked.get(d, False)
rows.append(mkrow(d, '!'))
if opts['unknown']:
for u in wctx.unknown():
checked[u] = checked.get(u, False)
rows.append(mkrow(u, '?'))
if opts['ignored']:
for i in wctx.ignored():
checked[i] = checked.get(i, False)
rows.append(mkrow(i, 'I'))
if opts['clean']:
for c in wctx.clean():
checked[c] = checked.get(c, False)
rows.append(mkrow(c, 'C'))
if opts['subrepo']:
for s in wctx.dirtySubrepos:
checked[s] = checked.get(s, False)
rows.append(mkrow(s, 'S'))
self.headers = ('*', _('Stat'), _('M'), _('Filename'),
_('Type'), _('Size (KB)'))
self.checked = checked
self.unfiltered = rows
self.rows = rows
def rowCount(self, parent):
if parent.isValid():
return 0 # no child
return len(self.rows)
def columnCount(self, parent):
if parent.isValid():
return 0 # no child
return len(self.headers)
def data(self, index, role):
if not index.isValid():
return QVariant()
path, status, mst, upath, ext, sz = self.rows[index.row()]
if index.column() == COL_PATH:
if role == Qt.CheckStateRole:
# also Qt.PartiallyChecked
if self.checked[path]:
return Qt.Checked
else:
return Qt.Unchecked
elif role == Qt.DisplayRole:
return QVariant(self.rows[index.row()][index.column()])
elif role == Qt.TextColorRole:
if mst:
return _colors.get(mst.lower(), QColor('black'))
else:
return _colors.get(status, QColor('black'))
elif role == Qt.ToolTipRole:
return QVariant(statusMessage(status, mst, upath))
'''
elif role == Qt.DecorationRole and index.column() == COL_STATUS:
if status in statusTypes:
ico = QIcon()
ico.addPixmap(QPixmap('icons/' + statusTypes[status].icon))
return QVariant(ico)
'''
return QVariant()
def headerData(self, col, orientation, role):
if role != Qt.DisplayRole or orientation != Qt.Horizontal:
return QVariant()
else:
return QVariant(self.headers[col])
def flags(self, index):
flags = Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled
if index.column() == COL_PATH:
flags |= Qt.ItemIsUserCheckable
return flags
# Custom methods
def anyMerge(self):
for r in self.rows:
if r[COL_MERGE_STATE]:
return True
return False
def getRow(self, index):
assert index.isValid()
return self.rows[index.row()]
def getAllRows(self):
for row in self.rows:
yield row
def toggleRow(self, index):
'Connected to "activated" signal, emitted by dbl-click or enter'
if QApplication.keyboardModifiers() & Qt.ControlModifier:
# ignore Ctrl-Enter events, the user does not want a row
# toggled just as they are committing.
return
assert index.isValid()
fname = self.rows[index.row()][COL_PATH]
self.emit(SIGNAL("layoutAboutToBeChanged()"))
self.checked[fname] = not self.checked[fname]
self.emit(SIGNAL("layoutChanged()"))
self.emit(SIGNAL("checkToggled()"))
def pressedRow(self, index):
'Connected to "pressed" signal, emitted by mouse clicks'
assert index.isValid()
if index.column() == COL_PATH:
self.toggleRow(index)
def sort(self, col, order):
self.emit(SIGNAL("layoutAboutToBeChanged()"))
if col == COL_PATH:
c = self.checked
self.rows.sort(lambda x, y: cmp(c[x[col]], c[y[col]]))
else:
self.rows.sort(lambda x, y: cmp(x[col], y[col]))
if order == Qt.DescendingOrder:
self.rows.reverse()
self.emit(SIGNAL("layoutChanged()"))
self.reset()
def setFilter(self, match):
'simple match in filename filter'
self.emit(SIGNAL("layoutAboutToBeChanged()"))
self.rows = [r for r in self.unfiltered if match in r[COL_PATH_DISPLAY]]
self.emit(SIGNAL("layoutChanged()"))
self.reset()
def getChecked(self):
return self.checked.copy()
def statusMessage(status, mst, upath):
tip = ''
if status in statusTypes:
upath = "<span style='font-family:Courier'>%s </span>" % upath
tip = statusTypes[status].desc % upath
if mst == 'R':
tip += _(', resolved merge')
elif mst == 'U':
tip += _(', unresolved merge')
return tip
class StatusType(object):
preferredOrder = 'MAR?!ICS'
def __init__(self, name, icon, desc, uilabel):
self.name = name
self.icon = icon
self.desc = desc
self.uilabel = uilabel
statusTypes = {
'M' : StatusType('modified', 'menucommit.ico', _('%s is modified'),
'status.modified'),
'A' : StatusType('added', 'fileadd.ico', _('%s is added'),
'status.added'),
'R' : StatusType('removed', 'filedelete.ico', _('%s is removed'),
'status.removed'),
'?' : StatusType('unknown', 'shelve.ico', _('%s is not tracked (unknown)'),
'status.unknown'),
'!' : StatusType('deleted', 'menudelete.ico', _('%s is missing!'),
'status.deleted'),
'I' : StatusType('ignored', 'ignore.ico', _('%s is ignored'),
'status.ignored'),
'C' : StatusType('clean', '', _('%s is not modified (clean)'),
'status.clean'),
'S' : StatusType('subrepo', 'hg.ico', _('%s is a dirty subrepo'),
'status.subrepo'),
}
class StatusDialog(QDialog):
'Standalone status browser'
def __init__(self, pats, opts, parent=None):
QDialog.__init__(self, parent)
layout = QVBoxLayout()
layout.setContentsMargins(0, 6, 0, 0)
self.setLayout(layout)
self.stwidget = StatusWidget(pats, opts, None, self)
layout.addWidget(self.stwidget, 1)
self.stbar = QStatusBar(self)
layout.addWidget(self.stbar)
s = QSettings()
self.stwidget.restoreState(s.value('status/state').toByteArray())
self.restoreGeometry(s.value('status/geom').toByteArray())
self.connect(self.stwidget, SIGNAL('titleTextChanged'), self.setTitle)
self.connect(self.stwidget, SIGNAL('errorMessage'), self.errorMessage)
self.setTitle(self.stwidget.getTitle())
def setTitle(self, title):
self.setWindowTitle(title)
def errorMessage(self, msg):
self.stbar.showMessage(msg)
def accept(self):
s = QSettings()
s.setValue('status/state', self.stwidget.saveState())
s.setValue('status/geom', self.saveGeometry())
QDialog.accept(self)
def reject(self):
s = QSettings()
s.setValue('status/state', self.stwidget.saveState())
s.setValue('status/geom', self.saveGeometry())
QDialog.reject(self)
def run(ui, *pats, **opts):
return StatusDialog(pats, opts)
|
Loading...