Added support for renamed file detection in cmds.git_status()
[ugit.git] / py / repobrowsercontroller.py
blobe381c25b266951b19a88df09102647117f6473b4
1 #!/usr/bin/env python
2 import os
3 from PyQt4.QtCore import SIGNAL
4 from PyQt4.QtGui import QFileDialog
5 from qobserver import QObserver
6 import cmds
7 import utils
8 import qtutils
9 import defaults
11 class GitRepoBrowserController (QObserver):
12 def __init__ (self, model, view):
13 QObserver.__init__ (self, model, view)
15 model.add_observer (self)
17 view.setWindowTitle ('Git Repo Browser')
19 self.add_signals ('itemSelectionChanged()',
20 view.commitList,)
22 self.add_actions (model, 'directory',
23 self.action_directory_changed)
25 self.add_callbacks (model, {
26 'commitList': self.cb_item_changed,
29 self.connect (view.commitList,
30 SIGNAL ('itemDoubleClicked(QListWidgetItem*)'),
31 lambda(x): self.cb_item_double_clicked (model))
33 # Collect data for the model
34 tree_info = cmds.git_ls_tree (model.get_branch())
36 types = map ( lambda (x): x[1], tree_info )
37 sha1s = map ( lambda (x): x[2], tree_info )
38 files = map ( lambda (x): x[3], tree_info )
40 model.add_types (*types)
41 model.add_files (*files)
42 model.add_sha1s (*sha1s)
44 model.setup_items()
46 self.__display_items (model)
48 ######################################################################
49 # ACTIONS
50 ######################################################################
52 def action_directory_changed (self, model, *args):
53 '''This is called in response to a change in the the
54 model's directory.'''
55 model.setup_items()
56 self.__display_items (model)
58 ######################################################################
59 # CALLBACKS
60 ######################################################################
62 def cb_item_changed (self, model, *args):
63 '''This is called when the current item changes in the
64 file/directory list (aka the commitList).'''
65 current = self.view.commitList.currentRow()
66 item = self.view.commitList.item (current)
67 if item is None or not item.isSelected():
68 self.view.revisionLine.setText ('')
69 self.view.commitText.setText ('')
70 return
71 item_names = model.get_item_names()
72 item_sha1s = model.get_item_sha1s()
73 item_types = model.get_item_types()
74 directories = model.get_directories()
75 directory_entries = model.get_directory_entries()
77 if current < len (directories):
78 # This is a directory...
79 dirent = directories[current]
80 if dirent != '..':
81 # This is a real directory for which
82 # we have child entries
83 msg = 'Directory: ' + dirent
84 header = utils.html_header (msg)
85 entries = directory_entries[dirent]
86 else:
87 # This is '..' which is a special case
88 # since it doesn't really exist
89 msg = 'Parent Directory'
90 header = utils.html_header (msg)
91 entries = []
93 contents = '<pre>%s</pre>' % '\n'.join (entries)
95 self.view.commitText.setHtml (header + contents)
96 self.view.revisionLine.setText ('')
97 else:
98 # This is a file entry. The current row is absolute,
99 # so get a relative index by subtracting the number
100 # of directory entries
101 idx = current - len (directories)
103 if idx >= len (item_sha1s):
104 # This can happen when changing directories
105 return
107 sha1 = item_sha1s[idx]
108 objtype = item_types[idx]
109 filename = item_names[idx]
111 guts = cmds.git_cat_file (objtype, sha1)
112 header = utils.html_header ('File: ' + filename)
113 contents = '<pre>%s</pre>' % utils.html_encode (guts)
115 self.view.commitText.setHtml (header + contents)
117 self.view.revisionLine.setText (sha1)
118 self.view.revisionLine.selectAll()
120 # Copy the sha1 into the clipboard
121 qtutils.set_clipboard (sha1)
123 def cb_item_double_clicked (self, model):
124 '''This is called when an entry is double-clicked.
125 This callback changes the model's directory when
126 invoked on a directory item. When invoked on a file
127 it allows the file to be saved.'''
129 current = self.view.commitList.currentRow()
130 directories = model.get_directories()
132 # A file item was double-clicked.
133 # Create a save-as dialog and export the file.
134 if current >= len (directories):
135 idx = current - len (directories)
137 names = model.get_item_names()
138 sha1s = model.get_item_sha1s()
139 types = model.get_item_types()
141 objtype = types[idx]
142 sha1 = sha1s[idx]
143 name = names[idx]
145 file_to_save = os.path.join(defaults.DIRECTORY, name)
147 qstr_filename = QFileDialog.getSaveFileName(self.view,
148 'Git File Export', file_to_save)
149 if not qstr_filename: return
151 filename = str (qstr_filename)
152 defaults.DIRECTORY = os.path.dirname (filename)
153 cmds.git_cat_file (objtype, sha1, filename)
154 return
156 dirent = directories[current]
157 curdir = model.get_directory()
159 if dirent == '..':
160 newdir = os.path.normpath (curdir + '..')
161 if newdir == '.' or not newdir:
162 model.set_directory ('')
163 else:
164 model.set_directory (newdir + '/')
165 else:
166 model.set_directory (curdir + dirent)
168 ######################################################################
169 # PRIVATE HELPER METHODS
170 ######################################################################
172 def __display_items (self, model):
173 '''This method populates the commitList (aka item list)
174 with the current directories and items. Directories are
175 always listed first.'''
177 self.view.commitList.clear()
178 self.view.commitText.setText ('')
179 self.view.revisionLine.setText ('')
181 dir_icon = utils.get_directory_icon()
182 file_icon = utils.get_file_icon()
184 for entry in model.get_directories():
185 item = qtutils.create_listwidget_item(entry, dir_icon)
186 self.view.commitList.addItem (item)
188 for entry in model.get_item_names():
189 item = qtutils.create_listwidget_item(entry, file_icon)
190 self.view.commitList.addItem (item)