PageRenderTime 50ms CodeModel.GetById 12ms app.highlight 34ms RepoModel.GetById 1ms app.codeStats 0ms

/tortoisehg/util/menuthg.py

https://bitbucket.org/tortoisehg/hgtk/
Python | 334 lines | 265 code | 49 blank | 20 comment | 50 complexity | 2d19a5544ee22fc717f6990ee7eaff4f MD5 | raw file
  1# menuthg.py - TortoiseHg shell extension menu
  2#
  3# Copyright 2009 Steve Borho <steve@borho.org>
  4#
  5# This software may be used and distributed according to the terms of the
  6# GNU General Public License version 2, incorporated herein by reference.
  7
  8import os
  9
 10from mercurial import hg, ui, node, error
 11
 12from tortoisehg.util.i18n import _ as gettext
 13from tortoisehg.util import cachethg, paths, hglib
 14
 15def _(msgid):
 16    return {'id': msgid, 'str': gettext(msgid)}
 17
 18thgcmenu = {
 19    'commit':     { 'label': _('Commit...'),
 20                    'help':  _('Commit changes in repository'),
 21                    'icon':  'menucommit.ico'},
 22    'init':       { 'label': _('Create Repository Here'),
 23                    'help':  _('Create a new repository'),
 24                    'icon':  'menucreaterepos.ico'},
 25    'clone':      { 'label': _('Clone...'),
 26                    'help':  _('Create clone here from source'),
 27                    'icon': 'menuclone.ico'},
 28    'status':     { 'label': _('File Status'),
 29                    'help':  _('Repository status & changes'),
 30                    'icon':  'menushowchanged.ico'},
 31    'add':        { 'label': _('Add Files...'),
 32                    'help':  _('Add files to version control'),
 33                    'icon':  'menuadd.ico'},
 34    'revert':     { 'label': _('Revert Files...'),
 35                    'help':  _('Revert file changes'),
 36                    'icon':  'menurevert.ico'},
 37    'forget':     { 'label': _('Forget Files...'),
 38                    'help':  _('Remove files from version control'),
 39                    'icon':  'menurevert.ico'},
 40    'remove':     { 'label': _('Remove Files...'),
 41                    'help':  _('Remove files from version control'),
 42                    'icon':  'menudelete.ico'},
 43    'rename':     { 'label': _('Rename File'),
 44                    'help':  _('Rename file or directory'),
 45                    'icon':  'general.ico'},
 46    'workbench':  { 'label': _('Workbench'),
 47                    'help':  _('View change history in repository'),
 48                    'icon':  'menulog.ico'},
 49    'log':        { 'label': _('File History'),
 50                    'help':  _('View change history of selected files'),
 51                    'icon':  'menulog.ico'},
 52    'synch':      { 'label': _('Synchronize'),
 53                    'help':  _('Synchronize with remote repository'),
 54                    'icon':  'menusynch.ico'},
 55    'serve':      { 'label': _('Web Server'),
 56                    'help':  _('Start web server for this repository'),
 57                    'icon':  'proxy.ico'},
 58    'update':     { 'label': _('Update...'),
 59                    'help':  _('Update working directory'),
 60                    'icon':  'menucheckout.ico'},
 61    'thgstatus':  { 'label': _('Update Icons'),
 62                    'help':  _('Update icons for this repository'),
 63                    'icon':  'refresh_overlays.ico'},
 64    'userconf':   { 'label': _('Global Settings'),
 65                    'help':  _('Configure user wide settings'),
 66                    'icon':  'settings_user.ico'},
 67    'repoconf':   { 'label': _('Repository Settings'),
 68                    'help':  _('Configure repository settings'),
 69                    'icon':  'settings_repo.ico'},
 70    'shellconf':  { 'label': _('Explorer Extension Settings'),
 71                    'help':  _('Configure Explorer extension'),
 72                    'icon':  'settings_user.ico'},
 73    'about':      { 'label': _('About TortoiseHg'),
 74                    'help':  _('Show About Dialog'),
 75                    'icon':  'menuabout.ico'},
 76    'vdiff':      { 'label': _('Visual Diff'),
 77                    'help':  _('View changes using GUI diff tool'),
 78                    'icon':  'TortoiseMerge.ico'},
 79    'hgignore':   { 'label': _('Edit Ignore Filter'),
 80                    'help':  _('Edit repository ignore filter'),
 81                    'icon':  'ignore.ico'},
 82    'guess':      { 'label': _('Guess Renames'),
 83                    'help':  _('Detect renames and copies'),
 84                    'icon':  'detect_rename.ico'},
 85    'grep':       { 'label': _('Search History'),
 86                    'help':  _('Search file revisions for patterns'),
 87                    'icon':  'menurepobrowse.ico'},
 88    'dndsynch':   { 'label': _('DnD Synchronize'),
 89                    'help':  _('Synchronize with dragged repository'),
 90                    'icon':  'menusynch.ico'}}
 91
 92_ALWAYS_DEMOTE_ = ('about', 'userconf', 'repoconf')
 93
 94class TortoiseMenu(object):
 95
 96    def __init__(self, menutext, helptext, hgcmd, icon=None, state=True):
 97        self.menutext = menutext
 98        self.helptext = helptext
 99        self.hgcmd = hgcmd
