Changeset a074e5d8ac31…
Parent 0ffaeff50c81…
by
Changes to 3 files · Browse files at a074e5d8ac31 Showing diff from parent 0ffaeff50c81 Diff from another changeset...
@@ -426,6 +426,11 @@ from tortoisehg.hgqt.serve import run
qtrun(run, ui, *pats, **opts)
+def sync(ui, *pats, **opts):
+ """Synchronize with other repositories"""
+ from tortoisehg.hgqt.sync import run
+ qtrun(run, ui, *pats, **opts)
+
def shellconfig(ui, *pats, **opts):
"""explorer extension configuration editor"""
from tortoisehg.hgqt.shellconf import run
@@ -753,6 +758,7 @@ "forget": (forget, [], _('thg forget [FILE]...')),
"rename|mv|copy": (rename, [], _('thg rename SOURCE [DEST]...')),
"^serve": (serve, [], _('thg serve [OPTION]')),
+ "^sync": (sync, [], _('thg sync')),
"^status": (status,
[('c', 'clean', False, _('show files without changes')),
('i', 'ignored', False, _('show ignored files'))],
|
|
@@ -1,22 +1,176 @@ # sync.py - TortoiseHg's sync widget
#
# Copyright 2010 Adrian Buehlmann <adrian@cadifra.com>
+# 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 or any later version.
+import os
+import re
+
from PyQt4.QtCore import *
from PyQt4.QtGui import *
+from tortoisehg.hgqt.i18n import _
+from tortoisehg.hgqt import qtlib
+
class SyncWidget(QWidget):
- def __init__(self, root, parent=None):
+ def __init__(self, root, parent=None, **opts):
QWidget.__init__(self, parent)
layout = QVBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
self.setLayout(layout)
- la = QLabel("Sync widget %s for repo '%s' "
- "(widget is under construction)" % (id(self), root))
- layout.addWidget(la)
+ self.root = root
+ self.thread = None
+ self.tv = PathsTree(root, self)
+ self.refresh()
+
+ pathsframe = QFrame()
+ pathsframe.setFrameStyle(QFrame.Panel|QFrame.Raised)
+ pathsbox = QVBoxLayout()
+ pathsframe.setLayout(pathsbox)
+ lbl = QLabel(_('<b>Configured Paths</b>'))
+ pathsbox.addWidget(lbl)
+ pathsbox.addWidget(self.tv)
+ layout.addWidget(pathsframe)
+
+ if parent:
+ self.closeonesc = False
+ else:
+ self.setWindowTitle(_('TortoiseHg Search'))
+ self.resize(800, 550)
+ self.closeonesc = True
+
+
+ def refresh(self):
+ fn = os.path.join(self.root, '.hg', 'hgrc')
+ try:
+ import iniparse
+ # Monkypatch this regex to prevent iniparse from considering
+ # 'rem' as a comment
+ iniparse.ini.CommentLine.regex = \
+ re.compile(r'^(?P<csep>[%;#])(?P<comment>.*)$')
+ cfg = iniparse.INIConfig(file(fn), optionxformvalue=None)
+ self.readonly = False
+ except ImportError:
+ from mercurial import config
+ cfg = config.config()
+ cfg.read(fn)
+ self.readonly = True
+ except Exception, e:
+ qtlib.WarningMsgBox(_('Unable to parse a config file'),
+ _('%s\nReverting to read-only mode.') % str(e),
+ parent=self)
+ self.readonly = True
+ cfg = {}
+ self.paths = {}
+ if 'paths' not in cfg:
+ return
+ for alias in cfg['paths']:
+ self.paths[ alias ] = cfg['paths'][ alias ]
+ tm = PathsModel(self.paths, self)
+ self.tv.setModel(tm)
+
+ def keyPressEvent(self, event):
+ if event.key() == Qt.Key_Escape:
+ if self.thread and self.thread.isRunning():
+ self.thread.terminate()
+ # This can lockup, so stop waiting after 2sec
+ self.thread.wait( 2000 )
+ self.finished()
+ self.thread = None
+ elif self.closeonesc:
+ self.close()
+ else:
+ return super(SyncWidget, self).keyPressEvent(event)
+
+class PathsTree(QTreeView):
+ def __init__(self, root, parent=None):
+ QTreeView.__init__(self, parent)
+ self.setSelectionMode(QTreeView.ExtendedSelection)
+ self.setContextMenuPolicy(Qt.CustomContextMenu)
+ self.connect(self, SIGNAL('customContextMenuRequested(const QPoint &)'),
+ self.customContextMenuRequested)
+
+ def keyPressEvent(self, event):
+ return super(PathsTree, self).keyPressEvent(event)
+
+ def dragObject(self):
+ urls = []
+ for index in self.selectedRows():
+ url = self.model().data(index)[1]
+ u = QUrl()
+ u.setPath(url)
+ 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 super(PathsTree, self).mousePressEvent(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 super(PathsTree, self).mouseMoveEvent(event)
+ self.dragObject()
+ return super(PathsTree, self).mouseMoveEvent(event)
+
+ def customContextMenuRequested(self, point):
+ point = self.mapToGlobal(point)
+ pass
+
+ def selectedRows(self):
+ return self.selectionModel().selectedRows()
+
+class PathsModel(QAbstractTableModel):
+ def __init__(self, pathdict, parent=None):
+ QAbstractTableModel.__init__(self, parent)
+ self.headers = (_('Alias'), _('URL'))
+ self.rows = []
+ for alias, url in pathdict.iteritems():
+ self.rows.append([alias, url])
+
+ 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()
+ if role == Qt.DisplayRole:
+ return QVariant(self.rows[index.row()][index.column()])
+ 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
+ return flags
+
+
+def run(ui, *pats, **opts):
+ from tortoisehg.util import paths
+ return SyncWidget(paths.find_root(), **opts)
|
@@ -422,7 +422,7 @@ sw = self.getSyncWidget(root)
if sw is None:
print "creating sync widget for %s" % root
- sw = SyncWidget(root)
+ sw = SyncWidget(root, self)
self.syncwidgets[root] = sw
self.syncStackedWidget.addWidget(sw)
return sw
|
Loading...