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