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.
## history.py - Changelog dialog for TortoiseHg## Copyright 2007 Brad Schick, brad at gmail . com# Copyright (C) 2007 TK Soh <teekaysoh@gmail.com>#importosimportpygtkpygtk.require('2.0')importgtkimportgobjectimportpangoimportStringIOfrommercurial.nodeimport*frommercurialimportui,hg,commands,extensionsfromgdialogimport*fromchangesetimportChangeSetfromlogfilterimportFilterDialogfromupdateimportUpdateDialogfrommergeimportMergeDialogfromvisimporttreemodelfromvis.treeviewimportTreeViewimportgtklibclassGLog(GDialog):"""GTK+ based dialog for displaying repository logs """defget_title(self):returnos.path.basename(self.repo.root)+' log'defget_icon(self):return'menulog.ico'defparse_opts(self):# Disable quiet to get full log infoself.ui.quiet=Falsedefget_tbbuttons(self):return[self.make_toolbutton(gtk.STOCK_REFRESH,'Re_fresh',self._refresh_clicked,tip='Reload revision history'),gtk.SeparatorToolItem(),self.make_toolbutton(gtk.STOCK_INDEX,'_Filter',self._filter_clicked,menu=self._filter_menu(),tip='Filter revisions for display'),gtk.SeparatorToolItem(),self.make_toolbutton(gtk.STOCK_FIND,'_DataMine',self._datamine_clicked,tip='Search Repository History'),gtk.SeparatorToolItem()]+self.changeview.get_tbbuttons()deftoggle_view_column(self,button,property):bool=button.get_active()self.graphview.set_property(property,bool)def_more_clicked(self,button):self.graphview.next_revision_batch()def_load_all_clicked(self,button):self.graphview.load_all_revisions()self.nextbutton.set_sensitive(False)self.allbutton.set_sensitive(False)defrevisions_loaded(self,graphview):'''Treeview reports log generator has exited'''ifnotself.graphview.graphdata:self.changeview._buffer.set_text('')self.changeview._filelist.clear()self._last_rev=Noneself.nextbutton.set_sensitive(False)self.allbutton.set_sensitive(False)def_datamine_clicked(self,toolbutton,data=None):fromdatamineimportDataMineDialogdialog=DataMineDialog(self.ui,self.repo,self.cwd,[],{},False)dialog.display()dialog.add_search_page()def_filter_clicked(self,toolbutton,data=None):ifself._filter_dialog:self._filter_dialog.show()self._filter_dialog.present()else:self._show_filter_dialog()def_show_filter_dialog(self):'''Launch a modeless filter dialog'''defdo_reload(opts):self.custombutton.set_active(True)self.reload_log(opts)defclose_filter_dialog(dialog,response_id):dialog.hide()revs=[]ifself.currowisnotNone:revs.append(self.currow[treemodel.REVID])ifself.graphview.get_mark_rev()isnotNone:revs.append(self.graphview.get_mark_rev())dlg=FilterDialog(self.repo.root,revs,self.pats,filterfunc=do_reload)dlg.connect('response',close_filter_dialog)dlg.set_modal(False)dlg.show()self._filter_dialog=dlgdef_filter_selected(self,widget,data=None):ifwidget.get_active():self._filter=dataself.reload_log()def_view_menu(self):menu=gtk.Menu()button=gtk.CheckMenuItem("Show Ids")button.connect("toggled",self.toggle_view_column,'rev-column-visible')button.set_active(True)button.set_draw_as_radio(True)menu.append(button)button=gtk.CheckMenuItem("Show Tags")button.connect("toggled",self.toggle_view_column,'tags-column-visible')button.set_active(True)button.set_draw_as_radio(True)menu.append(button)button=gtk.CheckMenuItem("Show Date")button.connect("toggled",self.toggle_view_column,'date-column-visible')button.set_active(True)button.set_draw_as_radio(True)menu.append(button)menu.show_all()returnmenudef_filter_menu(self):menu=gtk.Menu()button=gtk.RadioMenuItem(None,"Show All Revisions")button.set_active(True)button.connect("toggled",self._filter_selected,'all')menu.append(button)button=gtk.RadioMenuItem(button,"Show Tagged Revisions")button.connect("toggled",self._filter_selected,'tagged')menu.append(button)button=gtk.RadioMenuItem(button,"Show Parent Revisions")button.connect("toggled",self._filter_selected,'parents')menu.append(button)button=gtk.RadioMenuItem(button,"Show Head Revisions")button.connect("toggled",self._filter_selected,'heads')menu.append(button)button=gtk.RadioMenuItem(button,"Show Only Merge Revisions")button.connect("toggled",self._filter_selected,'only_merges')menu.append(button)button=gtk.RadioMenuItem(button,"Show Non-Merge Revisions")button.connect("toggled",self._filter_selected,'no_merges')menu.append(button)self.custombutton=gtk.RadioMenuItem(button,"Custom Filter")self.custombutton.set_sensitive(False)menu.append(self.custombutton)menu.show_all()returnmenudefopen_with_file(self,file):'''Call this before display() to open with file history'''self.opts['filehist']=filedefprepare_display(self):'''Called at end of display() method'''self._last_rev=Noneself._filter="all"self.currow=Noneself.curfile=Noneself.opts['rev']=[]# This option is dangerous - used directly by hgself.opts['revs']=Noneif'filehist'inself.opts:self.custombutton.set_active(True)self.graphview.refresh(True,None,self.opts)delself.opts['filehist']elif'revrange'inself.opts:self.custombutton.set_active(True)self.graphview.refresh(True,None,self.opts)elifself.pats==[self.repo.root]orself.pats==['']:self.pats=[]self.reload_log()elifself.pats:self.custombutton.set_active(True)self.graphview.refresh(False,self.pats,self.opts)else:self.reload_log()defsave_settings(self):settings=GDialog.save_settings(self)settings['glog']=(self._vpaned.get_position(),self._hpaned.get_position())returnsettingsdefload_settings(self,settings):'''Called at beginning of display() method'''limit_opt=self.repo.ui.config('tortoisehg','graphlimit','500')iflimit_opt:try:limit=int(limit_opt)exceptValueError:limit=0iflimit<=0:limit=Noneelse:limit=None# Allocate TreeView instance to use internallyself.limit=limitself.stbar=gtklib.StatusBar()self.graphview=TreeView(self.repo,limit,self.stbar)# Allocate ChangeSet instance to use internallyself.changeview=ChangeSet(self.ui,self.repo,self.cwd,[],self.opts,False)self.changeview.display(False)self.changeview.glog_parent=selfGDialog.load_settings(self,settings)ifsettings:set=settings['glog']iftype(set)==int:self._setting_vpos=setself._setting_hpos=-1else:(self._setting_vpos,self._setting_hpos)=setelse:self._setting_vpos=-1self._setting_hpos=-1defreload_log(self,filteropts={}):"""Send refresh event to treeview object""" os.chdir(self.repo.root) # paths relative to repo root do not work otherwise
self.nextbutton.set_sensitive(True)
self.allbutton.set_sensitive(True)
+ self.opts['rev'] = [] self.opts['revs'] = None
self.opts['no_merges'] = False
self.opts['only_merges'] = False
self.opts['revrange']=filteropts.get('revrange',None)self.opts['date']=filteropts.get('date',None)self.opts['keyword']=filteropts.get('keyword',[])revs=[]iffilteropts:branch=filteropts.get('branch',None)if'revrange'infilteroptsor'branch'infilteropts:self.graphview.refresh(True,branch,self.opts)else:filter=filteropts.get('pats',[])self.graphview.refresh(False,filter,self.opts)elifself._filter=="all":self.graphview.refresh(True,None,self.opts)elifself._filter=="only_merges":self.opts['only_merges']=Trueself.graphview.refresh(False,[],self.opts)elifself._filter=="no_merges":self.opts['no_merges']=Trueself.graphview.refresh(False,[],self.opts)elifself._filter=="tagged":tagged=[hex(r)fort,rinself.repo.tagslist()]tagged.reverse()self.opts['revs']=taggedself.graphview.refresh(False,[],self.opts)elifself._filter=="parents":repo_parents=[x.rev()forxinself.repo.workingctx().parents()]self.opts['revs']=[str(x)forxinrepo_parents]self.graphview.refresh(False,[],self.opts)elifself._filter=="heads":heads=[self.repo.changelog.rev(x)forxinself.repo.heads()]self.opts['revs']=[str(x)forxinheads]self.graphview.refresh(False,[],self.opts)deftree_context_menu(self):defcreate_menu(label,callback):menuitem=gtk.MenuItem(label,True)menuitem.connect('activate',callback)menuitem.set_border_width(1)returnmenuitem_menu=gtk.Menu()_menu.append(create_menu('di_splay',self._show_status))_menu.append(create_menu('_checkout',self._checkout))self._cmenu_merge=create_menu('_merge with',self._merge)_menu.append(self._cmenu_merge)_menu.append(create_menu('_export patch',self._export_patch))_menu.append(create_menu('e_mail patch',self._email_patch))_menu.append(create_menu('add/remove _tag',self._add_tag))_menu.append(create_menu('mark rev for diff',self._mark_rev))self._cmenu_diff=create_menu('_diff with mark',self._diff_revs)_menu.append(self._cmenu_diff)_menu.append(create_menu('backout revision',self._backout_rev))try:# Ensure mq extension is loadedextensions.loadall(self.ui)extensions.find('mq')_menu.append(create_menu('strip revision',self._strip_rev))exceptKeyError:pass_menu.show_all()return_menudefget_body(self):self._filter_dialog=Noneself._menu=self.tree_context_menu()self.tree_frame=gtk.Frame()self.tree_frame.set_shadow_type(gtk.SHADOW_ETCHED_IN)# PyGtk 2.6 and below did not automatically register typesifgobject.pygtk_version<(2,8,0):gobject.type_register(TreeView)self.tree=self.graphview.treeviewself.graphview.connect('revision-selected',self.selection_changed)self.graphview.connect('revisions-loaded',self.revisions_loaded)self.tree.connect('button-release-event',self._tree_button_release)self.tree.connect('popup-menu',self._tree_popup_menu)self.tree.connect('row-activated',self._tree_row_act)#self.tree.modify_font(pango.FontDescription(self.fontlist))hbox=gtk.HBox()hbox.pack_start(self.graphview,True,True,0)vbox=gtk.VBox()self.colmenu=gtk.MenuToolButton('')self.colmenu.set_menu(self._view_menu())# A MenuToolButton has two parts; a Button and a ToggleButton# we want to see the togglebutton, but not the buttonb=self.colmenu.child.get_children()[0]b.unmap()b.set_sensitive(False)self.nextbutton=gtk.ToolButton(gtk.STOCK_GO_DOWN)self.nextbutton.connect('clicked',self._more_clicked)self.allbutton=gtk.ToolButton(gtk.STOCK_GOTO_BOTTOM)self.allbutton.connect('clicked',self._load_all_clicked)vbox.pack_start(self.colmenu,False,False)vbox.pack_start(gtk.Label(''),True,True)# expanding blank labelvbox.pack_start(self.nextbutton,False,False)vbox.pack_start(self.allbutton,False,False)self.nextbutton.set_tooltip(self.tooltips,'show next %d revisions'%self.limit)self.allbutton.set_tooltip(self.tooltips,'show all remaining revisions')hbox.pack_start(vbox,False,False,0)self.tree_frame.add(hbox)self.tree_frame.show_all()# Add ChangeSet instance to bottom half of vpaneself.changeview.graphview=self.graphviewself._hpaned=self.changeview.get_body()self._vpaned=gtk.VPaned()self._vpaned.pack1(self.tree_frame,True,False)self._vpaned.pack2(self._hpaned)self._vpaned.set_position(self._setting_vpos)self._hpaned.set_position(self._setting_hpos)vbox=gtk.VBox()vbox.pack_start(self._vpaned,True,True)# Append status barvbox.pack_start(gtk.HSeparator(),False,False)vbox.pack_start(self.stbar,False,False)returnvboxdef_strip_rev(self,menuitem):rev=self.currow[treemodel.REVID]res=Confirm('Strip Revision(s)',[],self,'Remove revision %d and all descendants?'%rev).run()ifres!=gtk.RESPONSE_YES:returnfromhgcmdimportCmdDialogcmdline=['hg','strip',str(rev)]dlg=CmdDialog(cmdline)dlg.show_all()dlg.run()dlg.hide()self.repo.invalidate()self.reload_log()def_backout_rev(self,menuitem):frombackoutimportBackoutDialogrev=self.currow[treemodel.REVID]rev=short(self.repo.changelog.node(rev))parents=[x.node()forxinself.repo.workingctx().parents()]dialog=BackoutDialog(self.repo.root,rev)dialog.set_transient_for(self)dialog.show_all()dialog.set_notify_func(self.checkout_completed,parents)dialog.present()dialog.set_transient_for(None)def_diff_revs(self,menuitem):fromstatusimportGStatusfromgtoolsimportcmdtablerev0=self.graphview.get_mark_rev()rev1=self.currow[treemodel.REVID]statopts=self.merge_opts(cmdtable['gstatus|gst'][1],('include','exclude','git'))statopts['rev']=['%u:%u'%(rev0,rev1)]statopts['modified']=Truestatopts['added']=Truestatopts['removed']=Truedialog=GStatus(self.ui,self.repo,self.cwd,[],statopts,False)dialog.display()returnTruedef_mark_rev(self,menuitem):rev=self.currow[treemodel.REVID]self.graphview.set_mark_rev(rev)def_add_tag(self,menuitem):fromtagaddimportTagAddDialogrev=self.currow[treemodel.REVID]parents=self.currow[treemodel.PARENTS]# save tag info for detecting new tags addedoldtags=self.repo.tagslist()dialog=TagAddDialog(self.repo.root,rev=str(rev))dialog.set_transient_for(self)dialog.show_all()dialog.present()dialog.set_transient_for(None)# refresh if new tags addedself.repo.invalidate()newtags=self.repo.tagslist()ifnewtags!=oldtags:self.reload_log()def_show_status(self,menuitem):rev=self.currow[treemodel.REVID]statopts={'rev':[str(rev)]}dialog=ChangeSet(self.ui,self.repo,self.cwd,[],statopts,False)dialog.display()def_export_patch(self,menuitem):rev=self.currow[treemodel.REVID]filename="%s_rev%s.patch"%(os.path.basename(self.repo.root),rev)fd=NativeSaveFileDialogWrapper(Title="Save patch to",InitialDir=self.repo.root,FileName=filename)result=fd.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)def_email_patch(self,menuitem):fromhgemailimportEmailDialogrev=self.currow[treemodel.REVID]dlg=EmailDialog(self.repo.root,['--rev',str(rev)])dlg.set_transient_for(self)dlg.show_all()dlg.present()dlg.set_transient_for(None)def_checkout(self,menuitem):rev=self.currow[treemodel.REVID]parents=[x.node()forxinself.repo.workingctx().parents()]dialog=UpdateDialog(self.cwd,rev)dialog.set_transient_for(self)dialog.show_all()dialog.set_notify_func(self.checkout_completed,parents)dialog.present()dialog.set_transient_for(None)defcheckout_completed(self,oldparents):newparents=[x.node()forxinself.repo.workingctx().parents()]ifnotoldparents==newparents:self.reload_log()def_merge(self,menuitem):rev=self.currow[treemodel.REVID]parents=[x.node()forxinself.repo.workingctx().parents()]node=short(self.repo.changelog.node(rev))dialog=MergeDialog(self.repo.root,self.cwd,node)dialog.set_transient_for(self)dialog.show_all()dialog.set_notify_func(self.merge_completed,parents)dialog.present()dialog.set_transient_for(None)defmerge_completed(self,oldparents):newparents=[x.node()forxinself.repo.workingctx().parents()]ifnotoldparents==newparents:self.reload_log()defselection_changed(self,treeview):self.currow=self.graphview.get_revision()rev=self.currow[treemodel.REVID]ifrev!=self._last_rev:self._last_rev=revself.changeview.opts['rev']=[str(rev)]self.changeview.load_details(rev)returnFalsedef_refresh_clicked(self,toolbutton,data=None):self.reload_log()returnTruedef_tree_button_release(self,widget,event):ifevent.button==3andnot(event.state&(gtk.gdk.SHIFT_MASK|gtk.gdk.CONTROL_MASK)):self._tree_popup_menu(widget,event.button,event.time)returnFalsedef_tree_popup_menu(self,treeview,button=0,time=0):selrev=self.currow[treemodel.REVID]# disable/enable menus as requiredparents=[self.repo.changelog.rev(x.node())forxinself.repo.workingctx().parents()]can_merge=selrevnotinparentsand \
len(self.repo.heads())>1and \
len(parents)<2can_diff=self.graphview.get_mark_rev()isnotNoneself._cmenu_merge.set_sensitive(can_merge)self._cmenu_diff.set_sensitive(can_diff)# display the context menuself._menu.popup(None,None,None,button,time)returnTruedef_tree_row_act(self,tree,path,column):"""Default action is the first entry in the context menu """self._menu.get_children()[0].activate()returnTruedefrun(root='',cwd='',files=[],**opts):u=ui.ui()u.updateopts(debug=False,traceback=False)repo=hg.repository(u,path=root)files=[util.canonpath(root,cwd,f)forfinfiles]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':[]}dialog=GLog(u,repo,cwd,files,cmdoptions,True)gtk.gdk.threads_init()gtk.gdk.threads_enter()dialog.display()gtk.main()gtk.gdk.threads_leave()if__name__=="__main__":importsysopts={}opts['root']=len(sys.argv)>1andsys.argv[1]oros.getcwd()opts['files']=[opts['root']]run(**opts)
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.