Jens Alfke avatar Jens Alfke committed 8ff5e80

* Canonicalize paths to avoid opening multiple windows on the same repo (fixes #24)
* Push/Pull progress sheet now lets you stop the operation.

Comments (0)

Files changed (4)

English.lproj/Repo.xib

 		<string key="IBDocument.HIToolboxVersion">353.00</string>
 		<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
 			<bool key="EncodedWithXMLCoder">YES</bool>
-			<integer value="300194"/>
-			<integer value="300144"/>
+			<integer value="300213"/>
 		</object>
 		<object class="NSArray" key="IBDocument.PluginDependencies">
 			<bool key="EncodedWithXMLCoder">YES</bool>
 				</object>
 				<string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string>
 				<object class="NSView" key="NSWindowView" id="118353878">
-					<reference key="NSNextResponder"/>
+					<nil key="NSNextResponder"/>
 					<int key="NSvFlags">256</int>
 					<object class="NSMutableArray" key="NSSubviews">
 						<bool key="EncodedWithXMLCoder">YES</bool>
 																			<reference ref="8"/>
 																			<object class="NSCachedImageRep">
 																				<object class="NSData" key="NSTIFFRepresentation">
-																					<bytes key="NS.bytes">TU0AKgAAA4KAACBQOCQWDQeDgGBionCUAHlZNsAIuBtWBvyERmNRuChKBidSFgALM1K0AFx5PsAMaBvK
-OS+DgSZAyZAQGQMbjYOgIupMlA8oIRjP5mtp9BhtuOlJB3U1mQQBVEDP+qP0C1cJh6tEQJV0WAmwB4D2
-MPAGzBt52kKGwdPMHEkQP8AKNlwpYOMKgB03tHNW/HWBv4HYMPELDNKogIHgIBgMAY0CgAIhK8g8IA4A
-P8D5gBO9uAA7kVsgAAu52ABntUFABtCExgBT7FgsLaEp/bd7YkDFIqFV7jMdEgBB4RCQAV0GgAgC8TgA
-BL+TM0OCkAONcIEAE4cO4APp2u8ANhnPUANMOnIALFbrt0LP3CuB9yBlAplZ2lUslsJFopk6CnseaBHe
-NY4AAbYPJuEYcGWAAKAelR+HadYAHQbB4gAYp+ieABknIfh/k/EIVnzEhroIJQmCcagkCcJwVjaMrXnW
-lwAHMa5OgAYRhnsAAJmiUgACkNAIAAdpuHIAAGASAgAH4eULlubQWAAcIHhyABLyyLRyy4U6CCHMBbB2
-IQkCSQI6jcAB/GoPwAHmAx1AAbJhoEf4As+F4VOSZBcHGAAVBMAwAAOAp4AAXRhpudoXjQABMUeR5o0k
-9CBhxSxLheGofjQTBJEQzJzDuABum6jxnmofLshxJB+nmcwAGaX50AADwJsiCAKQuYpepcdYdOwUBRFI
-XpgWKIiCBXZI3hYGAdEgUhQEsAB+m4NIAGqdoqRqZBKAAIoiBFUZkmiAB7AiKQAAWcJZgADgMyQaJpMc
-YwHiqABfGEY5xlzfgPIIDWACAHYfiOX5Lkmih0G5VJvnMYgAB8DRdAAAwDtWVhKGEABqHsDAABkBhtAA
-JIgAPKhmnOh5nhQAB6H+BJ9GDmTVoGBubBCIwkCYbwYhk+BtmwiQOn1Bg8DqIrMn28h+nccrSH4fZ/n4
-dWUnqcR2H+c5wHSf4+mMA5Tl0bZ8j4gZwoIswAgGJO2Hce+3neeh5HedBKC2AQYhQFwTAGf5+n0uR8Hk
-uR7u4f55nSAB5HTpxv7OfxQpYZBPosLqBz8gbE5oAB9tufwJiiFoCEoSY7hqJxzHKdx9nGb52Hkbxwna
-dBu1mcRtHbUZwwua5xpcbPAXKgfEoFzCXgwGwMgANQCscBJn5SXB7H7IqB1SgR8IH7Pse16zAoIgIAAP
+																					<bytes key="NS.bytes">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
-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
+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
-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
+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
+AAAQ0AAAAChjcHJ0AAAQ+AAAACRYWVogAAAAAAAAYAAAADXEAAAHKlhZWiAAAAAAAABvkQAAs2MAABjy
+WFlaIAAAAAAAACdEAAAW8wAAswlYWVogAAAAAAAA81IAAQAAAAEWz3NmMzIAAAAAAAEMQgAABd7///Mm
 AAAHkgAA/ZH///ui///9owAAA9wAAMBsY3VydgAAAAAAAAABAc0AAGN1cnYAAAAAAAAAAQHNAABjdXJ2
-AAAAAAAAAAEBzQAAdmNndAAAAAAAAAAAAAMBAAACAAACLwNOBGgFfQaZB7AIwgnYCusL8g0KDhcPIRAt
-EToSQRNMFFQVVxZeF2MYaRlwGnMbdBx1HXgeex+AIIQhhCKHI4okjiWVJpsnoCioKa8quCvHLNUt4S72
-MAoxIjIzM1U0ezWgNso3+DkpOmE7mzzdPh8/aUC3QgxDXUSzRhJHckjRSi9LjUzxTkxPrlEPUmxTylUb
-VmxXvlkOWl9bqFz0XkNfimDNYg9jT2SSZc9nCmhBaXVqrmvhbRNuRG93cKxx2nMEdDB1X3aMd7x46HoR
-ez58cH2ffsd/3IDigeWC7IPwhPKF9ob9iASJDIoRixWMHY0ojjOPO5BBkUiSUZNWlFqVXpZjl2mYa5lr
-mmmbaZxqnWieYZ9aoFOhS6JAozGkKaUnpiWnIqggqR2qGasVrBGtEK4MrwWv/rD4sfOy7bPltNu10bbM
-t8O4ubmxuqy7qbyhvZa+jr+KwITBgcJ6w3LEbsVuxmzHYchDyRbJ4sqyy3/MSs0XzebOtM+E0FLRH9Ht
-0sDTkdRf1S3V+tbL15fYYdkt2fnaxtuP3FbdHd3k3q3fcuA24PnhuuJ74zrj9uS25XzmQecD58nojOlO
-6hDq0+uX7FjtGO3Y7pjvWPAY8NXxkfJO8w3zyfSE9UH1//a+93r4Nfjw+a36a/sp++b8ov1g/h/+2v9x
-//8AAAIEAxIEFgUUBhUHDwgLCQgJ/Qr5C+8M5A3ZDs0PwRCxEaISlBOFFHcVaxZdF08YQxk5GjYbLBwv
-HS4eNh8+IEUhPyI4Iy0kLCUsJionMCgsKTAqNitDLEotWC5pL3kwiTGdMrYzzzTuNhE3NDhTOXo6pzvX
-PQg+NT9xQK1B6EMrRGtFr0b4SEVJi0rYTDFNfE7RUBtRZ1K2VAFVTVaSV9xZKVpwW7Jc9144X31gv2H9
-YztkdmW3ZvNoLmlqaqpr6m0mblxvmHDWchNzVHSRdcp3CHhMeY56xXvjfOt97371f/mA+oH+gwWEDIUT
-hhmHHYgkiTCKOotCjEmNT45Yj1yQYJFkkmqTb5RwlXKWb5dumHCZbZpmm2CcWJ1QnkWfNqAtoS2iLKMp
-pCmlKKYmpySoI6kkqiOrH6wcrRquGa8YsBWxErIPsw+0DrUNtg23EbgWuRi6GLsbvCC9J74uvzXAOcFC
-wk7DWsRbxUfGIMbyx8nInMltykHLF8vtzMXNmc5tz0PQHdD20c3SotN31E7VItX11snXnNhv2UHaEdrd
-26zcfN1I3hHe29+i4GrhLuHw4rjjkORo5T/mF+bt58Tomelu6kXrGevq7Lztje5d7y7v+/DH8ZLyXvMp
-8/L0u/WG9lD3GPfc+KL5afow+vj7vPyA/UX+Dv7P/23//wAAAgQC9wPwBPQF7wbtB+0I7QneCtsL1AzL
-Db0Org+fEIsRdxJkE0wUMBUPFfMW0RerGIQZXBowGwUb1xylHXUeRR8PH90gpSFtIjojBiPWJKklfiZV
-JywoCCjnKccqqCuNLHQtWy5CLy4wHDEJMfcy5TPRNMA1sDadN4k4djlhOkw7PDwgPQY98D7VP7VAk0F2
-QmlDV0RGRThGJkcYSAVI9knpStlLyEy2TaZOmE+JUHhRZ1JWU0xUO1UsVh9XFlgNWQJZ9FrpW+Jc2l3U
-Xs1fw2C+Yb1iumOyZKNliWZyZ19oSGkvahprB2v1bORt0W6+b65wonGWcohzeHRodV52Tnc+eC95IXoU
-ewR783zgfc5+vn+rgJSBf4Jmg0+ENIUWhgGG94ftiOOJ2orQi8eMuo2vjqiPnJCLkX+ScJNklFWVRpY0
-lySYFZkFmfSa5ZvYnM2dvp6sn52gk6GFonyjb6RhpVemUadJqDupIqoAqtyrvKyYrXKuT68usA6w7rHN
-sqmzi7RvtVO2NbcWt/e43Lm9up27frxhvUO+Jb8Fv+PAw8GmwoTDYcQ9xRrF9sbQx6XIi8mcysHL4sz/
-zhrPOdBa0XzSnNPI1O3WHNdP2IvZzNsT3GDdud8T4H/h9OOB5Q7mp+hQ6hHr1u2u75bxkfOd9bH35vog
-/GD+fv//AABuZGluAAAAAAAABjYAAJh1AABY4QAAUqUAAI/9AAAoDAAAFqgAAFANAABUOQABwo8AAauF
-AAFCjwADAQAAAgAAAAAAAgAIABEAHgAtAD8AVABsAIYAowDEAOUBCgEyAVwBiAG4AekCHQJVAo4CygMI
-A0gDiwPRBBoEZASxBP8FTwWjBfkGUAaqBwQHYQfACCEIgwjoCU0JsQoaCoQK7AtXC8IMMgydDQcNdQ3i
-Dk8OvQ8rD5gQBxBzEOERUBG9EisSmBMFE3UT5RRTFMEVMBWgFhIWhRb5F2wX4BhZGM8ZRxnAGjwaths2
-G7ocPhzCHUgd0B5YHuUfch//IIwhHiGzIkki4SN7JBQksSVQJfImlyc+J+MojCk5KeYqlStEK/Mspi1e
-Lhgu0C+JMEUxADG9Mn8zQjQDNMI1hTZMNx44AjjuOdc6wjuzPKU9lD6FP3dAakFjQl1DU0RIRUJGP0dA
-SEBJQEpHS1BMWk1lTnBPg1CXUbFSyVPhVQFWJ1dNWHdZolrXXA9dOl5jX5RgwmHzYydkXmWXZs1oBmlH
-aolrzW0QblZvoHDvckFzi3TfdjR3iXjcei17h3zofkR/nYD7glaDuYUfhn6H2ok/irWMXI4cj9WRmZNi
-lSOW6piumn6cTZ4Tn+GhtqORpWSnSKkuqxSs+67usOey5LTetui49bsMvSO/TsFvw3/FoMe6yd7MB84w
-0FjSkNTI1wbZQ9uL3dzgJuJ85NXnKul96+PuSvCp8wv1c/fk+kb8vP//AAAAAAADAAoAFQAkADYATABl
-AIEAoQDDAOkBEgE+AW0BnwHVAg0CSAKGAsYDCQNPA5cD4QQrBHoExwUYBWgFugYOBmkGxwcpB4kH6whQ
-CLQJHgmHCfEKWgrICzULogwSDIMM9g1nDdoOTw7BDzUPqhAjEJoREBGHEf4SdhLyE2kT4RRbFNYVThXK
-FkYWwRc9F7gYNxi3GTMZrhoxGq8bMRu4HD4cwx1LHdUeXx7uH3wgCSCYISohwCJVIuwjhiQeJLklViX2
-JpcnOyfbKIApJynPKngrICvILHMtIS3ULoQvMy/kMJcxSDH9MrYzbjQkNNg1kDZNNxY39jjiOcs6tjun
-PJo9iT56P2xAX0FXQlFDSEQ9RTdGNEc0SDZJNUo9S0ZMUE1aTmZPeVCMUaZSv1PXVPdWHVdCWG1ZmFrM
-XAVdMF5XX4dgtGHiYxRkSGV+ZrFn5mkjamFrn2zebhxvX3Clce5zMnR5dcR3DnhWeZx65Xw2fYZ+0oAf
-gWyCuYQNhWGGrof6iU2KsoxJjf2PqJFekxmUzJaDmDeZ9Zu2nW6fKKDoorCkd6ZAqBOp56u8rZWvdrFi
-s0u1NrcxuS67NL09v1jBZMNBxTHHGskMyv3M+M7u0OnS9NT81wvZGts03Vffe+Gi49PmBOg06mvstO73
-8T3zgfXS+Cn6cvzU//8AAAAAAAMACwAXACYAOQBPAGgAhAClAMcA7QEWAUMBcwGmAd4CFwJVApcC3gMm
-A3QDxgQcBHcE1QU4BaAGCgZ7Bu0HaAfiCGAI3gldCd4KYgrlC2kL8Ax3DP8NiQ4WDqIPLw+/EFEQ5RF9
-EhQSrhNNE+0UkRU3FdwWjBc8F+wYpBliGiQa1RuOHEgdAR3AHn4fQiAEIMchkCJbIygj9STDJZYmaydD
-KBYo8SnMKqcrgSxcLT4uIi8DL+UwyTGtMpczgTRmNU42PDcxODc5PTpAO0k8Vz1hPms/dkCDQZVCp0Oz
-RMJF1UbrSARJGEo1S1RMc02STrRP21EGUjRTX1SPVclXAVhBWX9ax1wVXUxefl+4YO5iKWNkZKZl6Gcm
-aGxpumsEbFRtoW70cEtxpnL/dFl1uXcZeHd50ns0fJ9+Bn9ogNCCNIOfhQ6GdofbiUeKwYxWjfePkZEz
-kt2Uf5Yil8WZa5sbnMGeY6ALobmjaqUUpsiogKo2q+ytpa9ksSmy7rSttnm4S7oeu/K9zr+3wXnC6MRO
-xbzHMMiqyh7Lk80GznnP89FZ0s7UONWf1wDYWdmw2wTcVd2e3t7gJOFc4o3ju+TY5fXnFOgr6UDqTutS
-7E/tTe5K7z/wMvEg8gry7/PR9K71jPZp90L4EPje+az6evtJ/Bf83f2d/sP//wAAZGVzYwAAAAAAAAAK
+AAAAAAAAAAEBzQAAdmNndAAAAAAAAAAAAAMBAAACAAAAKQCQASABugJ2A1AERQVhBpQH3QlBCroMOQ3B
+D1cQ6BJ2E/4VeRbmGEoZmxrkHBUdNh5aH3kgmCG4Itkj/yUiJkYnaiiQKbsq5SwQLUMuci+lMNsyDzNJ
+NIU1xDcAOEU5gzq/O+s9ET46P1pAe0GgQsVD5kUKRi5HUUhxSZJKtkvYTPtOHE86UFlRfVKcU7tU2lX6
+Vx1YRFlvWqJb1F0FXjRfZGCRYcFi8mQiZVVmj2fEaP1qO2t/bL5uBW9PcJ1x7nNDdJV18HdAeGJ5bHpy
+e3l8g32Gfot/ioCMgYeCfYN4hGiFVYZChymIDYjsiceKoYt1jEqNGo3njrOPgJBWkS2SBJLbk7KUiJVe
+ljKXB5fdmLOZiZphmzicD5znncGenJ94oFWhNKIUovWj1aS4pYymVqcjp/KowKmNqlyrK6v4rMetmK5o
+rzqwCrDasayyfbNOtCC08rXFtpS3Y7gzuQO50LqQu028CLzEvYK+QL7/v77AfME9wgDCwsOFxEzFE8Xb
+xqXHccg9yQvJ28qty4DMU80lzfTOvs+I0FHRGdHi0q7Td9Q/1QrV1dag12zYOdkH2dXapNt03ETdFd3p
+3rrfj+Bj4TbiDeLq48LkleVl5jHm++fJ6JTpY+o26w3r6OzR7cbuxu/Y8P/yQvOZ9Qr2pPhc+kb8Zf6S
+//8AAABBAOQBcQIXAtMDtwSwBccG9wg9CZULBgx1DfQPfREAEoIT/hVuFs8YKhl4Grcb5h0GHigfSCBk
+IYEioSPFJOQmBicoKEYpbyqTK7gs4y4OLzcwZDGOMr4z8DUkNlM3iji8Oes7CDwdPTU+SD9YQG5Bg0KW
+Q6pEvUXPRuFH8kkGShhLKUw6TUlOV09qUHdRhFKSU6FUsVXGVuJYAlkjWkNbYVyBXZ9evl/fYP9iIWNK
+ZG9ll2bDZ/RpImpVa41sxm4Db0NwfnHEcvx0FXUcdh93I3gneSh6KHsnfCZ9In4afxOACYD8ge6C3oPN
+hLiFn4aKh22IU4k2iheK94vTjKuNhY5bjzOQDJDmkcCSmpNylFCVLZYMluyXzJiumY+adZtbnEOdK54W
+nwKf7qDaocaioqNtpD2lEKXjprWnjKhgqTWqDarlq76smq1yrkuvJa//sNmxsLKKs2O0OLUMteC2tLeI
+uF65M7oGuti7rLx/vVO+Jb73v8rAncFuwkDDFMPnxLnFjcZhxzXICsjfybXKjctkzD/NJM4TzwPP8tDd
+0cjStNOc1IPVatZS1znYH9kH2e/a2NvC3K/dm96L333gb+Fl4lvjUuRL5UbmROdB6D/pQ+pK61LsXO1q
+7nrvj/Co8cDy2vP39Rr2PPdf+IP5q/rS+/f9Hv4//0H//wAAABsAXgDDATYBrgI+AuQDmgRjBT4GKgcc
+CBkJGgoiCyQMLA0rDiQPEg/7ENoRrhJ2EzgT+RS1FXIWMBbvF68YbhkuGfAasxt2HDsdAR3MHpYfYSAv
+IPshzCKfI3IkRSUeJfMmwSeEKD4o+im0Km4rKyvoLKYtZi4mLucvqDBqMTEx9TK6M4A0RjULNdQ2mzdh
+OCg48Dm4On87RjwQPNo9pD5uPzdAAUDMQZdCY0MwRABEzkWdRm9HREgUSOhJvUqUS2tMRE0bTfROyU+V
+UFxRI1HsUrZTglRRVR5V8FbCV5ZYb1lGWiFa/1vfXMBdoV6DX2lgTGE1YhtjAWPoZMplqGaGZ2FoQGkf
+af9q4GvBbKFthm5rb09wN3EecgZy7nPXdMJ1rHaYd4R4cXlfekl7MXwBfMR9g35FfwN/wIB/gTiB8oKs
+g2eEIoTdhZiGU4cPh82IjIlKiguKzouQjFKNF43cjqGPWpATkMuRhJJBkwCTwZSElUmWEpbfl66Yf5lZ
+mjObEJvwnNSdup6jn4+gfaFvomGjTqQypRCl6qbFp6Gofqlfqj+rIKwDrOmtzq6zr56wh7FwsluzRbQw
+tRu2Brbwt9y4xbmuup67wLzkvgG/GcAzwVPCecOoxOLGKsd/yOzKcMwHzb/PpNG00/fWedla3J7gk+VO
+66T1Sv//AABuZGluAAAAAAAABjYAAJkCAABWyAAAVQQAAJGwAAAnkQAAFWAAAFANAABUOQACCj0AAfrh
+AAEmZgADAQAAAgAAABMALABFAF8AeACRAKsAxQDfAPkBFAEwAUwBagGHAaYBxgHnAgoCLgJUAnwCpwLT
+AwMDNQNqA6UD5AQkBGcErATzBTsFhQXPBhwGaga6BwwHXQewCAUIWwiwCQgJYQm6ChQKcQrNCyoLhwvm
+DEcMpg0JDWwN1Q5EDrUPJg+cEBQQixEEEX8R/RJ6EvoTexP/FIUVChWRFhsWpRcyF8IYUxjiGXYaCxqi
+Gzob0xxsHQQdnB4xHscfYB/6IJchNCHUInQjFCO2JFok/SWdJkIm5yeLKC4ozyl1KhkquyteLAAsoi1E
+LeYuiy8sL84wejFEMh0y+TPXNLM1mDZ7N2c4UTlDOj07Mzw2PT8+Sj9gQHtBokLMRAJFOUZ+R8hJEkpR
+S5BM1E4ZT2JQrVH+U09UoVX3V0pYo1n9W1VcrV4GX19gt2IPY2xkw2Y3Z8FpQmrIbFNt2m9pcPhyhXQV
+daV3PHjRemp8A32gfzuA4YKJhDKF4IexiY+Lc41SjzORFJL7lNqWvZiemnicV54woAih36O0pYanVqkp
+qwes8q7jsNiy0rTEtsK4v7q5vLi+tcCywq/ErcaqyKnKocyjzpzQntKd1IrWh9iS2qzc0t7v4RnjM+VC
+50fpMOr/7LvuW+/h8UvypvPw9Sn2Svdi+G75aPpX+zb8EPze/aT+l///AAAADAAjADwAVABuAIcAoQC7
+ANYA8QEMASkBRgFkAYIBogHDAeUCCQIuAlUCfwKrAtkDCQM9A3QDsAPwBDEEdAS6BQIFSwWVBeAGLwZ+
+Bs8HIwd1B8oIIgh5CNEJKwmHCeMKQgqhCwALYQvCDCcMigzwDVgNww44DrAPKA+kECMQoREhEaQSKBKu
+EzYTwBRMFNoVaBX5FowXIRe5GFMY6xmJGigayRtrHA4csR1SHfEekB8xH9QgeSEfIccicCMaI8UkciUe
+JcgmdickJ9IofSkqKdoqhyszK+AsjC05LeUuli9BL/AwrTGBMl4zPjQfNQE16TbRN744qzmgOpg7kDyR
+PZM+mz+lQLVBzkLkRAVFJEZMR3dIpknjSx5MYk2jTuZQK1FxUr1UAVVKVpFX2lkiWm5btFz8XkRfjGDT
+YhljZWSsZhJnmWkUapBsEW2Mbw5wjnIMc4x1CXaPeBR5m3sjfLR+QH/TgXCDEISyhlWH94mgi0+M/I6t
+kGCSGpPRlYyXTpkMmsyck55WoByh5KOspXSnOqkFqsKsY64Cr6exUrMCtK+2abglueG7n71kvyTA6MKq
+xG7GK8fvyajLY80dztLQi9JA0/fVptdX2Qzaudxg3gXfreFP4u3kiuYg57LpSurf7HDt+++I8RbypfQw
+9bj3R/jW+mT7/f2O//8AAAAdAEQAagCRALgA3wEIATIBXgGLAbwB7gIkAl4CngLiAywDfwPcBD4EpgUS
+BYEF8wZqBuMHXwfeCGAI4QlnCe4KeQsDC48MIAyvDUMN4Q6SD0UP/hC4EXQSMxL0E7cUfhVDFg0W2Beo
+GHoZTBolGv8b2xy6HZ8egh9oIFEhPiItIx0kESUFJfgm8SfpKN8p3SrXK9Qs0S3PLtIv0zDkMgQzJzRI
+NWs2izevOM458jsOPC89TT5pP4VAokHCQt1D/kUaRj1HYEiFSbhK7UwpTWFOmk/VURBSUVOMVMlWCVdE
+WIVZxlsIXEldjF7QYBVhWmKgY+5lQmbRaHJqD2u8bWZvH3DZcpR0UnYUd9l5nHtcfSJ+3oChgmSEJIXm
+h8eJsIubjXuPWJEwkwaUzpaVmFaaB5u6nWefDqCyolKj76WIpx6otKpZrBWt3q+osXSzPbUAtsm4j7pQ
+vBK92L+UwVfDGMTaxp7IZcooy/TNu8+L0V7TItSU1gnXidkT2p7cJN2j3xvgi+Hx40zkneXj5xjoQOli
+6nvrg+yF7XLuXe838A/w1/Gf8lfzDvO79Fj09vWL9hf2o/co95z4D/iD+PH5Uvm0+hb6ePrK+xP7XPul
+++78N/x2/Kb81f0F/TT9ZP2T/cP98/4i/k/+ev6l/tD++/8n/1L/ff+o/9T//wAAZGVzYwAAAAAAAAAK
 Q29sb3IgTENEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1sdWMAAAAAAAAAAQAAAAxlblVTAAAAEgAAABwAQwBv
-AGwAbwByACAATABDAEQAAG1tb2QAAAAAAAAGEAAAnGAAAAAAv/h7gAAAAAAAAAAAAAAAAAAAAAB0ZXh0
-AAAAAENvcHlyaWdodCBBcHBsZSwgSW5jLiwgMjAwOQA</bytes>
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1sdWMAAAAAAAAAEgAAAAxuYk5PAAAAEgAAAOhwdFBU
+AAAAFgAAAPpzdlNFAAAAEAAAARBmaUZJAAAAEAAAASBkYURLAAAAHAAAATB6aENOAAAADAAAAUxmckZS
+AAAAEgAAAVhqYUpQAAAADgAAAWplblVTAAAAEgAAAXhwbFBMAAAAEgAAAYpwdEJSAAAAGAAAAZxlc0VT
+AAAAEgAAAbR6aFRXAAAADgAAAcZydVJVAAAAJAAAAdRrb0tSAAAADAAAAfhkZURFAAAAEAAAAgRubE5M
+AAAAFgAAAhRpdElUAAAAFAAAAioARgBhAHIAZwBlAC0ATABDAEQATABDAEQAIABhACAAQwBvAHIAZQBz
+AEYA5AByAGcALQBMAEMARABWAOQAcgBpAC0ATABDAEQATABDAEQALQBmAGEAcgB2AGUAcwBrAOYAcgBt
+X2mCcgAgAEwAQwBEAMkAYwByAGEAbgAgAEwAQwBEMKsw6TD8ACAATABDAEQAQwBvAGwAbwByACAATABD
+AEQASwBvAGwAbwByACAATABDAEQATABDAEQAIABDAG8AbABvAHIAaQBkAG8ATABDAEQAIABjAG8AbABv
+AHJfaYJybbJmdphveTpWaAQmBDIENQRCBD0EPgQ5ACAEFgQaAC0ENAQ4BEEEPwQ7BDUEOc7st+wAIABM
+AEMARABGAGEAcgBiAC0ATABDAEQASwBsAGUAdQByAGUAbgAtAEwAQwBEAEwAQwBEACAAYwBvAGwAbwBy
+AGkAAG1tb2QAAAAAAAAGEAAAnIEAAAAAwb3/gAAAAAAAAAAAAAAAAAAAAAB0ZXh0AAAAAENvcHlyaWdo
+dCBBcHBsZSwgSW5jLiwgMjAwOQA</bytes>
 																				</object>
 																				<string key="NSCacheWindowColorSpace">NSCalibratedRGBColorSpace</string>
 																				<int key="NSCacheWindowBPS">8</int>
 											</object>
 											<string key="NSFrame">{{1, 17}, {571, 184}}</string>
 											<reference key="NSSuperview" ref="214279069"/>
-											<reference key="NSNextKeyView" ref="392325734"/>
 											<reference key="NSDocView" ref="392325734"/>
 											<reference key="NSBGColor" ref="131218211"/>
 											<int key="NScvFlags">4</int>
 											</object>
 											<string key="NSFrame">{{1, 0}, {571, 17}}</string>
 											<reference key="NSSuperview" ref="214279069"/>
-											<reference key="NSNextKeyView" ref="288602249"/>
 											<reference key="NSDocView" ref="288602249"/>
 											<reference key="NSBGColor" ref="131218211"/>
 											<int key="NScvFlags">4</int>
 									</object>
 									<string key="NSFrameSize">{588, 202}</string>
 									<reference key="NSSuperview" ref="333363212"/>
-									<reference key="NSNextKeyView" ref="61754055"/>
 									<int key="NSsFlags">18</int>
 									<reference key="NSVScroller" ref="746151416"/>
 									<reference key="NSHScroller" ref="834737768"/>
 													</object>
 													<string key="NSFrame">{{0, 17}, {281, 262}}</string>
 													<reference key="NSSuperview" ref="977457134"/>
-													<reference key="NSNextKeyView" ref="408726427"/>
 													<reference key="NSDocView" ref="408726427"/>
 													<reference key="NSBGColor" ref="131218211"/>
 													<int key="NScvFlags">4</int>
 													</object>
 													<string key="NSFrameSize">{281, 17}</string>
 													<reference key="NSSuperview" ref="977457134"/>
-													<reference key="NSNextKeyView" ref="435744945"/>
 													<reference key="NSDocView" ref="435744945"/>
 													<reference key="NSBGColor" ref="131218211"/>
 													<int key="NScvFlags">4</int>
 											</object>
 											<string key="NSFrameSize">{281, 279}</string>
 											<reference key="NSSuperview" ref="599257509"/>
-											<reference key="NSNextKeyView" ref="305294895"/>
 											<int key="NSsFlags">560</int>
 											<reference key="NSVScroller" ref="864508780"/>
 											<reference key="NSHScroller" ref="521395639"/>
 													</object>
 													<string key="NSFrame">{{1, 1}, {296, 277}}</string>
 													<reference key="NSSuperview" ref="554197517"/>
-													<reference key="NSNextKeyView" ref="1057217485"/>
 													<reference key="NSDocView" ref="1057217485"/>
 													<reference key="NSBGColor" ref="131218211"/>
 													<object class="NSCursor" key="NSCursor" id="770217247">
 											</object>
 											<string key="NSFrame">{{290, 0}, {298, 279}}</string>
 											<reference key="NSSuperview" ref="599257509"/>
-											<reference key="NSNextKeyView" ref="378280175"/>
 											<int key="NSsFlags">658</int>
 											<reference key="NSVScroller" ref="31961279"/>
 											<reference key="NSHScroller" ref="79423723"/>
 						</object>
 					</object>
 					<string key="NSFrameSize">{586, 488}</string>
-					<reference key="NSSuperview"/>
 				</object>
 				<string key="NSScreenRect">{{0, 0}, {1440, 878}}</string>
 				<string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string>
 				<string key="NSWindowContentMaxSize">{2000, 124}</string>
 				<string key="NSWindowContentMinSize">{300, 124}</string>
 				<object class="NSView" key="NSWindowView" id="192347478">
-					<reference key="NSNextResponder"/>
+					<nil key="NSNextResponder"/>
 					<int key="NSvFlags">256</int>
 					<object class="NSMutableArray" key="NSSubviews">
 						<bool key="EncodedWithXMLCoder">YES</bool>
 						</object>
 					</object>
 					<string key="NSFrameSize">{478, 124}</string>
-					<reference key="NSSuperview"/>
 				</object>
 				<string key="NSScreenRect">{{0, 0}, {1440, 878}}</string>
 				<string key="NSMinSize">{300, 146}</string>
 				<string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string>
 				<string key="NSWindowContentMinSize">{300, 124}</string>
 				<object class="NSView" key="NSWindowView" id="1008550395">
-					<nil key="NSNextResponder"/>
+					<reference key="NSNextResponder"/>
 					<int key="NSvFlags">256</int>
 					<object class="NSMutableArray" key="NSSubviews">
 						<bool key="EncodedWithXMLCoder">YES</bool>
 								<int key="NSButtonFlags">-2038284033</int>
 								<int key="NSButtonFlags2">129</int>
 								<string key="NSAlternateContents"/>
-								<string type="base64-UTF8" key="NSKeyEquivalent">DQ</string>
+								<string type="base64-UTF8" key="NSKeyEquivalent">Gw</string>
 								<int key="NSPeriodicDelay">200</int>
 								<int key="NSPeriodicInterval">25</int>
 							</object>
 						</object>
 					</object>
 					<string key="NSFrameSize">{478, 210}</string>
+					<reference key="NSSuperview"/>
 				</object>
 				<string key="NSScreenRect">{{0, 0}, {1440, 878}}</string>
 				<string key="NSMinSize">{300, 146}</string>
 				</object>
 				<object class="IBConnectionRecord">
 					<object class="IBBindingConnection" key="connection">
-						<string key="label">value: currentOperation.outputAndError</string>
-						<reference key="source" ref="1063712634"/>
-						<reference key="destination" ref="798535885"/>
-						<object class="NSNibBindingConnector" key="connector">
-							<reference key="NSSource" ref="1063712634"/>
-							<reference key="NSDestination" ref="798535885"/>
-							<string key="NSLabel">value: currentOperation.outputAndError</string>
-							<string key="NSBinding">value</string>
-							<string key="NSKeyPath">currentOperation.outputAndError</string>
-							<int key="NSNibBindingConnectorVersion">2</int>
-						</object>
-					</object>
-					<int key="connectionID">300246</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBBindingConnection" key="connection">
 						<string key="label">contentArray: selection.rootAsArray</string>
 						<reference key="source" ref="460789637"/>
 						<reference key="destination" ref="436694272"/>
 					</object>
 					<int key="connectionID">300269</int>
 				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBBindingConnection" key="connection">
+						<string key="label">value: currentOperation.outputAndError</string>
+						<reference key="source" ref="1063712634"/>
+						<reference key="destination" ref="798535885"/>
+						<object class="NSNibBindingConnector" key="connector">
+							<reference key="NSSource" ref="1063712634"/>
+							<reference key="NSDestination" ref="798535885"/>
+							<string key="NSLabel">value: currentOperation.outputAndError</string>
+							<string key="NSBinding">value</string>
+							<string key="NSKeyPath">currentOperation.outputAndError</string>
+							<object class="NSDictionary" key="NSOptions">
+								<string key="NS.key.0">NSContinuouslyUpdatesValue</string>
+								<boolean value="YES" key="NS.object.0"/>
+							</object>
+							<int key="NSNibBindingConnectorVersion">2</int>
+						</object>
+					</object>
+					<int key="connectionID">300270</int>
+				</object>
 			</object>
 			<object class="IBMutableOrderedSet" key="objectRecords">
 				<object class="NSArray" key="orderedObjects">
 					<string>300206.IBPluginDependency</string>
 					<string>300207.IBPluginDependency</string>
 					<string>300208.IBPluginDependency</string>
+					<string>300212.IBEditorWindowLastContentRect</string>
 					<string>300212.IBWindowTemplateEditedContentRect</string>
 					<string>300212.NSWindowTemplate.visibleAtLaunch</string>
 					<string>300212.editorWindowContentRectSynchronizationRect</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
-					<string>{{373, 432}, {478, 210}}</string>
+					<string>{{0, 635}, {478, 210}}</string>
+					<string>{{0, 635}, {478, 210}}</string>
 					<reference ref="8"/>
 					<string>{{373, 432}, {478, 210}}</string>
 					<reference ref="8"/>
 				</object>
 			</object>
 			<nil key="sourceID"/>
-			<int key="maxID">300269</int>
+			<int key="maxID">300270</int>
 		</object>
 		<object class="IBClassDescriber" key="IBDocument.Classes">
 			<object class="NSMutableArray" key="referencedPartialClassDescriptions">
 					</object>
 				</object>
 				<object class="IBPartialClassDescription">
+					<string key="className">NSWindow</string>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBProjectSource</string>
+						<string key="minorKey">../MYUtilities/MYWindowUtils.h</string>
+					</object>
+				</object>
+				<object class="IBPartialClassDescription">
 					<string key="className">RepoController</string>
 					<string key="superclassName">NSWindowController</string>
 					<object class="NSMutableDictionary" key="actions">

Source/HgRepository.m

 + (NSString*) findRootOf: (NSString*)absPath
                localPath: (NSString**)outLocalPath
 {
+    absPath = [absPath stringByStandardizingPath];  // Resolves '..', '~', symlinks
+    if (!absPath || !absPath.isAbsolutePath)
+        return nil;
+    
+    // Look for a ".hg" subdirectory. While not found, walk up to the parent directory:
     NSString *path = absPath;
     while(YES){
         NSString *hgDirPath = [path stringByAppendingPathComponent: @".hg"];
                 else
                     *outLocalPath = nil;
             }
+            if( ! [path hasSuffix: @"/"] )
+                path = [path stringByAppendingString: @"/"];
             return path;
         }
         NSString *oldPath = path;
         NSString *root = [[self class] findRootOf: path localPath: localPath];
         if( ! root )
             return nil;
-        if( ! [root hasSuffix: @"/"] )
-            root = [root stringByAppendingString: @"/"];
         _absolutePath = [root copy];
         
         _uncommittedRevision = [[HgUncommittedRevision alloc] initWithRepository: self];
         _watcher.latency = 5;
         if( ! [_watcher start] )
             Warn(@"HgRepository: Couldn't start MYDirectoryWatcher on %@",_absolutePath);
+        Log(@"Opened %@", self);
     }
     return self;
 }
 }
 
 
