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.
# thgmq.py - embeddable widget for MQ extension## Copyright 2009 Yuki KODAMA <endflow.net@gmail.com>## This software may be used and distributed according to the terms of the# GNU General Public License version 2, incorporated herein by reference.importosimportgtkimportgobjectimportpangofrommercurialimportextensionsfromtortoisehg.util.i18nimport_fromtortoisehg.utilimporthglibfromtortoisehg.hgtkimportgtklib,hgcmd# MQ patches row enumerationsMQ_INDEX=0MQ_STATUS=1MQ_NAME=2MQ_SUMMARY=3MQ_ESCAPED=4# Special patch indicesINDEX_SEPARATOR=-1INDEX_QPARENT=-2classMQWidget(gtk.VBox):__gproperties__={'index-column-visible':(gobject.TYPE_BOOLEAN,'Index','Show index column',False,gobject.PARAM_READWRITE),'status-column-visible':(gobject.TYPE_BOOLEAN,'Status','Show status column',False,gobject.PARAM_READWRITE),'name-column-visible':(gobject.TYPE_BOOLEAN,'Name','Show name column',False,gobject.PARAM_READWRITE),'summary-column-visible':(gobject.TYPE_BOOLEAN,'Summary','Show summary column',False,gobject.PARAM_READWRITE),'editable-cell':(gobject.TYPE_BOOLEAN,'EditableCell','Enable editable cells',False,gobject.PARAM_READWRITE),'show-qparent':(gobject.TYPE_BOOLEAN,'ShowQParent',"Show 'qparent'",False,gobject.PARAM_READWRITE)}__gsignals__={'repo-invalidated':(gobject.SIGNAL_RUN_FIRST,gobject.TYPE_NONE,()),'patch-selected':(gobject.SIGNAL_RUN_FIRST,gobject.TYPE_NONE,(int,# revision numberstr))# patch name}def__init__(self,repo,accelgroup=None,tooltips=None):gtk.VBox.__init__(self)self.repo=repoself.mqloaded=hasattr(repo,'mq')try:extensions.find('qup')self.hasqup=TrueexceptKeyError:self.hasqup=False# top toolbartbar=gtklib.SlimToolbar(tooltips)## buttonsself.btn={}popallbtn=tbar.append_stock(gtk.STOCK_GOTO_FIRST,_('Unapply all patches'))popallbtn.connect('clicked',self.popall_clicked)self.btn['popall']=popallbtnpopbtn=tbar.append_stock(gtk.STOCK_GO_BACK,_('Unapply last patch'))popbtn.connect('clicked',self.pop_clicked)self.btn['pop']=popbtnpushbtn=gtk.ToolButton(gtk.STOCK_GO_FORWARD)pushbtn=tbar.append_stock(gtk.STOCK_GO_FORWARD,_('Apply next patch'))pushbtn.connect('clicked',self.push_clicked)self.btn['push']=pushbtnpushallbtn=tbar.append_stock(gtk.STOCK_GOTO_LAST,_('Apply all patches'))pushallbtn.connect('clicked',self.pushall_clicked)self.btn['pushall']=pushallbtn## separatortbar.append_space()## drop-down menumenubtn=gtk.MenuToolButton('')menubtn.set_menu(self.create_view_menu())tbar.append_widget(menubtn,padding=0)self.btn['menu']=menubtnself.pack_start(tbar,False,False)# center panemainbox=gtk.VBox()self.pack_start(mainbox,True,True)## scrolled panepane=gtk.ScrolledWindow()pane.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)pane.set_shadow_type(gtk.SHADOW_IN)mainbox.pack_start(pane)### patch listself.model=gtk.ListStore(int,# patch indexstr,# patch statusstr,# patch namestr,# summarystr)# escaped summaryself.list=gtk.TreeView(self.model)self.list.set_row_separator_func(self.row_sep_func)# To support old PyGTK (<2.12)ifhasattr(self.list,'set_tooltip_column'):self.list.set_tooltip_column(MQ_ESCAPED)self.list.connect('cursor-changed',self.list_sel_changed)self.list.connect('button-press-event',self.list_pressed)self.list.connect('row-activated',self.list_row_activated)self.list.connect('size-allocate',self.list_size_allocated)self.cols={}self.cells={}defaddcol(header,col_idx,right=False,resizable=False,editable=False,editfunc=None):header=(rightand'%s 'or' %s')%headercell=gtk.CellRendererText()ifeditfunc:cell.set_property('editable',editable)cell.connect('edited',editfunc)col=gtk.TreeViewColumn(header,cell)col.add_attribute(cell,'text',col_idx)col.set_cell_data_func(cell,self.cell_data_func)col.set_resizable(resizable)col.set_visible(self.get_property(self.col_to_prop(col_idx)))ifright:col.set_alignment(1)cell.set_property('xalign',1)self.list.append_column(col)self.cols[col_idx]=colself.cells[col_idx]=celldefcell_edited(cell,path,newname):row=self.model[path]ifrow[MQ_INDEX]<0:returnpatchname=row[MQ_NAME]ifnewname!=patchname:self.qrename(newname,patch=patchname)addcol(_('#'),MQ_INDEX,right=True)addcol(_('st'),MQ_STATUS)addcol(_('Name'),MQ_NAME,editfunc=cell_edited)addcol(_('Summary'),MQ_SUMMARY,resizable=True)pane.add(self.list)## command widgetself.cmd=hgcmd.CmdWidget(style=hgcmd.STYLE_COMPACT,tooltips=tooltips)mainbox.pack_start(self.cmd,False,False)# acceleratorifaccelgroup:key,mod=gtk.accelerator_parse('F2')self.list.add_accelerator('thg-rename',accelgroup,key,mod,gtk.ACCEL_VISIBLE)defthgrename(list):sel=self.list.get_selection()ifsel.count_selected_rows()==1:model,paths=sel.get_selected_rows()self.qrename_ui(model[paths[0]][MQ_NAME])self.list.connect('thg-rename',thgrename)# prepare to showself.refresh()### public functions ###defrefresh(self):""" Refresh the list of patches. This operation will try to keep selection state. """ifnotself.mqloaded:return# store selected patch nameselname=Nonemodel,paths=self.list.get_selection().get_selected_rows()iflen(paths)>0:selname=model[paths[0]][MQ_NAME]# clear model dataself.model.clear()# insert 'qparent' rowtop=Noneifself.get_property('show-qparent'):top=self.model.append((INDEX_QPARENT,None,None,None,None))# add patchesfromhgextimportmqq=self.repo.mqq.parse_series()applied=set([p.nameforpinq.applied])forindex,patchnameinenumerate(q.series):stat=patchnameinappliedand'A'or'U'try:msg=mq.patchheader(q.join(patchname)).message[0]msg_esc=gtklib.markup_escape_text(msg)exceptIndexError:msg=msg_esc=Noneiter=self.model.append((index,stat,patchname,msg,msg_esc))ifstat=='A':top=iter# insert separatoriftop:self.model.insert_after(top,(INDEX_SEPARATOR,None,None,None,None))# restore patch selectionifselname:iter=self.get_iter_by_patchname(selname)ifiter:self.list.get_selection().select_iter(iter)# update UI sensitivesself.update_sensitives()defqgoto(self,patch):""" [MQ] Execute 'qgoto' command. patch: the patch name or an index to specify the patch. """ifnotself.is_operable():returncmdline=['hg','qgoto',patch]self.cmd.execute(cmdline,self.cmd_done)defqpop(self,all=False):""" [MQ] Execute 'qpop' command. all: if True, use '--all' option. (default: False) """ifnotself.is_operable():returncmdline=['hg','qpop']ifall:cmdline.append('--all')self.cmd.execute(cmdline,self.cmd_done)defqpush(self,all=False):""" [MQ] Execute 'qpush' command. all: if True, use '--all' option. (default: False) """ifnotself.is_operable():returncmdline=['hg','qpush']ifall:cmdline.append('--all')self.cmd.execute(cmdline,self.cmd_done)defqdelete(self,patch,keep=False):""" [MQ] Execute 'qdelete' command. patch: the patch name or an index to specify the patch. """ifnotself.has_patch():returncmdline=['hg','qdelete',patch]ifkeep:cmdline.append('--keep')self.cmd.execute(cmdline,self.cmd_done,noemit=True)defqrename(self,name,patch='qtip'):""" [MQ] Execute 'qrename' command. If 'patch' param isn't specified, renaming should be applied 'qtip' (current) patch. name: the new patch name for renaming. patch: the target patch name or index. (default: 'qtip') """ifnotnameornotself.has_patch():returncmdline=['hg','qrename',patch,name]self.cmd.execute(cmdline,self.cmd_done)defqrename_ui(self,patch='qtip'):""" Prepare the user interface for renaming the patch. If 'patch' param isn't specified, renaming should be started 'qtip' (current) patch. Return True if succeed to prepare; otherwise False. patch: the target patch name or index. (default: 'qtip') """ifnotself.mqloadedor \
patch=='qtip'and'qtip'inself.repo.tags():returnFalsetarget=self.repo.mq.lookup(patch)ifnottarget:returnFalsepath=self.get_path_by_patchname(target)ifnotpath:returnFalse# make the cell editablecell=self.cells[MQ_NAME]ifnotcell.get_property('editable'):cell.set_property('editable',True)defcanceled(cell,*arg):cell.disconnect(cancel_id)cell.disconnect(edited_id)cell.set_property('editable',False)cancel_id=cell.connect('editing-canceled',canceled)edited_id=cell.connect('edited',canceled)# start editing patchname cellself.list.set_cursor_on_cell(path,self.cols[MQ_NAME],None,True)returnTruedefqfinish(self,applied=False):""" [MQ] Execute 'qfinish' command. applied: if True, enable '--applied' option. (default: False) """ifnotself.has_applied():returncmdline=['hg','qfinish']ifapplied:cmdline.append('--applied')self.cmd.execute(cmdline,self.cmd_done)defqfold(self,patch):""" [MQ] Execute 'qfold' command. patch: the patch name or an index to specify the patch. """ifnotpatchornotself.has_applied():returncmdline=['hg','qfold',patch]self.cmd.execute(cmdline,self.cmd_done)defmknext(self,patch):""" [MQ] Execute 'qup patch' patch: the patch name or an index to specify the patch. """ifnot(self.hasqupandpatchandself.is_operable()):returncmdline=['hg','qup',patch]self.cmd.execute(cmdline,self.cmd_done)defhas_patch(self):""" return True if MQ has applicable patch """ifself.mqloaded:returnlen(self.repo.mq.series)>0returnFalsedefhas_applied(self):""" return True if MQ has applied patches """ifself.mqloaded:returnlen(self.repo.mq.applied)>0returnFalsedefnumber_applied(self):""" return the number of applied patches """ifself.mqloaded:returnlen(self.repo.mq.applied)return0defis_operable(self):""" return True if MQ is operable """ifself.mqloaded:repo=self.repoif'qtip'inself.repo.tags():returnrepo['.']==repo['qtip']returnlen(repo.mq.series)>0returnFalsedefis_qtip(self,patchname):ifpatchname:returnpatchname==self.get_qtip_patchname()returnFalse### internal functions ###defget_iter_by_patchname(self,name):""" return iter has specified patch name """ifname:forrowinself.model:ifrow[MQ_NAME]==name:returnrow.iterreturnNonedefget_path_by_patchname(self,name):""" return path has specified patch name """returnself.model.get_path(self.get_iter_by_patchname(name))defget_qtip_patchname(self):ifself.mqloadedand'qtip'inself.repo.tags():returnself.repo.mq.applied[-1].namereturnNonedefupdate_sensitives(self):""" Update the sensitives of entire UI """defdisable_mqmoves():fornamein('popall','pop','push','pushall'):self.btn[name].set_sensitive(False)ifself.mqloaded:self.list.set_sensitive(True)self.btn['menu'].set_sensitive(True)ifself.is_operable():q=self.repo.mqin_bottom=len(q.applied)==0in_top=len(q.unapplied(self.repo))==0self.btn['popall'].set_sensitive(notin_bottom)self.btn['pop'].set_sensitive(notin_bottom)self.btn['push'].set_sensitive(notin_top)self.btn['pushall'].set_sensitive(notin_top)else:disable_mqmoves()else:self.list.set_sensitive(False)self.btn['menu'].set_sensitive(False)disable_mqmoves()defscroll_to_current(self):""" Scroll to current patch in the patch list. If the patch is selected, it will do nothing. """ifself.list.get_selection().count_selected_rows()>0:returnqtipname=self.get_qtip_patchname()ifnotqtipname:returnpath=self.get_path_by_patchname(qtipname)ifpath:self.list.scroll_to_cell(path)defcell_data_func(self,column,cell,model,iter):row=model[iter]ifrow[MQ_INDEX]==INDEX_QPARENT:ifcolumn==self.cols[MQ_INDEX]:cell.set_property('text','')elifcolumn==self.cols[MQ_NAME]:cell.set_property('text','[qparent]')stat=row[MQ_STATUS]ifstat=='A':cell.set_property('foreground','blue')elifstat=='U':cell.set_property('foreground','#909090')else:cell.set_property('foreground','black')patchname=row[MQ_NAME]ifself.is_qtip(patchname):cell.set_property('weight',pango.WEIGHT_BOLD)else:cell.set_property('weight',pango.WEIGHT_NORMAL)defrow_sep_func(self,model,iter,data=None):returnmodel[iter][MQ_INDEX]==INDEX_SEPARATORdefshow_patch_cmenu(self,list,path):row=self.model[path]ifrow[MQ_INDEX]==INDEX_SEPARATOR:returnmenu=gtk.Menu()defappend(label,handler=None):item=gtk.MenuItem(label,True)item.set_border_width(1)ifhandler:item.connect('activate',handler,row)menu.append(item)is_operable=self.is_operable()has_patch=self.has_patch()has_applied=self.has_applied()is_qtip=self.is_qtip(row[MQ_NAME])is_qparent=row[MQ_INDEX]==INDEX_QPARENTis_applied=row[MQ_STATUS]=='A'is_next=row[MQ_INDEX]==self.number_applied()ifis_operableandnotis_qtipand(notis_qparentorhas_applied):append(_('_goto'),self.goto_activated)ifhas_patchandnotis_qparent:append(_('_rename'),self.rename_activated)ifhas_appliedandnotis_qparent:append(_('_finish applied'),self.finish_activated)ifnotis_appliedandnotis_qparent:append(_('_delete'),self.delete_activated)append(_('delete --keep'),self.delete_keep_activated)ifhas_appliedandnotis_qparent:append(_('f_old'),self.fold_activated)ifself.hasqupandnotis_next:append(_('make it _next'),self.mknext_activated)iflen(menu.get_children())>0:menu.show_all()menu.popup(None,None,None,0,0)defcreate_view_menu(self):menu=gtk.Menu()defappend(item=None,handler=None,check=False,active=False,sep=False):ifsep:item=gtk.SeparatorMenuItem()else:ifisinstance(item,str):ifcheck:item=gtk.CheckMenuItem(item)item.set_active(active)else:item=gtk.MenuItem(item)item.set_border_width(1)ifhandler:item.connect('activate',handler)menu.append(item)returnitemdefcolappend(label,col_idx,active=True):defhandler(menuitem):col=self.cols[col_idx]col.set_visible(menuitem.get_active())propname=self.col_to_prop(col_idx)item=append(label,handler,check=True,active=active)self.vmenu[propname]=itemself.vmenu={}colappend(_('Show index'),MQ_INDEX)colappend(_('Show status'),MQ_STATUS,active=False)colappend(_('Show name'),MQ_NAME)colappend(_('Show summary'),MQ_SUMMARY,active=False)append(sep=True)defenable_editable(item):self.cells[MQ_NAME].set_property('editable',item.get_active())item=append(_('Enable editable cells'),enable_editable,check=True,active=False)self.vmenu['editable-cell']=itemitem=append(_("Show 'qparent'"),lambdaitem:self.refresh(),check=True,active=True)self.vmenu['show-qparent']=itemmenu.show_all()returnmenudefqgoto_by_row(self,row):ifself.get_qtip_patchname()==row[MQ_NAME]:returnifrow[MQ_INDEX]==INDEX_QPARENT:self.qpop(all=True) else:
self.qgoto(row[MQ_NAME])
- def cmd_done(self, returncode, noemit=False):
+ def cmd_done(self, returncode, useraborted, noemit=False):
+ if returncode == 0:+ if self.cmd.get_pbar():+ self.cmd.set_result(_('Succeed'), style='ok')+ elif useraborted:+ self.cmd.set_result(_('Canceled'), style='error')+ else:+ self.cmd.set_result(_('Failed'), style='error') self.repo.mq.invalidate()
self.refresh()
if not noemit:
self.emit('repo-invalidated')defdo_get_property(self,property):try:returnself.vmenu[property.name].get_active()except:raiseAttributeError,'unknown property %s'%property.namedefdo_set_property(self,property,value):try:self.vmenu[property.name].set_active(value)except:raiseAttributeError,'unknown property %s'%property.namedefcol_to_prop(self,col_idx):ifcol_idx==MQ_INDEX:return'index-column-visible'ifcol_idx==MQ_STATUS:return'status-column-visible'elifcol_idx==MQ_NAME:return'name-column-visible'elifcol_idx==MQ_SUMMARY:return'summary-column-visible'return''### signal handlers ###deflist_pressed(self,list,event):x,y=int(event.x),int(event.y)pathinfo=list.get_path_at_pos(x,y)ifevent.button==1:ifnotpathinfo:# HACK: clear selection after this function calling,# against selection by getting focusdefunselect():selection=list.get_selection()selection.unselect_all()gobject.idle_add(unselect)elifevent.button==3:ifpathinfo:self.show_patch_cmenu(self.list,pathinfo[0])deflist_sel_changed(self,list):path,focus=list.get_cursor()row=self.model[path]ifrow[MQ_INDEX]<0:returnpatchname=row[MQ_NAME]try:ctx=self.repo[patchname]revid=ctx.rev()excepthglib.RepoError:revid=-1self.emit('patch-selected',revid,patchname)deflist_row_activated(self,list,path,column):self.qgoto_by_row(self.model[path])deflist_size_allocated(self,list,req):ifself.mqloadedandself.has_applied():self.scroll_to_current()defpopall_clicked(self,toolbutton):self.qpop(all=True)defpop_clicked(self,toolbutton):self.qpop()defpush_clicked(self,toolbutton):self.qpush()defpushall_clicked(self,toolbutton):self.qpush(all=True)### context menu signal handlers ###defgoto_activated(self,menuitem,row):self.qgoto_by_row(row)defdelete_activated(self,menuitem,row):self.qdelete(row[MQ_NAME])defdelete_keep_activated(self,menuitem,row):self.qdelete(row[MQ_NAME],keep=True)defrename_activated(self,menuitem,row):self.qrename_ui(row[MQ_NAME])deffinish_activated(self,menuitem,row):self.qfinish(applied=True)deffold_activated(self,menuitem,row):self.qfold(row[MQ_NAME])defmknext_activated(self,menuitem,row):self.mknext(row[MQ_NAME])
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.