100        self.icon = icon
101        self.state = state
102
103    def isSubmenu(self):
104        return False
105
106    def isSep(self):
107        return False
108
109
110class TortoiseSubmenu(TortoiseMenu):
111
112    def __init__(self, menutext, helptext, menus=[], icon=None):
113        TortoiseMenu.__init__(self, menutext, helptext, None, icon)
114        self.menus = menus[:]
115
116    def add_menu(self, menutext, helptext, hgcmd, icon=None, state=True):
117        self.menus.append(TortoiseMenu(menutext, helptext,
118                hgcmd, icon, state))
119
120    def add_sep(self):
121        self.menus.append(TortoiseMenuSep())
122
123    def get_menus(self):
124        return self.menus
125
126    def append(self, entry):
127        self.menus.append(entry)
128
129    def isSubmenu(self):
130        return True
131
132
133class TortoiseMenuSep(object):
134
135    hgcmd = '----'
136
137    def isSubmenu(self):
138        return False
139
140    def isSep(self):
141        return True
142
143
144class thg_menu(object):
145
146    def __init__(self, ui, promoted, name = "TortoiseHg"):
147        self.menus = [[]]
148        self.ui = ui
149        self.name = name
150        self.sep = [False]
151        self.promoted = promoted
152
153    def add_menu(self, hgcmd, icon=None, state=True):
154        if hgcmd in self.promoted:
155            pos = 0
156        else:
157            pos = 1
158        while len(self.menus) <= pos: #add Submenu
159            self.menus.append([])
160            self.sep.append(False)
161        if self.sep[pos]:
162            self.sep[pos] = False
163            self.menus[pos].append(TortoiseMenuSep())
164        self.menus[pos].append(TortoiseMenu(
165                thgcmenu[hgcmd]['label']['str'],
166                thgcmenu[hgcmd]['help']['str'], hgcmd,
167                thgcmenu[hgcmd]['icon'], state))
168
169    def add_sep(self):
170        self.sep = [True for _s in self.sep]
171
172    def get(self):
173        menu = self.menus[0][:]
174        for submenu in self.menus[1:]:
175            menu.append(TortoiseSubmenu(self.name, 'Mercurial', submenu, "hg.ico"))
176        menu.append(TortoiseMenuSep())
177        return menu
178
179    def __iter__(self):
180        return iter(self.get())
181
182
183def open_repo(path):
184    root = paths.find_root(path)
185    if root:
186        try:
187            repo = hg.repository(ui.ui(), path=root)
188            return repo
189        except error.RepoError:
190            pass
191        except StandardError, e:
192            print "error while opening repo %s:" % path
193            print e
194
195    return None
196
197
198class menuThg:
199    """shell extension that adds context menu items"""
200
201    def __init__(self, internal=False):
202        self.name = "TortoiseHg"
203        promoted = []
204        pl = ui.ui().config('tortoisehg', 'promoteditems', 'commit,log')
205        for item in pl.split(','):
206            item = item.strip()
207            if item:
208                promoted.append(item)
209        if internal:
210            for item in thgcmenu.keys():
211                promoted.append(item)
212        for item in _ALWAYS_DEMOTE_:
213            if item in promoted:
214                promoted.remove(item)
215        self.promoted = promoted
216
217
218    def get_commands_dragdrop(self, srcfiles, destfolder):
219        """
220        Get a list of commands valid for the current selection.
221
222        Commands are instances of TortoiseMenu, TortoiseMenuSep or TortoiseMenu
223        """
224
225        # we can only accept dropping one item
226        if len(srcfiles) > 1:
227            return []
228
229        # open repo
230        drag_repo = None
231        drop_repo = None
232
233        drag_path = srcfiles[0]
234        drag_repo = open_repo(drag_path)
235        if not drag_repo:
236            return []
237        if drag_repo and drag_repo.root != drag_path:
238            return []   # dragged item must be a hg repo root directory
239
240        drop_repo = open_repo(destfolder)
241
242        menu = thg_menu(drag_repo.ui, self.promoted, self.name)
243        menu.add_menu('clone')
244
245        if drop_repo:
246            menu.add_menu('dndsynch')
247        return menu
248
249    def get_norepo_commands(self, cwd, files):
250        menu = thg_menu(ui.ui(), self.promoted, self.name)
251        menu.add_menu('clone')
252        menu.add_menu('init')
253        menu.add_menu('userconf')
254        menu.add_sep()
255        menu.add_menu('about')
256        menu.add_sep()
257        return menu
258
259    def get_commands(self, repo, cwd, files):
260        """
261        Get a list of commands valid for the current selection.
262
263        Commands are instances of TortoiseMenu, TortoiseMenuSep or TortoiseMenu
264        """
265        states = set()
266        onlyfiles = len(files) > 0
267        hashgignore = False
268        for f in files:
269            if not os.path.isfile(f):
270                onlyfiles = False
271            if f.endswith('.hgignore'):
272                hashgignore = True
273            states.update(cachethg.get_states(f, repo))
274        if not files:
275            states.update(cachethg.get_states(cwd, repo))
276            if cachethg.ROOT in states and len(states) == 1:
277                states.add(cachethg.MODIFIED)
278
279        changed = bool(states & set([cachethg.ADDED, cachethg.MODIFIED]))
280        modified = cachethg.MODIFIED in states
281        clean = cachethg.UNCHANGED in states
282        tracked = changed or modified or clean
283        new = bool(states & set([cachethg.UNKNOWN, cachethg.IGNORED]))
284
285        menu = thg_menu(repo.ui, self.promoted, self.name)
286        if changed or cachethg.UNKNOWN in states or 'qtip' in repo['.'].tags():
287            menu.add_menu('commit')
288        if hashgignore or new and len(states) == 1:
289            menu.add_menu('hgignore')
290        if changed or cachethg.UNKNOWN in states:
291            menu.add_menu('status')
292
293        # Visual Diff (any extdiff command)
294        has_vdiff = repo.ui.config('tortoisehg', 'vdiff', 'vdiff') != ''
295        if has_vdiff and modified:
296            menu.add_menu('vdiff')
297
298        if len(files) == 0 and cachethg.UNKNOWN in states:
299            menu.add_menu('guess')
300        elif len(files) == 1 and tracked: # needs ico
301            menu.add_menu('rename')
302
303        if files and new:
304            menu.add_menu('add')
305        if files and tracked:
306            menu.add_menu('remove')
307        if files and changed:
308            menu.add_menu('revert')
309
310        menu.add_sep()
311
312        if tracked:
313            menu.add_menu(files and 'log' or 'workbench')
314
315        if len(files) == 0:
316            menu.add_sep()
317            menu.add_menu('grep')
318            menu.add_sep()
319            menu.add_menu('synch')
320            menu.add_menu('serve')
321            menu.add_sep()
322            menu.add_menu('clone')
323            if repo.root != cwd:
324                menu.add_menu('init')
325
326        # add common menu items
327        menu.add_sep()
328        menu.add_menu('userconf')
329        if tracked:
330            menu.add_menu('repoconf')
331        menu.add_menu('about')
332
333        menu.add_sep()
334        return menu