Staging
v0.5.1
v0.5.1
https://foss.heptapod.net/mercurial/hgview
Revision be670f46836846f4010b82ca4c2ad3e217ad24cf authored by Alain Leufroy on 11 June 2013, 16:58:04 UTC, committed by Alain Leufroy on 11 June 2013, 16:58:04 UTC
On some repo the tree graph was not full filled. The problem comes from the selection of the working directory parent. To select the wd parent we ensure it has already been built. This action encreases the number of built nodes in revision tree (see ``hggraph.Graph.build_nodes``: requested revision + nnodes) But we ensure the wd parent is built the first time the model is filled. It is performed after the first graph rendering but before the timer event that refreshes the tree graph. In some case the first rendering displays only a partial revisions tree graph. Once displayed the wd parent selection complete the revision tree in cache but not yet on the screen. If the revision tree is full filled, the table row count is not updated (see the diff) while a part of the revision tree graph is still missing. Introduced by `always select the working directory at startup <fb5ee4cf21dd>`_ due to `New implementation of the background graph building mecanism <e28a5e3dc5c4>`_. .. note:: I will factorize code in the next commit.
1 parent 60548a5
Tip revision: be670f46836846f4010b82ca4c2ad3e217ad24cf authored by Alain Leufroy on 11 June 2013, 16:58:04 UTC
[qt4] Fix partial tree graph filling
[qt4] Fix partial tree graph filling
Tip revision: be670f4
config.py
# -*- coding: utf-8 -*-
# Copyright (c) 2003-2012 LOGILAB S.A. (Paris, FRANCE).
# http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
#
# pylint: disable=C0103
"""
Module for managing configuration parameters of hgview using Hg's
configuration system
"""
from functools import partial
import os
import re
import shlex
def cached(meth):
"""
decorator to cache config values once they are read
"""
name = meth.func_name
def wrapper(self, *args, **kw):
if name in self._cache:
return self._cache[name]
res = meth(self, *args, **kw)
self._cache[name] = res
return res
wrapper.__doc__ = meth.__doc__
return wrapper
class HgConfig(object):
"""
Class managing user configuration from hg standard configuration system (.hgrc)
"""
def __init__(self, ui, section="hgview"):
self.ui = ui
self.section = section
self._cache = {}
def _fromconfig(self, name, default):
'''allow per-interface configuration.
look for ``interface.config`` then for ``config`` if the first were not
found'''
out = self.ui.config(self.section,
'.'.join((self.ui.opts.interface, name)),
None)
if out is not None:
return out
return self.ui.config(self.section, name, default)
@cached
def getFancyReplace(self):
r"""
fancyreplace: ``"patt" "repl"`` used to modify description by replacing
``patt`` by ``repl`` using regular expression (``re.sub`` for instance).
Ex: "#(\d+)":"`#\\1 <http://www.logilab.org/ticket/\\1>`_"
"""
data = self._fromconfig('fancyreplace', None)
if data is None:
return data
data = shlex.split(data)
assert len(data) == 2
patt, repl = data
return partial(re.compile(patt).sub, repl)
@cached
def getFont(self, default='Monospace'):
"""
font: default font used to display diffs and files. Use Qt4 format.
"""
return self._fromconfig('font', default)
@cached
def getFontSize(self, default=9):
"""
fontsize: text size in file content viewer
"""
return int(self._fromconfig('fontsize', default))
@cached
def getDotRadius(self, default=8):
"""
dotradius: radius (in pixels) of the dot in the revision graph
"""
return int(self._fromconfig('dotradius', default))
@cached
def getUsers(self):
"""
users: path of the file holding users configurations
"""
users = {}
aliases = {}
usersfile = self._fromconfig('users', os.path.join('~', ".hgusers"))
cfgfile = None
if usersfile:
try:
cfgfile = open(os.path.expanduser(usersfile))
except IOError:
cfgfile = None
if cfgfile:
currid = None
for line in cfgfile:
line = line.strip()
if not line or line.startswith('#'):
continue
cmd, val = line.split('=', 1)
if cmd == 'id':
currid = val
if currid in users:
print "W: user %s is defined several times" % currid
users[currid] = {'aliases': set()}
elif cmd == "alias":
users[currid]['aliases'].add(val)
if val in aliases:
print ("W: alias %s is used in several "
"user definitions" % val)
aliases[val] = currid
else:
users[currid][cmd] = val
return users, aliases
@cached
def getFileDescriptionView(self, default='persistent'):
"""
descriptionview:
:asfile: compact view with changeset description in the file list
:persistent: persistent view with changeset description always visible (default)
"""
return self._fromconfig('descriptionview', default).lower()
@cached
def getFileDescriptionColor(self, default='magenta'):
"""
filedescriptioncolor: display color of the "description" entry
"""
return self._fromconfig('filedescriptioncolor', default)
@cached
def getFileModifiedColor(self, default='blue'):
"""
filemodifiedcolor: display color of a modified file
"""
return self._fromconfig('filemodifiedcolor', default)
@cached
def getFileRemovedColor(self, default='red'):
"""
fileremovedcolor: display color of a removed file
"""
return self._fromconfig('fileremovededcolor', default)
@cached
def getFileDeletedColor(self, default='darkred'):
"""
filedeletedcolor: display color of a deleted file
"""
return self._fromconfig('filedeletedcolor', default)
@cached
def getFileAddedColor(self, default='green'):
"""
fileaddedcolor: display color of an added file
"""
return self._fromconfig('fileaddedcolor', default)
@cached
def getRowHeight(self, default=20):
"""
rowheight: height (in pixels) on a row of the revision table
"""
return int(self._fromconfig('rowheight', default))
@cached
def getHideFindDelay(self, default=10000):
"""
hidefinddelay: delay (in ms) after which the find bar will disappear
"""
return int(self._fromconfig('hidefindddelay', default))
@cached
def getFillingStep(self, default=300):
"""
fillingstep: number of nodes 'loaded' at a time when updating repo graph log
"""
return int(self._fromconfig('fillingstep', default))
@cached
def getChangelogColumns(self, default=None):
"""
changelogcolumns: ordered list of displayed columns in changelog views;
defaults to ID, Branch, Log, Author, Date, Tags
"""
cols = self._fromconfig('changelogcolumns', default)
if cols is None:
return None
return [col.strip() for col in cols.split(',') if col.strip()]
@cached
def getFilelogColumns(self, default=None):
"""
filelogcolumns: ordered list of displayed columns in filelog views;
defaults to ID, Log, Author, Date
"""
cols = self._fromconfig('filelogcolumns', default)
if cols is None:
return None
return [col.strip() for col in cols.split(',') if col.strip()]
@cached
def getDisplayDiffStats(self, default="yes"):
"""
displaydiffstats: flag controlling the appearance of the
'Diff' column in a revision's file list
"""
val = str(self._fromconfig('displaydiffstats', default))
return val.lower() in ['true', 'yes', '1', 'on']
@cached
def getMaxFileSize(self, default=100000):
"""
maxfilesize: max size of a file for diff computations, display content, etc.
(-1 means no max size)
"""
return int(self._fromconfig('maxfilesize', default))
@cached
def getDiffBGColor(self, default='black'):
"""
diffbgcolor: background color of diffs
"""
return self._fromconfig('diffbgcolor', default)
@cached
def getDiffFGColor(self, default='white'):
"""
difffgcolor: text color of diffs
"""
return self._fromconfig('difffgcolor', default)
@cached
def getDiffPlusColor(self, default='green'):
"""
diffpluscolor: text color of added lines in diffs
"""
return self._fromconfig('diffpluscolor', default)
@cached
def getDiffMinusColor(self, default='red'):
"""
diffminuscolor: text color of removed lines in diffs
"""
return self._fromconfig('diffminuscolor', default)
@cached
def getDiffSectionColor(self, default='magenta'):
"""
diffsectioncolor: text color of new section in diffs
"""
return self._fromconfig('diffsectioncolor', default)
@cached
def getMQFGColor(self, default='#ff8183'):
"""
mqfgcolor: bg color to highlight mq patches
"""
return self._fromconfig('mqfgcolor', default)
@cached
def getMQHideTags(self, default=False):
"""
mqhidetags: hide mq tags
"""
return self._fromconfig('mqhidetags', default)
@cached
def getToolBarRevAtStartup(self, default=True):
"""
toolbarrev: show hidden changeset at startup
"""
return bool(self._fromconfig('toolbarrev', default))
@cached
def getToolBarDiffAtStartup(self, default=True):
"""
toolbardiff: show hidden changeset at startup
"""
return bool(self._fromconfig('toolbardiff', default))
@cached
def getContentAtStartUp(self, default=True):
"""
contentatstartup: show the content of changeset at startup (bottom part)
"""
return bool(self._fromconfig('contentatstartup', default))
@cached
def getShowHidden(self, default=False):
"""
showhidden: show hidden changeset at startup
"""
return bool(self._fromconfig('showhidden', default))
@cached
def getInterface(self, default=None):
"""
interface: which GUI interface to use (among "qt", "raw" and "curses")
"""
return self.ui.config(self.section, 'interface', default)
@cached
def getNonPublicOnTop(self, default=False):
"""
nonpublicontop: display non public changesets on top of the graph log
(disabled with *show hidden*)
"""
return bool(self._fromconfig('nonpublicontop', default))
@cached
def getShowObsolete(self, default=True):
"""
showobsolete: display obsolete relations
"""
return bool(self._fromconfig('showobsolete', default))
@cached
def getExportTemplate(self):
"""
exporttemplate: template used to serialize changeset metadata
while exporting into the window manager clipboard.
(default to `ui.logtemplate`)
"""
return self._fromconfig('exporttemplate', None) or \
self.ui.config('ui', 'logtemplate')
_HgConfig = HgConfig
# HgConfig is instantiated only once (singleton)
#
# this 'factory' is used to manage this (not using heavy guns of
# metaclass or so)
_hgconfig = None
def HgConfig(ui):
"""Factory to instantiate HgConfig class as a singleton
"""
# pylint: disable=E0102
global _hgconfig
if _hgconfig is None:
_hgconfig = _HgConfig(ui)
return _hgconfig
def get_option_descriptions(rest=False):
"""
Extract options descriptions (docstrings of HgConfig methods)
"""
options = []
for attr in dir(_HgConfig):
if attr.startswith('get'):
meth = getattr(_HgConfig, attr)
if callable(meth):
doc = meth.__doc__
if doc and doc.strip():
doc = doc.strip()
if rest:
doc = re.sub(r' *(?P<arg>.*) *: *(?P<desc>.*)', r'``\1`` \2', doc.strip())
doc = ' '.join(doc.split()) # remove \n and other multiple whitespaces
options.append(doc)
return options
Computing file changes ...