compare: add a 'Compare File Across Commits...' menu item
[git-cola.git] / cola / controllers / repobrowser.py
blobcf0eb3047deb752adaeffd8ef7e518d55399667f
1 #!/usr/bin/env python
2 import os
3 from PyQt4.QtGui import QDialog
5 from cola import utils
6 from cola import qtutils
7 from cola import defaults
8 from cola.views import CommitView
9 from cola.qobserver import QObserver
11 def select_file_from_repo(model, parent):
12 model = model.clone()
13 view = CommitView(parent)
14 controller = RepoBrowserController(model, view,
15 title='Select File',
16 get_file=True)
17 view.show()
18 if view.exec_() == QDialog.Accepted:
19 return controller.filename
20 else:
21 return None
23 def browse_git_branch(model, parent, branch):
24 if not branch:
25 return
26 # Clone the model to allow opening multiple browsers
27 # with different sets of data
28 model = model.clone()
29 model.set_currentbranch(branch)
30 view = CommitView(parent)
31 controller = RepoBrowserController(model, view)
32 view.show()
33 return view.exec_() == QDialog.Accepted
35 class RepoBrowserController(QObserver):
36 def init(self, model, view, title='File Browser', get_file=False):
37 self.get_file = get_file
38 self.filename = None
39 view.setWindowTitle(title)
40 self.add_signals('itemSelectionChanged()', view.commit_list,)
41 self.add_actions(directory = self.action_directory_changed)
42 self.add_callbacks(commit_list = self.item_changed)
43 self.connect(view.commit_list,
44 'itemDoubleClicked(QListWidgetItem*)',
45 self.item_double_clicked)
47 # Start at the root of the tree
48 model.set_directory('')
50 ######################################################################
51 # Actions
52 def action_directory_changed(self):
53 """This is called in response to a change in the the
54 model's directory."""
55 self.model.init_browser_data()
56 self.__display_items()
58 ######################################################################
59 # Qt callbacks
60 def item_changed(self,*rest):
61 """This is called when the current item changes in the
62 file/directory list(aka the commit_list)."""
63 current = self.view.commit_list.currentRow()
64 item = self.view.commit_list.item(current)
65 if item is None or not item.isSelected():
66 self.view.revision.setText('')
67 self.view.commit_text.setText('')
68 return
69 directories = self.model.get_directories()
70 directory_entries = self.model.get_directory_entries()
71 if current < len(directories):
72 # This is a directory...
73 dirent = directories[current]
74 if dirent != '..':
75 # This is a real directory for which
76 # we have child entries
77 entries = directory_entries[dirent]
78 else:
79 # This is '..' which is a special case
80 # since it doesn't really exist
81 entries = []
82 self.view.commit_text.setText('\n'.join(entries))
83 self.view.revision.setText('')
84 else:
85 # This is a file entry. The current row is absolute,
86 # so get a relative index by subtracting the number
87 # of directory entries
88 idx = current - len(directories)
89 if idx >= len(self.model.get_subtree_sha1s()):
90 # This can happen when changing directories
91 return
92 objtype, sha1, name = self.model.get_subtree_node(idx)
94 catguts = self.model.git.cat_file(objtype, sha1,
95 with_raw_output=True)
96 self.view.commit_text.setText(catguts)
98 self.view.revision.setText(sha1)
99 self.view.revision.selectAll()
101 # Copy the sha1 into the clipboard
102 qtutils.set_clipboard(sha1)
104 def item_double_clicked(self,*rest):
105 """This is called when an entry is double-clicked.
106 This callback changes the model's directory when
107 invoked on a directory item. When invoked on a file
108 it allows the file to be saved."""
110 current = self.view.commit_list.currentRow()
111 directories = self.model.get_directories()
113 # A file item was double-clicked.
114 # Create a save-as dialog and export the file.
115 if current >= len(directories):
116 idx = current - len(directories)
118 objtype, sha1, name = self.model.get_subtree_node(idx)
120 if self.get_file:
121 self.filename = name
122 self.view.accept()
123 return
125 nameguess = os.path.join(defaults.DIRECTORY, name)
127 filename = qtutils.save_dialog(self.view, 'Save', nameguess)
128 if not filename:
129 return
130 defaults.DIRECTORY = os.path.dirname(filename)
131 contents = self.model.cat_file(objtype, sha1, raw=True)
133 utils.write(filename, contents)
134 return
136 dirent = directories[current]
137 curdir = self.model.get_directory()
139 # '..' is a special case--it doesn't really exist...
140 if dirent == '..':
141 newdir = os.path.dirname(os.path.dirname(curdir))
142 if newdir == '':
143 self.model.set_directory(newdir)
144 else:
145 self.model.set_directory(newdir + os.sep)
146 else:
147 self.model.set_directory(curdir + dirent)
149 ######################################################################
151 def __display_items(self):
152 """This method populates the commit_list(aka item list)
153 with the current directories and items. Directories are
154 always listed first."""
156 self.view.commit_text.setText('')
157 self.view.revision.setText('')
159 dir_icon = utils.get_icon('dir.png')
160 file_icon = utils.get_icon('generic.png')
161 creator = qtutils.create_listwidget_item
163 qtutils.set_items(self.view.commit_list,
164 map(lambda d: creator(d, dir_icon),
165 self.model.get_directories()))
167 qtutils.add_items(self.view.commit_list,
168 map(lambda s: creator(s, file_icon),
169 self.model.get_subtree_names()))