diff --git a/English.lproj/MainMenu.xib b/English.lproj/MainMenu.xib
index e5c4743..4db7912 100644
--- a/English.lproj/MainMenu.xib
+++ b/English.lproj/MainMenu.xib
@@ -9,7 +9,7 @@
-
+
printDocument:
@@ -507,7 +507,7 @@ ELIAAAAAAAgACAAIAAgAAQABAAEAAQ
NSToolbarSeparatorItem
-
+
Separator
@@ -524,18 +524,18 @@ ELIAAAAAAAgACAAIAAgAAQABAAEAAQ
NSToolbarShowColorsItem
- Colors
-
+ Colors
+
Show Color Panel
@@ -624,7 +624,7 @@ ELIAAAAAAAgACAAIAAgAAQABAAEAAQ
-
+
orderFrontColorPanel:
@@ -638,8 +638,8 @@ ELIAAAAAAAgACAAIAAgAAQABAAEAAQ
NSToolbarShowFontsItem
- Fonts
-
+ Fonts
+
Show Font Panel
@@ -728,7 +728,7 @@ ELIAAAAAAAgACAAIAAgAAQABAAEAAQ
-
+
orderFrontFontPanel:
@@ -742,7 +742,7 @@ ELIAAAAAAAgACAAIAAgAAQABAAEAAQ
NSToolbarSpaceItem
-
+
Space
@@ -759,12 +759,12 @@ ELIAAAAAAAgACAAIAAgAAQABAAEAAQ
@@ -849,7 +849,7 @@ ELIAAAAAAAgACAAIAAgAAQABAAEAAQ
0
-
+
1.100000e+01
3100
@@ -859,7 +859,7 @@ ELIAAAAAAAgACAAIAAgAAQABAAEAAQ
6
-
+
headerTextColor
@@ -867,12 +867,12 @@ ELIAAAAAAAgACAAIAAgAAQABAAEAAQ
337772096
2048
- Text Cell
+ Text Cell
6
-
+
controlBackgroundColor
3
@@ -901,7 +901,7 @@ ELIAAAAAAAgACAAIAAgAAQABAAEAAQ
337772096
2048
-
+
@@ -918,7 +918,7 @@ ELIAAAAAAAgACAAIAAgAAQABAAEAAQ
6
-
+
gridColor
3
@@ -1039,7 +1039,7 @@ ELIAAAAAAAgACAAIAAgAAQABAAEAAQ
-
+
ApplicationController.h
@@ -4957,7 +4957,7 @@ ELIAAAAAAAgACAAIAAgAAQABAAEAAQ
-
+
PBWebGitController.h
@@ -4976,11 +4976,11 @@ ELIAAAAAAAgACAAIAAgAAQABAAEAAQ
YES
-
-
-
-
-
+
+
+
+
+
@@ -5001,7 +5001,7 @@ ELIAAAAAAAgACAAIAAgAAQABAAEAAQ
-
+
PBDetailController.h
@@ -5052,8 +5052,8 @@ EmQSZRJmEmcSaBJpEmoSaxJsEm0SbhJvEnAScRJyEnMSdBJ1EnYSdxJ4EnkSehJ7EnwSfRJ+En8SgBKB
EoISgxKEEoUShhKHEogSiRKKEosSjBKNEo4SjxKQEpESkhKTEpQSlRKWEpcSmBKZEpoSmxKcEp0SnhKf
EqASoRKiEqMSpBKlEqYSpxKoEqkSqhKrEqwSrRKuEq8SsBKxErISsxK0ErUSthK3ErgSuRK6ErsSvBK9
Er4SvxLAEsESwhLDEsQSxRLGEscSyBLJEsoSyxLMEs0SzhLPEtAS0RLSEtMS1BLVEtYS1xLYEtkS2hLb
-EtwS3RLeEt8S4AfoEuES4hLjEuQS5RLmEucS6BLpEuoS6xLsEu0S7hLvEvAS8RLyEvMS9BL1EvYS9wEl
-EvgS+RL6EvsS/BL9Ev4S/xMAEwETAhMDEwQAXRMFEwYTBxMIEwkTChMLEwwTDRMOEw8TEBMRExITExMU
+B+gS3BLdEt4S3xLgEuES4hLjEuQS5RLmEucS6BLpEuoS6xLsEu0S7hLvEvAS8RLyEvMS9AElEvUS9hL3
+EvgS+RL6EvsS/BL9Ev4S/xMAEwEAXRMCEwMTBBMFEwYTBxMIEwkTChMLEwwTDRMOEw8TEBMRExITExMU
ExUTFhMXExoTHRMgVSRudWxs3xASAA0ADgAPABAAEQASABMAFAAVABYAFwAYABkAGgAbABwAHQAeAB8A
IAAhACIAIwAkACUAJgAnACgAKQAqACsALAAtAC4ALwAwVk5TUm9vdFYkY2xhc3NdTlNPYmplY3RzS2V5
c18QD05TQ2xhc3Nlc1ZhbHVlc18QGU5TQWNjZXNzaWJpbGl0eU9pZHNWYWx1ZXNdTlNDb25uZWN0aW9u
@@ -5843,24 +5843,24 @@ ZWxsaW5nIGFuZCBHcmFtbWFyKVtNZW51IChGaW5kKV8QJ01lbnUgSXRlbSAoQ2hlY2sgU3BlbGxpbmcg
V2hpbGUgVHlwaW5nKVtUZXh0IFZpZXctMV8QHE1lbnUgSXRlbSAoU21hcnQgQ29weS9QYXN0ZSlfEBBN
ZW51IEl0ZW0gKFZpZXcpXxAVSG9yaXpvbnRhbCBTY3JvbGxlci0zXxAYTWVudSBJdGVtIChHaXRUZXN0
IEhlbHAp0gAOAEUBhBCMgE2hBNGBAQbSAA4ARQGEEJCATaEE5oEBB9IADgBFAYQQlIBNrxDWAB8L8AP/
-CA4L9ATRC/kLFAv8CF4KewgkA5QJRQN4CD8I3AOeCDwIqQwPCLcIJQgnCDsDiQSfAJYKbQgUA3oKXwmQ
-CsoKiQgmBA4EtwnbCXMIIwgoCD4EuwwsAJQMLgJ7AGAHHAwzCBsGqggtCAoMOAMNBwwIBQr4DDwEuAKS
-ChkMQgh0CBkAmQi/DE0IfQBICB8KvQgPBKoIdQMiDF4DswT7CMoJXggdALgDewjqCDAIEAx0CYEICwgS
-CToIEwJnCckILgyBCtgFLwrrBxkA0wOIC/gL+ggXCCAIMwhEBqkMAQnwCAkMBAgBCBEIQAgsDAUIPQgx
-CCELBgg5CqkH3QgCCC8ERwwRAJUICAg1CCsAlwwXCBUMGgayCDQMIAiZByECjQCQBPUK4AgiCB4MMAgY
-CAMINwCaDDUMNwgHBMMMQAxBCDYAmAxFCk0IageUBzAJnwgNAJIIDAg6CBoMUwgpAJMDeQeqAJEIkQqc
-CgwMXQkyCBwI0gn+DGYIFggyA8wLIAnTAFUEAAKqClUJwQa/CbMEmwKrDHoITQgqCjoFPwyACAYIOAgE
-BSmAAoEDB4DZgQIrgQMYgQEGgQMLgQLDgQMlgQHggQKQgQKFgPaBAiyAyYEDAoECCYDygQL4gQH6gQM8
-gQH+gQKKgQKUgQLtgPyA/oB5gQKLgQI+gQG9gQKGgQJEgQKqgQKVgQKPgOCBAQKBAluBAjuBAn+BApmB
-Av+BARWBA0+AbYEDWYCOgAyBAa+BAw+BAl6BAZiBAqmBAgOBAzmAtoEBmoEB74ECuYEDUYEBGICQgQJx
-gQNfgQHsgQJTgKeBAf+BAx2BAeqACIECbIECpoECL4EBAIEB6YC4gQMqgM+BARCBAgSBAjSBAmKAHYEB
-yoECDYECuIECMYEDPoECP4ECCIECOIECKIECOoCMgQJVgQKugQNVgQKvgQF1gQK1gQGcgB+Ay4EDE4ED
-GoECTIECcIECxoEB2YEBgIEDCIECY4EB/YEDYYEB2IECM4EDBYECpYEDF4EC/IECvYECeYECvoEC5YEC
-n4EBzIEB34ECtIDqgQNLgHKBAfmBAsyBAqOAiYEDDIECQ4EDIYEBgoECyoEDWoEB84EBrYCPgBqBAQ2B
-ArCBAn2BAmeBA0aBAk6BAeSBAtWAsoEDI4EDP4EB94EBE4EDZoEDRYEC0YCggQMygQKAgQHlgQG6gQGg
-gQJIgQImgFKBAgyBAuiBAlmBAziBApqAYoEBuIEBv4BBgQHygQKbgQJtgQMQgQIngQJggQIFgQJogQMv
-gQJHgQLCgNGBAseBAlqAxoDngJWBAoGBAlSBAYSBAk+BAbSAmIEDRIEB2oECnoECeoEBHIEDH4EB8YEC
-4IEB6IEBd9IADgBFAYQRbYBNrxDWEW4RbxFwEXERchFzEXQRdRF2EXcReBF5EXoRexF8EX0RfhF/EYAR
+C/QIAwTRC/kLFAv8CF4IKwp7A5QIEAgECUUDeAgJCD8I3AOeCDEIPAipDA8ItwgpCDsILQOJBJ8Algpt
+A3oIBwpfCZAIIwrKCokEDgS3CBwJ2wlzCD4EuwwsAJQMLgJ7AGAHHAwzBqoIDQgfDDgDDQcMCCAK+Aw8
+BLgCkgoZDEIIdAgLAJkIvwxNCH0ASAgPCr0IKgSqCHUIFggyAyIMXgOzBPsIygleCBUAuAN7COoMdAmB
+CToCZwnJDIEK2AUvCusHGQgbCAwA0wOIC/gL+ggoCEQGqQwBCfAIEQgTDAQIQAwFCBgIPQsGCDkKqQg0
+B90IJQRHCB0IMwwRAJUILwgFCDUAlwwXCBIMGgayCBoMIAiZByECjQCQCAYE9QrgDDAICAg3AJoMNQw3
+BMMIIQgCDEAMQQg2AJgMRQpNCGoIAQeUBzAJnwg6AJIIJAguCAoMUwgeAJMDeQeqAJEIkQgZCpwKDAxd
+CTIIIggOCNIJ/gxmA8wLIAnTAFUIFwQAAqoKVQnBBr8JswgsBJsIMAKrDHoITQo6CCcFPwyACDgIFAUp
+CCaAAoEDB4DZgQMYgQHkgQEGgQMLgQLDgQMlgQHggQKjgQKQgPaBAjGBAeiBAiyAyYEB/YEDAoECCYDy
+gQK9gQL4gQH6gQM8gQH+gQKagQLtgQKpgPyA/oB5gQKLgQG9gQH3gQKGgQJEgQJ/gQKqgQKVgOCBAQKB
+AmCBAluBAjuBAv+BARWBA0+AbYEDWYCOgAyBAa+BAw+BAZiBAiaBAmyBAzmAtoEBmoECcIECuYEDUYEB
+GICQgQJxgQNfgQHsgQIIgKeBAf+BAx2BAeqACIECL4ECpoECnoEBAIEB6YECR4ECwoC4gQMqgM+BARCB
+AgSBAjSBAkOAHYEByoECDYEDPoECP4ECKICMgQJVgQNVgQKvgQF1gQK1gQGcgQJegQIMgB+Ay4EDE4ED
+GoECmYEB2YEBgIEDCIECY4ECM4ECOoEDYYEDBYEDF4ECToEC/IECvoEC5YECn4ECyoEBzIECioDqgQJi
+gQLGgQNLgHKBArSBAe+BAsyAiYEDDIECOIEDIYEBgoECWYEDWoEB84EBrYCPgBqBAfGBAQ2BArCBA0aB
+AfmBAtWAsoEDI4EDP4EBE4ECeYEB34EDZoEDRYEC0YCggQMygQKAgQHlgQHYgQG6gQGggQJIgQLogFKB
+AoWBAq6BAgOBAziBAmeAYoEBuIEBv4BBgQHygQJTgQKbgQJtgQMQgQIngQJ9gQIrgQIFgQJogQMvgNGB
+AseBAlqAxoECTIDngJWBAoGBAlSBAYSBAk+BAqWBAbSBAriAmIEDRIEB2oECeoEClIEBHIEDH4EC4IEC
+PoEBd4ECj9IADgBFAYQRbYBNrxDWEW4RbxFwEXERchFzEXQRdRF2EXcReBF5EXoRexF8EX0RfhF/EYAR
gRGCEYMRhBGFEYYRhxGIEYkRihGLEYwRjRGOEY8RkBGREZIRkxGUEZURlhGXEZgRmRGaEZsRnBGdEZ4R
nxGgEaERohGjEaQRpRGmEacRqBGpEaoRqxGsEa0RrhGvEbARsRGyEbMRtBG1EbYRtxG4EbkRuhG7EbwR
vRG+Eb8RwBHBEcIRwxHEEcURxhHHEcgRyRHKEcsRzBHNEc4RzxHQEdER0hHTEdQR1RHWEdcR2BHZEdoR
@@ -5878,16 +5878,16 @@ BIOBBISBBIWBBIaBBIeBBIiBBImBBIqBBIuBBIyBBI2BBI6BBI+BBJCBBJGBBJKBBJOBBJSBBJWBBJaB
BJeBBJiBBJmBBJqBBJuBBJyBBJ2BBJ6BBJ+BBKCBBKGBBKKBBKOBBKSBBKWBBKaBBKeBBKiBBKmBBKqB
BKuBBKyBBK2BBK6BBK+BBLCBBLGBBLKBBLOBBLSBBLWBBLaBBLeBBLiBBLmBBLqBBLuBBLyBBL2BBL6B
BL+BBMCBBMGBBMKBBMOBBMSBBMWBBMaBBMeBBMiBBMmBBMqBBMuBBMyBBM2BBM6BBM+BBNCBBNGBBNKB
-BNOBBNSBBNWBBNYRA3sQOBEBxhCZEJURAoYQxBEBVBBSEQJLEE0QtBEB1hCWEQG0EQNFEJoRAdURAzwQ
-pxBwEIgQsxCwEQH9EQIxEQJHEQKkEKwQmBEClBCeEJEQrRCrEFcRAccRAoMQ4REDUBCvEM4RAg0RAoUQ
-1BECqxEDTxEDWRECoBECQBCPEQNkEQIyELIQfxBQEQNgEQI5ENAQvRDgEQKcEQNaEQMxEPMRAzsQvBEC
-oRA5ENcRAVMQFRD4EKIRA0MRAzoRA1MRA2EQUxEBxBECixB+EPYQyxECqBEDdREBixC+EQN3EEoQhhDH
-EQNOEPIRA1URA1gQuRB6EQFSEG8RAp0QOhECPhECqREBwBCCENYRA2MRA3IQwxChEQIzEB0QmxCLEGcQ
-yhD3EQM9EMkQkBECDhC1EMAQnREDTRBOEQN2EQJNEI4RAcgQuBECphDIEQMwEQN0EQNeEIEQkhDbEQI0
-EQN6EPEQURECPxEDWxECqhECiBBqEQJMEQFWEKgQwREDXxECrxEDYhDYEQJVEQKEE//////////9EK4R
-AzgRAqUQfBCgEM0RAfQRAkERA1QQ+RECoxEC7hEDRxEBAhBPEQEBEQKnEQHzEQKVEQKiEOMQ9BCDEPUR
-AlQQfREBVRBIEQNXEQFXEQHXEKQQ5BEBxREDXBCpELsRAkgQSRECRhEDXRCcEJ8QVhC/EQKfENoQ0xEC
-sBEDVhECntIADgBFAT4TGYA6oNIADgBFAYQTHIBNoNIADgBFAYQTH4BNoNIAOgA7EyETIqITIgA/Xk5T
+BNOBBNSBBNWBBNYRA3sQOBEBxhCVEQNfEQKGEMQRAVQQUhECSxEDdBBNEQHWEQN3EQNWEJYRAbQQixED
+RRCaEQHVELURAzwQpxBwEIgRAQERAf0QshECMRECRxECpBCsEQKUEQJVEJ4QkRCvEK0QqxEBxxECgxEC
+VBDhEQNQEQINEQKFENQRAqsRA08RA1kRAqARAkAQjxECMhD5EPgQUBEDYBECOREDchC9EOARApwRA1oR
+AzEQ8xEDOxDHEQKhEDkQ1xEBUxAVEQNDEKIQVhEDOhEDUxEDVxEBVxEDYRBTEQHEEQKLEH4Q9hCSEQKo
+EQN1EQGLEEoQhhDyEQNYELkRAVIQbxECnRA6EQI+EQNkEQLuEQKpEQHAEIIQ1hDOEKERAjMQHRCbEPcR
+A1UQZxEDPRCQEMERAg4QnREDTRBOEQN6EQN2ELMRAcgQyxDDELgRAqYQjhDQEQMwEQNeEIERA04Q2xEC
+NBEBAhDxEFERAj8RA1sRAqoQ0xECiBBqEKgQyBECrxEDYhDYEQKEEMARAk0T//////////0QrhEDOBEC
+pRB8EKAQzRDKEQH0EQJBEQNUEQNHEQKjELQQehB/EE8RAVYRAqcRAfMRApURAqIQvBDjEPQQgxD1EQJM
+EJkQfREBVRBIEQHXEKQQ5BEDYxEBxREDXBCpELsRAkgQSRDJEQJGEL4RA10QnBCfEL8QsBECnxDaEQKw
+EJgRAp4QV9IADgBFAT4TGYA6oNIADgBFAYQTHIBNoNIADgBFAYQTH4BNoNIAOgA7EyETIqITIgA/Xk5T
SUJPYmplY3REYXRhAAgAGQAiACcAMQA6AD8ARABSAFQAZgogCiYKcQp4Cn8KjQqfCrsKyQrVCuEK7wr6
CwgLJAsyC0ULVwtxC3sLiAuKC40LkAuTC5YLmQucC54LoQukC6cLqgusC64LsQu0C7cLugvDC88L0QvT
C9wL5gvoC/YL/wwIDBMMGgwsDDUMPgxHDEwMWwxuDHcMggyFDIgMigy7DMgM1QzjDO0M+w0IDRINJA04
@@ -6030,13 +6030,13 @@ ujK6TLpfunS6iLqUurK6yLrWuuS6+bsXuzO7QLtMu3a7jrusu7i71rvpu/G7/bwVvDS8TrxhvHe8ory+
vMW84rz3vQW9G70vvTu9Tb1ZvWW9gr2Wvai9wr3avea+AL4MviS+Sb5gvmq+hr6Svq2+xL7Rvui+/r8N
vyC/M79Uv2e/fr+Rv7C/xb/iv/vAFsA2wEzAY8B4wIzAqMC1wM3A4sDuwRjBLMFjwWzBeMGTwafBvsHM
weHB7cIFwiPCL8JZwmXChMKXwq/CysLTwtXC2MLbwuTC5sLpwuzC9cL3xKbEqMSrxK3EsMSzxLbEucS8
-xL/EwsTFxMjEysTNxM/E0sTVxNfE2sTdxODE48TmxOnE7MTuxPDE8sT1xPjE+8T+xQHFBMUHxQrFDMUP
-xRLFFcUYxRvFHsUhxSTFJsUpxSvFLcUwxTPFNsU5xTzFP8VCxUTFR8VKxU3FUMVTxVXFWMVbxV7FYcVj
-xWbFacVsxW7FccV0xXfFesV9xX/FgsWExYfFisWNxZDFksWVxZjFm8WexaHFpMWnxarFrcWwxbLFtcW4
-xbvFvsXBxcTFx8XJxcvFzsXRxdTF18Xaxd3F4MXjxebF6cXsxe/F8sX1xfjF+8X+xgHGBMYHxgrGDcYQ
-xhPGFsYYxhvGHcYgxiPGJsYoxivGLsYxxjTGN8Y6xj3GQMZCxkTGR8ZKxk3GUMZTxlbGWcZcxl7GYcZk
-xmfGasZtxnDGc8Z1xnjGe8Z+xoHGhMaHxorGjMaPxpLGlcaYxpvGncagxqPGpcaoxqvGrsaxxrTGt8a6
-xr3GwMbDxsbGyMbLxs7G0MbSxtTG18baxt3G4MbjxuXG6Mbrxu7G8cb0xvfG+sb9xwDHA8cMxw7IvcjA
+xL/EwsTFxMjEysTNxNDE08TVxNjE28TexODE48TmxOnE7MTvxPLE9cT4xPrE/MT+xQHFBMUHxQrFDcUQ
+xRPFFsUYxRvFHsUhxSTFJ8UqxS3FL8UyxTTFNsU5xTzFP8VCxUXFSMVKxU3FUMVTxVbFWcVbxV7FYcVk
+xWfFacVsxW/FcsV0xXfFesV9xYDFg8WGxYnFi8WOxZDFk8WWxZnFnMWexaHFpMWnxarFrcWvxbLFtcW4
+xbvFvsXBxcTFx8XJxcvFzsXRxdTF18Xaxd3F4MXjxebF6cXsxe/F8sX1xfjF+8X+xgHGBMYHxgnGDMYP
+xhLGFMYXxhrGHcYfxiLGJcYoxivGLsYxxjTGN8Y5xjvGPsZBxkTGR8ZKxk3GT8ZSxlXGWMZbxl7GYcZk
+xmfGacZsxm/GcsZ1xnjGe8Z+xoHGg8aGxonGjMaPxpLGlMaXxprGnMafxqLGpcaoxqvGrsaxxrTGt8a6
+xr3Gv8bCxsXGx8bKxszGzsbRxtTG18baxt3G4MbjxuXG6Mbrxu7G8cb0xvfG+sb9xwDHA8cMxw7IvcjA
yMPIxsjJyMzIz8jSyNXI2MjbyN7I4cjkyOfI6sjtyPDI88j2yPnI/Mj/yQLJBckIyQvJDskRyRTJF8ka
yR3JIMkjySbJKcksyS/JMsk1yTjJO8k+yUHJRMlHyUrJTclQyVPJVslZyVzJX8liyWXJaMlryW7Jccl0
yXfJesl9yYDJg8mGyYnJjMmPyZLJlcmYyZvJnsmhyaTJp8mqya3JsMmzybbJucm8yb/JwsnFycjJy8nO
@@ -6044,14 +6044,14 @@ ydHJ1MnXydrJ3cngyePJ5snpyezJ78nyyfXJ+Mn7yf7KAcoEygfKCsoNyhDKE8oWyhnKHMofyiLKJcoo
yivKLsoxyjTKN8o6yj3KQMpDykbKScpMyk/KUspVyljKW8peymHKZMpnymrKbcpwynPKdsp5ynzKf8qC
yoXKiMqLyo7KkcqUypfKmsqdyqDKo8qmyqnKrMqvyrLKtcq4yrvKvsrBysTKx8rKys3K0MrTytbK2crc
yt/K4srlyujK68ruyvHK9Mr3yvrK/csAywPLBssJywzLD8sSyxXLGMsbyx7LIcskyyfLKsstyzDLM8s2
-yznLPMs/y0LLRMtHy0nLS8tOy1DLU8tVy1jLWstcy1/LYctky2fLactsy2/Lcctzy3XLd8t5y3zLf8uC
-y4XLh8uJy4zLjsuQy5LLlMuWy5nLnMuey6HLo8uly6jLq8uty7DLs8u2y7nLvMu+y8HLxMvGy8jLysvN
-y9DL0svUy9bL2cvcy9/L4cvky+bL6cvry+3L8Mvyy/TL9sv5y/zL/8wCzATMB8wKzAzMDswQzBPMFswZ
-zBvMHswgzCLMJMwnzCnMLMwvzDHMM8w2zDjMO8w9zEDMQ8xGzEjMSsxNzFDMUsxUzFfMWcxbzF3MX8xh
-zGPMZsxozGrMbcxvzHHMc8x2zHjMe8x+zIDMg8yFzIjMisyNzJDMk8yVzJfMmcyczJ/MocyjzKbMqcys
-zK/Mscy0zLfMucy7zL7MwczEzMbMyczMzNXM18zazN3M38zhzOPM5szpzOzM7szxzPTM98z6zPzM/80C
-zQXNCM0LzQ3ND80RzRPNFs0YzRvNHc0gzSPNJs0ozSrNLc0wzTLNNM03zTnNPM0/zUHNQ81FzUfNSs1M
-zU7NUc1UzVfNYM1izWPNbM1uzW/NeM16zXvNhM2JAAAAAAAAAgIAAAAAAAATIwAAAAAAAAAAAAAAAAAA
+yznLPMs/y0LLRMtHy0nLTMtPy1HLVMtWy1nLXMtey2HLZMtny2nLbMtuy3HLc8t2y3jLe8t9y3/LgcuE
+y4fLicuMy4/LksuUy5fLmsucy57LoMuiy6TLp8uqy63Lr8uyy7XLuMu6y73LwMvDy8bLycvLy87L0MvS
+y9TL18vay93L38vhy+TL58vqy+zL78vxy/TL9sv4y/vL/cwAzALMBMwHzArMDcwQzBPMFcwYzBvMHcwf
+zCHMJMwnzCrMLMwuzDDMM8w1zDjMOsw9zD/MQsxFzEjMS8xOzFDMUsxUzFbMWcxbzF3MX8xizGTMZ8xp
+zGvMbsxwzHPMdcx4zHvMfcyAzILMhMyGzInMi8yNzJDMk8yVzJjMmsydzKDMosykzKfMqsytzK/Mssy0
+zLbMuMy7zL7MwMzDzMXMyMzRzNPM1szZzNvM3czfzOHM5MznzOrM7czwzPLM9Mz2zPjM+8z+zQHNBM0H
+zQnNC80NzQ/NEc0UzRbNGM0bzR3NIM0izSTNJ80qzS3NL80xzTTNNs04zTvNPc1AzULNRM1GzUjNS81N
+zVDNUs1VzVfNYM1izWPNbM1uzW/NeM16zXvNhM2JAAAAAAAAAgIAAAAAAAATIwAAAAAAAAAAAAAAAAAA
zZg
diff --git a/GitX.xcodeproj/project.pbxproj b/GitX.xcodeproj/project.pbxproj
index 6d7f868..6fb3eb6 100644
--- a/GitX.xcodeproj/project.pbxproj
+++ b/GitX.xcodeproj/project.pbxproj
@@ -29,6 +29,7 @@
F58A8F280E043698007E3FC0 /* commits.css in Resources */ = {isa = PBXBuildFile; fileRef = F58A8F270E043698007E3FC0 /* commits.css */; };
F5945E170E02B0C200706420 /* PBGitRepository.m in Sources */ = {isa = PBXBuildFile; fileRef = F5945E160E02B0C200706420 /* PBGitRepository.m */; };
F5B721C40E05CF7E00AF29DC /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = F5B721C20E05CF7E00AF29DC /* MainMenu.xib */; };
+ F5DFFA6C0E075D8800617813 /* PBEasyFS.m in Sources */ = {isa = PBXBuildFile; fileRef = F5DFFA6B0E075D8800617813 /* PBEasyFS.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@@ -70,6 +71,8 @@
F5945E150E02B0C200706420 /* PBGitRepository.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBGitRepository.h; sourceTree = ""; };
F5945E160E02B0C200706420 /* PBGitRepository.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBGitRepository.m; sourceTree = ""; };
F5B721C30E05CF7E00AF29DC /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = ""; };
+ F5DFFA6A0E075D8800617813 /* PBEasyFS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBEasyFS.h; sourceTree = ""; };
+ F5DFFA6B0E075D8800617813 /* PBEasyFS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBEasyFS.m; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -206,6 +209,8 @@
F56524BA0E02D22D00F03B52 /* NSFileHandleExt.h */,
F57CC38F0E05DDF2000472E2 /* PBEasyPipe.h */,
F57CC3900E05DDF2000472E2 /* PBEasyPipe.m */,
+ F5DFFA6A0E075D8800617813 /* PBEasyFS.h */,
+ F5DFFA6B0E075D8800617813 /* PBEasyFS.m */,
F53EE3590E06BBA00022B925 /* CWQuickLook.h */,
F51308590E0740F2000C8BCD /* PBQLOutlineView.h */,
F513085A0E0740F2000C8BCD /* PBQLOutlineView.m */,
@@ -299,6 +304,7 @@
F57CC3910E05DDF2000472E2 /* PBEasyPipe.m in Sources */,
F57CC4410E05E496000472E2 /* PBDetailController.m in Sources */,
F513085B0E0740F2000C8BCD /* PBQLOutlineView.m in Sources */,
+ F5DFFA6C0E075D8800617813 /* PBEasyFS.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -361,6 +367,7 @@
26FC0A890875C7B200E6366F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ GCC_ENABLE_OBJC_GC = required;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
PREBINDING = NO;
@@ -375,6 +382,7 @@
ppc,
i386,
);
+ GCC_ENABLE_OBJC_GC = required;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
PREBINDING = NO;
diff --git a/PBDetailController.m b/PBDetailController.m
index 6cb9a92..2eab94d 100644
--- a/PBDetailController.m
+++ b/PBDetailController.m
@@ -29,6 +29,12 @@
- (void) updateKeys
{
NSArray* selection = [commitController selectedObjects];
+
+ // Remove any references in the QLPanel
+ [[QLPreviewPanel sharedPreviewPanel] setURLs:[NSArray array] currentIndex:0 preservingDisplayState:YES];
+ // We have to do this manually, as NSTreeController leaks memory?
+ [treeController setSelectionIndexPaths:[NSArray array]];
+
if ([selection count] > 0)
realCommit = [selection objectAtIndex:0];
else
@@ -38,6 +44,7 @@
self.rawCommit = nil;
self.gitTree = nil;
+
int num = [self.selectedTab intValue];
if (num == 0) // Detailed view
diff --git a/PBEasyFS.h b/PBEasyFS.h
new file mode 100644
index 0000000..0007fa4
--- /dev/null
+++ b/PBEasyFS.h
@@ -0,0 +1,18 @@
+//
+// PBEasyFS.h
+// GitX
+//
+// Created by Pieter de Bie on 6/17/08.
+// Copyright 2008 __MyCompanyName__. All rights reserved.
+//
+
+#import
+
+
+@interface PBEasyFS : NSObject {
+
+}
++ (NSString*) tmpNameWithSuffix: (NSString*) path;
++ (NSString*) tmpDirWithPrefix: (NSString*) path;
+
+@end
diff --git a/PBEasyFS.m b/PBEasyFS.m
new file mode 100644
index 0000000..ed9c30b
--- /dev/null
+++ b/PBEasyFS.m
@@ -0,0 +1,31 @@
+//
+// PBEasyFS.m
+// GitX
+//
+// Created by Pieter de Bie on 6/17/08.
+// Copyright 2008 __MyCompanyName__. All rights reserved.
+//
+
+#import "PBEasyFS.h"
+
+
+@implementation PBEasyFS
+
++ (NSString*) tmpNameWithSuffix: (NSString*) path
+{
+ NSString* newName = [NSString stringWithFormat: @"%@/XXXXXX%@", NSTemporaryDirectory(), path];
+ char *template = (char*) [newName fileSystemRepresentation];
+ int fd = mkstemps(template, [path length]);
+ close(fd);
+ return [NSString stringWithUTF8String:template];
+}
+
++ (NSString*) tmpDirWithPrefix: (NSString*) path
+{
+ NSString* newName = [NSString stringWithFormat: @"%@%@.XXXXXX", NSTemporaryDirectory(), path];
+ char *template = (char*) [newName fileSystemRepresentation];
+ template = mkdtemp(template);
+ return [NSString stringWithUTF8String:template];
+}
+
+@end
diff --git a/PBEasyPipe.h b/PBEasyPipe.h
index 2c424c6..5c21ed7 100644
--- a/PBEasyPipe.h
+++ b/PBEasyPipe.h
@@ -18,6 +18,4 @@
+ (NSString*) outputForCommand: (NSString*) cmd withArgs: (NSArray*) args;
+ (NSString*) outputForCommand: (NSString*) cmd withArgs: (NSArray*) args inDir: (NSString*) dir;
-
-+ (NSString*) writeData:(NSData*) data toTempFileWithName: (NSString *) fileName;
@end
diff --git a/PBEasyPipe.m b/PBEasyPipe.m
index 81ee7c3..fc12ba8 100644
--- a/PBEasyPipe.m
+++ b/PBEasyPipe.m
@@ -51,15 +51,4 @@
return [self outputForCommand:cmd withArgs:args inDir:nil];
}
-+ (NSString*) writeData:(NSData*) data toTempFileWithName: (NSString *) fileName
-{
- NSString* newName = [NSString stringWithFormat: @"%@/XXXXXX%@", NSTemporaryDirectory(), fileName];
- char *template = (char*) [newName fileSystemRepresentation];
- int fd = mkstemps(template, [fileName length]);
- NSFileHandle* handle = [[NSFileHandle alloc] initWithFileDescriptor:fd];
- [handle writeData: data];
- [handle closeFile];
- return [NSString stringWithUTF8String:template];
-}
-
@end
diff --git a/PBGitRepository.m b/PBGitRepository.m
index 49a2b88..c8aed80 100644
--- a/PBGitRepository.m
+++ b/PBGitRepository.m
@@ -73,7 +73,7 @@ static NSString* gitPath = @"/usr/bin/env";
- (void) initializeCommits
{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ //NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableArray * newArray = [NSMutableArray array];
NSDate* start = [NSDate date];
@@ -96,7 +96,7 @@ static NSString* gitPath = @"/usr/bin/env";
NSTimeInterval duration = [[NSDate date] timeIntervalSinceDate:start];
NSLog(@"Loaded %i commits in %f seconds", num, duration);
- [pool release];
+ //[pool release];
[NSThread exit];
}
diff --git a/PBGitTree.h b/PBGitTree.h
index 874d60a..096d47b 100644
--- a/PBGitTree.h
+++ b/PBGitTree.h
@@ -13,9 +13,12 @@
NSString* sha;
NSString* path;
PBGitRepository* repository;
- PBGitTree* parent;
+ __weak PBGitTree* parent;
NSArray* children;
BOOL leaf;
+
+ NSString* localFileName;
+ NSDate* localMtime;
}
+ (PBGitTree*) rootForCommit: (id) commit;
@@ -27,7 +30,7 @@
@property(copy) NSString* path;
@property(assign) BOOL leaf;
@property(retain) PBGitRepository* repository;
-@property(assign) PBGitTree* parent;
+@property(assign) __weak PBGitTree* parent;
@property(readonly) NSArray* children;
@property(readonly) NSString* fullPath;
diff --git a/PBGitTree.m b/PBGitTree.m
index ebc9277..790e77f 100644
--- a/PBGitTree.m
+++ b/PBGitTree.m
@@ -10,6 +10,7 @@
#import "PBGitCommit.h"
#import "NSFileHandleExt.h"
#import "PBEasyPipe.h"
+#import "PBEasyFS.h"
@implementation PBGitTree
@@ -40,6 +41,7 @@
- init
{
children = nil;
+ localFileName = nil;
leaf = YES;
return self;
}
@@ -49,25 +51,89 @@
return [NSString stringWithFormat:@"%@:%@", self.sha, self.fullPath];
}
+- (BOOL) isLocallyCached
+{
+ NSFileManager* fs = [NSFileManager defaultManager];
+ if (localFileName && [fs fileExistsAtPath:localFileName])
+ {
+ NSDate* mtime = [[fs attributesOfItemAtPath:localFileName error: nil] objectForKey:NSFileModificationDate];
+ if ([mtime compare:localMtime] == 0)
+ return YES;
+ }
+ return NO;
+}
+
- (NSString*) contents
{
if (!leaf)
return [NSString stringWithFormat:@"This is a tree with path %@", self];
- NSFileHandle* handle = [repository handleForArguments:[NSArray arrayWithObjects:@"show", [self refSpec], nil]];
- NSData* data = [handle readDataToEndOfFile];
- NSString* string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
- return string;
+ NSData* data = nil;
+
+ if ([self isLocallyCached])
+ data = [NSData dataWithContentsOfFile: localFileName];
+ else {
+ NSFileHandle* handle = [repository handleForArguments:[NSArray arrayWithObjects:@"show", [self refSpec], nil]];
+ data = [handle readDataToEndOfFile];
+ }
+
+ return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
+- (void) saveToFolder: (NSString *) dir
+{
+ NSString* newName = [dir stringByAppendingPathComponent:path];
+
+ if (leaf) {
+ NSFileHandle* handle = [repository handleForArguments:[NSArray arrayWithObjects:@"show", [self refSpec], nil]];
+ NSData* data = [handle readDataToEndOfFile];
+ [data writeToFile:newName atomically:YES];
+ } else { // Directory
+ [[NSFileManager defaultManager] createDirectoryAtPath:newName attributes:nil];
+ for (PBGitTree* child in children)
+ [child saveToFolder: newName];
+ }
+}
+
+- (NSString*) tmpDirWithContents
+{
+ if (leaf)
+ return nil;
+
+ if (!localFileName)
+ localFileName = [PBEasyFS tmpDirWithPrefix: path];
+
+ NSLog(@"Exporting children..");
+
+ for (PBGitTree* child in [self children]) {
+ NSLog(@"Telling %@ to save to %@!", [child fullPath], localFileName);
+ [child saveToFolder: localFileName];
+ }
+
+ return localFileName;
+}
+
+
+
- (NSString*) tmpFileNameForContents
{
if (!leaf)
- return nil;
- NSLog(@"Getting tmp file");
+ return [self tmpDirWithContents];
+
+ if ([self isLocallyCached])
+ return localFileName;
+
+ if (!localFileName)
+ localFileName = [PBEasyFS tmpNameWithSuffix: path];
+
NSFileHandle* handle = [repository handleForArguments:[NSArray arrayWithObjects:@"show", [self refSpec], nil]];
NSData* data = [handle readDataToEndOfFile];
- return [PBEasyPipe writeData:data toTempFileWithName:path];
+ [data writeToFile:localFileName atomically:YES];
+
+ NSFileManager* fs = [NSFileManager defaultManager];
+ localMtime = [[fs attributesOfItemAtPath:localFileName error: nil] objectForKey:NSFileModificationDate];
+
+ return localFileName;
}
- (NSArray*) children
@@ -111,4 +177,10 @@
return [parent.fullPath stringByAppendingPathComponent: self.path];
}
+- (void) finalize
+{
+ if (localFileName)
+ [[NSFileManager defaultManager] removeFileAtPath:localFileName handler:nil];
+ [super finalize];
+}
@end