kballard / gitnub forked from Caged/gitnub

A Gitk-like application written in RubyCocoa that looks like it belongs on a Mac. See the wiki for downloads and screenshots.

This URL has Read+Write access

gitnub / CommitsController.rb
a6ad7f3e » Caged 2008-03-03 Scrap big html view in fav... 1 #
2 # CommitsController.rb
3 # GitNub
4 #
5 # Created by Justin Palmer on 3/2/08.
6 # Copyright (c) 2008 Active Reload, LLC. All rights reserved.
7 #
8
9 require 'osx/cocoa'
87d207d0 » Caged 2008-03-03 Implement gravatars in the ... 10 require 'md5'
d4b7e48b » Caged 2008-03-04 Updated interface, now incl... 11 require 'cgi'
a6ad7f3e » Caged 2008-03-03 Scrap big html view in fav... 12
5ff35a94 » kballard 2008-03-21 Implement async load of gra... 13 def gravatar_url(email, size=36)
14 hash = MD5.hexdigest(email.downcase)
15 NSURL.URLWithString("http://www.gravatar.com/avatar.php?gravatar_id=#{hash}&size=#{size}")
16 end
17
a6ad7f3e » Caged 2008-03-03 Scrap big html view in fav... 18 class CommitsController < OSX::NSObject
19 ib_outlet :commits_table
cc55a449 » Caged 2008-03-03 Gittin some data to that br... 20 ib_outlet :branch_select
3ba71262 » Caged 2008-03-04 Add commit paging UI and fu... 21 ib_outlet :paging_segment
d4b7e48b » Caged 2008-03-04 Updated interface, now incl... 22 ib_outlet :commit_details
083bfdf7 » Caged 2008-03-09 Add manual refresh capabili... 23 ib_outlet :application_controller
a6ad7f3e » Caged 2008-03-03 Scrap big html view in fav... 24
25 def awakeFromNib
3ba71262 » Caged 2008-03-04 Add commit paging UI and fu... 26 @current_commit_offset = 0
27 @offset = 50
d4b7e48b » Caged 2008-03-04 Updated interface, now incl... 28 @active_commit = nil
5ff35a94 » kballard 2008-03-21 Implement async load of gra... 29 @branch = :master
30 @icon_queue = NSOperationQueue.alloc.init
31 @icon_url_map = {}
210a3f37 » benstiglitz 2008-03-12 Added support for simple sy... 32 @icons = Hash.new do |hash, email|
5ff35a94 » kballard 2008-03-21 Implement async load of gra... 33 url = gravatar_url(email)
34 @icon_url_map[url] = email
35 @icon_queue.addOperation(ImageLoadOperation.alloc.initWithURL_delegate(url, self))
36 hash[email] = NSImage.imageNamed(NSImageNameUser)
210a3f37 » benstiglitz 2008-03-12 Added support for simple sy... 37 end
3ba71262 » Caged 2008-03-04 Add commit paging UI and fu... 38
39 if(fetch_git_repository)
78657c76 » Caged 2008-03-06 Add icons for diff list. A... 40 setup_commit_detail_view
a1d6f9d1 » Caged 2008-03-21 Hookup branch menu [Paul Sc... 41 fetch_commits_for @branch, @offset
3ba71262 » Caged 2008-03-04 Add commit paging UI and fu... 42 setup_branches_menu
43 setup_paging_control
44 @commits_table.reloadData
78d3665c » Caged 2008-03-03 Will now accept the pwd fro... 45 end
3ba71262 » Caged 2008-03-04 Add commit paging UI and fu... 46 end
47
083bfdf7 » Caged 2008-03-09 Add manual refresh capabili... 48 ib_action :perform_utility_action
49 def perform_utility_action(segment)
50 tag = segment.cell.tagForSegment(segment.selectedSegment)
51 case tag
52 when 0 then refresh_commits(segment)
53 when 1 then @application_controller.show_info_panel(segment)
54 end
55 end
56
57 ib_action :refresh_commits
58 def refresh_commits(sender)
59 refresh
60 end
61
3ba71262 » Caged 2008-03-04 Add commit paging UI and fu... 62 ib_action :page_commits
63 def page_commits(segment)
64 tag = segment.cell.tagForSegment(segment.selectedSegment)
65 case tag
66 when 0 then @current_commit_offset -= @offset
67 when 1 then @current_commit_offset = 0
68 when 2 then @current_commit_offset += @offset
69 end
70
71 @current_commit_offset = 0 if @current_commit_offset == -(@offset)
a1d6f9d1 » Caged 2008-03-21 Hookup branch menu [Paul Sc... 72 fetch_commits_for(@branch, @offset, @current_commit_offset)
a6ad7f3e » Caged 2008-03-03 Scrap big html view in fav... 73 @commits_table.reloadData
cc55a449 » Caged 2008-03-03 Gittin some data to that br... 74
4bfd4e9a » Caged 2008-03-09 Reset scroll position when ... 75 select_latest_commit
3ba71262 » Caged 2008-03-04 Add commit paging UI and fu... 76
77 if @commits.size == 0 || @current_commit_offset == 0
78 @paging_segment.setEnabled_forSegment(false, 0)
79 @paging_segment.setEnabled_forSegment(true, 2) unless @commits.size == 0
80 elsif ((@current_commit_offset >= @offset) && (@commits.size % @offset == 0))
81 @paging_segment.setEnabled_forSegment(true, 0)
82 @paging_segment.setEnabled_forSegment(true, 2)
83 elsif @commits.size % @offset != 0
84 @paging_segment.setEnabled_forSegment(true, 0)
85 @paging_segment.setEnabled_forSegment(false, 2)
cc55a449 » Caged 2008-03-03 Gittin some data to that br... 86 end
a6ad7f3e » Caged 2008-03-03 Scrap big html view in fav... 87 end
88
89 def tableViewSelectionDidChange(notification)
0e0ed38a » Caged 2008-03-09 Selecting latest now select... 90 update_main_document
4bfd4e9a » Caged 2008-03-09 Reset scroll position when ... 91 scrollView = @commit_details.mainFrame.frameView.documentView.enclosingScrollView
92 scrollView.documentView.scrollPoint([0,0])
a6ad7f3e » Caged 2008-03-03 Scrap big html view in fav... 93 end
94
78d3665c » Caged 2008-03-03 Will now accept the pwd fro... 95 # DataSource Methods
a6ad7f3e » Caged 2008-03-03 Scrap big html view in fav... 96 def numberOfRowsInTableView(table_view)
97 @commits ? @commits.size : 0
98 end
99
100 def tableView_objectValueForTableColumn_row(table_view, table_column, row)
66e4e62e » Caged 2008-03-16 Only show first line of com... 101 @commits[row].message.split(/\n/).first.to_s
a6ad7f3e » Caged 2008-03-03 Scrap big html view in fav... 102 end
103
88e97175 » benstiglitz 2008-03-12 Cleaned up the image and te... 104 objc_method :tableView_willDisplayCell_forTableColumn_row, 'v@:@@@i'
105 def tableView_willDisplayCell_forTableColumn_row(table_view, cell, table_column, row)
106 commit = @commits[row]
b4da17cd » Caged 2008-03-14 Respect users system time p... 107 cell.subtitle = %(by #{commit.author.name} on #{commit.authored_date.to_system_time})
4f75917d » Caged 2008-03-13 Use author instead of commi... 108 cell.gravatarImage = @icons[commit.author.email]
3ba71262 » Caged 2008-03-04 Add commit paging UI and fu... 109 end
110
4bfd4e9a » Caged 2008-03-09 Reset scroll position when ... 111 def webView_didFinishLoadForFrame(view, frame)
112 select_latest_commit
d4b7e48b » Caged 2008-03-04 Updated interface, now incl... 113 end
d054f6d8 » kballard 2008-03-21 Remove context menu from th... 114
115 def webView_contextMenuItemsForElement_defaultMenuItems(view, element, defaultMenuItems)
116 nil
117 end
5ff35a94 » kballard 2008-03-21 Implement async load of gra... 118
119 def imageLoadForURL_didFinishLoading(url, image)
120 email = @icon_url_map[url]
121 @icons[email] = image
122 # indices = NSMutableIndexSet.indexSet
123 # @commits.each_with_index do |commit, idx|
124 # if commit.author.email == email
125 # indices.addIndex(idx)
126 # end
127 # end
128 @commits_table.setNeedsDisplay(true)
129 end
130
131 def imageLoadForURL_didFailWithError(url, error)
132 STDERR.puts "Async image load failed for URL: #{url}\n#{error}"
133 end
87efc5b9 » Caged 2008-03-12 Remove the commented async ... 134
4bfd4e9a » Caged 2008-03-09 Reset scroll position when ... 135 def select_latest_commit
136 @commits_table.selectRowIndexes_byExtendingSelection(NSIndexSet.indexSetWithIndex(0), false)
d4b7e48b » Caged 2008-03-04 Updated interface, now incl... 137 end
0e0ed38a » Caged 2008-03-09 Selecting latest now select... 138
139 def update_main_document
140 diffs = []
141 doc = @commit_details.mainFrame.DOMDocument
40708baa » kballard 2008-03-21 Split messages into title/m... 142 title, message = active_commit.message.split("\n", 2)
143 set_html("title", title.strip.gsub("\n", "<br />"))
144 if message
145 set_html("message", message.strip.gsub("\n", "<br />"))
146 show_element("message")
147 else
148 hide_element("message")
149 end
0e0ed38a » Caged 2008-03-09 Selecting latest now select... 150 set_html("hash", active_commit.id)
151
4f75917d » Caged 2008-03-13 Use author instead of commi... 152 if Time.now.day == active_commit.authored_date.day
b4da17cd » Caged 2008-03-14 Respect users system time p... 153 cdate = active_commit.authored_date.to_system_time(:time)
0e0ed38a » Caged 2008-03-09 Selecting latest now select... 154 else
b4da17cd » Caged 2008-03-14 Respect users system time p... 155 cdate = active_commit.authored_date.to_system_time
0e0ed38a » Caged 2008-03-09 Selecting latest now select... 156 end
4f75917d » Caged 2008-03-13 Use author instead of commi... 157 set_html("date", "#{cdate} by #{active_commit.author.name}")
0e0ed38a » Caged 2008-03-09 Selecting latest now select... 158
159 file_list = doc.getElementById('files')
160 diff_list = doc.getElementById('diffs')
161 diff_list.setInnerHTML("")
162 file_list.setInnerHTML("")
163
164 active_commit.diffs.each_with_index do |diff, i|
165 li = doc.createElement('li')
166 li.setAttribute__('id', "item-#{i}")
167 li.setAttribute__('class', 'add') if diff.new_file
168 li.setAttribute__('class', 'delete') if diff.deleted_file
169 li.setInnerHTML(%(<a href="#diff-#{i}" class="">#{diff.b_path}</a>))
170 file_list.appendChild(li)
171
98b5ff64 » kballard 2008-03-21 Fix crash when viewing comm... 172 unless diff.deleted_file or diff.diff.nil?
0e0ed38a » Caged 2008-03-09 Selecting latest now select... 173 diff_div = doc.createElement('div')
174 diff_div.setAttribute__('class', 'diff')
175 diff_div.setAttribute__('id', "diff-#{i}")
176
177 colored_diff = []
178 html = CGI.escapeHTML(diff.diff)
179 html.each_line do |line|
180 if line =~ /^\+/
181 colored_diff << %(<div class="addline">#{line}</div>)
182 elsif line =~ /^\-/
183 colored_diff << %(<div class="removeline">#{line}</div>)
184 elsif line =~ /^@/
185 colored_diff << %(<div class="meta">#{line}</div>)
186 else
187 colored_diff << line
188 end
189 end
190
191 diff_div.setInnerHTML(%(
192 <h3>#{File.basename(diff.b_path)}</h3>
193 <pre><code class="diffcode">#{colored_diff}</pre></code>
194 ))
195 diff_list.appendChild(diff_div)
196 end
197 end
198 end
4bfd4e9a » Caged 2008-03-09 Reset scroll position when ... 199
083bfdf7 » Caged 2008-03-09 Add manual refresh capabili... 200 def refresh
201 current_commit = active_commit && active_commit.id
a1d6f9d1 » Caged 2008-03-21 Hookup branch menu [Paul Sc... 202 @branch = @branch_select.titleOfSelectedItem
203 fetch_commits_for @branch, @offset
083bfdf7 » Caged 2008-03-09 Add manual refresh capabili... 204
205 @commits_table.reloadData
206
207 if current_commit
208 new_commit = @commits.find { |x| x.id == current_commit }
209 new_row = @commits.index(new_commit)
210 @commits_table.selectRow_byExtendingSelection(new_row, false)
211 end
212 end
213
4bfd4e9a » Caged 2008-03-09 Reset scroll position when ... 214
215 private
216
217 def active_commit
218 @commits[@commits_table.selectedRow]
219 end
220
221 def fetch_git_repository
222 begin
223 @repo = Grit::Repo.new(REPOSITORY_LOCATION)
224 rescue Grit::InvalidGitRepositoryError
225 return false
226 end
227 end
228
229 def fetch_commits_for(branch, quanity, offset = 0)
230 @commits = @repo.commits(branch, quanity, offset)
231 end
232
233 def setup_branches_menu
234 @branch_select.removeAllItems
235 @repo.branches.each do |branch|
236 @branch_select.addItemWithTitle(branch.name)
237 end
a1d6f9d1 » Caged 2008-03-21 Hookup branch menu [Paul Sc... 238 @branch_select.selectItemWithTitle(@branch)
4bfd4e9a » Caged 2008-03-09 Reset scroll position when ... 239 end
240
241 def setup_paging_control
242 if @commits.size < @offset
243 @paging_segment.setEnabled_forSegment(false, 2)
244 @paging_segment.setEnabled_forSegment(false, 1)
245 end
246 end
247
248 def setup_commit_detail_view
249 commit_detail = File.join(NSBundle.mainBundle.bundlePath, "Contents", "Resources", "commit.html")
250 @commit_details.mainFrame.loadRequest(NSURLRequest.requestWithURL(NSURL.fileURLWithPath(commit_detail)))
251 end
252
253 def set_html(element, html)
254 @commit_details.mainFrame.DOMDocument.getElementById(element).setInnerHTML(html)
255 end
40708baa » kballard 2008-03-21 Split messages into title/m... 256
257 def show_element(element)
258 element = @commit_details.mainFrame.DOMDocument.getElementById(element)
259 element.style.removeProperty("display")
260 end
261
262 def hide_element(element)
263 element = @commit_details.mainFrame.DOMDocument.getElementById(element)
264 element.style.setProperty_value_priority("display", "none", nil)
265 end
a6ad7f3e » Caged 2008-03-03 Scrap big html view in fav... 266 end