Mercurial and Git clients can push and pull from this alias URL to interact with this repository. You can change to which repository an alias points by going to the Aliases link on the project page.
stable
history: show details of custom filter in window title
The statusbar is small to show details of custom filter. When it shows file patterns, the area of statusbar will be filled by them entirely. So I show them only in title.
# history.py - Changelog dialog for TortoiseHg## Copyright 2007 Brad Schick, brad at gmail . com# Copyright 2008 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.importosimportsysimportgtkimportgobjectimportshutilimporttempfileimportatexitfrommercurialimportui,hg,cmdutil,commands,extensions,util,match,urlfrommercurialimporthbisect,errorfromtortoisehg.util.i18nimport_fromtortoisehg.utilimporthglibfromtortoisehg.hgtk.logview.treeviewimportTreeViewasLogTreeViewfromtortoisehg.hgtk.logview.treeviewimportCOLSDEFAULT_COLS='graph msg user age'.split()fromtortoisehg.hgtkimportgdialog,gtklib,hgcmd,gorev,thgstripfromtortoisehg.hgtkimportbackout,status,hgemail,tagadd,update,mergefromtortoisehg.hgtkimportarchive,changeset,thgconfig,thgmq,histdetailsfromtortoisehg.hgtkimportstatusbar,bookmark,thgimportMODE_REVRANGE=0MODE_FILEPATS=1MODE_KEYWORDS=2MODE_DATE=3MODE_USER=4HIST_DND_URI_LIST=1024DND_DEST_GRAPHVIEW=0DND_DEST_PATHENTRY=1classFilterBar(gtklib.SlimToolbar):'Filter Toolbar for repository log'def__init__(self,tooltips,filter_mode,branch_names):gtklib.SlimToolbar.__init__(self,tooltips)self.filter_mode=filter_modeself.buttons={}self.handlers={}self.all=gtk.RadioButton(None,_('All'))self.all.set_active(True)self.append_widget(self.all,padding=0)self.buttons['all']=self.allself.tagged=gtk.RadioButton(self.all,_('Tagged'))self.append_widget(self.tagged,padding=0)self.buttons['tagged']=self.taggedself.ancestry=gtk.RadioButton(self.all,_('Ancestry'))self.append_widget(self.ancestry,padding=0)self.buttons['ancestry']=self.ancestryself.parents=gtk.RadioButton(self.all,_('Parents'))self.append_widget(self.parents,padding=0)self.buttons['parents']=self.parentsself.heads=gtk.RadioButton(self.all,_('Heads'))self.append_widget(self.heads,padding=0)self.buttons['heads']=self.headsself.merges=gtk.RadioButton(self.all,_('Merges'))self.append_widget(self.merges,padding=0)self.buttons['only_merges']=self.mergesself.hidemerges=gtk.CheckButton(_('Hide Merges'))self.append_widget(self.hidemerges,padding=0)self.buttons['no_merges']=self.hidemergesself.branches=gtk.RadioButton(self.all)tooltips.set_tip(self.branches,_('Branch Filter'))self.branches.set_sensitive(False)self.append_widget(self.branches,padding=0)self.buttons['branch']=self.branchesself.branchcombo=gtk.combo_box_new_text()self.refresh(branch_names)self.branchcombo.set_active(0)self.append_widget(self.branchcombo,padding=0)self.custombutton=gtk.RadioButton(self.all)tooltips.set_tip(self.custombutton,_('Custom Filter'))self.custombutton.set_sensitive(False)self.append_widget(self.custombutton,padding=0)self.buttons['custom']=self.custombuttonself.filtercombo=gtk.combo_box_new_text()self.filtercombo_entries=(_('Rev Range'),_('File Patterns'),_('Keywords'),_('Date'),_('User'))forfinself.filtercombo_entries:self.filtercombo.append_text(f)if(self.filter_mode>=len(self.filtercombo_entries)orself.filter_mode<0):self.filter_mode=1self.filtercombo.set_active(self.filter_mode)self.append_widget(self.filtercombo,padding=0)searchlist=gtk.ListStore(int,# filtercombo valuestr,# search string (utf-8)str)# mode string (utf-8)entrycombo=gtk.ComboBoxEntry(searchlist,1)cell=gtk.CellRendererText()entrycombo.pack_end(cell,False)entrycombo.add_attribute(cell,'text',2)entry=entrycombo.childself.entrycombo=entrycomboself.entry=entryself.append_widget(entrycombo,expand=True,padding=0)defconnect(self,detailed_signal,handler,*opts):'''Connect an external signal handler to an internal widget Signal format is '[widget_name]_[signal]'.'''widget_name,signal=detailed_signal.split('_')widget=self.__dict__[widget_name]widget.connect(signal,handler,*opts)ifnotself.handlers.has_key(widget_name):self.handlers[widget_name]=[]self.handlers[widget_name].append(handler)defget_button(self,type):returnself.buttons.get(type)defrefresh(self,branch_names):''' refresh branch names in drop-down list '''# block all handlersifself.handlers.has_key('branchcombo'):handlers=self.handlers['branchcombo']forhandlerinhandlers:self.branchcombo.handler_block_by_func(handler)else:handlers=()# save selected itemtext=self.branchcombo.get_active_text()# refresh branch namesself.branchcombo.get_model().clear()self.branchcombo.append_text(_('Branches...'))fornameinbranch_names:self.branchcombo.append_text(name)# try to restore previously selected itemforrowinself.branchcombo.get_model():ifrow[0]==text:self.branchcombo.set_active_iter(row.iter)breakelse:# fallback to 'All' filter if no matchesself.branchcombo.set_active(0)self.all.set_active(True)# unblock all handlersforhandlerinhandlers:self.branchcombo.handler_unblock_by_func(handler)classGLog(gdialog.GWindow):'GTK+ based dialog for displaying repository logs'definit(self):self.filter='all'self.no_merges=Falseself.lastrevid=Noneself.currevid=Noneself.origtip=len(self.repo)self.ready=Falseself.filterbar=Noneself.details_model=Noneself.syncbox=Noneself.filteropts=Noneself.bundledir=Noneself.bfile=Noneself.npreviews=0self.outgoing=[]self.useproxy=Noneself.revrange=Noneself.forcepush=Falseself.bundle_autoreject=Falseself.runner=hgcmd.CmdRunner()os.chdir(self.repo.root)self.exs=[nameforname,moduleinextensions.extensions()]defget_help_url(self):return'changelog.html'defdelete(self,window,event):ifnotself.should_live():self.destroy()else:returnTruedefshould_live(self,widget=None,event=None):live=Falseifself.bfileandnotself.bundle_autoreject:t=_('New changesets from the preview bundle are still pending.''\n\nAccept or reject the new changesets?')# response: 0=Yes, 1=No, 2=Cancelresponse=gdialog.CustomPrompt(_('Accept new Changesets'),t,self,(_('&Accept'),_('&Reject'),_('&Cancel')),2,2).run()ifresponse==0:self.apply_clicked(None)elifresponse==2:live=Trueifnotlive:self._destroying(widget)returnlivedefget_title(self):str=self.get_reponame()+' - '+_('Repository Explorer')ifself.bfile:str+=_(' (Bundle Preview)')returnstrdefget_icon(self):return'menulog.ico'defget_default_setting(self):return'tortoisehg.authorcolor'defparse_opts(self):# Disable quiet to get full log infoself.ui.quiet=Falsedefget_tbbuttons(self):tbar=[self.make_toolbutton(gtk.STOCK_REFRESH,_('Re_fresh'),self.refresh_clicked,name='refresh',tip=_('Reload revision history')),self.make_toolbutton(gtk.STOCK_CLEAR,_('Reset _Marks'),self.refresh_clicked,userdata=True,name='reset',tip=_('Reset revision marks')),]if'mq'inself.exs:self.mqtb=self.make_toolbutton(gtk.STOCK_DIRECTORY,_('Patch Queue'),self.mq_clicked,name='mq',tip=_('Show/Hide Patch Queue'),toggle=True,icon='menupatch.ico')tbar+=[gtk.SeparatorToolItem(),self.mqtb]sep=gtk.SeparatorToolItem()sep.set_expand(True)sep.set_draw(False)tbar.append(sep)tbar+=[self.make_toolbutton(gtk.STOCK_OK,_('Commit'),self.launch,userdata='commit',icon='menucommit.ico',tip=_('Launch commit tool')),self.make_toolbutton(gtk.STOCK_OK,_('Datamine'),self.launch,userdata='datamine',icon='menurepobrowse.ico',tip=_('Launch data mining tool')),self.make_toolbutton(gtk.STOCK_OK,_('Recovery'),self.launch,userdata='recovery',icon='general.ico',tip=_('Launch recovery tool')),self.make_toolbutton(gtk.STOCK_OK,_('Serve'),self.launch,userdata='serve',icon='proxy.ico',tip=_('Launch web server')),self.make_toolbutton(gtk.STOCK_OK,_('Shelve'),self.launch,userdata='shelve',icon='shelve.ico',tip=_('Launch shelve tool')),]returntbardefget_menu_list(self):deftoggle_proxy(menuitem):self.useproxy=menuitem.get_active()deftoggle_force(menuitem):self.forcepush=menuitem.get_active()defrefresh(menuitem,resetmarks):ifresetmarks:self.stbar.set_idle_text(None)self.outgoing=[]self.origtip=len(self.repo)self.reload_log()defnavigate(menuitem,revname):ifrevname:self.goto_rev(revname)elifself.gorev_dialog:self.gorev_dialog.show()self.gorev_dialog.present()else:self.show_goto_dialog()defdisable_maxdiff(menuitem):ifmenuitem.get_active():hglib._maxdiff=sys.maxintelse:hglib._maxdiff=Noneself.reload_log()# navigation menu (branches, tags)navi_menu=[]lb=hglib.getlivebranch(self.repo)filter_b=[]iflen(lb)>1or(lbandlb[0]!='default'):navi_b=[]fornameinlb[:10]:lname=hglib.fromutf(name)navi_b.append(dict(text=name,func=navigate,args=[lname],use_underline=False))filter_b.append(dict(text=name,name='@'+name,func=self.filter_handler,args=['branch',name],asradio=True,rg='all',use_underline=False))iflen(navi_b)>0:navi_menu.append(dict(text='----'))navi_menu.append(dict(text=_('Branches'),subitems=navi_b,icon='branch.ico'))ft=hglib.getfilteredtags(self.repo)ft.sort()ft.reverse()navi_t=[]fortaginft:tname=hglib.toutf(tag)navi_t.append(dict(text=tname,func=navigate,args=[tag],use_underline=False))iflen(navi_t)>0:iflen(navi_menu)==0:navi_menu.append(dict(text='----'))navi_menu.append(dict(text=_('Tags'),subitems=navi_t,icon=gtk.STOCK_ITALIC))# sync menufnc=self.toggle_view_columnifself.repo.ui.configbool('tortoisehg','disable-syncbar'):sync_bar_item=[]else:sync_bar_item=[dict(text=_('Sync Bar'),ascheck=True,func=self.toggle_show_syncbar,check=self.show_syncbar)]# MQ extension menuif'mq'inself.exs:mq_item=[dict(text=_('Patch Queue'),name='mq',ascheck=True,func=self.mq_clicked,check=self.setting_mqvis)]else:mq_item=[]# Perforce extension menuif'perfarce'inself.exs:p4menu=[dict(text=_('_Perforce'),subitems=[dict(text=_('Identify'),func=self.p4identify,icon=gtk.STOCK_PROPERTIES),dict(text=_('Pending'),func=self.p4pending,icon=gtk.STOCK_APPLY),])]else:p4menu=[]return[dict(text=_('_View'),subitems=[dict(text=_('Load more Revisions'),name='load-more',func=self.more_clicked,icon=gtk.STOCK_GO_DOWN),dict(text=_('Load all Revisions'),name='load-all',func=self.load_all_clicked,icon=gtk.STOCK_GOTO_BOTTOM),dict(text='----'),dict(text=_('Toolbar'),ascheck=True,check=self.show_toolbar,func=self.toggle_show_toolbar),]+sync_bar_item+[dict(text=_('Filter Bar'),ascheck=True,func=self.toggle_show_filterbar,check=self.show_filterbar),]+mq_item+[dict(text='----'),dict(text=_('Refresh'),func=refresh,args=[False],icon=gtk.STOCK_REFRESH),dict(text=_('Reset Marks'),func=refresh,args=[True],icon=gtk.STOCK_CLEAR),dict(text='----'),dict(text=_('Choose Details...'),func=self.details_clicked,icon='general.ico'),dict(text='----'),dict(name='compact-graph',text=(_('Compact Graph')),ascheck=True,func=self.toggle_compactgraph,check=self.compactgraph),dict(name='color-by-branch',text=_('Color by Branch'),ascheck=True,func=self.toggle_branchcolor,check=self.branch_color),dict(text=_('Ignore Max Diff Size'),ascheck=True,func=disable_maxdiff),dict(name='always-show-output',text=(_('Always Show Output')),ascheck=True,func=self.toggle_showoutput,check=self.showoutput),]),dict(text=_('_Navigate'),subitems=[dict(text=_('Tip'),func=navigate,args=['tip'],icon=gtk.STOCK_ABOUT),dict(text=_('Working Parent'),func=navigate,args=['.'],icon=gtk.STOCK_HOME),dict(text=_('Previously Selected'),icon=gtk.STOCK_GO_BACK,func=lambda*a:self.goto_prev_sel()),dict(text='----'),dict(text=_('Revision...'),icon=gtk.STOCK_JUMP_TO,func=lambda*a:self.show_goto_dialog()),]+navi_menu),dict(text=_('_Synchronize'),subitems=[dict(text=_('Incoming'),name='incoming',func=self.incoming_clicked,icon=gtk.STOCK_GO_DOWN),dict(text=_('Pull'),name='pull',func=self.pull_clicked,icon=gtk.STOCK_GOTO_BOTTOM),dict(text=_('Outgoing'),name='outgoing',func=self.outgoing_clicked,icon=gtk.STOCK_GO_UP),dict(text=_('Push'),name='push',func=self.push_clicked,icon=gtk.STOCK_GOTO_TOP),dict(text=_('Email...'),name='email',func=self.email_clicked,icon=gtk.STOCK_GOTO_LAST),dict(text=_('Stop'),name='stop',sensitive=False,func=self.stop_clicked,icon=gtk.STOCK_STOP),dict(text='----'),dict(text=_('Accept Bundle'),name='accept',sensitive=bool(self.bfile),func=self.apply_clicked,icon=gtk.STOCK_APPLY),dict(text=_('Reject Bundle'),name='reject',sensitive=bool(self.bfile),func=self.reject_clicked,icon=gtk.STOCK_DIALOG_ERROR),dict(text='----'),dict(text=_('Import...'),name='import',func=self.import_clicked,icon='menuimport.ico'),dict(text=_('Add Bundle...'),name='add-bundle',sensitive=notbool(self.bfile),func=self.add_bundle_clicked,icon=gtk.STOCK_ADD),dict(text='----'),dict(text=_('Configure Paths...'),name='path',func=self.conf_clicked,icon=gtk.STOCK_PREFERENCES),dict(text='----'),dict(text=_('Use proxy server'),name='use-proxy-server',ascheck=True,func=toggle_proxy),dict(text=_('Force push'),ascheck=True,func=toggle_force),]),dict(text=_('_Filter'),subitems=[dict(text=_('All'),name='all',asradio=True,func=self.filter_handler,args=['all'],check=True),dict(text=_('Tagged'),name='tagged',asradio=True,func=self.filter_handler,args=['tagged'],rg='all'),dict(text=_('Ancestry'),name='ancestry',asradio=True,func=self.filter_handler,args=['ancestry'],rg='all'),dict(text=_('Parents'),name='parents',asradio=True,func=self.filter_handler,args=['parents'],rg='all'),dict(text=_('Heads'),name='heads',asradio=True,func=self.filter_handler,args=['heads'],rg='all'),dict(text=_('Merges'),name='only_merges',asradio=True,func=self.filter_handler,args=['only_merges'],rg='all'),dict(text=_('Branch'),name='branch',icon='branch.ico',subitems=filter_b),dict(text=_('Custom'),name='custom',subitems=[dict(text=_('Revision Range'),name='revrange',asradio=True,rg='all',func=self.filter_handler,args=['custom',MODE_REVRANGE]),dict(text=_('File Patterns'),name='filepats',asradio=True,rg='all',func=self.filter_handler,args=['custom',MODE_FILEPATS]),dict(text=_('Keywords'),name='keywords',asradio=True,rg='all',func=self.filter_handler,args=['custom',MODE_KEYWORDS]),dict(text=_('Date'),name='date',asradio=True,rg='all',func=self.filter_handler,args=['custom',MODE_DATE]),dict(text=_('User'),name='user',asradio=True,rg='all',func=self.filter_handler,args=['custom',MODE_USER]),],icon='general.ico'),dict(text='----'),dict(text=_('Hide Merges'),name='no_merges',ascheck=True,func=self.filter_handler,args=['no_merges']),])]+p4menudeftoggle_view_column(self,button,property):active=button.get_active()self.graphview.set_property(property,active)deftoggle_branchcolor(self,button):active=button.get_active()ifself.branch_color!=active:self.graphview.set_property('branch-color',active)self.branch_color=activeself.reload_log()deftoggle_compactgraph(self,button):active=button.get_active()ifself.compactgraph!=active:self.compactgraph=activeself.reload_log()deftoggle_showoutput(self,button):active=button.get_active()ifself.showoutput!=active:self.showoutput=activedeftoggle_show_filterbar(self,button):self.show_filterbar=button.get_active()ifself.filterbarisnotNone:self.filterbar.set_property('visible',self.show_filterbar)deftoggle_show_syncbar(self,button):self.show_syncbar=button.get_active()ifself.syncboxisnotNone:self.syncbox.set_property('visible',self.show_syncbar)deftoggle_show_toolbar(self,button):self.show_toolbar=button.get_active()self.syncbox.set_visible('reload',notself.show_toolbar)self.sttool.set_visible('load',notself.show_toolbar)self._show_toolbar(self.show_toolbar)defexecute_command(self,cmd,callback=None,status=None,title=None,force=False):ifself.showoutputorforce:dlg=hgcmd.CmdDialog(cmd)dlg.show_all()dlg.run()dlg.hide()callbackandcallback(dlg.return_code(),dlg.get_buffer())returndlgdefwrapper(*args):self.stbar.end()self.syncbox.set_enable('stop',False)self.cmd_set_sensitive('stop',False)callbackandcallback(*args)self.stbar.begin(*(statusand(status,)or()))iftitle:self.runner.set_title(title)self.syncbox.set_enable('stop',True)self.cmd_set_sensitive('stop',True)returnself.runner.execute(cmd,wrapper)defp4pending(self,button):'revert or submit these pending changelists'cmd=['hg','p4pending','--verbose']defcallback(return_code,buffer,*args):pending={}ifreturn_code==0:submitted=0forlineinbuffer.splitlines()[:-1]:try:hashes=line.split(' ')changelist=hashes.pop(0)iflen(hashes)>1andlen(hashes[0])==1:state=hashes.pop(0)ifstate=='s':changelist=_('%s (submitted)')%changelistelifstate=='p':changelist=_('%s (pending)')%changelistelse:ifchangelist=='submitted':changelist=_('Submitted')+str(submitted)submitted+=1else:changelist=_('%s (pending)')%changelistpending[changelist]=hashesexcept(ValueError,IndexError):text=_('Unable to parse p4pending output')ifpending:text=_('%d pending changelists found')%len(pending)else:text=_('No pending Perforce changelists')elifreturn_codeisNone:text=_('Aborted p4pending')else:text=_('Unable to determine pending changesets')self.stbar.set_idle_text(text)ifpending:fromtortoisehg.hgtk.p4pendingimportPerforcePendingdialog=PerforcePending(self.repo,pending,self.graphview)dialog.show_all()dialog.present()ifnotself.execute_command(cmd,callback,status=_('Finding pending Perforce changelists...'),title=_('Pending Perforce changelists')):gdialog.Prompt(_('Cannot run now'),_('Please try again after running ''operation is completed'),self).run()defp4identify(self,button):cmd=['hg','p4identify']defcallback(return_code,buffer,*args):ifreturn_code==0:lines=buffer.splitlines()[:-1]iflen(lines)==1:changelist,hash=lines[0].split(' ')text=_('Perforce changelist %s')%changelisttry:ctx=self.repo[hash]self.graphview.set_revision_id(ctx.rev(),load=True)excepterror.LookupError:text=_('Unable to find rev %s')%hashelifreturn_codeisNone:text=_('Aborted p4identify')else:text=_('Unable to identify Perforce tip')self.stbar.set_idle_text(text)ifnotself.execute_command(cmd,callback,status=_('Finding tip Perforce changelist...'),title=_('Identifying Perforce tip')):gdialog.Prompt(_('Cannot run now'),_('Please try again after running ''operation is completed'),self).run()defmore_clicked(self,button,data=None):self.graphview.next_revision_batch(self.limit)defload_all_clicked(self,button,data=None):self.graphview.load_all_revisions()self.cmd_set_sensitive('load-more',False)self.cmd_set_sensitive('load-all',False)self.sttool.set_enable('load',False)defselection_changed(self,graphview):'Graphview reports a new row selected'treeview=graphview.treeviewpath,col=treeview.get_cursor()ifnotpath:self.currevid=NonereturnFalseself.prevrevid=self.currevidself.currevid=graphview.get_revid_at_path(path)self.filterbar.get_button('ancestry').set_sensitive(True)self.menuitems['ancestry'].set_sensitive(True)ifself.currevid!=self.lastrevid:self.lastrevid=self.currevidself.changeview.opts['rev']=[str(self.currevid)]self.changeview.load_details(self.currevid)returnFalsedefrevisions_loaded(self,graphview):'Graphview reports log generator has exited'ifnotgraphview.graphdata:self.changeview.clear()self.cmd_set_sensitive('load-more',False)self.cmd_set_sensitive('load-all',False)self.sttool.set_enable('load',False)defdetails_clicked(self,toolbutton,data=None):self.show_details_dialog()defshow_details_dialog(self):columns={}columns['graph']=(self.graphcol,_('Graph'),'graphcol','graph')defcolumn(col,text):prop=col+'-column-visible'vis=self.graphview.get_property(prop)columns[col]=(vis,text,prop,col)column('rev',_('Revision Number'))column('id',_('Changeset ID'))column('revhex',_('Revision Number/ID'))column('branch',_('Branch Name'))column('changes',_('Changes'))column('msg',_('Summary'))column('user',_('User'))column('date',_('Local Date'))column('utc',_('UTC Date'))column('age',_('Age'))column('tag',_('Tags'))model=gtk.ListStore(gobject.TYPE_BOOLEAN,gobject.TYPE_STRING,gobject.TYPE_STRING,gobject.TYPE_STRING)forcinself.column_order.split():vis,text,prop,col=columns[c]model.append([vis,text,prop,col])self.details_model=modeldlg=histdetails.LogDetailsDialog(model,self.apply_details)dlg.show()defapply_details(self):ifself.details_model:columns=[]forshow,uitext,property,colnameinself.details_model:columns.append(colname)self.graphview.set_columns(columns)self.column_order=' '.join(columns)reload=Falseforshow,uitext,property,colnameinself.details_model:ifproperty=='graphcol':ifself.graphcol!=show:self.graphcol=showreload=Trueself.cmd_set_sensitive('compact-graph',self.graphcol)self.cmd_set_sensitive('color-by-branch',self.graphcol)else:self.graphview.set_property(property,show)self.showcol[property]=showifreload:self.reload_log()deffilter_entry_changed(self,entrycombo,filtercombo):row=entrycombo.get_active()ifrow<0:returnmode,text,display=entrycombo.get_model()[row]filtercombo.set_active(mode)entrycombo.child.set_text(text)self.activate_filter(text,mode)deffilter_entry_activated(self,entry,combo):'User pressed enter in the filter entry'mode=combo.get_active()text=entry.get_text()ifnottext:returnrow=[mode,text,combo.get_active_text()]model=self.entrycombo.get_model()forrinmodel:ifr[0]==row[0]andr[1]==row[1]:breakelse:self.entrycombo.get_model().append(row)self.activate_filter(text,mode)defcheck_filter_text(self,text,mode):ifnottext:returnFalseelifmode==0:try:cmdutil.revrange(self.repo,[text])exceptException,e:gdialog.Prompt(_('Invalid revision range'),str(e),self).run()returnFalseelifmode==3:try:util.matchdate(text)except(ValueError,util.Abort),e:gdialog.Prompt(_('Invalid date specification'),str(e),self).run()returnFalsereturnTruedefactivate_filter(self,text,mode):ifnotself.check_filter_text(text,mode):returnopts={}ifmode==MODE_REVRANGE:opts['revlist']=cmdutil.revrange(self.repo,[text])name='revrange'elifmode==MODE_FILEPATS:opts['pats']=[w.strip()forwintext.split(',')]name='filepats'elifmode==MODE_KEYWORDS:opts['keyword']=[w.strip()forwintext.split(',')]name='keywords'elifmode==MODE_DATE:opts['date']=textname='date'elifmode==MODE_USER:opts['user']=[w.strip()forwintext.split(',')]name='user'else:returnself.filterbar.get_button('custom').set_active(True)self.filter='custom'self.reload_log(**opts)# update menu itemmenu=self.menuitems[name]menu.handler_block_by_func(self.filter_handler)menu.set_active(True)menu.handler_unblock_by_func(self.filter_handler)deffilter_handler(self,menu,type,*args):ifnottype=='no_merges'andnotmenu.get_active():self.lastfilterinfo=(menu,type)returniftype=='branch':branch=args[0]combo=self.branchcombomodel=combo.get_model()forrowinmodel:ifrow[0]==branch:ifcombo.get_active_text()==branch:# need to activate 'branch' radio button if specified# branch was already selected at drop-down listself.filterbar.get_button('branch').set_active(True)else:combo.set_active_iter(row.iter)breakeliftype=='custom':fromtortoisehg.hgtkimportdialogdesc=_("'%s' filter:")%menu.child.get_text()mode=args[0]text=dialog.entry_dialog(self,desc)ifself.check_filter_text(text,mode):self.filterentry.set_text(text)self.filtercombo.set_active(mode)self.filter_entry_activated(self.filterentry,self.filtercombo)elifself.lastfilterinfo:# restore previously selected filterpmenu,ptype=self.lastfilterinfoifptype=='custom':pmenu.handler_block_by_func(self.filter_handler)pmenu.set_active(True)ifptype=='custom':pmenu.handler_unblock_by_func(self.filter_handler)else:button=self.filterbar.get_button(type)ifbutton:button.set_active(menu.get_active())deffilter_selected(self,widget,type):ifnottype=='no_merges'andnotwidget.get_active():returniftype=='branch':self.lastbranchrow=Noneself.select_branch(self.branchcombo)returnmenu=self.menuitems[type]menu.handler_block_by_func(self.filter_handler)menu.set_active(widget.get_active())menu.handler_unblock_by_func(self.filter_handler)iftype=='no_merges':self.no_merges=widget.get_active()self.reload_log()returnself.filter=typeself.filteropts=Noneself.reload_log()defupdate_hide_merges_button(self):button=self.filterbar.get_button('no_merges')menu=self.menuitems['no_merges']compatible=self.filterin['all','branch','custom']ifcompatible:button.set_sensitive(True)menu.set_sensitive(True)else:button.set_active(False)button.set_sensitive(False)menu.set_active(False)menu.set_sensitive(False)self.no_merges=Falsedefpatch_selected(self,mqwidget,revid,patchname):ifrevid<0:patchfile=os.path.join(self.repo.root,'.hg','patches',patchname)self.currevid=self.lastrevid=Noneself.changeview.load_patch_details(patchfile)else:self.goto_rev(revid)defrepo_invalidated(self,mqwidget):self.reload_log()deffiles_dropped(self,mqwidget,files,*args):self.import_clicked(None,thgimport.DEST_MQ,files)defprepare_display(self):'Called at end of display() method'self.ready=Trueroot=self.repo.rootos.chdir(root)# for paths relative to repo rootself.origtip=len(self.repo)self.graphview.set_property('branch-color',self.branch_color)style=self.repo.ui.config('tortoisehg','logtbarstyle','theme')ifstyle=='small':self.toolbar.set_icon_size(gtk.ICON_SIZE_MENU)self.toolbar.set_property('toolbar-style',gtk.TOOLBAR_ICONS)ifstyle=='large':self.toolbar.set_icon_size(gtk.ICON_SIZE_LARGE_TOOLBAR)self.toolbar.set_property('toolbar-style',gtk.TOOLBAR_BOTH)# ignore file patterns that imply repo rootiflen(self.pats)==1andself.pats[0]in(root,root+os.sep,''):self.pats=[]opts=self.optsifopts['filehist']:self.filterbar.get_button('custom').set_active(True)self.filter='custom'self.filtercombo.set_active(1)path=hglib.escapepath(opts['filehist'])self.filterentry.set_text(hglib.toutf(path))self.filter_entry_activated(self.filterentry,self.filtercombo)elifself.pats:self.filterbar.get_button('custom').set_active(True)self.filter='custom'self.filtercombo.set_active(1)paths=[hglib.escapepath(p)forpinself.pats]self.filterentry.set_text(hglib.toutf(', '.join(paths)))self.filter_entry_activated(self.filterentry,self.filtercombo)elif'bundle'inopts:self.set_bundlefile(opts['bundle'])self.bundle_autoreject=Trueelse:self.reload_log(**opts)self.filterbar.set_property('visible',self.show_filterbar)self.filterbar.set_no_show_all(True)self.syncbox.set_property('visible',self.show_syncbar)self.syncbox.set_no_show_all(True)columns=[]forcolin[cforcinself.column_order.split()]:ifcol=='graph':vis=self.graphcolelse:vis=self.showcol[col]self.graphview.set_property(col+'-column-visible',vis)ifvis:columns.append(col)self.graphview.set_columns(columns)self.cmd_set_sensitive('compact-graph',self.graphcol)self.cmd_set_sensitive('color-by-branch',self.graphcol)item=self.get_menuitem('use-proxy-server')ifui.ui().config('http_proxy','host'):item.set_sensitive(True)item.set_active(True)else:item.set_sensitive(False)# enable MQ panelself.enable_mqpanel()defget_proxy_args(self):item=self.get_menuitem('use-proxy-server')ifitem.get_property('sensitive')andnotitem.get_active():return['--config','http_proxy.host=']else:return[]defget_graphlimit(self,suggestion):limit_opt=self.repo.ui.config('tortoisehg','graphlimit','500')l=0forlimitin(suggestion,limit_opt):try:l=int(limit)ifl>0:returnlexcept(TypeError,ValueError):passreturnlor500defsave_settings(self):settings=gdialog.GWindow.save_settings(self)settings['glog-vpane']=self.vpaned.get_position()settings['glog-hpane']=self.hpaned.get_position()ifhasattr(self,'mqpaned')andself.mqwidget.has_patch():curpos=self.mqpaned.get_position()settings['glog-mqpane']=curposorself.setting_mqhpossettings['glog-mqvis']=bool(curpos)else:settings['glog-mqpane']=self.setting_mqhpossettings['glog-mqvis']=self.setting_mqvissettings['branch-color']=self.graphview.get_property('branch-color')settings['show-output']=self.showoutputsettings['show-toolbar']=self.show_toolbarsettings['show-filterbar']=self.show_filterbarsettings['show-syncbar']=self.show_syncbarsettings['graphcol']=self.graphcolsettings['compactgraph']=self.compactgraphforcolin[colforcolinCOLS.split()ifcol!='graph']:vis=self.graphview.get_property(col+'-column-visible')settings['glog-vis-'+col]=vissettings['filter-mode']=self.filtercombo.get_active()settings['column-order']=self.column_orderreturnsettingsdefload_settings(self,settings):'Called at beginning of display() method'gdialog.GWindow.load_settings(self,settings)self.setting_vpos=settings.get('glog-vpane',-1)self.setting_hpos=settings.get('glog-hpane',-1)self.setting_mqhpos=settings.get('glog-mqpane',140)or140self.setting_mqvis=settings.get('glog-mqvis',False)self.branch_color=settings.get('branch-color',False)self.showoutput=settings.get('show-output',False)self.show_toolbar=settings.get('show-toolbar',True)self.show_filterbar=settings.get('show-filterbar',True)self.show_syncbar=settings.get('show-syncbar',True)ifself.repo.ui.configbool('tortoisehg','disable-syncbar'):self.show_syncbar=Falseself.graphcol=settings.get('graphcol',True)self.compactgraph=settings.get('compactgraph',False)self.showcol={}forcolin[colforcolinCOLS.split()ifcol!='graph']:key='glog-vis-'+colself.showcol[col]=settings.get(key,colinDEFAULT_COLS)self.filter_mode=settings.get('filter-mode',1)order=settings.get('column-order',COLS)order_list,def_list=order.split(),COLS.split()order_len,def_len=len(order_list),len(def_list)iforder_len!=def_len:# add newly added columns if existsadded=set(def_list).difference(set(order_list))ifadded:order_list+=list(added)# remove obsoleted columns if existsorder_list=[cforcinorder_listifcindef_list]order=' '.join(order_list)self.column_order=orderdefshow_toolbar_on_start(self):returnself.show_toolbardefrefresh_model(self):'Refresh data in the history model, without reloading graph'ifself.graphview.model:self.graphview.model.refresh()# refresh MQ widget if existsifhasattr(self,'mqwidget'):self.mqwidget.refresh()# force a redraw of the visible rowsself.graphview.hide()self.graphview.show()defreload_log(self,**kwopts):'Send refresh event to treeview object'self.update_hide_merges_button()self.changeview.clear_cache()opts={'date':None,'no_merges':False,'only_merges':False,'keyword':[],'branch':None,'pats':[],'filehist':None,'revrange':[],'revlist':[],'noheads':False,'branch-view':False,'rev':[],'user':[]}ifself.filteroptsandnotkwopts:opts=self.filteroptsopts.update(kwopts)# handle strips, rebases, etcself.origtip=min(len(self.repo),self.origtip)ifnotself.bfile:self.npreviews=0opts['branch-view']=self.compactgraphopts['outgoing']=self.outgoingopts['orig-tip']=self.origtipopts['npreviews']=self.npreviewsopts['no_merges']=self.no_mergesself.cmd_set_sensitive('load-more',len(self.repo)>0)self.cmd_set_sensitive('load-all',len(self.repo)>0)self.sttool.set_enable('load',len(self.repo)>0)self.filterbar.get_button('ancestry').set_sensitive(False)self.menuitems['ancestry'].set_sensitive(False)pats=opts.get('pats',[])self.changeview.pats=patsself.pats=patsself.lastrevid=Nonedefftitle(filtername):t=self.get_title()iffilternameisnotNone:t=t+' - '+filternameself.set_title(t)ifself.filter!='custom':self.filterentry.set_text('')graphcol=self.graphcolifself.no_merges:graphcol=Falsefilterprefix=_('Filter')filtertext=filterprefix+': 'ifself.filter=='branch':branch=opts.get('branch',None)self.graphview.refresh(graphcol,None,opts)ftitle(_('%s branch')%branch)filtertext+=_("Branch '%s'")%branchelifself.filter=='custom':npats=hglib.normpats(pats)iflen(npats)==1:kind,name=match._patsplit(npats[0],None)ifkind=='path'andnotos.path.isdir(name):ftitle(_('file history: ')+hglib.toutf(name))lname=hglib.fromutf(name) opts['filehist'] = lname
self.graphview.refresh(graphcol, [lname], opts)
if not opts.get('filehist'):
- ftitle(self.filtercombo.get_active_text())
+ ftitle('%s: %s' % (self.filtercombo.get_active_text(),+ self.filterentry.get_text()))
self.graphview.refresh(False, npats, opts)
filtertext += self.filtercombo.get_active_text()
elif self.filter == 'all':
ftitle(None)self.graphview.refresh(graphcol,None,opts)filtertext=''elifself.filter=='only_merges':ftitle(_('merges'))opts['only_merges']=Trueself.graphview.refresh(False,[],opts)filtertext+=_('only Merges')elifself.filter=='ancestry':ftitle(_('revision ancestry'))range=[self.currevid,0]opts['noheads']=Trueopts['revrange']=rangeself.graphview.refresh(graphcol,None,opts)filtertext+=_("Ancestry of %s")%self.currevidelifself.filter=='tagged':ftitle(_('tagged revisions'))tagged=[]fort,rinself.repo.tagslist():hr=self.repo[r].rev()ifhrnotintagged:tagged.insert(0,hr)opts['revlist']=taggedself.graphview.refresh(False,[],opts)filtertext+=_("Tagged Revisions")elifself.filter=='parents':ftitle(_('working parents'))repo_parents=[x.rev()forxinself.repo.parents()]opts['revlist']=[str(x)forxinrepo_parents]self.graphview.refresh(False,[],opts)filtertext+=_("Parents")elifself.filter=='heads':ftitle(_('heads'))heads=[self.repo[x].rev()forxinself.repo.heads()]opts['revlist']=[str(x)forxinheads]self.graphview.refresh(False,[],opts)filtertext+=_("Heads")nomergestext=_('no Merges')ifself.no_merges:iffiltertext:filtertext+=', %s'%nomergestextelse:filtertext='%s: %s'%(filterprefix,nomergestext)self.stbar.set_text(filtertext,name='filter')# refresh MQ widget if existsifhasattr(self,'mqwidget'):self.mqwidget.refresh()# update status messagesmq_text=Nonentotal=self.mqwidget.get_num_patches()ifntotal>0:ncount=self.mqwidget.get_num_applied()mq_text=''ifncount>0:mq_text+=_('Current patch: %s, ')% \
self.mqwidget.get_qtip_patchname()mq_text+=_('%(count)d of %(total)d applied patches')%{'count':ncount,'total':ntotal}self.stbar.set_text(mq_text,name='mq')# refresh filterbarself.filterbar.refresh(hglib.getlivebranch(self.repo))# Remember options to next time reload_log is calledself.filteropts=optsdeftree_context_menu(self):m=gtklib.MenuBuilder()m.append(_('Visualize Change'),self.vdiff_change,gtk.STOCK_JUSTIFY_FILL)m.append(_('Di_splay Change'),self.show_status)m.append(_('Diff to Local'),self.vdiff_local)m.append_sep()m.append(_('_Copy Hash'),self.copy_hash,gtk.STOCK_COPY)ifself.bfile:ifself.currevid>=len(self.repo)-self.npreviews:m.append_sep()m.append(_('Pull to Here'),self.pull_to,gtk.STOCK_GOTO_BOTTOM)menu=m.build()menu.show_all()returnmenuifself.repo[self.currevid].node()inself.outgoing:m.append_sep()m.append(_('Push to Here'),self.push_to,gtk.STOCK_GOTO_TOP)m.append_sep()m.append(_('_Update...'),self.checkout,'menucheckout.ico')mmerge=m.append(_('_Merge with...'),self.domerge,'menumerge.ico')mbackout=m.append(_('Backout...'),self.backout_rev,gtk.STOCK_UNDO)m.append(_('_Revert'),self.revert,gtk.STOCK_MEDIA_REWIND)m.append_sep()m.append_submenu(_('Export'),self.export_context_menu(),gtk.STOCK_GO_FORWARD)m.append_sep()m.append_submenu(_('Tag'),self.tags_context_menu(),gtk.STOCK_ITALIC)m.append_sep()# disable/enable menus as requiredparents=self.repo.parents()iflen(parents)>1:can_merge=Falsecan_backout=Falseelse:pctx=parents[0]cctx=self.repo[self.currevid]actx=cctx.ancestor(pctx)can_merge=actx!=pctxorpctx.branch()!=cctx.branch()can_backout=actx==cctxmmerge.set_sensitive(can_merge)mbackout.set_sensitive(can_backout)# need mq extension for strip commandif'mq'inself.exs:m.append_submenu(_('Mercurial Queues'),self.mq_context_menu(),'menupatch.ico')# need transplant extension for transplant commandif'transplant'inself.exs:m.append(_('Transp_lant to Local'),self.transplant_rev,gtk.STOCK_CONVERT)m.append_sep()m.append_submenu(_('Bisect'),self.bisect_context_menu(),gtk.STOCK_FIND)menu=m.build()menu.show_all()returnmenudefexport_context_menu(self):m=gtklib.MenuBuilder()m.append(_('_Export Patch...'),self.export_patch,'menupatch.ico')m.append(_('E_mail Patch...'),self.email_patch,gtk.STOCK_GOTO_LAST)m.append(_('_Bundle rev:tip...'),self.bundle_rev_to_tip,'menurelocate.ico')m.append(_('_Archive...'),self.archive,gtk.STOCK_SAVE)returnm.build()deftags_context_menu(self):m=gtklib.MenuBuilder()m.append(_('Add/Remove _Tag...'),self.add_tag)if'bookmarks'inself.exs:m.append(_('Add/Move/Remove B_ookmark...'),self.add_bookmark)m.append(_('Rename Bookmark...'),self.rename_bookmark,gtk.STOCK_EDIT)ifself.repo.ui.configbool('bookmarks','track.current'):m.append(_('Set Current Bookmark...'),self.current_bookmark,gtk.STOCK_YES)returnm.build()defmq_context_menu(self):m=gtklib.MenuBuilder()mqimport=m.append(_('Import Revision to MQ'),self.qimport_rev,'menuimport.ico')mstrip=m.append(_('Strip Revision...'),self.strip_rev,'menudelete.ico')m.append_sep()try:ctx=self.repo[self.currevid]qbase=self.repo['qbase']actx=ctx.ancestor(qbase)ifself.repo['qparent']==ctx:mqimport.set_sensitive(True)mstrip.set_sensitive(False)elifactx==qbaseoractx==ctx:# we're in the mq revision range or the mq# is a descendant of usmqimport.set_sensitive(False)mstrip.set_sensitive(False)except:passreturnm.build()defbisect_context_menu(self):m=gtklib.MenuBuilder()m.append(_('Reset'),self.bisect_reset,gtk.STOCK_CLEAR)m.append(_('Mark as Good'),self.bisect_good,gtk.STOCK_YES)m.append(_('Mark as Bad'),self.bisect_bad,gtk.STOCK_NO)m.append(_('Skip Testing'),self.bisect_skip,gtk.STOCK_MEDIA_FORWARD)returnm.build()defrestore_single_sel(self,widget,*args):self.tree.get_selection().set_mode(gtk.SELECTION_SINGLE)ifself.origsel:self.tree.get_selection().select_path(self.origsel)self.revrange=Nonedeftree_diff_context_menu(self):m=gtklib.MenuBuilder()m.append(_('_Diff with selected'),self.diff_revs)m.append(_('Visual Diff with selected'),self.vdiff_selected,gtk.STOCK_JUSTIFY_FILL)ifself.bfile:menu=m.build()menu.connect_after('selection-done',self.restore_single_sel)menu.show_all()returnmenum.append_sep()m.append(_('Email from here to selected...'),self.email_revs,gtk.STOCK_GOTO_LAST)m.append(_('Bundle from here to selected...'),self.bundle_revs,'menurelocate.ico')m.append(_('Export Patches from here to selected...'),self.export_revs,gtk.STOCK_GO_FORWARD)m.append_sep()mmerge=m.append(_('_Merge with...'),self.domerge,'menumerge.ico')m.append_sep()# disable/enable menus as requiredparents=self.repo.parents()iflen(parents)>1:can_merge=Falseelse:rev0,rev1=self.revrangec0,c1=self.repo[rev0],self.repo[rev1]can_merge=c0.branch()!=c1.branch()orc0.ancestor(c1)!=c1mmerge.set_sensitive(can_merge)# need transplant extension for transplant commandif'transplant'inself.exs:m.append(_('Transplant Revision range to local'),self.transplant_revs,gtk.STOCK_CONVERT)# need rebase extension for rebase commandif'rebase'inself.exs:m.append(_('Rebase on top of selected'),self.rebase_selected,gtk.STOCK_CUT)# need MQ extension for qimport commandif'mq'inself.exs:m.append(_('Import from here to selected to MQ'),self.qimport_revs,'menuimport.ico')m.append_sep()m.append(_('Select common ancestor revision'),self.select_common_ancestor,gtk.STOCK_JUMP_TO)menu=m.build()menu.connect_after('selection-done',self.restore_single_sel)menu.show_all()returnmenudefget_body(self):self.connect('delete-event',self.delete)self.gorev_dialog=Noneself.limit=self.get_graphlimit(None)# prepare statusbarself.stbar=statusbar.StatusBar()self.stbar.append_field('mq')self.stbar.append_field('filter')self.stbar.append_field('rev')## add load buttons to statusbarself.sttool=gtklib.SlimToolbar(self.tooltips)self.stbar.append_widget(self.sttool)more=self.sttool.append_button(gtk.STOCK_GO_DOWN,_('Load more Revisions'),group='load')more.connect('clicked',self.more_clicked)all=self.sttool.append_button(gtk.STOCK_GOTO_BOTTOM,_('Load all Revisions'),group='load')all.connect('clicked',self.load_all_clicked)self.sttool.set_visible('load',notself.show_toolbar)# Allocate TreeView instance to use internallylimit=self.limitifself.opts['limit']:limit=self.get_graphlimit(self.opts['limit'])self.graphview=LogTreeView(self.repo,limit,self.stbar)# dnd setup for TreeViewtargets=[('text/uri-list',0,HIST_DND_URI_LIST)]self.graphview.drag_dest_set(gtk.DEST_DEFAULT_MOTION| \
gtk.DEST_DEFAULT_DROP,targets,gtk.gdk.ACTION_MOVE)self.graphview.connect('drag-data-received',self.dnd_received,DND_DEST_GRAPHVIEW)# Allocate ChangeSet instance to use internallyself.changeview=changeset.ChangeSet(self.ui,self.repo,self.cwd,[],self.opts,self.stbar)self.changeview.display(False)self.changeview.glog_parent=self# Add extra toolbar buttonssep=gtk.SeparatorToolItem()sep.set_expand(True)sep.set_draw(False)loadnext=self.make_toolbutton(gtk.STOCK_GO_DOWN,_('Load more'),self.more_clicked,tip=_('load more revisions'),name='load-more')loadall=self.make_toolbutton(gtk.STOCK_GOTO_BOTTOM,_('Load all'),self.load_all_clicked,tip=_('load all revisions'),name='load-all')tbar=self.changeview.get_tbbuttons()tbar+=[sep,loadnext,loadall]fortbuttonintbar:self.toolbar.insert(tbutton,-1)# PyGtk 2.6 and below did not automatically register typesifgobject.pygtk_version<(2,8,0):gobject.type_register(LogTreeView)self.tree=self.graphview.treeviewself.graphview.connect('revision-selected',self.selection_changed)self.graphview.connect('revisions-loaded',self.revisions_loaded)self.tree.connect('popup-menu',self.tree_popup_menu)self.tree.connect('button-press-event',self.tree_button_press)self.tree.connect('row-activated',self.tree_row_act)accelgroup=gtk.AccelGroup()self.add_accel_group(accelgroup)mod=gtklib.get_thg_modifier()key,modifier=gtk.accelerator_parse(mod+'d')self.tree.add_accelerator('thg-diff',accelgroup,key,modifier,gtk.ACCEL_VISIBLE)self.tree.connect('thg-diff',self.thgdiff)key,modifier=gtk.accelerator_parse(mod+'p')self.tree.add_accelerator('thg-parent',accelgroup,key,modifier,gtk.ACCEL_VISIBLE)self.tree.connect('thg-parent',self.thgparent)key,modifier=gtk.accelerator_parse(mod+'g')self.tree.add_accelerator('thg-revision',accelgroup,key,modifier,gtk.ACCEL_VISIBLE)self.tree.connect('thg-revision',self.thgnavigate)self.connect('thg-refresh',self.thgrefresh)# synch barself.syncbox=gtklib.SlimToolbar(self.tooltips)syncbox=self.syncboxrefresh=syncbox.append_button(gtk.STOCK_REFRESH,_('Reload revision history'),group='reload')syncbox.append_separator(group='reload')incoming=syncbox.append_button(gtk.STOCK_GO_DOWN,_('Download and view incoming changesets'))apply=syncbox.append_button(gtk.STOCK_APPLY,_('Accept changes from Bundle preview'),group='bundle')reject=syncbox.append_button(gtk.STOCK_DIALOG_ERROR,_('Reject changes from Bundle preview'),group='bundle')pull=syncbox.append_button(gtk.STOCK_GOTO_BOTTOM,_('Pull incoming changesets'))importbtn=syncbox.append_button('menuimport.ico',_('Import patches'))syncbox.append_separator()outgoing=syncbox.append_button(gtk.STOCK_GO_UP,_('Determine and mark outgoing changesets'))push=syncbox.append_button(gtk.STOCK_GOTO_TOP,_('Push outgoing changesets'))email=syncbox.append_button(gtk.STOCK_GOTO_LAST,_('Email outgoing changesets'))syncbox.append_separator(group='stop')stop=syncbox.append_button(gtk.STOCK_STOP,_('Stop current transaction'),group='stop')syncbox.set_visible('reload',notself.show_toolbar)syncbox.set_enable('bundle',False)syncbox.set_enable('stop',False)self.syncbar_apply=applyself.syncbar_reject=rejectself.stop_button=stop## target path comboboxurllist=gtk.ListStore(str,# path (utf-8)str)# alias (utf-8)urlcombo=gtk.ComboBoxEntry(urllist,0)cell=gtk.CellRendererText()urlcombo.pack_end(cell,False)urlcombo.add_attribute(cell,'text',1)self.urlcombo=urlcomboself.pathentry=urlcombo.get_child()syncbox.append_widget(urlcombo,expand=True)## dnd setup for path entryself.pathentry.drag_dest_set(gtk.DEST_DEFAULT_MOTION| \
gtk.DEST_DEFAULT_DROP,targets,gtk.gdk.ACTION_MOVE)self.pathentry.connect('drag-data-received',self.dnd_received,DND_DEST_PATHENTRY)self.update_urllist()## post pull drop-down listppullbox=gtk.HBox()syncbox.append_widget(ppullbox)ppullbox.pack_start(gtk.Label(_('After Pull:')),False,False,4)ppulldata=[('none',_('Nothing')),('update',_('Update'))]ppull=self.repo.ui.config('tortoisehg','postpull','none')if'fetch'inself.exsor'fetch'==ppull:ppulldata.append(('fetch',_('Fetch')))if'rebase'inself.exsor'rebase'==ppull:ppulldata.append(('rebase',_('Rebase')))ppulllist=gtk.ListStore(str,# namestr)# label (utf-8)ppullcombo=gtk.ComboBox(ppulllist)ppullbox.pack_start(ppullcombo,False,False)cell=gtk.CellRendererText()ppullcombo.pack_start(cell)ppullcombo.add_attribute(cell,'text',1)forname,labelinppulldata:ppulllist.append((name,label))self.ppullcombo=ppullcomboself.ppulldata=ppulldataself.ppullbox=ppullboxself.update_postpull(ppull)## add conf buttonconf=syncbox.append_button(gtk.STOCK_PREFERENCES,_('Configure aliases and after pull behavior'))## connect syncbar buttonsrefresh.connect('clicked',self.refresh_clicked)incoming.connect('clicked',self.incoming_clicked)pull.connect('clicked',self.pull_clicked)importbtn.connect('clicked',self.import_clicked)outgoing.connect('clicked',self.outgoing_clicked)push.connect('clicked',self.push_clicked)apply.connect('clicked',self.apply_clicked)reject.connect('clicked',self.reject_clicked)conf.connect('clicked',self.conf_clicked)email.connect('clicked',self.email_clicked)stop.connect('clicked',self.stop_clicked)# filter barself.filterbar=FilterBar(self.tooltips,self.filter_mode,hglib.getlivebranch(self.repo))filterbar=self.filterbarself.lastbranchrow=Noneself.lastfilterinfo=Noneself.filter_mode=filterbar.filter_modeself.filtercombo=filterbar.filtercomboself.filterentry=filterbar.entryself.branchcombo=filterbar.branchcomboself.entrycombo=filterbar.entrycombofcon=self.filterbar.connectfsel=self.filter_selectedfcon('all_toggled',fsel,'all')fcon('tagged_toggled',fsel,'tagged')fcon('ancestry_toggled',fsel,'ancestry')fcon('parents_toggled',fsel,'parents')fcon('heads_toggled',fsel,'heads')fcon('merges_toggled',fsel,'only_merges')fcon('hidemerges_toggled',fsel,'no_merges')fcon('branches_toggled',fsel,'branch')fcon('branchcombo_changed',self.select_branch)fcon('entry_activate',self.filter_entry_activated,self.filtercombo)fcon('entrycombo_changed',self.filter_entry_changed,self.filtercombo)midpane=gtk.VBox()midpane.pack_start(syncbox,False)midpane.pack_start(filterbar,False)midpane.pack_start(self.graphview)midpane.show_all()# MQ widgetif'mq'inself.exs:# create MQWidgetself.mqwidget=thgmq.MQWidget(self.repo,accelgroup,self.tooltips)self.mqwidget.connect('patch-selected',self.patch_selected)self.mqwidget.connect('repo-invalidated',self.repo_invalidated)self.mqwidget.connect('files-dropped',self.files_dropped)defwrapframe(widget):frame=gtk.Frame()frame.set_shadow_type(gtk.SHADOW_ETCHED_IN)frame.add(widget)returnframeself.mqpaned=gtk.HPaned()self.mqpaned.add1(wrapframe(self.mqwidget))self.mqpaned.add2(wrapframe(midpane))# register signal handlerdefnotify(paned,gparam):ifnothasattr(self,'mqtb'):returnpos=paned.get_position()ifself.cmd_get_active('mq'):ifpos<140:paned.set_position(140)else:ifpos!=0:paned.set_position(0)self.mqpaned.connect('notify::position',notify)midpane=self.mqpaned# Add ChangeSet instance to bottom half of vpaneself.changeview.graphview=self.graphviewself.hpaned=self.changeview.get_body()self.vpaned=gtk.VPaned()self.vpaned.pack1(midpane,True,False)self.vpaned.pack2(self.hpaned)gtklib.idle_add_single_call(self.realize_settings)vbox=gtk.VBox()vbox.pack_start(self.vpaned,True,True)returnvboxdefget_extras(self):returnself.stbardefrefresh_on_marker_change(self,oldlen,oldmarkers,newmarkers):# Note that oldmarkers/newmarkers may be either dicts# (for add/remove bookmarks, which can also 'move'# bookmarks), or lists (everything else)self.repo.invalidate()self.changeview.clear_cache()iflen(self.repo)!=oldlen:self.reload_log()else:ifnewmarkers!=oldmarkers:self.refresh_model()defrefresh_on_current_marker_change(self,oldlen,oldmarkers,oldcurrent,newmarkers,newcurrent):self.repo.invalidate()self.changeview.clear_cache()iflen(self.repo)!=oldlen:self.reload_log()else:ifnewmarkers!=oldmarkersor \
oldcurrent!=newcurrent:self.refresh_model()defapply_clicked(self,button):combo=self.ppullcombolist,iter=combo.get_model(),combo.get_active_iter()ppull,label=list[list.get_path(iter)]ifppull=='fetch':cmd=['fetch','--message','merge']# load the fetch extension explicitlyhglib.loadextension(self.ui,'fetch')else:cmd=['pull']ifppull=='update':cmd.append('--update')elifppull=='rebase':cmd.append('--rebase')# load the rebase extension explicitlyhglib.loadextension(self.ui,'rebase')cmdline=['hg']+cmd+[self.bfile]defcallback(return_code,*args):self.remove_overlay('--rebase'incmd)ifnotself.execute_command(cmdline,callback,status=_('Applying bundle...'),title=_('Applying bundle')):gdialog.Prompt(_('Cannot run now'),_('Please try again after running ''operation is completed'),self).run()defremove_overlay(self,resettip):self.bfile=Noneself.npreviews=0ifisinstance(self.origurl,int):self.urlcombo.set_active(self.origurl)else:self.pathentry.set_text(self.origurl)self.repo=hg.repository(self.ui,path=self.repo.root)self.graphview.set_repo(self.repo,self.stbar)self.changeview.set_repo(self.repo)self.changeview.bfile=Noneifhasattr(self,'mqwidget'):self.mqwidget.set_repo(self.repo)self.mqwidget.set_sensitive(True)ifresettip:self.origtip=len(self.repo)self.reload_log()self.toolbar.remove(self.toolbar.get_nth_item(0))self.toolbar.remove(self.toolbar.get_nth_item(0))self.cmd_set_sensitive('accept',False)self.cmd_set_sensitive('reject',False)self.syncbox.set_enable('bundle',False)forwinself.incoming_disabled:w.set_sensitive(True)forcmdinself.incoming_disabled_cmds:self.cmd_set_sensitive(cmd,True)self.stbar.set_idle_text(None)defreject_clicked(self,button):self.remove_overlay(False)defincoming_clicked(self,toolbutton):defcleanup():try:shutil.rmtree(self.bundledir)exceptOSError:passpath=hglib.fromutf(self.pathentry.get_text()).strip()ifnotpath:gdialog.Prompt(_('No remote path specified'),_('Please enter or select a remote path'),self).run()self.pathentry.grab_focus()returnifpath.startswith('p4://'):cmdline=['hg','incoming','--verbose',path]self.execute_command(cmdline,force=True)returnifnotself.bundledir:self.bundledir=tempfile.mkdtemp(prefix='thg-incoming-')atexit.register(cleanup)bfile=pathforbadcharin(':','*','\\','?','#'):bfile=bfile.replace(badchar,'')bfile=bfile.replace('/','_')bfile=os.path.join(self.bundledir,bfile)+'.hg'cmdline=['hg','incoming','--bundle',bfile]cmdline+=self.get_proxy_args()cmdline+=[hglib.validate_synch_path(path,self.repo)]defcallback(return_code,*args):ifreturn_code==0andos.path.isfile(bfile):self.set_bundlefile(bfile)text=_('%d incoming changesets')%self.npreviewselifreturn_codeisNone:text=_('Aborted incoming')else:text=_('No incoming changesets')self.stbar.set_idle_text(text)ifnotself.execute_command(cmdline,callback,status=_('Checking incoming changesets...'),title=_('Incoming')):gdialog.Prompt(_('Cannot run now'),_('Please try again after running ''operation is completed'),self).run()defset_bundlefile(self,bfile,**kwopts):self.origurl=self.urlcombo.get_active()ifself.origurl==-1:self.origurl=self.pathentry.get_text()self.pathentry.set_text(bfile)# disable MQ panelifhasattr(self,'mqwidget'):self.mqwidget.set_sensitive(False)# create apply/reject toolbar buttonsapply=gtk.ToolButton(gtk.STOCK_APPLY)apply.set_tooltip(self.tooltips,_('Accept incoming previewed changesets'))apply.set_label(_('Accept'))apply.show()reject=gtk.ToolButton(gtk.STOCK_DIALOG_ERROR)reject.set_tooltip(self.tooltips,_('Reject incoming previewed changesets'))reject.set_label(_('Reject'))reject.show()apply.connect('clicked',self.apply_clicked)reject.connect('clicked',self.reject_clicked)self.toolbar.insert(reject,0)self.toolbar.insert(apply,0)self.cmd_set_sensitive('accept',True)self.cmd_set_sensitive('reject',True)cmds=('incoming','outgoing','push','pull','email','refresh','synchronize','mq','add-bundle')self.incoming_disabled_cmds=[]forcmdincmds:self.cmd_set_sensitive(cmd,False)self.incoming_disabled_cmds.append(cmd)ignore=(self.syncbar_apply,self.syncbar_reject,self.ppullbox,self.stop_button)self.incoming_disabled=[]defdisable_child(w):if(wnotinignore)andw.get_property('sensitive'):w.set_sensitive(False)self.incoming_disabled.append(w)self.syncbox.foreach(disable_child)self.syncbox.set_enable('bundle',True)self.bfile=bfileoldtip=len(self.repo)try:self.repo=hg.repository(self.ui,path=bfile)self.graphview.set_repo(self.repo,self.stbar)self.changeview.set_repo(self.repo)self.changeview.bfile=bfileifhasattr(self,'mqwidget'):self.mqwidget.set_repo(self.repo)self.npreviews=len(self.repo)-oldtipself.reload_log(**kwopts)self.stbar.set_idle_text(_('Bundle Preview'))self.bundle_autoreject=Falseexcepterror.LookupError:self.remove_overlay(False)gtklib.idle_add_single_call(self.stbar.set_idle_text,_('Failed to preview, a bundle file unrelated ''to this repository'))excepterror.Abort:self.remove_overlay(False)gtklib.idle_add_single_call(self.stbar.set_idle_text,_('Failed to preview, not a Mercurial bundle file'))defadd_bundle_clicked(self,button):result=gtklib.NativeSaveFileDialogWrapper(title=_('Open Bundle'),open=True).run()ifresult:self.set_bundlefile(result)defpull_clicked(self,toolbutton):combo=self.ppullcombolist,iter=combo.get_model(),combo.get_active_iter()ppull,label=list[list.get_path(iter)]ifppull=='fetch':cmd=['fetch','--message','merge']# load the fetch extension explicitlyhglib.loadextension(self.ui,'fetch')else:cmd=['pull']ifppull=='update':cmd.append('--update')elifppull=='rebase':cmd.append('--rebase')# load the rebase extension explicitlyhglib.loadextension(self.ui,'rebase')path=hglib.fromutf(self.pathentry.get_text()).strip()remote_path=hglib.validate_synch_path(path,self.repo)ifnotpath:gdialog.Prompt(_('No remote path specified'),_('Please enter or select a remote path'),self).run()self.pathentry.grab_focus()returncmdline=['hg']+cmd+self.get_proxy_args()+[remote_path]defcallback(return_code,*args):ifreturn_code==0:self.repo.invalidate()self.changeview.clear_cache()if'--rebase'incmd:self.origtip=len(self.repo)self.reload_log()text=_('Finished pull with rebase')eliflen(self.repo)>self.origtip:self.reload_log()text=_('Finished pull')else:text=_('No changesets to pull')else:text=_('Aborted pull')self.stbar.set_idle_text(text)ifnotself.execute_command(cmdline,callback,status=_('Pulling changesets...'),title=_('Pull')):gdialog.Prompt(_('Cannot run now'),_('Please try again after running ''operation is completed'),self).run()defoutgoing_clicked(self,toolbutton):path=hglib.fromutf(self.pathentry.get_text()).strip()ifnotpath:gdialog.Prompt(_('No remote path specified'),_('Please enter or select a remote path'),self).run()self.pathentry.grab_focus()returnifpath.startswith('p4://'):# hg out -q p4://server/client output hashes (thanks Frank)cmd=['hg','outgoing','--quiet',path]else:cmd=['hg','outgoing','--quiet','--template','{node}\n']cmd+=self.get_proxy_args()cmd+=[hglib.validate_synch_path(path,self.repo)]defcallback(return_code,buffer,*args):ifreturn_code==0:outgoing=[]forlineinbuffer.splitlines()[:-1]:try:node=self.repo[line].node()outgoing.append(node)except:passself.outgoing=outgoingself.reload_log()text=_('%d outgoing changesets')%len(outgoing)elifreturn_codeisNone:text=_('Aborted outgoing')else:text=_('No outgoing changesets')self.stbar.set_idle_text(text)ifnotself.execute_command(cmd,callback,status=_('Checking outgoing changesets...'),title=_('Outgoing')):gdialog.Prompt(_('Cannot run now'),_('Please try again after running ''operation is completed'),self).run()defemail_clicked(self,toolbutton):path=hglib.fromutf(self.pathentry.get_text()).strip()ifnotpath:gdialog.Prompt(_('No repository selected'),_('Select a peer repository to compare with'),self).run()self.pathentry.grab_focus()returnopts=['--outgoing',path]dlg=hgemail.EmailDialog(self.repo.root,opts)self.show_dialog(dlg)defpush_clicked(self,toolbutton):remote_path=self.validate_path()ifnotremote_path:returncmdline=['hg','push']+self.get_proxy_args()ifself.forcepush:cmdline+=['--force']cmdline+=[remote_path]defcallback(return_code,*args):ifreturn_code==0:ifself.outgoing:self.outgoing=[]self.reload_log()text=_('Finished push')else:text=_('Aborted push')self.stbar.set_idle_text(text)ifnotself.execute_command(cmdline,callback,status=_('Pushing changesets...'),title=_('Push')):gdialog.Prompt(_('Cannot run now'),_('Please try again after running ''operation is completed'),self).run()defconf_clicked(self,*args):newpath=hglib.fromutf(self.pathentry.get_text()).strip()foralias,pathinself.repo.ui.configitems('paths'):ifnewpathin(path,url.hidepassword(path)):newpath=Nonebreakdlg=thgconfig.ConfigDialog(True)dlg.show_all()ifnewpath:dlg.new_path(newpath,'default')else:dlg.focus_field('tortoisehg.postpull')dlg.run()dlg.hide()self.refreshui()self.update_urllist()self.update_postpull()defstop_clicked(self,toolbutton):self.runner.stop()defimport_clicked(self,widget,dest=thgimport.DEST_REPO,paths=None):oldlen=len(self.repo)enabled=hasattr(self,'mqpaned')ifenabled:oldnum=self.mqwidget.get_num_patches()defimport_completed():hglib.invalidaterepo(self.repo)self.changeview.clear()ifoldlen<len(self.repo):self.reload_log()ifenabledandoldnum<self.mqwidget.get_num_patches():self.mqwidget.refresh()self.enable_mqpanel(enable=True)dialog=thgimport.ImportDialog(self.repo,dest,paths)dialog.set_notify_func(import_completed)self.show_dialog(dialog)defupdate_urllist(self):ifself.bfile:return# save current selection & default patholdurl=self.pathentry.get_text()urllist=self.urlcombo.get_model()forpath,aliasinurllist:ifalias=='default':defurl=pathbreakelse:defurl=None# update URL listurllist.clear()new_defurl=Noneforalias,pathinself.repo.ui.configitems('paths'):path=url.hidepassword(path)urllist.append((hglib.toutf(path),hglib.toutf(alias)))ifalias=='default':self.urlcombo.set_active(len(urllist)-1)new_defurl=path# restore previous selectionifoldurlanddefurl==new_defurl:forrowinurllist:path,alias=rowifoldurl==path:self.urlcombo.set_active_iter(row.iter)breakelse:self.pathentry.set_text(oldurl)defupdate_postpull(self,ppull=None):ifppullisNone:ppull=self.repo.ui.config('tortoisehg','postpull','none')forrowinself.ppullcombo.get_model():name,label=rowifname==ppull:self.ppullcombo.set_active_iter(row.iter)breakdefdnd_received(self,widget,context,x,y,sel,target,tm,dest):iftarget==HIST_DND_URI_LIST:paths=gtklib.normalize_dnd_paths(sel.data)ifnotpaths:returnifdest==DND_DEST_PATHENTRY:path=paths[0]# use only first pathifos.path.isfile(path):self.set_bundlefile(path)else:self.pathentry.set_text(path)# HACK: I don't know why, but 'drag-data-received' signal# is emitted twice: the former has correct dropped path,# the latter has previously dropped (old) path. To avoid# overwriting with old one, I had to block dnd signal# right after this signal handler is called.widget.handler_block_by_func(self.dnd_received)defafter():widget.handler_unblock_by_func(self.dnd_received)gtklib.idle_add_single_call(after)elifdest==DND_DEST_GRAPHVIEW:self.import_clicked(None,thgimport.DEST_REPO,paths)else:raise_('unknown dnd dest: %s')%destdefrealize_settings(self):self.vpaned.set_position(self.setting_vpos)self.hpaned.set_position(self.setting_hpos)ifhasattr(self,'mqpaned')andself.mqtb.get_active():self.mqpaned.set_position(self.setting_mqhpos)defthgdiff(self,treeview):'ctrl-d handler'self.vdiff_change(None,self.pats)defthgparent(self,treeview):'ctrl-p handler'parent=self.repo['.'].rev()self.graphview.set_revision_id(parent)defthgnavigate(self,treeview):'ctrl-g handler'self.show_goto_dialog()defselect_branch(self,combo):row=combo.get_active()ifrow==0:ifself.lastbranchrow:combo.set_active(self.lastbranchrow)elifrow!=self.lastbranchrow:self.filter='branch'self.lastbranchrow=rowself.filterbar.get_button('branch').set_active(True)self.filterbar.get_button('branch').set_sensitive(True)self.reload_log(branch=combo.get_model()[row][0])bname=combo.get_active_text()# utf8 encodedmenu=self.menuitems.get('@'+bname)ifmenu:menu.handler_block_by_func(self.filter_handler)menu.set_active(True)menu.handler_unblock_by_func(self.filter_handler)defshow_goto_dialog(self):'Launch a modeless goto revision dialog'defgoto_rev_(rev):self.goto_rev(rev)defresponse_(dialog,response_id):dialog.hide()defdelete_event(dialog,event,data=None):# return True to prevent the dialog from being destroyedreturnTruedlg=gorev.GotoRevDialog(goto_rev_)dlg.connect('response',response_)dlg.connect('delete-event',delete_event)dlg.set_modal(False)dlg.show()self.gorev_dialog=dlgdefgoto_rev(self,revision):rid=self.repo[revision].rev()self.graphview.set_revision_id(rid,load=True)defgoto_prev_sel(self):ifhasattr(self,'prevrevid')andself.prevrevid:self.goto_rev(self.prevrevid)defstrip_rev(self,menuitem):defstrip_completed():hglib.invalidaterepo(self.repo)self.reload_log()self.changeview.clear()rev=self.curreviddialog=thgstrip.StripDialog(rev,self.graphview)dialog.set_notify_func(strip_completed)self.show_dialog(dialog)defshow_dialog(self,dlg):dlg.set_transient_for(self)dlg.show_all()dlg.present()ifgtk.pygtk_version<(2,12,0):# Workaround for old PyGTK (< 2.12.0) issue.# See background of this: f668034aeda3dlg.set_transient_for(None)defbackout_rev(self,menuitem):oldlen=len(self.repo)hash=str(self.repo[self.currevid])parents=[x.node()forxinself.repo.parents()]defrefresh(*args):self.repo.invalidate()self.changeview.clear_cache()iflen(self.repo)!=oldlen:self.reload_log()iflen(self.repo.parents())!=len(parents):# User auto-merged the backoutdefcinotify():'User comitted the merge'dlg.ready=Falsedlg.hide()self.reload_log()fromtortoisehg.hgtkimportcommitdlg=commit.run(ui.ui())dlg.set_transient_for(self)dlg.set_modal(True)dlg.set_notify_func(cinotify)dlg.display()dlg=backout.BackoutDialog(hash)dlg.connect('destroy',refresh)self.show_dialog(dlg)defrevert(self,menuitem):rev=self.currevidres=gdialog.Confirm(_('Confirm Revert All Files'),[],self,_('Revert all files to revision %d?\nThis will overwrite your ''local changes')%rev).run()ifres!=gtk.RESPONSE_YES:returncmdline=['hg','revert','--verbose','--all','--rev',str(rev)]self.execute_command(cmdline,force=True)defvdiff_change(self,menuitem,pats=[]):ifself.currevidisNone:returnrev=self.currevidopts={'change':str(rev),'bundle':self.bfile}parents=self.repo[rev].parents()iflen(parents)==2:ifself.changeview.diff_other_parent():parent=parents[1].rev()else:parent=parents[0].rev()opts['rev']=[str(parent),str(rev)]self._do_diff(pats,opts)defvdiff_local(self,menuitem):opts={'rev':[str(self.currevid)],'bundle':self.bfile}self._do_diff(self.pats,{'rev':[str(self.currevid)]})defdiff_revs(self,menuitem):rev0,rev1=self.revrangestatopts=self.merge_opts(commands.table['^status|st'][1],('include','exclude','git'))statopts['rev']=['%u:%u'%(rev0,rev1)]statopts['modified']=Truestatopts['added']=Truestatopts['removed']=Truedialog=status.GStatus(self.ui,self.repo,self.cwd,self.pats,statopts)dialog.display()returnTruedefvdiff_selected(self,menuitem):strrevs=[str(r)forrinself.revrange]self._do_diff(self.pats,{'rev':strrevs})defemail_revs(self,menuitem):revrange=list(self.revrange)revrange.sort()opts=['--rev',str(revrange[0])+':'+str(revrange[1])]dlg=hgemail.EmailDialog(self.repo.root,opts)self.show_dialog(dlg)defexport_revs(self,menuitem):result=gtklib.NativeFolderSelectDialog(title=_('Save patches to'),initial=self.repo.root).run()ifresult:revs=list(self.revrange)revs.sort()rev='%d:%d'%(revs[0],revs[1])# In case new export args are added in the future, merge the# hg defaultsopts=self.merge_opts(commands.table['^export'][1],())opts['output']=os.path.join(result,'%b_rev%R.patch')defdohgexport():commands.export(self.ui,self.repo,rev,**opts)s,o=self._hg_call_wrapper('Export',dohgexport,False)defbundle_rev_to_tip(self,menuitem):try:parent=self.repo[self.currevid].parents()[0].rev()except(ValueError,error.LookupError):returnself.bundle_revs(menuitem,parent)defbundle_revs(self,menuitem,base=None):data=dict(name=os.path.basename(self.repo.root))ifbaseisNone:revrange=list(self.revrange)revrange.sort()parent=self.repo[revrange[0]].parents()[0].rev()data.update(base=revrange[0],rev=revrange[1])filename='%(name)s_rev%(base)s_to_rev%(rev)s.hg'%dataelse:parent=basedata.update(base=self.currevid)filename='%(name)s_rev%(base)s_to_tip.hg'%data# Special case for revision 0's parent.ifparent==-1:parent='null'result=gtklib.NativeSaveFileDialogWrapper(title=_('Write bundle to'),initial=self.repo.root,filename=filename).run()ifnotresult:returnparent=str(parent)cmdline=['hg','bundle','--base',parent]data=dict(base=parent)ifbaseisNone:rev=str(revrange[1])cmdline+=['--rev',rev]data.update(rev=rev)status=_('Bundling from %(base)s to %(rev)s...')%dataelse:status=_('Bundling from %(base)s to tip...')%datacmdline.append(result)defcallback(return_code,*args):ifreturn_code==0:text=_('Finish bundling')elifreturn_codeisNone:text=_('Aborted bundling')else:text=_('Failed to bundle')self.stbar.set_idle_text(text)ifnotself.execute_command(cmdline,callback,status,_('Bundling')):gdialog.Prompt(_('Cannot run now'),_('Please try again after running ''operation is completed'),self).run()defqimport_rev(self,menuitem):"""QImport selected revision."""rev=str(self.currevid)self.qimport_revs(menuitem,rev)defqimport_revs(self,menuitem,rev=None):"""QImport revision range."""ifrev==None:revs=list(self.revrange)revs.sort()rev='%s:%s'%(str(revs[0]),str(revs[1]))cmdline=['hg','qimport','--rev',rev]defcallback(return_code,*args):ifreturn_code==0:hglib.invalidaterepo(self.repo)self.reload_log()self.changeview.clear()self.enable_mqpanel()text=_('Finish importing')elifreturn_codeisNone:text=_('Aborted importing')else:text=_('Failed to import')self.stbar.set_idle_text(text)ifnotself.execute_command(cmdline,callback,title=_('Importing'),status=_('Importing to Patch Queue...')):gdialog.Prompt(_('Cannot run now'),_('Please try again after running ''operation is completed'),self).run()defrebase_selected(self,menuitem):"""Rebase revision on top of selection (1st on top of 2nd)."""revs=self.revrangeres=gdialog.Confirm(_('Confirm Rebase Revision'),[],self,_('Rebase revision %d on top of %d?')%(revs[0],revs[1])).run()ifres!=gtk.RESPONSE_YES:returncmdline=['hg','rebase','--source',str(revs[0]),'--dest',str(revs[1])]self.execute_command(cmdline,force=True)self.repo.invalidate()self.reload_log()self.changeview.clear()deftransplant_rev(self,menuitem):"""Transplant selection on top of current revision."""rev=str(self.currevid)self.transplant_revs(menuitem,rev)deftransplant_revs(self,menuitem,rev=None):"""Transplant revision range on top of current revision."""ifrevisNone:revs=list(self.revrange)revs.sort()rev='%d:%d'%(revs[0],revs[1])cmdline=['hg','transplant',rev]self.execute_command(cmdline,force=True)self.repo.invalidate()self.reload_log()self.changeview.clear()defget_rev_tag(self,rev,include=None,exclude=None):fortaginself.repo.nodetags(self.repo[rev].node()):iftag!='tip' \
and((notinclude)or(includeandtagininclude)) \
and((notexclude)or(excludeandtagnotinexclude)):returntagreturn''defadd_tag(self,menuitem):# save tag info for detecting new tags addedbmarks=hglib.get_repo_bookmarks(self.repo)oldtags=self.repo.tagslist()oldlen=len(self.repo)rev=str(self.currevid)tag=self.get_rev_tag(rev,exclude=bmarks)defrefresh(*args):self.refresh_on_marker_change(oldlen,oldtags,self.repo.tagslist())dialog=tagadd.TagAddDialog(self.repo,tag,rev)dialog.connect('destroy',refresh)self.show_dialog(dialog)defadd_bookmark(self,menuitem):# save bookmark info for detecting new bookmarks added# since we can now move bookmarks, need to store# the associated changesets as welloldbookmarks=hglib.get_repo_bookmarks(self.repo,values=True)oldlen=len(self.repo)rev=str(self.currevid)bmark=self.get_rev_tag(rev,include=oldbookmarks)defrefresh(*args):self.refresh_on_marker_change(oldlen,oldbookmarks,hglib.get_repo_bookmarks(self.repo,values=True))dialog=bookmark.BookmarkDialog(self.repo,bookmark.TYPE_ADDREMOVE,bmark,rev)dialog.connect('destroy',refresh)self.show_dialog(dialog)defrename_bookmark(self,menuitem):# save bookmark info for detecting bookmarks renamedoldbookmarks=hglib.get_repo_bookmarks(self.repo)oldlen=len(self.repo)rev=str(self.currevid)bmark=self.get_rev_tag(rev,include=oldbookmarks)defrefresh(*args):self.refresh_on_marker_change(oldlen,oldbookmarks,hglib.get_repo_bookmarks(self.repo))dialog=bookmark.BookmarkDialog(self.repo,bookmark.TYPE_RENAME,bmark,rev)dialog.connect('destroy',refresh)self.show_dialog(dialog)defcurrent_bookmark(self,menuitem):# save current bookmark info for detecting current bookmark changedbookmarks=extensions.find('bookmarks')# Note that the dialog shouldn't change the repo len, or # of bookmarks,# etc, but check in case they've been modified by something else...oldbookmarks=hglib.get_repo_bookmarks(self.repo)oldlen=len(self.repo)oldcurrent=hglib.get_repo_bookmarkcurrent(self.repo)rev=str(self.currevid)bmark=self.get_rev_tag(rev,include=oldbookmarks)defrefresh(*args):self.refresh_on_current_marker_change(oldlen,oldbookmarks,oldcurrent,hglib.get_repo_bookmarks(self.repo),hglib.get_repo_bookmarkcurrent(self.repo))dialog=bookmark.BookmarkDialog(self.repo,bookmark.TYPE_CURRENT,bmark,rev)dialog.connect('destroy',refresh)self.show_dialog(dialog)defbisect_reset(self,menuitem):commands.bisect(ui=self.ui,repo=self.repo,good=False,bad=False,skip=False,reset=True)defbisect_good(self,menuitem):cmd=['hg','bisect','--good',str(self.currevid)]self.execute_command(cmd,force=True)self.refresh_model()defbisect_bad(self,menuitem):cmd=['hg','bisect','--bad',str(self.currevid)]self.execute_command(cmd,force=True)self.refresh_model()defbisect_skip(self,menuitem):cmd=['hg','bisect','--skip',str(self.currevid)]self.execute_command(cmd,force=True)self.refresh_model()defshow_status(self,menuitem):rev=self.currevidstatopts=self.merge_opts(commands.table['^status|st'][1],('include','exclude','git'))ifself.changeview.diff_other_parent():parent=self.repo[rev].parents()[1].rev()else:parent=self.repo[rev].parents()[0].rev()statopts['rev']=[str(parent),str(rev)]statopts['modified']=Truestatopts['added']=Truestatopts['removed']=Truedialog=status.GStatus(self.ui,self.repo,self.cwd,self.pats,statopts)dialog.display()defvalidate_path(self):original_path=hglib.fromutf(self.pathentry.get_text()).strip()remote_path=hglib.validate_synch_path(original_path,self.repo)ifnotremote_path:gdialog.Prompt(_('No remote path specified'),_('Please enter or select a remote path'),self).run()self.pathentry.grab_focus()returnNoneelse:confirm_push=Falseifnothg.islocal(remote_path):ifself.forcepush:title=_('Confirm Forced Push to Remote Repository')text=_('Forced push to remote repository\n%s\n''(creating new heads in remote if needed)?')%original_pathbuttontext=_('Forced &Push')else:title=_('Confirm Push to remote Repository')text=_('Push to remote repository\n%s\n?')%original_pathbuttontext=_('&Push')confirm_push=Trueelifself.forcepush:title=_('Confirm Forced Push')text=_('Forced push to repository\n%s\n''(creating new heads if needed)?')%original_pathbuttontext=_('Forced &Push')confirm_push=Trueifconfirm_push:dlg=gdialog.CustomPrompt(title,text,None,(buttontext,_('&Cancel')),default=1,esc=1)ifdlg.run()!=0:returnNoneelse:returnremote_pathelse:returnremote_pathdefpush_to(self,menuitem):remote_path=self.validate_path()ifnotremote_path:returnnode=self.repo[self.currevid].node()rev=str(self.currevid)cmdline=['hg','push','--rev',rev,remote_path]ifself.forcepush:cmdline+=['--force']defcallback(return_code,*args):ifreturn_code==0:ifself.outgoing:ancestors=set([self.repo[node].rev()])whileancestors:n=self.repo[ancestors.pop()]try:d=self.outgoing.index(n.node())exceptValueError:continuedelself.outgoing[d]forpinn.parents():ancestors.add(p.rev())self.reload_log()text=_('Finished push to revision %s')%revelse:text=_('Aborted push')self.stbar.set_idle_text(text)ifnotself.execute_command(cmdline,callback,status=_('Pushing changesets to revision %s...')%rev,title=_('Push to %s')%rev):gdialog.Prompt(_('Cannot run now'),_('Please try again after running ''operation is completed'),self).run()defpull_to(self,menuitem):rev=str(self.currevid)cmdline=['hg','pull','--rev',rev,self.bfile]defcallback(return_code,*args):ifreturn_code==0:curtip=len(hg.repository(self.ui,self.repo.root))self.repo=hg.repository(self.ui,path=self.bfile)self.graphview.set_repo(self.repo,self.stbar)self.changeview.set_repo(self.repo)ifhasattr(self,'mqwidget'):self.mqwidget.set_repo(self.repo)self.npreviews=len(self.repo)-curtipifself.npreviews==0:self.remove_overlay(False)else:self.reload_log()text=_('Finished pull to revision %s')%revelse:text=_('Aborted pull')self.stbar.set_idle_text(text)ifnotself.execute_command(cmdline,callback,status=_('Pulling changesets to revision %s...')%rev,title=_('Pull to %s')%rev):gdialog.Prompt(_('Cannot run now'),_('Please try again after running ''operation is completed'),self).run()defcopy_hash(self,menuitem):hash=self.repo[self.currevid].hex()clipboard=gtk.Clipboard()clipboard.set_text(hash)defexport_patch(self,menuitem):rev=self.currevidfilename="%s_rev%s.patch"%(os.path.basename(self.repo.root),rev)result=gtklib.NativeSaveFileDialogWrapper(title=_('Save patch to'),initial=self.repo.root,filename=filename).run()ifresult:# In case new export args are added in the future, merge the# hg defaultsexportOpts=self.merge_opts(commands.table['^export'][1],())exportOpts['output']=resultdefdohgexport():commands.export(self.ui,self.repo,str(rev),**exportOpts)success,outtext=self._hg_call_wrapper("Export",dohgexport,False)defemail_patch(self,menuitem):rev=self.curreviddlg=hgemail.EmailDialog(self.repo.root,['--rev',str(rev)])self.show_dialog(dlg)defcheckout(self,menuitem):rev=self.currevidparents=[x.node()forxinself.repo.parents()]dialog=update.UpdateDialog(rev)dialog.set_notify_func(self.checkout_completed,parents)self.show_dialog(dialog)defcheckout_completed(self,oldparents):self.repo.invalidate()self.repo.dirstate.invalidate()self.changeview.clear_cache()newparents=[x.node()forxinself.repo.parents()]ifnotoldparents==newparents:self.refresh_model()defdomerge(self,menuitem):ifself.revrange:rev0,rev1=self.revrangeelse:rev0,rev1=self.repo['.'].rev(),self.curreviddlg=merge.MergeDialog(rev0,rev1)defmerge_notify(oldparents,repolen,func):hglib.invalidaterepo(self.repo)self.changeview.clear_cache()iflen(self.repo)!=repolen:self.reload_log()elifnotoldparents==self.repo.parents():self.refresh_model()# update arguments for notify funcoldparents=self.repo.parents()dlg.set_notify_func(func,oldparents,repolen,func)args=[self.repo.parents(),len(self.repo),merge_notify]dlg.set_notify_func(merge_notify,*args)merge_notify(*args)# could have immediately switched parentsself.show_dialog(dlg)defarchive(self,menuitem):rev=self.currevidparents=[x.node()forxinself.repo.parents()]dlg=archive.ArchiveDialog(rev)self.show_dialog(dlg)defselect_common_ancestor(self,menuitem):rev1,rev2=self.revrangechangelog=self.repo.changeloglookup=self.repo.lookupancestor=changelog.ancestor(lookup(rev1),lookup(rev2))rev=changelog.rev(ancestor)self.goto_rev(rev)self.origsel=Nonedefthgrefresh(self,window):self.refresh_clicked()defrefresh_clicked(self,widget=None,reset=False):ifreset:self.stbar.set_idle_text(None)self.outgoing=[]self.origtip=len(self.repo)self.refreshui()self.update_urllist()self.reload_log()returnTruedefenable_mqpanel(self,enable=None):ifnothasattr(self,'mqpaned'):returnifenableisNone:enable=self.setting_mqvisandself.mqwidget.has_patch()# set the state of MQ toolbuttonself.cmd_handler_block_by_func('mq',self.mq_clicked)self.cmd_set_active('mq',enable)self.cmd_handler_unblock_by_func('mq',self.mq_clicked)self.cmd_set_sensitive('mq',self.mqwidget.has_mq())# show/hide MQ paneoldpos=self.mqpaned.get_position()self.mqpaned.set_position(enableandself.setting_mqhposor0)ifnotenableandoldpos:self.setting_mqhpos=oldposdefmq_clicked(self,widget,*args):self.enable_mqpanel(widget.get_active())deftree_button_press(self,tree,event):ifevent.button==3andnot(event.state&(gtk.gdk.SHIFT_MASK|gtk.gdk.CONTROL_MASK)):path=tree.get_path_at_pos(int(event.x),int(event.y))ifnotpath:returnFalsecrow=path[0](model,pathlist)=tree.get_selection().get_selected_rows()ifpathlist==[]:returnFalsesrow=pathlist[0]ifsrow==crow:self.tree_popup_menu(tree,event.button,event.time)else:tree.get_selection().set_mode(gtk.SELECTION_MULTIPLE)tree.get_selection().select_path(crow)self.origsel=srowrev0=self.graphview.get_revid_at_path(srow)rev1=self.graphview.get_revid_at_path(crow)self.revrange=(rev0,rev1)self.tree_popup_menu_diff(tree,event.button,event.time)returnTruereturnFalsedeftree_popup_menu(self,treeview,button=0,time=0):menu=self.tree_context_menu()menu.popup(None,None,None,button,time)returnTruedeftree_popup_menu_diff(self,treeview,button=0,time=0):menu=self.tree_diff_context_menu()menu.popup(None,None,None,button,time)returnTruedeftree_row_act(self,tree,path,column):self.vdiff_change(None,self.pats)returnTruedefrun(ui,*pats,**opts):cmdoptions={'follow':False,'follow-first':False,'copies':False,'keyword':[],'limit':0,'rev':[],'removed':False,'no_merges':False,'date':None,'only_merges':None,'prune':[],'git':False,'verbose':False,'include':[],'exclude':[],'filehist':None,'canonpats':[]}cmdoptions.update(opts)pats=hglib.canonpaths(pats)+cmdoptions['canonpats']returnGLog(ui,None,None,pats,cmdoptions)
Attach a Trello Card
Add a tag
Your session has expired
You are no longer logged in. Please log in and try your request again.
Filter RSS Feed
This RSS feed URL allows you to see the contents of your current filter using any feed reader.
This link includes a special authentication token. If you share the URL with anyone else, they can see this RSS feed's activity. You can disable these tokens when needed.
Your current filter is unsaved; changing it won't affect this RSS feed.