by
Changes to 23 files · Browse files at 36e87958af73 Showing diff from parent ca666161b014 ed75d8f72a86 Diff from another changeset...
|
|
|
|
@@ -47,7 +47,7 @@ return None
try:
data = fctx.data()
- if '\0' in data:
+ if '\0' in data or ctx.isStandin(wfile):
self.error = p + _('File is binary.\n')
return None
except (EnvironmentError, util.Abort), e:
@@ -72,6 +72,7 @@ return 'C'
return None
+ isbfile = False
repo = ctx._repo
self.flabel += u'<b>%s</b>' % hglib.tounicode(wfile)
@@ -302,6 +303,9 @@ else:
self.contents = olddata
self.flabel += _(' <i>(was deleted)</i>')
+ elif hasattr(ctx.p1(), 'hasStandin') and ctx.p1().hasStandin(wfile):
+ self.error = 'binary file'
+ self.flabel += _(' <i>(was deleted)</i>')
else:
self.flabel += _(' <i>(was added, now missing)</i>')
return
@@ -315,6 +319,8 @@ return
else:
data = util.posixfile(absfile, 'r').read()
+ elif ctx.hasStandin(wfile):
+ data = '\0'
else:
data = ctx.filectx(wfile).data()
if '\0' in data:
@@ -324,6 +330,9 @@ return
if status in ('M', 'A'):
+ if ctx.hasStandin(wfile):
+ wfile = ctx.findStandin(wfile)
+ isbfile = True
res = self.checkMaxDiff(ctx, wfile, maxdiff)
if res is None:
if status == 'A':
@@ -367,5 +376,8 @@ revs = [str(ctx), str(ctx2)]
diffopts = patch.diffopts(repo.ui, {})
diffopts.git = False
+ if isbfile:
+ olddata += '\0'
+ newdata += '\0'
self.diff = mdiff.unidiff(olddata, olddate, newdata, newdate,
oldname, wfile, revs, diffopts)
|
@@ -144,6 +144,7 @@ for lst, flag in ((added, 'A'), (modified, 'M'), (removed, 'R')):
for f in filter(func, lst):
wasmerged = ismerge and f in ctxfiles
+ f = self._ctx.removeStandin(f)
files.append({'path': f, 'status': flag, 'parent': parent,
'wasmerged': wasmerged})
return files
|
@@ -10,7 +10,7 @@
from mercurial import ui, hg, error, commands, match, util, subrepo
-from tortoisehg.hgqt import htmlui, visdiff, qtlib, htmldelegate, thgrepo, cmdui
+from tortoisehg.hgqt import htmlui, visdiff, qtlib, htmldelegate, thgrepo, cmdui, settings
from tortoisehg.util import paths, hglib, thread2
from tortoisehg.hgqt.i18n import _
@@ -385,6 +385,8 @@ pass
def run(self):
+ haskbf = settings.hasExtension('kbfiles')
+ haslf = settings.hasExtension('largefiles')
self.thread_id = int(QThread.currentThreadId())
def emitrow(row):
@@ -400,6 +402,10 @@ try:
fname, line, rev, addremove, user, text, tail = \
self.fullmsg.split('\0', 6)
+ if haslf and thgrepo.isLfStandin(fname):
+ raise ValueError
+ if (haslf or haskbf) and thgrepo.isBfStandin(fname):
+ raise ValueError
text = hglib.tounicode(text)
text = Qt.escape(text)
text = '<b>%s</b> <span>%s</span>' % (addremove, text)
@@ -469,9 +475,15 @@ unit = _('files')
total = len(ctx.manifest())
count = 0
+ haskbf = settings.hasExtension('kbfiles')
+ haslf = settings.hasExtension('largefiles')
for wfile in ctx: # walk manifest
if self.canceled:
break
+ if haslf and thgrepo.isLfStandin(wfile):
+ continue
+ if (haslf or haskbf) and thgrepo.isBfStandin(wfile):
+ continue
self.progress.emit(topic, count, wfile, unit, total)
count += 1
if not matchfn(wfile):
|
|
@@ -0,0 +1,73 @@ + # bfprompt.py - prompt to add large files as bfiles
+#
+# Copyright 2011 Fog Creek Software
+#
+# 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
+
+from mercurial import match
+from tortoisehg.hgqt import qtlib
+from tortoisehg.hgqt.i18n import _
+
+class LfilesPrompt(qtlib.CustomPrompt):
+ def __init__(self, parent, files=None):
+ qtlib.CustomPrompt.__init__(self, _('Confirm Add'),
+ _('Some of the files that you have selected are of a size '
+ 'over 10 MB. You may make more efficient use of disk space '
+ 'by adding these files as largefiles, which will store only the '
+ 'most recent revision of each file in your local repository, '
+ 'with older revisions available on the server. Do you wish '
+ 'to add these files as largefiles?'), parent,
+ (_('Add as &Largefiles'), _('Add as &Normal Files'), _('Cancel')),
+ 0, 2, files)
+
+class BfilesPrompt(qtlib.CustomPrompt):
+ def __init__(self, parent, files=None):
+ qtlib.CustomPrompt.__init__(self, _('Confirm Add'),
+ _('Some of the files that you have selected are of a size '
+ 'over 10 MB. You may make more efficient use of disk space '
+ 'by adding these files as bfiles, which will store only the '
+ 'most recent revision of each file in your local repository, '
+ 'with older revisions available on the server. Do you wish '
+ 'to add these files as bfiles?'), parent,
+ (_('Add as &Bfiles'), _('Add as &Normal Files'), _('Cancel')),
+ 0, 2, files)
+
+def promptForLfiles(parent, ui, repo, files, haskbf=False):
+ lfiles = []
+ usekbf = os.path.exists('.kbf')
+ uself = os.path.exists('.hglf')
+ useneither = not usekbf and not uself
+ if haskbf:
+ section = 'kilnbfiles'
+ else:
+ section = 'largefiles'
+ minsize = int(ui.config(section, 'size', default='10'))
+ patterns = ui.config(section, 'patterns', default=())
+ if patterns:
+ patterns = patterns.split(' ')
+ matcher = match.match(repo.root, '', list(patterns))
+ else:
+ matcher = None
+ for wfile in files:
+ if not matcher or not matcher(wfile) or useneither:
+ filesize = os.path.getsize(repo.wjoin(wfile))
+ if filesize >= 10*1024*1024 and (filesize < minsize*1024*1024 or useneither):
+ lfiles.append(wfile)
+ if lfiles:
+ if haskbf:
+ ret = BfilesPrompt(parent, files).run()
+ else:
+ ret = LfilesPrompt(parent, files).run()
+ if ret == 0:
+ # add as largefiles/bfiles
+ for lfile in lfiles:
+ files.remove(lfile)
+ elif ret == 1:
+ # add as normal files
+ lfiles = []
+ elif ret == 2:
+ return None
+ return files, lfiles
|
|
|
@@ -1,157 +1,157 @@ - # messageentry.py - TortoiseHg's commit message editng widget
-#
-# Copyright 2011 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 PyQt4.QtCore import *
-from PyQt4.QtGui import *
-from PyQt4.Qsci import QsciScintilla, QsciLexerMakefile
-
-from tortoisehg.hgqt.i18n import _
-from tortoisehg.hgqt import qtlib, qscilib
-
-class MessageEntry(qscilib.Scintilla):
-
- def __init__(self, parent, getCheckedFunc=None):
- super(MessageEntry, self).__init__(parent)
- self.setEdgeColor(QColor('LightSalmon'))
- self.setEdgeMode(QsciScintilla.EdgeLine)
- self.setReadOnly(False)
- self.setMarginWidth(1, 0)
- self.setFont(qtlib.getfont('fontcomment').font())
- self.setCaretWidth(10)
- self.setCaretLineBackgroundColor(QColor("#e6fff0"))
- self.setCaretLineVisible(True)
- self.setAutoIndent(True)
- self.setAutoCompletionThreshold(2)
- self.setAutoCompletionSource(QsciScintilla.AcsAPIs)
- self.setAutoCompletionFillupsEnabled(True)
- self.setLexer(QsciLexerMakefile(self))
- font = qtlib.getfont('fontcomment').font()
- self.fontHeight = QFontMetrics(font).height()
- self.lexer().setFont(font)
- self.lexer().setColor(QColor(Qt.red), QsciLexerMakefile.Error)
- self.setMatchedBraceBackgroundColor(Qt.yellow)
- self.setIndentationsUseTabs(False)
- self.setBraceMatching(QsciScintilla.SloppyBraceMatch)
- #self.setIndentationGuidesBackgroundColor(QColor("#e6e6de"))
- #self.setFolding(QsciScintilla.BoxedFoldStyle)
- # http://www.riverbankcomputing.com/pipermail/qscintilla/2009-February/000461.html
- self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
- self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
- # default message entry widgets to word wrap, user may override
- self.setWrapMode(QsciScintilla.WrapWord)
-
- self.getChecked = getCheckedFunc
- self.setContextMenuPolicy(Qt.CustomContextMenu)
- self.customContextMenuRequested.connect(self.menuRequested)
-
-
- def menuRequested(self, point):
- line = self.lineAt(point)
- point = self.viewport().mapToGlobal(point)
-
- def apply():
- line = 0
- while True:
- line = self.reflowBlock(line)
- if line is None:
- break;
- def paste():
- files = self.getChecked()
- self.insert(', '.join(files))
- def settings():
- from tortoisehg.hgqt.settings import SettingsDialog
- dlg = SettingsDialog(True, focus='tortoisehg.summarylen')
- dlg.exec_()
-
- menu = self.createStandardContextMenu()
- menu.addSeparator()
- if self.getChecked:
- action = menu.addAction(_('Paste &Filenames'))
- action.triggered.connect(paste)
- for name, func in [(_('App&ly Format'), apply),
- (_('C&onfigure Format'), settings)]:
- def add(name, func):
- action = menu.addAction(name)
- action.triggered.connect(func)
- add(name, func)
- return menu.exec_(point)
-
- def refresh(self, repo):
- self.setEdgeColumn(repo.summarylen)
- self.setIndentationWidth(repo.tabwidth)
- self.setTabWidth(repo.tabwidth)
- self.summarylen = repo.summarylen
-
- def reflowBlock(self, line):
- lines = self.text().split('\n', QString.KeepEmptyParts)
- if line >= len(lines):
- return None
- if not len(lines[line]) > 1:
- return line+1
-
- # find boundaries (empty lines or bounds)
- b = line
- while b and len(lines[b-1]) > 1:
- b = b - 1
- e = line
- while e+1 < len(lines) and len(lines[e+1]) > 1:
- e = e + 1
- group = QStringList([lines[l].simplified() for l in xrange(b, e+1)])
- sentence = group.join(' ')
- parts = sentence.split(' ', QString.SkipEmptyParts)
-
- outlines = QStringList()
- line = QStringList()
- partslen = 0
- for part in parts:
- if partslen + len(line) + len(part) + 1 > self.summarylen:
- if line:
- outlines.append(line.join(' '))
- line, partslen = QStringList(), 0
- line.append(part)
- partslen += len(part)
- if line:
- outlines.append(line.join(' '))
-
- self.beginUndoAction()
- self.setSelection(b, 0, e+1, 0)
- self.removeSelectedText()
- self.insertAt(outlines.join('\n')+'\n', b, 0)
- self.endUndoAction()
- self.setCursorPosition(b, 0)
- return b + len(outlines) + 1
-
- def moveCursorToEnd(self):
- lines = self.lines()
- if lines:
- lines -= 1
- pos = self.lineLength(lines)
- self.setCursorPosition(lines, pos)
- self.ensureLineVisible(lines)
- self.horizontalScrollBar().setSliderPosition(0)
-
- def keyPressEvent(self, event):
- if event.modifiers() == Qt.ControlModifier and event.key() == Qt.Key_E:
- line, col = self.getCursorPosition()
- self.reflowBlock(line)
- elif event.key() == Qt.Key_Backtab:
- event.accept()
- newev = QKeyEvent(event.type(), Qt.Key_Tab, Qt.ShiftModifier)
- super(MessageEntry, self).keyPressEvent(newev)
- else:
- super(MessageEntry, self).keyPressEvent(event)
-
- def resizeEvent(self, event):
- super(MessageEntry, self).resizeEvent(event)
- self.showHScrollBar(self.frameGeometry().height() > self.fontHeight * 3)
-
- def minimumSizeHint(self):
- size = super(MessageEntry, self).minimumSizeHint()
- size.setHeight(self.fontHeight * 3 / 2)
- return size
+# messageentry.py - TortoiseHg's commit message editng widget
+#
+# Copyright 2011 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 PyQt4.QtCore import *
+from PyQt4.QtGui import *
+from PyQt4.Qsci import QsciScintilla, QsciLexerMakefile
+
+from tortoisehg.hgqt.i18n import _
+from tortoisehg.hgqt import qtlib, qscilib
+
+class MessageEntry(qscilib.Scintilla):
+
+ def __init__(self, parent, getCheckedFunc=None):
+ super(MessageEntry, self).__init__(parent)
+ self.setEdgeColor(QColor('LightSalmon'))
+ self.setEdgeMode(QsciScintilla.EdgeLine)
+ self.setReadOnly(False)
+ self.setMarginWidth(1, 0)
+ self.setFont(qtlib.getfont('fontcomment').font())
+ self.setCaretWidth(10)
+ self.setCaretLineBackgroundColor(QColor("#e6fff0"))
+ self.setCaretLineVisible(True)
+ self.setAutoIndent(True)
+ self.setAutoCompletionThreshold(2)
+ self.setAutoCompletionSource(QsciScintilla.AcsAPIs)
+ self.setAutoCompletionFillupsEnabled(True)
+ self.setLexer(QsciLexerMakefile(self))
+ font = qtlib.getfont('fontcomment').font()
+ self.fontHeight = QFontMetrics(font).height()
+ self.lexer().setFont(font)
+ self.lexer().setColor(QColor(Qt.red), QsciLexerMakefile.Error)
+ self.setMatchedBraceBackgroundColor(Qt.yellow)
+ self.setIndentationsUseTabs(False)
+ self.setBraceMatching(QsciScintilla.SloppyBraceMatch)
+ #self.setIndentationGuidesBackgroundColor(QColor("#e6e6de"))
+ #self.setFolding(QsciScintilla.BoxedFoldStyle)
+ # http://www.riverbankcomputing.com/pipermail/qscintilla/2009-February/000461.html
+ self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
+ self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
+ # default message entry widgets to word wrap, user may override
+ self.setWrapMode(QsciScintilla.WrapWord)
+
+ self.getChecked = getCheckedFunc
+ self.setContextMenuPolicy(Qt.CustomContextMenu)
+ self.customContextMenuRequested.connect(self.menuRequested)
+
+
+ def menuRequested(self, point):
+ line = self.lineAt(point)
+ point = self.viewport().mapToGlobal(point)
+
+ def apply():
+ line = 0
+ while True:
+ line = self.reflowBlock(line)
+ if line is None:
+ break;
+ def paste():
+ files = self.getChecked()
+ self.insert(', '.join(files))
+ def settings():
+ from tortoisehg.hgqt.settings import SettingsDialog
+ dlg = SettingsDialog(True, focus='tortoisehg.summarylen')
+ dlg.exec_()
+
+ menu = self.createStandardContextMenu()
+ menu.addSeparator()
+ if self.getChecked:
+ action = menu.addAction(_('Paste &Filenames'))
+ action.triggered.connect(paste)
+ for name, func in [(_('App&ly Format'), apply),
+ (_('C&onfigure Format'), settings)]:
+ def add(name, func):
+ action = menu.addAction(name)
+ action.triggered.connect(func)
+ add(name, func)
+ return menu.exec_(point)
+
+ def refresh(self, repo):
+ self.setEdgeColumn(repo.summarylen)
+ self.setIndentationWidth(repo.tabwidth)
+ self.setTabWidth(repo.tabwidth)
+ self.summarylen = repo.summarylen
+
+ def reflowBlock(self, line):
+ lines = self.text().split('\n', QString.KeepEmptyParts)
+ if line >= len(lines):
+ return None
+ if not len(lines[line]) > 1:
+ return line+1
+
+ # find boundaries (empty lines or bounds)
+ b = line
+ while b and len(lines[b-1]) > 1:
+ b = b - 1
+ e = line
+ while e+1 < len(lines) and len(lines[e+1]) > 1:
+ e = e + 1
+ group = QStringList([lines[l].simplified() for l in xrange(b, e+1)])
+ sentence = group.join(' ')
+ parts = sentence.split(' ', QString.SkipEmptyParts)
+
+ outlines = QStringList()
+ line = QStringList()
+ partslen = 0
+ for part in parts:
+ if partslen + len(line) + len(part) + 1 > self.summarylen:
+ if line:
+ outlines.append(line.join(' '))
+ line, partslen = QStringList(), 0
+ line.append(part)
+ partslen += len(part)
+ if line:
+ outlines.append(line.join(' '))
+
+ self.beginUndoAction()
+ self.setSelection(b, 0, e+1, 0)
+ self.removeSelectedText()
+ self.insertAt(outlines.join('\n')+'\n', b, 0)
+ self.endUndoAction()
+ self.setCursorPosition(b, 0)
+ return b + len(outlines) + 1
+
+ def moveCursorToEnd(self):
+ lines = self.lines()
+ if lines:
+ lines -= 1
+ pos = self.lineLength(lines)
+ self.setCursorPosition(lines, pos)
+ self.ensureLineVisible(lines)
+ self.horizontalScrollBar().setSliderPosition(0)
+
+ def keyPressEvent(self, event):
+ if event.modifiers() == Qt.ControlModifier and event.key() == Qt.Key_E:
+ line, col = self.getCursorPosition()
+ self.reflowBlock(line)
+ elif event.key() == Qt.Key_Backtab:
+ event.accept()
+ newev = QKeyEvent(event.type(), Qt.Key_Tab, Qt.ShiftModifier)
+ super(MessageEntry, self).keyPressEvent(newev)
+ else:
+ super(MessageEntry, self).keyPressEvent(event)
+
+ def resizeEvent(self, event):
+ super(MessageEntry, self).resizeEvent(event)
+ self.showHScrollBar(self.frameGeometry().height() > self.fontHeight * 3)
+
+ def minimumSizeHint(self):
+ size = super(MessageEntry, self).minimumSizeHint()
+ size.setHeight(self.fontHeight * 3 / 2)
+ return size
|
@@ -97,14 +97,17 @@
def run(self):
try:
- wctx = repo[None]
- wctx.status(ignored=True, unknown=True)
+ repo.bfstatus = True
+ repo.lfstatus = True
+ stat = repo.status(ignored=True, unknown=True)
+ repo.bfstatus = False
+ repo.lfstatus = False
trashcan = repo.join('Trashcan')
if os.path.isdir(trashcan):
trash = os.listdir(trashcan)
else:
trash = []
- self.files = wctx.unknown(), wctx.ignored(), trash
+ self.files = stat[4], stat[5], trash
except Exception, e:
self.error = str(e)
@@ -213,8 +216,12 @@ self.showMessage.emit('')
match = hglib.matchall(repo)
match.dir = directories.append
+ repo.bfstatus = True
+ repo.lfstatus = True
status = repo.status(match=match, ignored=opts['ignored'],
unknown=opts['unknown'], clean=False)
+ repo.bfstatus = False
+ repo.lfstatus = False
files = status[4] + status[5]
def remove(remove_func, name):
|
|
@@ -12,7 +12,7 @@
from tortoisehg.util import hglib, shlib
from tortoisehg.hgqt.i18n import _
-from tortoisehg.hgqt import qtlib, status, cmdui
+from tortoisehg.hgqt import qtlib, status, cmdui, lfprompt
from PyQt4.QtCore import *
from PyQt4.QtGui import *
@@ -107,6 +107,17 @@ hbox.addWidget(bb)
toplayout.addLayout(hbox)
self.bb = bb
+
+ if self.command == 'add':
+ if 'largefiles' in self.repo.extensions():
+ self.addLfilesButton = QPushButton(_('Add &Largefiles'))
+ elif 'kbfiles' in self.repo.extensions():
+ self.addLfilesButton = QPushButton(_("Add &Bfiles"))
+ else:
+ self.addLfilesButton = None
+ if self.addLfilesButton:
+ self.addLfilesButton.clicked.connect(self.addLfiles)
+ bb.addButton(self.addLfilesButton, BB.ActionRole)
layout.addWidget(self.statusbar)
@@ -147,9 +158,14 @@ _('No operation to perform'),
parent=self)
return
+ self.repo.bfstatus = True
+ self.repo.lfstatus = True
+ repostate = self.repo.status()
+ self.repo.bfstatus = False
+ self.repo.lfstatus = False
if self.command == 'remove':
if not self.chk.isChecked():
- modified = self.repo.status()[0]
+ modified = repostate[0]
selmodified = []
for wfile in files:
if wfile in modified:
@@ -167,14 +183,18 @@ cmdline.append('--force')
elif ret == 2:
return
- wctx = self.repo[None]
+ unknown, ignored = repostate[4:6]
for wfile in files:
- if wfile not in wctx:
+ if wfile in unknown or wfile in ignored:
try:
util.unlink(wfile)
except EnvironmentError:
pass
files.remove(wfile)
+ elif self.command == 'add':
+ if 'largefiles' in self.repo.extensions() or 'kbfiles' in self.repo.extensions():
+ self.addWithPrompt(files)
+ return
if files:
cmdline.extend(files)
self.files = files
@@ -198,6 +218,40 @@ s.setValue('quickop/forceremove', self.chk.isChecked())
QDialog.reject(self)
+ def addLfiles(self):
+ if 'kbfiles' in self.repo.extensions():
+ cmdline = ['add', '--bf']
+ else:
+ cmdline = ['add', '--large']
+ files = self.stwidget.getChecked()
+ if not files:
+ qtlib.WarningMsgBox(_('No files selected'),
+ _('No operation to perform'),
+ parent=self)
+ return
+ cmdline.extend(files)
+ self.files = files
+ self.cmd.run(cmdline)
+
+ def addWithPrompt(self, files):
+ result = lfprompt.promptForLfiles(self, self.repo.ui, self.repo, files,
+ 'kbfiles' in self.repo.extensions())
+ if not result:
+ return
+ files, bfiles = result
+ if files:
+ cmdline = ['add']
+ cmdline.extend(files)
+ self.files = files
+ self.cmd.run(cmdline)
+ if bfiles:
+ if 'kbfiles' in self.repo.extensions():
+ cmdline = ['add', '--bf']
+ else:
+ cmdline = ['add', '--large']
+ cmdline.extend(bfiles)
+ self.files = bfiles
+ self.cmd.run(cmdline)
instance = None
class HeadlessQuickop(QWidget):
|
|
@@ -7,7 +7,7 @@
import os
-from mercurial import ui, util, error
+from mercurial import ui, util, error, extensions
from tortoisehg.util import hglib, settings, paths, wconfig, i18n, bugtraq
from tortoisehg.hgqt.i18n import _
@@ -24,6 +24,12 @@_unspecstr = _('<unspecified>')
ENTRY_WIDTH = 300
+def hasExtension(extname):
+ for name, module in extensions.extensions():
+ if name == extname:
+ return True
+ return False
+
class SettingsCombo(QComboBox):
def __init__(self, parent=None, **opts):
QComboBox.__init__(self, parent, toolTip=opts['tooltip'])
@@ -315,6 +321,46 @@ return self.value() != self.curvalue
+class PathBrowser(QWidget):
+ def __init__(self, parent=None, **opts):
+ QWidget.__init__(self, parent, toolTip=opts['tooltip'])
+ self.opts = opts
+
+ self.lineEdit = QLineEdit()
+ completer = QCompleter(self)
+ completer.setModel(QDirModel(completer))
+ self.lineEdit.setCompleter(completer)
+
+ self.browseButton = QPushButton(_('&Browse...'))
+ self.browseButton.clicked.connect(self.browse)
+
+ layout = QHBoxLayout()
+ layout.setContentsMargins(0, 0, 0, 0)
+ layout.addWidget(self.lineEdit)
+ layout.addWidget(self.browseButton)
+ self.setLayout(layout)
+
+ def browse(self):
+ dir = QFileDialog.getExistingDirectory(self, directory=self.lineEdit.text(),
+ options=QFileDialog.ShowDirsOnly)
+ if dir:
+ self.lineEdit.setText(dir)
+
+ ## common APIs for all edit widgets
+ def setValue(self, curvalue):
+ self.curvalue = curvalue
+ if curvalue:
+ self.lineEdit.setText(hglib.tounicode(curvalue))
+ else:
+ self.lineEdit.setText('')
+
+ def value(self):
+ utext = self.lineEdit.text()
+ return utext and hglib.fromunicode(utext) or None
+
+ def isDirty(self):
+ return self.value() != self.curvalue
+
def genEditCombo(opts, defaults=[]):
opts['canedit'] = True
opts['defaults'] = defaults
@@ -352,6 +398,9 @@def genBugTraqEdit(opts):
return BugTraqConfigureEntry(**opts)
+def genPathBrowser(opts):
+ return PathBrowser(**opts)
+
def findIssueTrackerPlugins():
plugins = bugtraq.get_issue_plugins_with_names()
names = [("%s %s" % (key[0], key[1])) for key in plugins]
@@ -737,6 +786,26 @@ _fi(_('Target People'), 'reviewboard.target_people', genEditCombo,
_('A comma separated list of target people')),
)),
+
+({'name': 'kbfiles', 'label': _('Kiln Bfiles'), 'icon': 'kiln', 'extension': 'kbfiles'}, (
+ _fi(_('Patterns'), 'kilnbfiles.patterns', genEditCombo,
+ _('Files with names meeting the specified patterns will be automatically '
+ 'added as bfiles')),
+ _fi(_('Size'), 'kilnbfiles.size', genEditCombo,
+ _('Files of at least the specified size (in megabytes) will be added as bfiles')),
+ _fi(_('System Cache'), 'kilnbfiles.systemcache', genPathBrowser,
+ _('Path to the directory where a system-wide cache of bfiles will be stored')),
+ )),
+
+({'name': 'largefiles', 'label': _('Largefiles'), 'icon': 'kiln', 'extension': 'largefiles'}, (
+ _fi(_('Patterns'), 'largefiles.patterns', genEditCombo,
+ _('Files with names meeting the specified patterns will be automatically '
+ 'added as largefiles')),
+ _fi(_('Size'), 'largefiles.size', genEditCombo,
+ _('Files of at least the specified size (in megabytes) will be added as largefiles')),
+ _fi(_('System Cache'), 'largefiles.systemcache', genPathBrowser,
+ _('Path to the directory where a system-wide cache of largefiles will be stored')),
+ )),
)
@@ -915,6 +984,8 @@
# add page items to treeview
for meta, info in INFO:
+ if 'extension' in meta and not hasExtension(meta['extension']):
+ continue
if isinstance(meta['icon'], str):
icon = qtlib.geticon(meta['icon'])
else:
|
@@ -11,7 +11,7 @@
from tortoisehg.util import paths, hglib
from tortoisehg.hgqt.i18n import _
-from tortoisehg.hgqt import qtlib, wctxactions, visdiff, cmdui, fileview
+from tortoisehg.hgqt import qtlib, wctxactions, visdiff, cmdui, fileview, thgrepo
from PyQt4.QtCore import *
from PyQt4.QtGui import *
@@ -413,7 +413,7 @@
def __init__(self, repo, pctx, pats, opts, parent=None):
super(StatusThread, self).__init__()
- self.repo = hg.repository(repo.ui, repo.root)
+ self.repo = thgrepo.repository(repo.ui, repo.root)
self.pctx = pctx
self.pats = pats
self.opts = opts
@@ -434,7 +434,11 @@ # status and commit only pre-check MAR files
precheckfn = lambda x: x < 4
m = hglib.match(self.repo[None], self.pats)
+ self.repo.bfstatus = True
+ self.repo.lfstatus = True
status = self.repo.status(match=m, **stopts)
+ self.repo.bfstatus = False
+ self.repo.lfstatus = False
# Record all matched files as initially checked
for i, stat in enumerate(StatusType.preferredOrder):
if stat == 'S':
@@ -446,11 +450,19 @@ wctx = context.workingctx(self.repo, changes=status)
self.patchecked = patchecked
elif self.pctx:
+ self.repo.bfstatus = True
+ self.repo.lfstatus = True
status = self.repo.status(node1=self.pctx.p1().node(), **stopts)
+ self.repo.bfstatus = False
+ self.repo.lfstatus = False
wctx = context.workingctx(self.repo, changes=status)
else:
wctx = self.repo[None]
+ self.repo.bfstatus = True
+ self.repo.lfstatus = True
wctx.status(**stopts)
+ self.repo.bfstatus = False
+ self.repo.lfstatus = False
self.wctx = wctx
wctx.dirtySubrepos = []
|
|
@@ -12,6 +12,7 @@ import sys
import shutil
import tempfile
+import re
from PyQt4.QtCore import *
@@ -24,6 +25,8 @@from tortoisehg.util.patchctx import patchctx
_repocache = {}
+_kbfregex = re.compile(r'^\.kbf/')
+_lfregex = re.compile(r'^\.hglf/')
if 'THGDEBUG' in os.environ:
def dbgoutput(*args):
@@ -262,8 +265,8 @@def _extendrepo(repo):
class thgrepository(repo.__class__):
- def changectx(self, changeid):
- '''Extends Mercurial's standard changectx() method to
+ def __getitem__(self, changeid):
+ '''Extends Mercurial's standard __getitem__() method to
a) return a thgchangectx with additional methods
b) return a patchctx if changeid is the name of an MQ
unapplied patch
@@ -282,7 +285,7 @@ os.path.isabs(changeid) and os.path.isfile(changeid):
return genPatchContext(repo, changeid)
- changectx = super(thgrepository, self).changectx(changeid)
+ changectx = super(thgrepository, self).__getitem__(changeid)
changectx.__class__ = _extendchangectx(changectx)
return changectx
@@ -535,6 +538,28 @@ dest = tempfile.mktemp(ext+'.bak', root+'_', trashcan)
shutil.copyfile(path, dest)
+ def isStandin(self, path):
+ if 'largefiles' in self.extensions():
+ if _lfregex.match(path):
+ return True
+ if 'largefiles' in self.extensions() or 'kbfiles' in self.extensions():
+ if _kbfregex.match(path):
+ return True
+ return False
+
+ def removeStandin(self, path):
+ if 'largefiles' in self.extensions():
+ path = _lfregex.sub('', path)
+ if 'largefiles' in self.extensions() or 'kbfiles' in self.extensions():
+ path = _kbfregex.sub('', path)
+ return path
+
+ def bfStandin(self, path):
+ return '.kbf/' + path
+
+ def lfStandin(self, path):
+ return '.hglf/' + path
+
return thgrepository
@@ -601,11 +626,30 @@ summary += u' \u2026' # ellipsis ...
return summary
+
+ def hasStandin(self, file):
+ if 'largefiles' in self._repo.extensions():
+ if self._repo.lfStandin(file) in self.manifest():
+ return True
+ elif 'largefiles' in self._repo.extensions() or 'kbfiles' in self._repo.extensions():
+ if self._repo.bfStandin(file) in self.manifest():
+ return True
+ return False
+ def isStandin(self, path):
+ return self._repo.isStandin(path)
+
+ def removeStandin(self, path):
+ return self._repo.removeStandin(path)
+
+ def findStandin(self, file):
+ if 'largefiles' in self._repo.extensions():
+ if self._repo.lfStandin(file) in self.manifest():
+ return self._repo.lfStandin(file)
+ return self._repo.bfStandin(file)
+
return thgchangectx
-
-
_pctxcache = {}
def genPatchContext(repo, patchpath, rev=None):
global _pctxcache
@@ -650,3 +694,9 @@ raise
else:
f.close()
+
+def isBfStandin(path):
+ return _kbfregex.match(path)
+
+def isLfStandin(path):
+ return _lfregex.match(path)
|
@@ -6,10 +6,9 @@ # GNU General Public License version 2, incorporated herein by reference.
import os
-import re
-from mercurial import util, error, merge, commands
-from tortoisehg.hgqt import qtlib, htmlui, visdiff
+from mercurial import util, error, merge, commands, extensions
+from tortoisehg.hgqt import qtlib, htmlui, visdiff, bfprompt
from tortoisehg.util import hglib, shlib
from tortoisehg.hgqt.i18n import _
@@ -52,6 +51,10 @@ allactions.append(None)
make(_('&Forget'), forget, frozenset('MAC!'), 'filedelete')
make(_('&Add'), add, frozenset('I?'), 'fileadd')
+ if 'largefiles' in self.repo.extensions():
+ make(_('Add &Largefiles...'), addlf, frozenset('I?'))
+ elif 'kbfiles' in self.repo.extensions():
+ make(_('Add &Bfiles'), addlf, frozenset('I?'))
make(_('&Detect Renames...'), guessRename, frozenset('A?!'),
'detect_rename')
make(_('&Ignore...'), ignore, frozenset('?'), 'ignore')
@@ -266,9 +269,42 @@ return True
def add(parent, ui, repo, files):
+ haslf = 'largefiles' in repo.extensions()
+ if haslf or 'kbfiles' in repo.extensions():
+ result = bfprompt.promptForBfiles(parent, ui, repo, files)
+ if not result:
+ return False
+ files, lfiles = result
+ for name, module in extensions.extensions():
+ if name == 'largefiles':
+ override_add = module.lfsetup.override_add
+ if files:
+ override_add(commands.add, ui, repo, *files)
+ if lfiles:
+ override_add(commands.add, ui, repo, large=True, *lfiles)
+ return True
+ if name == 'kbfiles':
+ override_add = module.bfsetup.override_add
+ if files:
+ override_add(commands.add, ui, repo, *files)
+ if lfiles:
+ override_add(commands.add, ui, repo, bf=True, *lfiles)
+ return True
commands.add(ui, repo, *files)
return True
+def addlf(parent, ui, repo, files):
+ for name, module in extensions.extensions():
+ if name == 'largefiles':
+ override_add = module.lfsetup.override_add
+ override_add(commands.add, ui, repo, large=True, *files)
+ return True
+ if name == 'kbfiles':
+ override_add = module.bfsetup.override_add
+ override_add(commands.add, ui, repo, bf=True, *files)
+ return True
+ return False
+
def guessRename(parent, ui, repo, files):
from tortoisehg.hgqt.guess import DetectRenameDialog
dlg = DetectRenameDialog(repo, parent, *files)
|
@@ -128,6 +128,11 @@ def thgmqunappliedpatch(self): return True
def thgid(self): return self._identity
+ # largefiles/kbfiles methods
+ def hasStandin(self, file): return False
+ def isStandin(self, path): return False
+ def removeStandin(self, path): return path
+
def longsummary(self):
summary = hglib.tounicode(self.description())
if self._repo.ui.configbool('tortoisehg', 'longsummary'):
|
@@ -90,7 +90,11 @@ time.sleep(tdelta)
repo = hg.repository(ui, root) # a fresh repo object is needed
+ repo.bfstatus = True
+ repo.lfstatus = True
repostate = repo.status() # will update .hg/dirstate as a side effect
+ repo.bfstatus = False
+ repo.lfstatus = False
modified, added, removed, deleted = repostate[:4]
dirstatus = {}
|
|
@@ -0,0 +1,13 @@ + <Include>
+ <?define CLSID_TortoiseHgCmenu = {46605027-5B8C-4DCE-BFE0-051B7972D64C} ?>
+ <?define CLSID_TortoiseHgDropHandler = {CEBD95BE-B733-415F-82A8-673D9158466E} ?>
+ <?define CLSID_TortoiseHgNormal = {869C8877-2C3C-438D-844B-31B86BFE5E8A} ?>
+ <?define CLSID_TortoiseHgAdded = {AF42ADAB-8C2E-4285-B746-99B31094708E} ?>
+ <?define CLSID_TortoiseHgModified = {CDA1C89D-E9B5-4981-A857-82DD932EA2FD} ?>
+ <?define CLSID_TortoiseHgUnversioned = {9E3D4EC9-0624-4393-8B48-204C217ED1FF} ?>
+ <?define CLSID_TortoiseHgKeyboard = {36BFF16B-4EA0-4D91-9D2C-39941CF0BFE4} ?>
+ <?define CLSID_TortoiseHgCopyHook = {61047697-7E8B-46FE-9CF8-2CE603EB3017} ?>
+ <?define OverlayCLSIDList =
+ {869C8877-2C3C-438D-844B-31B86BFE5E8A};{AF42ADAB-8C2E-4285-B746-99B31094708E};{CDA1C89D-E9B5-4981-A857-82DD932EA2FD};{9E3D4EC9-0624-4393-8B48-204C217ED1FF}
+ ?>
+</Include>
|
|
@@ -0,0 +1,24 @@ + <Include>
+ <!-- copy hook component -->
+ <RegistryValue
+ Root='HKCR' Key='CLSID\$(var.CLSID_TortoiseHgCopyHook)'
+ Type='string' Value='TortoiseHg'
+ />
+ <RegistryValue
+ Root='HKCR' Key='CLSID\$(var.CLSID_TortoiseHgCopyHook)\InProcServer32'
+ Type='string' Name='ThreadingModel' Value='Apartment'
+ />
+
+ <!-- register copy hook handler -->
+ <RegistryValue
+ Root='HKCR' Key='Directory\shellex\CopyHookHandlers\TortoiseHgCopyHook'
+ Type='string' Value='$(var.CLSID_TortoiseHgCopyHook)'
+ />
+
+ <!-- Mark all as approved -->
+ <RegistryValue
+ Root='HKLM' Key='Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved'
+ Type='string' Name='$(var.CLSID_TortoiseHgCopyHook)' Value='TortoiseHg'
+ />
+
+</Include>
|
|
@@ -0,0 +1,23 @@ + <Include>
+ <!-- keyboard hook component -->
+ <RegistryValue
+ Root='HKCR' Key='CLSID\$(var.CLSID_TortoiseHgKeyboard)'
+ Type='string' Value='TortoiseHg'
+ />
+ <RegistryValue
+ Root='HKCR' Key='CLSID\$(var.CLSID_TortoiseHgKeyboard)\InProcServer32'
+ Type='string' Name='ThreadingModel' Value='Apartment'
+ />
+
+ <!-- register browser helper object -->
+ <RegistryValue
+ Root='HKLM' Key='Software\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects\$(var.CLSID_TortoiseHgKeyboard)'
+ Type='string' Value='TortoiseHg'
+ />
+
+ <!-- Mark all as approved -->
+ <RegistryValue
+ Root='HKLM' Key='Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved'
+ Type='string' Name='$(var.CLSID_TortoiseHgKeyboard)' Value='TortoiseHg'
+ />
+</Include>
|
Loading...