From 20256abbd66b16013af66cbc6e6e08f3f763459c Mon Sep 17 00:00:00 2001 From: stuconnolly Date: Fri, 9 Oct 2009 22:42:24 +0000 Subject: Yet more export redesign work. Export is now currently working for single tables, but produces deadlock errors when attempting to export multiple tables as a result of the initial streaming request for the tables' data all being done from the same thread. To resolve this each of the streaming requests will be made concurrently in separate operations and once the data is available a new concurrent operation (SPExporter subclass instance) will be spawned to perform the data conversion process. --- Interfaces/English.lproj/ExportDialog.xib | 1027 ++++++++++++++++++++++++----- Source/SPCSVExporter.h | 14 +- Source/SPCSVExporter.m | 183 ++--- Source/SPExportController.h | 5 + Source/SPExportController.m | 160 +++-- 5 files changed, 1057 insertions(+), 332 deletions(-) diff --git a/Interfaces/English.lproj/ExportDialog.xib b/Interfaces/English.lproj/ExportDialog.xib index a3318d9d..b0027a75 100644 --- a/Interfaces/English.lproj/ExportDialog.xib +++ b/Interfaces/English.lproj/ExportDialog.xib @@ -1,24 +1,26 @@ - + 1050 - 9L30 - 677 - 949.54 - 353.00 + 10B504 + 732 + 1038.2 + 437.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 732 + YES - YES - com.apple.InterfaceBuilderKit com.apple.InterfaceBuilder.CocoaPlugin YES - + YES @@ -39,7 +41,7 @@ 4103 2 - {{196, 75}, {450, 420}} + {{196, 53}, {450, 442}} 603980800 Export NSWindow @@ -56,7 +58,7 @@ 1 YES - + YES 71D44334-3FBC-45B1-B724-01DC3CF04BC0 8029B183-E568-4575-BF79-8BF794BC1220 @@ -253,21 +255,21 @@ YES switch - 1.500000e+01 - 1.500000e+01 - 1.000000e+03 + 15 + 15 + 1000 - 612498944 - 0 + 612499008 + 2048 LucidaGrande - 1.100000e+01 + 11 3100 3 - MC4zMzMzMzI5OQA + MC4zMzMzMzI5ODU2AA 6 @@ -306,12 +308,12 @@ tables - 1.370000e+02 - 1.000000e+01 - 3.402823e+38 + 137 + 10 + 3.4028230607370965e+38 - 612498944 - 0 + 612499008 + 2048 @@ -339,7 +341,7 @@ controlBackgroundColor 3 - MC42NjY2NjY2OQA + MC42NjY2NjY2ODY1AA @@ -354,8 +356,8 @@ - 3.000000e+00 - 2.000000e+00 + 3 + 2 6 @@ -366,16 +368,20 @@ MC41AA - 1.700000e+01 + 17 306184192 + + 4 15 0 YES + 0 {{1, 1}, {158, 228}} + 4 @@ -388,7 +394,7 @@ 256 _doScroller: - 9.956332e-01 + 0.99563318490982056 @@ -398,11 +404,12 @@ 1 _doScroller: - 9.947917e-01 + 0.99479168653488159 - {{40, 60}, {160, 230}} + {{40, 82}, {160, 230}} + 530 @@ -412,7 +419,7 @@ 268 - {{20, 296}, {104, 64}} + {{20, 318}, {104, 64}} YES 3 @@ -424,8 +431,8 @@ 131072 Filtered Results - 1 + 1 1211912703 128 @@ -441,8 +448,8 @@ 131072 Custom Query - 2 + 2 1211912703 128 @@ -452,7 +459,7 @@ YES YES - + TU0AKgAABRgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAMAAAADAAAAAwAAAAAAAAAA @@ -478,7 +485,7 @@ AAAAFwAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAoAAAAXAAAAJAAAAC4AAAAu AAAAJAAAABcAAAAKAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAwAAAAMAAAADAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgEAAAMAAAABABIAAAEB AAMAAAABABIAAAECAAMAAAAEAAAFxgEDAAMAAAABAAEAAAEGAAMAAAABAAIAAAERAAQAAAABAAAACAES -AAMAAAABAAEAAAEVAAMAAAABAAQAAAEWAAMAAAABBxwAAAEXAAQAAAABAAAFEAEcAAMAAAABAAEAAAFS +AAMAAAABAAEAAAEVAAMAAAABAAQAAAEWAAMAAAABABIAAAEXAAQAAAABAAAFEAEcAAMAAAABAAEAAAFS AAMAAAABAAEAAAFTAAMAAAAEAAAFzodzAAcAAAMgAAAF1gAAAAAACAAIAAgACAABAAEAAQABAAADIGFw cGwCAAAAbW50clJHQiBYWVogB9kAAQAMABEAHAA7YWNzcEFQUEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAPbWAAEAAAAA0y1hcHBsJLKKiNBg7ZAGaKx3V39pDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA @@ -512,8 +519,8 @@ ZSwgSW5jLiwgMjAwOQA 131072 Selected Tables - 3 + 3 1211912703 128 @@ -523,7 +530,7 @@ ZSwgSW5jLiwgMjAwOQA YES YES - + TU0AKgAAA1AAAAAAAAAAAAAAAAAAAAAhDAwMdicnJ8krKyvwNTU18CMjI8kaGhp2AgICIQAAAAAAAAAA @@ -541,7 +548,7 @@ m5ub9TAwMLgAAABHAAAACAAAAAAAAAAAAAAAAAAAAAkAAAA4BwcHgAAAAJ8AAACzAAAAswAAAJ8HBweA AAAAOAAAAAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAATAAAAJwAAADUAAAA1AAAAJwAAABMAAAAD AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAADgEAAAMAAAABAA4AAAEBAAMAAAABAA8AAAECAAMAAAAEAAAD/gEDAAMAAAABAAEAAAEG -AAMAAAABAAIAAAERAAQAAAABAAAACAESAAMAAAABAAEAAAEVAAMAAAABAAQAAAEWAAMAAAABCSQAAAEX +AAMAAAABAAIAAAERAAQAAAABAAAACAESAAMAAAABAAEAAAEVAAMAAAABAAQAAAEWAAMAAAABAA8AAAEX AAQAAAABAAADSAEcAAMAAAABAAEAAAFSAAMAAAABAAEAAAFTAAMAAAAEAAAEBodzAAcAAAMgAAAEDgAA AAAACAAIAAgACAABAAEAAQABAAADIGFwcGwCAAAAbW50clJHQiBYWVogB9kAAQAMABEAHAA7YWNzcEFQ UEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPbWAAEAAAAA0y1hcHBsJLKKiNBg7ZAGaKx3V39pDwAA @@ -586,7 +593,7 @@ AAB0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSwgSW5jLiwgMjAwOQA YES YES - + TU0AKgAABRgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAMAAAADAAAAAwAAAAAAAAAA @@ -612,7 +619,7 @@ AAAAFwAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAoAAAAXAAAAJAAAAC4AAAAu AAAAJAAAABcAAAAKAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAwAAAAMAAAADAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQEAAAMAAAABABIAAAEB AAMAAAABABIAAAECAAMAAAAEAAAFugEDAAMAAAABAAEAAAEGAAMAAAABAAIAAAERAAQAAAABAAAACAES -AAMAAAABAAEAAAEVAAMAAAABAAQAAAEWAAMAAAABBxwAAAEXAAQAAAABAAAFEAEcAAMAAAABAAEAAAFS +AAMAAAABAAEAAAEVAAMAAAABAAQAAAEWAAMAAAABABIAAAEXAAQAAAABAAAFEAEcAAMAAAABAAEAAAFS AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA @@ -634,14 +641,14 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA LucidaGrande - 1.300000e+01 + 13 1044 12 - {{204, 56}, {230, 236}} + {{204, 78}, {230, 236}} YES @@ -768,8 +775,8 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 131072 Sheet per table - 1 + 1 1211912703 128 @@ -793,7 +800,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA YES YES - + TU0AKgAABRgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAMAAAADAAAAAwAAAAAAAAAA @@ -819,10 +826,10 @@ AAAAFwAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAoAAAAXAAAAJAAAAC4AAAAu AAAAJAAAABcAAAAKAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAwAAAAMAAAADAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgEAAAMAAAABABIAAAEB AAMAAAABABIAAAECAAMAAAAEAAAFxgEDAAMAAAABAAEAAAEGAAMAAAABAAIAAAERAAQAAAABAAAACAES -AAMAAAABAAEAAAEVAAMAAAABAAQAAAEWAAMAAAABBxwAAAEXAAQAAAABAAAFEAEcAAMAAAABAAEAAAFS +AAMAAAABAAEAAAEVAAMAAAABAAQAAAEWAAMAAAABABIAAAEXAAQAAAABAAAFEAEcAAMAAAABAAEAAAFS AAMAAAABAAEAAAFTAAMAAAAEAAAFzodzAAcAAAwYAAAF1gAAAAAACAAIAAgACAABAAEAAQABAAAMGGFw cGwCAAAAbW50clJHQiBYWVogB9YABAADABMALAASYWNzcEFQUEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAPbWAAEAAAAA0y1hcHBs2U706y3Sst1fqit5+wYbUQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAPbWAAEAAAAA0y1hcHBsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAOclhZWgAAASwAAAAUZ1hZWgAAAUAAAAAUYlhZWgAAAVQAAAAUd3RwdAAAAWgAAAAUY2hhZAAA AXwAAAAsclRSQwAAAagAAAAOZ1RSQwAAAbgAAAAOYlRSQwAAAcgAAAAOdmNndAAAAdgAAAMSbmRpbgAA BOwAAAY+ZGVzYwAACywAAABkZHNjbQAAC5AAAAAubW1vZAAAC8AAAAAoY3BydAAAC+gAAAAtWFlaIAAA @@ -902,7 +909,7 @@ QXBwbGUgQ29tcHV0ZXIsIEluYy4sIDIwMDUAAAAAA YES YES - + TU0AKgAABRgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAMAAAADAAAAAwAAAAAAAAAA @@ -928,7 +935,7 @@ AAAAFwAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAoAAAAXAAAAJAAAAC4AAAAu AAAAJAAAABcAAAAKAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAwAAAAMAAAADAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQEAAAMAAAABABIAAAEB AAMAAAABABIAAAECAAMAAAAEAAAFugEDAAMAAAABAAEAAAEGAAMAAAABAAIAAAERAAQAAAABAAAACAES -AAMAAAABAAEAAAEVAAMAAAABAAQAAAEWAAMAAAABBxwAAAEXAAQAAAABAAAFEAEcAAMAAAABAAEAAAFS +AAMAAAABAAEAAAEVAAMAAAABAAQAAAEWAAMAAAABABIAAAEXAAQAAAABAAAFEAEcAAMAAAABAAEAAAFS AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA @@ -1094,10 +1101,10 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA YES - - 1.000000e+01 - 1.000000e+01 - 1.000000e+03 + + 10 + 10 + 1000 75628032 0 @@ -1106,12 +1113,12 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA LucidaGrande - 1.200000e+01 + 12 16 3 - MC4zMzMzMzI5OQA + MC4zMzMzMzI5ODU2AA @@ -1129,11 +1136,11 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA - 3.000000e+00 - 2.000000e+00 + 3 + 2 - 1.600000e+01 + 16 tableViewAction: -765427712 @@ -1143,6 +1150,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 15 0 YES + 0 @@ -1155,7 +1163,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 343014977 132096 - Ig + " YES @@ -1165,7 +1173,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA YES YES - Ig + " @@ -1179,10 +1187,10 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA YES - - 1.000000e+01 - 1.000000e+01 - 1.000000e+03 + + 10 + 10 + 1000 75628032 0 @@ -1192,7 +1200,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 3 - MC4zMzMzMzI5OQA + MC4zMzMzMzI5ODU2AA @@ -1210,11 +1218,11 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA - 3.000000e+00 - 2.000000e+00 + 3 + 2 - 1.600000e+01 + 16 tableViewAction: -765427712 @@ -1224,6 +1232,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 15 0 YES + 0 @@ -1247,7 +1256,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA YES \ - Ig + " @@ -1260,10 +1269,10 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA YES - - 1.000000e+01 - 1.000000e+01 - 1.000000e+03 + + 10 + 10 + 1000 75628032 0 @@ -1273,7 +1282,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 3 - MC4zMzMzMzI5OQA + MC4zMzMzMzI5ODU2AA @@ -1291,11 +1300,11 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA - 3.000000e+00 - 2.000000e+00 + 3 + 2 - 1.600000e+01 + 16 tableViewAction: -765427712 @@ -1305,6 +1314,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 15 0 YES + 0 @@ -1358,10 +1368,10 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA YES - - 1.000000e+01 - 1.000000e+01 - 1.000000e+03 + + 10 + 10 + 1000 75628032 0 @@ -1371,7 +1381,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 3 - MC4zMzMzMzI5OQA + MC4zMzMzMzI5ODU2AA @@ -1389,11 +1399,11 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA - 3.000000e+00 - 2.000000e+00 + 3 + 2 - 1.600000e+01 + 16 tableViewAction: -765427712 @@ -1403,6 +1413,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 15 0 YES + 0 @@ -1504,7 +1515,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA -2080244224 131072 - PGhlYWQ+IGFuZCA8Ym9keT4gdGFncw + <head> and <body> tags 1211912703 @@ -1684,7 +1695,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 268 - {{226, 344}, {116, 18}} + {{226, 366}, {116, 18}} YES @@ -1706,7 +1717,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 268 - {{246, 299}, {168, 42}} + {{246, 321}, {168, 42}} YES @@ -1722,7 +1733,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 268 - {{17, 386}, {31, 14}} + {{17, 408}, {31, 14}} YES @@ -1738,7 +1749,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 268 - {{53, 384}, {285, 19}} + {{53, 406}, {285, 19}} YES @@ -1760,7 +1771,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 12 - {{20, 373}, {410, 5}} + {{20, 395}, {410, 5}} {0, 0} @@ -1771,7 +1782,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 3 - MCAwLjgwMDAwMDAxAA + MCAwLjgwMDAwMDAxMTkAA 3 @@ -1782,7 +1793,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 268 - {{341, 378}, {94, 28}} + {{341, 400}, {94, 28}} YES @@ -1799,8 +1810,30 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 25 + + + 268 + {{37, 58}, {230, 18}} + + YES + + 67239424 + 131072 + Low memory export (may block server) + + + 1211912703 + 2 + + + + + 200 + 25 + + - {450, 420} + {450, 442} {{0, 0}, {1920, 1178}} @@ -1885,7 +1918,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 3 - MCAwLjgwMDAwMDAxAA + MCAwLjgwMDAwMDAxMTkAA @@ -1936,7 +1969,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 68288064 272761856 - PG5hbWU+A + <name> @@ -1971,22 +2004,24 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA {{18, 56}, {343, 20}} + 16394 - 1.000000e+02 + 100 256 {{59, 84}, {300, 17}} + YES 67239488 4197120 - RXhwb3J0aW5n4oCmA + Exporting… LucidaGrande - 1.100000e+01 + 11 16 @@ -2005,6 +2040,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 256 {{279, 12}, {83, 32}} + YES 67239424 @@ -2016,7 +2052,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 1 LucidaGrande - 1.300000e+01 + 13 16 @@ -2030,14 +2066,15 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 256 {{59, 104}, {300, 17}} + YES 67239488 4196352 - RG9pbmcgU3R1ZmbigKY + Doing Stuff… LucidaGrande-Bold - 1.300000e+01 + 13 2072 @@ -2050,7 +2087,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 268 YES - + YES Apple PDF pasteboard type Apple PICT pasteboard type @@ -2062,6 +2099,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA {{20, 87}, {32, 32}} + YES 130560 @@ -2080,6 +2118,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA {379, 139} + {{0, 0}, {1680, 1028}} {213, 72} @@ -2441,34 +2480,40 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 309 + + + exportProcessLowMemory + + + + 312 + YES 0 - - YES - + -2 - - RmlsZSdzIE93bmVyA + + File's Owner -1 - + First Responder -3 - + Application @@ -2479,7 +2524,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA - + Export Window @@ -2498,6 +2543,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA + @@ -3207,7 +3253,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA - + Token Name View @@ -3357,7 +3403,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA YES - + Export Progress Sheet @@ -3434,16 +3480,29 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA + + 310 + + + YES + + + + + + 311 + + + YES - + YES - -1.IBPluginDependency - -2.IBPluginDependency -3.IBPluginDependency 1.IBEditorWindowLastContentRect + 1.IBPluginDependency 1.IBViewEditorWindowController.showingBoundsRectangles 1.IBViewEditorWindowController.showingLayoutRectangles 1.IBWindowTemplateEditedContentRect @@ -3496,6 +3555,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 290.IBPluginDependency 291.IBPluginDependency 294.IBEditorWindowLastContentRect + 294.IBPluginDependency 294.IBWindowTemplateEditedContentRect 294.ImportedFromIB2 294.windowTemplate.hasMinSize @@ -3520,6 +3580,8 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA 303.IBPluginDependency 304.IBPluginDependency 31.IBPluginDependency + 310.IBPluginDependency + 311.IBPluginDependency 32.IBPluginDependency 33.IBPluginDependency 34.IBPluginDependency @@ -3610,13 +3672,12 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA YES com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilderKit - com.apple.InterfaceBuilderKit - {{484, 290}, {450, 420}} - - - {{484, 290}, {450, 420}} - + {{637, 328}, {450, 442}} + com.apple.InterfaceBuilder.CocoaPlugin + + + {{637, 328}, {450, 442}} + com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -3632,15 +3693,13 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA NSTokenField YES - - YES - + YES com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -3682,25 +3741,28 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {{523, 449}, {379, 139}} + com.apple.InterfaceBuilder.CocoaPlugin {{523, 449}, {379, 139}} - - + + {213, 50} com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + {{657, 476}, {616, 0}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -3723,7 +3785,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin ToolTip @@ -3734,15 +3796,15 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + ToolTip @@ -3752,7 +3814,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA com.apple.InterfaceBuilder.CocoaPlugin - + ToolTip @@ -3762,7 +3824,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA com.apple.InterfaceBuilder.CocoaPlugin - + ToolTip @@ -3772,9 +3834,9 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin - + com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -3819,14 +3881,12 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA com.apple.InterfaceBuilder.CocoaPlugin {{454, 460}, {424, 164}} com.apple.InterfaceBuilder.CocoaPlugin - + YES - - YES - + YES @@ -3834,15 +3894,13 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA YES - - YES - + YES - 309 + 312 @@ -3879,7 +3937,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA NSObject IBProjectSource - Source/SPExporter.h + Source/SPContentFilterManager.h @@ -3912,7 +3970,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA NSObject YES - + YES cancelExport: changeExportOutputPath: @@ -3931,7 +3989,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA YES - + YES exampleNameLabel exportCSVFieldsEscapedField @@ -3947,6 +4005,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA exportInputMatrix exportPDFIncludeStructureCheck exportPathField + exportProcessLowMemory exportProgressIndicator exportProgressText exportProgressTitle @@ -3959,6 +4018,7 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA exportToolbar exportWindow exportXMLIncludeStructureCheck + tableDataInstance tableDocumentInstance tableWindow tablesListInstance @@ -4000,6 +4060,8 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA id id id + id + id @@ -4008,8 +4070,667 @@ AAMAAAABAAEAAAFTAAMAAAAEAAAFwgAAAAAACAAIAAgACAABAAEAAQABA + + YES + + NSActionCell + NSCell + + IBFrameworkSource + AppKit.framework/Headers/NSActionCell.h + + + + NSApplication + NSResponder + + IBFrameworkSource + AppKit.framework/Headers/NSApplication.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSApplicationScripting.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSColorPanel.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSHelpManager.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSPageLayout.h + + + + NSApplication + + IBFrameworkSource + AppKit.framework/Headers/NSUserInterfaceItemSearching.h + + + + NSBox + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSBox.h + + + + NSButton + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSButton.h + + + + NSButtonCell + NSActionCell + + IBFrameworkSource + AppKit.framework/Headers/NSButtonCell.h + + + + NSCell + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSCell.h + + + + NSComboBox + NSTextField + + IBFrameworkSource + AppKit.framework/Headers/NSComboBox.h + + + + NSComboBoxCell + NSTextFieldCell + + IBFrameworkSource + AppKit.framework/Headers/NSComboBoxCell.h + + + + NSControl + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSControl.h + + + + NSFormatter + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSFormatter.h + + + + NSImageCell + NSCell + + IBFrameworkSource + AppKit.framework/Headers/NSImageCell.h + + + + NSImageView + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSImageView.h + + + + NSMatrix + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSMatrix.h + + + + NSMenu + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSMenu.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSAccessibility.h + + + + NSObject + + + + NSObject + + + + NSObject + + + + NSObject + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSDictionaryController.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSDragging.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSFontManager.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSFontPanel.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSKeyValueBinding.h + + + + NSObject + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSNibLoading.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSOutlineView.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSPasteboard.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSSavePanel.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSTableView.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSToolbarItem.h + + + + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSView.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSArchiver.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSClassDescription.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSError.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSFileManager.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyValueCoding.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyValueObserving.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyedArchiver.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSObject.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSObjectScripting.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSPortCoder.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSRunLoop.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptClassDescription.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptKeyValueCoding.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptObjectSpecifiers.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSScriptWhoseTests.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSThread.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURL.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURLConnection.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURLDownload.h + + + + NSObject + + IBFrameworkSource + Growl.framework/Headers/GrowlApplicationBridge.h + + + + NSObject + + IBFrameworkSource + Sparkle.framework/Headers/SUAppcast.h + + + + NSObject + + IBFrameworkSource + Sparkle.framework/Headers/SUUpdater.h + + + + NSObject + + IBFrameworkSource + WebKit.framework/Headers/WebDownload.h + + + + NSObject + + IBFrameworkSource + WebKit.framework/Headers/WebEditingDelegate.h + + + + NSObject + + IBFrameworkSource + WebKit.framework/Headers/WebFrameLoadDelegate.h + + + + NSObject + + IBFrameworkSource + WebKit.framework/Headers/WebJavaPlugIn.h + + + + NSObject + + IBFrameworkSource + WebKit.framework/Headers/WebPlugin.h + + + + NSObject + + IBFrameworkSource + WebKit.framework/Headers/WebPluginContainer.h + + + + NSObject + + IBFrameworkSource + WebKit.framework/Headers/WebPolicyDelegate.h + + + + NSObject + + IBFrameworkSource + WebKit.framework/Headers/WebResourceLoadDelegate.h + + + + NSObject + + IBFrameworkSource + WebKit.framework/Headers/WebScriptObject.h + + + + NSObject + + IBFrameworkSource + WebKit.framework/Headers/WebUIDelegate.h + + + + NSPanel + NSWindow + + IBFrameworkSource + AppKit.framework/Headers/NSPanel.h + + + + NSProgressIndicator + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSProgressIndicator.h + + + + NSResponder + + IBFrameworkSource + AppKit.framework/Headers/NSInterfaceStyle.h + + + + NSResponder + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSResponder.h + + + + NSScrollView + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSScrollView.h + + + + NSScroller + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSScroller.h + + + + NSTabView + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSTabView.h + + + + NSTabViewItem + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSTabViewItem.h + + + + NSTableColumn + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSTableColumn.h + + + + NSTableView + NSControl + + + + NSTextField + NSControl + + IBFrameworkSource + AppKit.framework/Headers/NSTextField.h + + + + NSTextFieldCell + NSActionCell + + IBFrameworkSource + AppKit.framework/Headers/NSTextFieldCell.h + + + + NSTokenField + NSTextField + + IBFrameworkSource + AppKit.framework/Headers/NSTokenField.h + + + + NSToolbar + NSObject + + IBFrameworkSource + AppKit.framework/Headers/NSToolbar.h + + + + NSToolbarItem + NSObject + + + + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSClipView.h + + + + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSMenuItem.h + + + + NSView + + IBFrameworkSource + AppKit.framework/Headers/NSRulerView.h + + + + NSView + NSResponder + + + + NSWindow + + IBFrameworkSource + AppKit.framework/Headers/NSDrawer.h + + + + NSWindow + NSResponder + + IBFrameworkSource + AppKit.framework/Headers/NSWindow.h + + + + NSWindow + + IBFrameworkSource + AppKit.framework/Headers/NSWindowScripting.h + + + 0 + + com.apple.InterfaceBuilder.CocoaPlugin.macosx + + + + com.apple.InterfaceBuilder.CocoaPlugin.macosx + + + + com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 + + + YES ../../sequel-pro.xcodeproj 3 diff --git a/Source/SPCSVExporter.h b/Source/SPCSVExporter.h index c0cc75c4..b0edc04e 100644 --- a/Source/SPCSVExporter.h +++ b/Source/SPCSVExporter.h @@ -28,21 +28,11 @@ #import "MCPKit.h" #import "SPExporter.h" -/** - * - */ -@interface SPCSVExporterDelegate - -- (void)csvDataAvailable:(NSString *)data; - -@end - - @interface SPCSVExporter : SPExporter { // CSV data NSArray *csvDataArray; - MCPResult *csvDataResult; + MCPStreamingResult *csvDataResult; // CSV options BOOL csvOutputFieldNames; @@ -55,7 +45,7 @@ } @property (readwrite, retain) NSArray *csvDataArray; -@property (readwrite, retain) MCPResult *csvDataResult; +@property (readwrite, retain) MCPStreamingResult *csvDataResult; @property (readwrite, assign) BOOL csvOutputFieldNames; @property (readwrite, retain) NSString *csvFieldSeparatorString; diff --git a/Source/SPCSVExporter.m b/Source/SPCSVExporter.m index 9bbbb4af..4937e7c9 100644 --- a/Source/SPCSVExporter.m +++ b/Source/SPCSVExporter.m @@ -48,18 +48,19 @@ @try { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSMutableArray *csvRow = [NSMutableArray array]; - NSMutableString *csvCell = [NSMutableString string]; - NSMutableString *csvString = [NSMutableString string]; - NSMutableString *csvData = [NSMutableString string]; - + NSMutableString *csvString = [NSMutableString string]; + NSMutableString *csvData = [NSMutableString string]; + NSMutableString *csvCellString = [NSMutableString string]; + + NSArray *csvRow; NSScanner *csvNumericTester; NSString *escapedEscapeString, *escapedFieldSeparatorString, *escapedEnclosingString, *escapedLineEndString, *dataConversionString; - + + id csvCell; BOOL csvCellIsNumeric; BOOL quoteFieldSeparators = [[self csvEnclosingCharacterString] isEqualToString:@""]; - - NSUInteger i, j, startingRow, totalRows; + + NSUInteger i, totalRows, csvCellCount = 0; // Check that we have all the required info before starting the export if ((![self csvOutputFieldNames]) || @@ -82,12 +83,10 @@ // Check that we have at least some data to export if ((![self csvDataArray]) && (![self csvDataResult])) return; - + // Mark the process as running [self setExportProcessIsRunning:YES]; - if ([self csvDataResult] != nil && [[self csvDataResult] numOfRows]) [[self csvDataResult] dataSeek:0]; - // Detect and restore special characters being used as terminating or line end strings NSMutableString *tempSeparatorString = [NSMutableString stringWithString:[self csvFieldSeparatorString]]; @@ -132,143 +131,165 @@ escapedEnclosingString = [[self csvEscapeString] stringByAppendingString:[self csvEnclosingCharacterString]]; escapedLineEndString = [[self csvEscapeString] stringByAppendingString:[self csvLineEndingString]]; - // Determine the total number of rows and starting row depending on supplied data format - if ([self csvDataArray] == nil) { - startingRow = [self csvOutputFieldNames] ? 1 : 0; - totalRows = [[self csvDataResult] numOfRows]; - } - else { - startingRow = [self csvOutputFieldNames] ? 0 : 1; - totalRows = [[self csvDataArray] count]; - } + // Set up the starting row; for supplied arrays, which include the column + // headers as the first row, decide whether to skip the first row. + NSUInteger currentRowIndex = 0; [csvData setString:@""]; - - // Walk through the supplied data constructing the CSV string - for (i = startingRow; i < totalRows; i++) + + if (([self csvDataArray]) && (![self csvOutputFieldNames])) currentRowIndex++; + + // Drop into the processing loop + NSAutoreleasePool *csvExportPool = [[NSAutoreleasePool alloc] init]; + + NSUInteger currentPoolDataLength = 0; + + while (1) { - // Check to see if the operation has been cancelled. If so exit the loop. - if ([self isCancelled]) { - break; - } - - // Update the progress value - if (totalRows) [self setExportProgressValue:(((i + 1) * 100) / totalRows)]; - - // Retrieve the row from the supplied data - if ([self csvDataArray] == nil) { - // Header row - [csvRow setArray:(i == -1) ? [[self csvDataResult] fetchFieldNames] : [[self csvDataResult] fetchRowAsArray]]; + // Retrieve the next row from the supplied data, either directly from the array... + if ([self csvDataArray]) { + csvRow = NSArrayObjectAtIndex([self csvDataArray], currentRowIndex); } + // Or by reading an appropriate row from the streaming result else { - [csvRow setArray:NSArrayObjectAtIndex([self csvDataArray], i)]; + // If still requested to read the field names, get the field names + if ([self csvOutputFieldNames]) { + csvRow = [[self csvDataResult] fetchFieldNames]; + [self setCsvOutputFieldNames:NO]; + } + else { + csvRow = [[self csvDataResult] fetchNextRowAsArray]; + + if (!csvRow) break; + } } + // Get the cell count if we don't already have it stored + if (!csvCellCount) csvCellCount = [csvRow count]; + [csvString setString:@""]; - for (j = 0; j < [csvRow count]; j++) + for (i = 0 ; i < csvCellCount; i++) { + csvCell = NSArrayObjectAtIndex(csvRow, i); + // For NULL objects supplied from a queryResult, add an unenclosed null string as per prefs - if ([[csvRow objectAtIndex:j] isKindOfClass:[NSNull class]]) { + if ([csvCell isKindOfClass:[NSNull class]]) { [csvString appendString:[self csvNULLString]]; - if (j < [csvRow count] - 1) [csvString appendString:[self csvFieldSeparatorString]]; + if (i < (csvCellCount - 1)) [csvString appendString:[self csvFieldSeparatorString]]; continue; } // Retrieve the contents of this cell - if ([NSArrayObjectAtIndex(csvRow, j) isKindOfClass:[NSData class]]) { - dataConversionString = [[NSString alloc] initWithData:NSArrayObjectAtIndex(csvRow, j) encoding:[self exportOutputEncoding]]; + if ([csvCell isKindOfClass:[NSData class]]) { + dataConversionString = [[NSString alloc] initWithData:csvCell encoding:[self exportOutputEncoding]]; if (dataConversionString == nil) { - dataConversionString = [[NSString alloc] initWithData:NSArrayObjectAtIndex(csvRow, j) encoding:NSASCIIStringEncoding]; + dataConversionString = [[NSString alloc] initWithData:csvCell encoding:NSASCIIStringEncoding]; } - [csvCell setString:[NSString stringWithString:dataConversionString]]; + [csvCellString setString:[NSString stringWithString:dataConversionString]]; [dataConversionString release]; } else { - [csvCell setString:[NSArrayObjectAtIndex(csvRow, j) description]]; + [csvCellString setString:[csvCell description]]; } // For NULL values supplied via an array add the unenclosed null string as set in preferences - if ([csvCell isEqualToString:[self csvNULLString]]) { + if ([csvCellString isEqualToString:[self csvNULLString]]) { [csvString appendString:[self csvNULLString]]; } // Add empty strings as a pair of enclosing characters. - else if ([csvCell length] == 0) { + else if ([csvCellString length] == 0) { [csvString appendString:[self csvEnclosingCharacterString]]; [csvString appendString:[self csvEnclosingCharacterString]]; - - } + } else { - // Test whether this cell contains a number - if ([NSArrayObjectAtIndex(csvRow, j) isKindOfClass:[NSData class]]) { + // If an array of bools supplying information as to whether the column is numeric has been supplied, use it. + if ([self csvTableColumnNumericStatus] != nil) { + csvCellIsNumeric = [NSArrayObjectAtIndex([self csvTableColumnNumericStatus], i) boolValue]; + } + // Otherwise, first test whether this cell contains data + else if ([NSArrayObjectAtIndex(csvRow, i) isKindOfClass:[NSData class]]) { csvCellIsNumeric = NO; } - // If an array of bools supplying information as to whether the column is numeric has been supplied, use it. - else if ([self csvTableColumnNumericStatus] != nil) { - csvCellIsNumeric = [NSArrayObjectAtIndex([self csvTableColumnNumericStatus], j) boolValue]; - } // Or fall back to testing numeric content via an NSScanner. else { - csvNumericTester = [NSScanner scannerWithString:csvCell]; + csvNumericTester = [NSScanner scannerWithString:csvCellString]; + csvCellIsNumeric = [csvNumericTester scanFloat:nil] && [csvNumericTester isAtEnd] && - ([csvCell characterAtIndex:0] != '0' || - [csvCell length] == 1 || - ([csvCell length] > 1 && - [csvCell characterAtIndex:1] == '.')); + ([csvCellString characterAtIndex:0] != '0' || + [csvCellString length] == 1 || + ([csvCellString length] > 1 && + [csvCellString characterAtIndex:1] == '.')); } // Escape any occurrences of the escaping character - [csvCell replaceOccurrencesOfString:[self csvEscapeString] - withString:escapedEscapeString - options:NSLiteralSearch - range:NSMakeRange(0, [csvCell length])]; + [csvCellString replaceOccurrencesOfString:[self csvEscapeString] + withString:escapedEscapeString + options:NSLiteralSearch + range:NSMakeRange(0, [csvCellString length])]; // Escape any occurrences of the enclosure string if (![[self csvEscapeString] isEqualToString:[self csvEnclosingCharacterString]]) { - [csvCell replaceOccurrencesOfString:[self csvEnclosingCharacterString] - withString:escapedEnclosingString - options:NSLiteralSearch - range:NSMakeRange(0, [csvCell length])]; + [csvCellString replaceOccurrencesOfString:[self csvEnclosingCharacterString] + withString:escapedEnclosingString + options:NSLiteralSearch + range:NSMakeRange(0, [csvCellString length])]; } // Escape occurrences of the line end character - [csvCell replaceOccurrencesOfString:[self csvLineEndingString] - withString:escapedLineEndString - options:NSLiteralSearch - range:NSMakeRange(0, [csvCell length])]; + [csvCellString replaceOccurrencesOfString:[self csvLineEndingString] + withString:escapedLineEndString + options:NSLiteralSearch + range:NSMakeRange(0, [csvCellString length])]; // If the string isn't quoted or otherwise enclosed, escape occurrences of the field separators if (quoteFieldSeparators || csvCellIsNumeric) { - [csvCell replaceOccurrencesOfString:[self csvFieldSeparatorString] - withString:escapedFieldSeparatorString - options:NSLiteralSearch - range:NSMakeRange(0, [csvCell length])]; + [csvCellString replaceOccurrencesOfString:[self csvFieldSeparatorString] + withString:escapedFieldSeparatorString + options:NSLiteralSearch + range:NSMakeRange(0, [csvCellString length])]; } // Write out the cell data by appending strings - this is significantly faster than stringWithFormat. if (csvCellIsNumeric) { - [csvString appendString:csvCell]; + [csvString appendString:csvCellString]; } else { [csvString appendString:[self csvEnclosingCharacterString]]; - [csvString appendString:csvCell]; + [csvString appendString:csvCellString]; [csvString appendString:[self csvEnclosingCharacterString]]; } } - if (j < ([csvRow count] - 1)) [csvString appendString:[self csvFieldSeparatorString]]; + if (i < ([csvRow count] - 1)) [csvString appendString:[self csvFieldSeparatorString]]; } - // Append the line ending to the string for this row + // Append the line ending to the string for this row, and record the length processed for pool flushing [csvString appendString:[self csvLineEndingString]]; [csvData appendString:csvString]; + + currentPoolDataLength += [csvString length]; + + currentRowIndex++; + + // Update the progress value + if (totalRows) [self setExportProgressValue:(((i + 1) * 100) / totalRows)]; + + // If an array was supplied and we've processed all rows, break + if ([self csvDataArray] && (totalRows == currentRowIndex)) break; + + // Drain the autorelease pool as required to keep memory usage low + if (currentPoolDataLength > 250000) { + [csvExportPool drain]; + csvExportPool = [[NSAutoreleasePool alloc] init]; + } } - + // Assign the resulting CSV data to the expoter's export data [self setExportData:csvData]; @@ -276,7 +297,7 @@ [self setExportProcessIsRunning:NO]; // Call the delegate's didEndSelector while passing this exporter to it - [[self delegate] performSelectorOnMainThread:[self didEndSelector] withObject:self waitUntilDone:YES]; + [[self delegate] performSelectorOnMainThread:[self didEndSelector] withObject:self waitUntilDone:NO]; [pool release]; } diff --git a/Source/SPExportController.h b/Source/SPExportController.h index eec8ce63..294f5851 100644 --- a/Source/SPExportController.h +++ b/Source/SPExportController.h @@ -27,6 +27,8 @@ #import "SPExporterDataAccess.h" +#import "SPLogger.h" + // Export type constants enum { SP_SQL_EXPORT = 1, @@ -67,6 +69,7 @@ typedef NSUInteger SPExportSource; IBOutlet id exportInputMatrix; IBOutlet id exportFilePerTableCheck; IBOutlet id exportFilePerTableNote; + IBOutlet id exportProcessLowMemory; // Export progress sheet IBOutlet id exportProgressWindow; @@ -116,6 +119,8 @@ typedef NSUInteger SPExportSource; // Concurrent operation queue NSOperationQueue *operationQueue; + + SPLogger *log; } @property (readwrite, assign) BOOL exportCancelled; diff --git a/Source/SPExportController.m b/Source/SPExportController.m index b6adc58a..f7b1878f 100644 --- a/Source/SPExportController.m +++ b/Source/SPExportController.m @@ -32,9 +32,8 @@ @interface SPExportController (PrivateAPI) -- (NSString *)_htmlEscapeString:(NSString *)string; - (void)_initializeExportUsingSelectedOptions; -- (BOOL)_exportTablesAsCSV:(NSArray *)exportTables usingDataExporter:(SPExporter *)exporter; +- (BOOL)_exportTables:(NSArray *)exportTables asType:(SPExportType)type; @end @@ -53,6 +52,8 @@ tables = [[NSMutableArray alloc] init]; operationQueue = [[NSOperationQueue alloc] init]; + + log = [SPLogger logger]; } return self; @@ -163,7 +164,12 @@ [panel setCanChooseDirectories:YES]; [panel setCanCreateDirectories:YES]; - [panel beginSheetForDirectory:NSHomeDirectory() file:nil modalForWindow:exportWindow modalDelegate:self didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:) contextInfo:nil]; + [panel beginSheetForDirectory:NSHomeDirectory() + file:nil + modalForWindow:exportWindow + modalDelegate:self + didEndSelector:@selector(savePanelDidEnd:returnCode:contextInfo:) + contextInfo:nil]; } #pragma mark - @@ -227,6 +233,8 @@ */ - (void)exporterDataConversionProcessComplete:(SPExporter *)exporter { + // Do something with the data... + // If there are no more operations in the queue, close the progress sheet if ([[operationQueue operations] count] == 0) { [NSApp endSheet:exportProgressWindow returnCode:0]; @@ -277,32 +285,6 @@ @implementation SPExportController (PrivateAPI) -/** - * Escapes the supplied HTML string - */ -- (NSString *)_htmlEscapeString:(NSString *)string -{ - NSMutableString *mutableString = [NSMutableString stringWithString:string]; - - [mutableString replaceOccurrencesOfString:@"&" withString:@"&" - options:NSLiteralSearch - range:NSMakeRange(0, [mutableString length])]; - - [mutableString replaceOccurrencesOfString:@"<" withString:@"<" - options:NSLiteralSearch - range:NSMakeRange(0, [mutableString length])]; - - [mutableString replaceOccurrencesOfString:@">" withString:@">" - options:NSLiteralSearch - range:NSMakeRange(0, [mutableString length])]; - - [mutableString replaceOccurrencesOfString:@"\"" withString:@""" - options:NSLiteralSearch - range:NSMakeRange(0, [mutableString length])]; - - return [NSString stringWithString:mutableString]; -} - /** * */ @@ -319,7 +301,7 @@ } } - // Determine what data to use (filtered result, custom query result or selected tables) for the export operation + // Determine what data to use (filtered result, custom query result or selected table(s)) for the export operation SPExportSource exportSource = ([exportInputMatrix selectedRow] + 1); NSMutableArray *exportTables = [NSMutableArray array]; @@ -345,43 +327,7 @@ break; } - SPExporter *exporter; - SPCSVExporter *csvExporter; - - // Based on the type of export create a new instance of the corresponding exporter and set it's specific options - switch (exportType) - { - case SP_SQL_EXPORT: - - break; - case SP_CSV_EXPORT: - csvExporter = [[SPCSVExporter alloc] initWithDelegate:self]; - - [csvExporter setCsvOutputFieldNames:[exportCSVIncludeFieldNamesCheck state]]; - [csvExporter setCsvFieldSeparatorString:[exportCSVFieldsTerminatedField stringValue]]; - [csvExporter setCsvEnclosingCharacterString:[exportCSVFieldsWrappedField stringValue]]; - [csvExporter setCsvLineEndingString:[exportCSVLinesTerminatedField stringValue]]; - [csvExporter setCsvEscapeString:[exportCSVFieldsEscapedField stringValue]]; - - [csvExporter setExportOutputEncoding:[MCPConnection encodingForMySQLEncoding:[[tableDocumentInstance connectionEncoding] UTF8String]]]; - [csvExporter setCsvNULLString:[[NSUserDefaults standardUserDefaults] objectForKey:@"NullValue"]]; - - exporter = csvExporter; - break; - case SP_XML_EXPORT: - - break; - case SP_PDF_EXPORT: - - break; - case SP_HTML_EXPORT: - - break; - case SP_EXCEL_EXPORT: - - break; - } - + // Begin the export based on the type switch (exportSource) { case SP_FILTERED_EXPORT: @@ -391,24 +337,23 @@ break; case SP_TABLE_EXPORT: - [self _exportTablesAsCSV:exportTables usingDataExporter:exporter]; + [self _exportTables:exportTables asType:exportType]; break; } } /** - * Exports the contents' of the supplied array of tables using the supplied exporter and export type. Note that - * this method currently only supports exporting in CSV and XML formats. + * Exports the contents' of the supplied array of tables. Note that this method currently only supports + * exporting in CSV and XML formats. */ -- (BOOL)_exportTablesAsCSV:(NSArray *)exportTables usingDataExporter:(SPCSVExporter *)exporter +- (BOOL)_exportTables:(NSArray *)exportTables asType:(SPExportType)type { - NSUInteger tableCount, i; + NSUInteger i; NSMutableString *errors = [NSMutableString string]; NSMutableString *infoString = [NSMutableString string]; NSDictionary *tableDetails; - NSMutableArray *tableColumnNumericStatus; NSStringEncoding encoding = [[self connection] encoding]; // Reset the interface @@ -440,19 +385,21 @@ options:NSLiteralSearch range:NSMakeRange(0, [csvLineEnd length])]; - if ([exportTables count] > 1) { + /*if ([exportTables count] > 1) { [infoString setString:[NSString stringWithFormat:@"Host: %@ Database: %@ Generation Time: %@%@%@", [tableDocumentInstance host], [tableDocumentInstance database], [NSDate date], csvLineEnd, csvLineEnd]]; - } + }*/ - tableCount = [exportTables count]; + NSUInteger tableCount = [exportTables count]; // Loop through the tables - for (i = 0 ; i < ((tableCount) && (![self exportCancelled])); i++) + for (i = 0 ; i < tableCount; i++) { + if ([self exportCancelled]) break; + // Update the progress text and reset the progress bar to indeterminate status NSString *tableName = [exportTables objectAtIndex:i]; - + [exportProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %d of %d (%@): fetching data...", @"text showing that app is fetching data for table dump"), (i + 1), tableCount, tableName]]; [exportProgressText displayIfNeeded]; @@ -475,7 +422,7 @@ } // Retrieve the table details via the data class, and use it to build an array containing column numeric status - tableColumnNumericStatus = [NSMutableArray array]; + NSMutableArray *tableColumnNumericStatus = [NSMutableArray array]; for (NSDictionary *column in [tableDetails objectForKey:@"columns"]) { @@ -485,19 +432,60 @@ [tableColumnTypeGrouping isEqualToString:@"integer"] || [tableColumnTypeGrouping isEqualToString:@"float"])]]; } - - [exporter setCsvTableColumnNumericStatus:tableColumnNumericStatus]; - // Retrieve all the content within this table - queryResult = [connection queryString:[NSString stringWithFormat:@"SELECT * FROM %@", [tableName backtickQuotedString]]]; - + // Use low memory export? + BOOL useLowMemoryBlockingStreaming = ([exportProcessLowMemory state] == NSOnState); + + // Make a streaming request for the data + MCPStreamingResult *queryResultStreaming = [connection streamingQueryString:[NSString stringWithFormat:@"SELECT * FROM %@", [tableName backtickQuotedString]] useLowMemoryBlockingStreaming:useLowMemoryBlockingStreaming]; + // Note any errors during retrieval if (![[connection getLastErrorMessage] isEqualToString:@""]) { [errors appendString:[NSString stringWithFormat:@"%@\n", [connection getLastErrorMessage]]]; } - // Assign the data to the exporter - [exporter setCsvDataResult:queryResult]; + SPExporter *exporter; + SPCSVExporter *csvExporter; + + // Based on the type of export create a new instance of the corresponding exporter and set it's specific options + switch (type) + { + case SP_SQL_EXPORT: + + break; + case SP_CSV_EXPORT: + csvExporter = [[SPCSVExporter alloc] initWithDelegate:self]; + + [csvExporter setCsvOutputFieldNames:[exportCSVIncludeFieldNamesCheck state]]; + [csvExporter setCsvFieldSeparatorString:[exportCSVFieldsTerminatedField stringValue]]; + [csvExporter setCsvEnclosingCharacterString:[exportCSVFieldsWrappedField stringValue]]; + [csvExporter setCsvLineEndingString:[exportCSVLinesTerminatedField stringValue]]; + [csvExporter setCsvEscapeString:[exportCSVFieldsEscapedField stringValue]]; + + [csvExporter setExportOutputEncoding:[MCPConnection encodingForMySQLEncoding:[[tableDocumentInstance connectionEncoding] UTF8String]]]; + [csvExporter setCsvNULLString:[[NSUserDefaults standardUserDefaults] objectForKey:@"NullValue"]]; + + [csvExporter setCsvTableColumnNumericStatus:tableColumnNumericStatus]; + + // Assign the data to the exporter + [csvExporter setCsvDataResult:queryResultStreaming]; + + exporter = csvExporter; + + break; + case SP_XML_EXPORT: + + break; + case SP_PDF_EXPORT: + + break; + case SP_HTML_EXPORT: + + break; + case SP_EXCEL_EXPORT: + + break; + } // Update the progress text and set the progress bar back to determinate [exportProgressText setStringValue:[NSString stringWithFormat:NSLocalizedString(@"Table %d of %d (%@): Writing...", @"text showing that app is writing data for table export"), (i + 1), tableCount, tableName]]; -- cgit v1.2.3