More refactoring.
[giterdone.git] / giterdone / repositorymanager.py
blob73ac7f534f4e2b8ebda0b2b69f99a946ca840425
1 # Copyright 2010 -- Robert Toscano
3 import os.path, tempfile
4 import gtk
5 import gedit
6 import git
8 popup_xml = '''<ui>
9 <popup name="RepositoryManagerPopup">
10 <menuitem action="SvcCommit"/>
11 <menuitem action="SvcPull"/>
12 <menuitem action="SvcFetch"/>
13 <menuitem action="SvcPush"/>
14 </popup>
15 </ui>'''
17 def load_emblem(name):
18 return gtk.icon_theme_get_default().load_icon(name, 20, gtk.ICON_LOOKUP_USE_BUILTIN)
21 emblems = { 'synced': load_emblem('emblem-default'),
22 'untracked': load_emblem('emblem-new'),
23 'dirty': load_emblem('emblem-danger'),
24 'staged': load_emblem('emblem-draft') }
27 class RepositoryManager(gtk.TreeView):
28 def __init__(self, repos, svc_interfaces, window, statusbar_id, commit_msg_header):
29 self.iters = {}
30 self.repos = repos
31 self.svc_interfaces = svc_interfaces
32 self.gedit_window = window
33 self.statusbar = window.get_statusbar()
34 self.statusbar_id = statusbar_id
35 self.commit_msg_header = commit_msg_header
37 self.model = gtk.ListStore(str, # full path to repo
38 str, # name to be displayed
39 str, # branch
40 gtk.gdk.Pixbuf) # emblem
42 super(RepositoryManager, self).__init__(self.model)
44 self.set_grid_lines(False)
45 self.set_headers_clickable(True)
46 self.append_column(gtk.TreeViewColumn(None, gtk.CellRendererPixbuf(), pixbuf=3))
47 self.append_column(gtk.TreeViewColumn('Name', gtk.CellRendererText(), text=1))
48 self.append_column(gtk.TreeViewColumn('Branch', gtk.CellRendererText(), text=2))
49 self.connect('button-release-event', self.on_button_released)
51 # Create the Repository Manager popup
52 self.uimanager = gtk.UIManager()
53 self.uimanager.add_ui_from_string(popup_xml)
55 self.actiongroup = gtk.ActionGroup('SvcBase')
56 self.actiongroup.add_actions([ ('SvcCommit', gtk.STOCK_SAVE_AS, 'Commit', None,
57 'Commit all staged files', self.on_svc_commit_all),
58 ('SvcPush', gtk.STOCK_GOTO_TOP, 'Push', None,
59 'Push to origin repository', self.on_svc_push),
60 ('SvcPull', gtk.STOCK_GOTO_BOTTOM, 'Pull', None,
61 'Pull from remote reposities', self.on_svc_pull),
62 ('SvcFetch', gtk.STOCK_GO_DOWN, 'Fetch', None,
63 'Fetch from remote repositories', self.on_svc_fetch) ])
65 self.uimanager.insert_action_group(self.actiongroup, 0)
67 self.commit_tabs = {} # tab -> repo
68 self.on_tab_closed_id = window.connect('tab-removed', self.on_tab_closed)
70 # watch for selection changes and make the actions sensitive as needed
71 self.get_selection().connect('changed', self.on_selection_changed)
74 def update_root(self, root):
75 '''Adds/removes repos to/from the RM based on the new root and each repo's path'''
77 self.curr_root = root
79 toadd = []
80 for path in self.repos.keys():
81 if path.startswith(self.curr_root): toadd.append(path)
83 toremove = []
84 tokeep = []
85 for row in self.model:
86 if not row[0].startswith(self.curr_root): toremove.append(row)
87 else: tokeep.append(row[0])
89 # remove paths already in the model from toadd
90 for path in tokeep: toadd.remove(path)
92 # remove paths from the model
93 for row in toremove:
94 self.model.remove(row.iter)
96 # modify existing rows to match new root
97 for row in self.model:
98 if row[0] == self.curr_root: row[1] = os.path.basename(row[0])
99 elif self.curr_root.startswith(row[0]): row[1] = os.path.basename(row[0])
100 else: row[1] = '.'+row[0][len(self.curr_root):]
102 # append new repos
103 for path in toadd:
104 self.add_repo(self.repos[path])
107 def get_emblem(self, repo):
108 if repo.path in repo.state['untracked']: return emblems['untracked']
109 elif repo.path in repo.state['dirty']: return emblems['dirty']
110 elif repo.path in repo.state['staged']: return emblems['staged']
111 else: return emblems['synced']
114 def add_repo(self, repo):
115 if repo.path == self.curr_root:
116 name = os.path.basename(repo.path)
117 else:
118 name = '.'+repo.path[len(self.curr_root):]
120 self.iters[repo.path] = self.model.append( ( repo.path,
121 name,
122 self.get_branch(repo),
123 self.get_emblem(repo) ) )
126 def update_repo(self, repo):
127 # update emblem of row
128 self.model.set_value( self.iters[repo.path], 3, self.get_emblem(repo) )
131 def on_button_released(self, widget, event):
132 if event.button == 3: # right-click
133 # show context menu
134 self.uimanager.get_widget('/RepositoryManagerPopup').popup(None, None, None, event.button, 0)
137 def on_svc_commit_all(self, action):
138 model, rows = self.get_selection().get_selected_rows()
140 if len(rows) > 1:
141 gtk.MessageDialog().run()
142 return
144 repo_path = model[rows[0]][0]
145 repo = self.repos[repo_path]
147 f = tempfile.NamedTemporaryFile(suffix='.commit',
148 prefix='gedit-'+repo.type+'-commit-message-',
149 delete=False)
150 f.write( self.commit_msg_header + self.svc_interfaces[repo.type].status_msg(repo.path) )
151 msg_path = f.name
152 f.close()
154 # open file in gedit
155 tab = self.gedit_window.create_tab_from_uri('file://'+msg_path,
156 gedit.encoding_get_utf8(), 0, False, True)
157 tab.get_document().goto_line(0)
158 self.commit_tabs[tab] = repo
160 def on_svc_pull(self, action):
161 model, rows = self.get_selection().get_selected_rows()
163 for path in [ row[0] for row in rows ]:
164 pass
166 def on_svc_push(self, action):
167 model, rows = self.get_selection().get_selected_rows()
169 for path in [ row[0] for row in rows ]:
170 pass
172 def on_svc_fetch(self, action):
173 model, rows = self.get_selection().get_selected_rows()
175 for repo_path in [ model[row][0] for row in rows ]:
176 repo = self.repos[repo_path]
177 self.statusbar.flash_message(self.statusbar_id, 'Fetching repository: '+repo.path)
178 self.svc_interfaces[repo.type].fetch(repo.path)
181 def on_tab_closed(self, window, tab):
182 if not tab in self.commit_tabs.keys(): return
184 repo = self.commit_tabs[tab]
185 commit_msg_path = tab.get_document().get_uri()[len('file://'):]
187 # check if commit_msg had any text in it
188 has_msg = False
189 f = open(commit_msg_path, 'r')
190 for line in f:
191 line = line.strip(' \n')
192 if line.startswith('#'):
193 continue
194 elif line != '':
195 print 'Line has message: \''+line+'\''
196 has_msg = True
197 break
198 f.close()
200 if has_msg:
201 self.svc_interfaces[repo.type].commit( repo.path, commit_msg_path )
203 # clean up
204 del self.commit_tabs[tab]
205 os.remove(commit_msg_path)
208 def on_selection_changed(self, selection):
209 model, rows = selection.get_selected_rows()
211 if len(rows) != 1:
212 for action in self.actiongroup.list_actions():
213 action.set_sensitive(False)
214 return
216 selected_path = model[rows[0]][0]
218 if len(self.repos[selected_path].state['staged']) == 0:
219 for action in self.actiongroup.list_actions():
220 action.set_sensitive(True)
221 self.actiongroup.get_action('SvcCommit').set_sensitive(False)
223 else:
224 for action in self.actiongroup.list_actions():
225 action.set_sensitive(True)
228 def get_branch(self, repo):
229 return 'master'