+- (NSString*) description {
+    return $sprintf(@"%@[%@]", [self class], [self absolutePath]);
+}
+
+
 - (HgConfigFile*) configFile
 {
     if( ! _hgrc ) 

Source/RepoController.m

 
 + (RepoController*) existingRepoControllerWithDirectory: (NSString*)directory
 {
+    directory = [HgRepository findRootOf: directory localPath: nil];
+    if (!directory)
+        return nil;
     for( RepoController *repoController in [self allRepoControllers]) {
         if( [[repoController directory] isEqualToString: directory] )
             return repoController;
 
 + (RepoController*) repoControllerWithDirectory: (NSString*)directory error: (NSError**)error
 {
-    for( RepoController *repoController in [self allRepoControllers]) {
-        if( [[repoController directory] isEqualToString: directory] )
-            return repoController;
-    }
-    return [[self alloc] initWithDirectory: directory error: error];
+    RepoController *controller = [self existingRepoControllerWithDirectory: directory];
+    if (!controller)
+        controller = [[self alloc] initWithDirectory: directory error: error];
+    return controller;
 }
 
 

Source/RepoController_Actions.m

                      didEndSelector: (SEL)didEndSelector
                             context: (void*)context
 {
-    [operation start];
+    Assert(!self.currentOperation);
     self.currentOperation = operation;
+    if (![operation start]) {
+        [self performSelector: didEndSelector withObject: _progressSheet withObject: (id)context];
+        return;
+    }
     _progressMessageField.stringValue = message;
-    _progressStopButton.title = @"Close";
+    _progressStopButton.title = @"Stop";
+    NSView *superview = _progressStopButton.superview;
+    [_progressStopButton removeFromSuperview];
+    _progressStopButton.keyEquivalent = @"\033"; // esc
+    [superview addSubview: _progressStopButton];
+    
     [NSApp beginSheet: _progressSheet
        modalForWindow: self.window
         modalDelegate: self
-       didEndSelector: didEndSelector ?:@selector(_closeProgressSheet:)
+       didEndSelector: didEndSelector ?:@selector(_closeProgressSheet)
           contextInfo: context];
+    
+    [operation addObserver: self 
+                forKeyPath: @"isRunning"
+                   options: 0
+                   context: @selector(_currentOperationStopped)];
+}
+
+
+- (void) _currentOperationStopped {
+    _progressStopButton.title = @"Close";
+    _progressStopButton.keyEquivalent = @"\r";
 }
 
 
 - (IBAction) stopProgress: (id)sender
 {
-    if( self.currentOperation.isRunning )
+    int button = NSOKButton;
+    if( self.currentOperation.isRunning ) {
         self.currentOperation.stop;
-    else
-        [NSApp endSheet: _progressSheet];
+        button = NSCancelButton;
+    }
+    [NSApp endSheet: _progressSheet returnCode: button];
 }
 
-- (void) _closeProgressSheet: (NSPanel*)sheet
+- (void) _closeProgressSheet
 {
-    [sheet orderOut: self];
+    [_progressSheet orderOut: self];
+    [self.currentOperation removeObserver: self forKeyPath: @"isRunning"];
     self.currentOperation = nil;
 }
 
 
 - (void) _pushDidEnd: (NSPanel*)sheet result: (int)result url: (NSURL*)url
 {
-    [sheet orderOut: self];
-    self.currentOperation = nil;
+    [self _closeProgressSheet];
     // If pushed to a repo open in another window, update that one:
     RepoController *other = [[self class] existingRepoControllerWithDirectory: url.path];
     NSError *error;
 
 - (void) _cloneDidEnd: (NSPanel*)sheet result: (int)result url: (NSURL*)url
 {
-    [sheet orderOut: self];
-    self.currentOperation = nil;
+    [self _closeProgressSheet];
     // If cloned to a local filesystem, open the new cloned repo:
     NSError *error;
     RepoController *other = [[self class] repoControllerWithDirectory: url.path
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.