diff --git a/camino/Chimera.pbproj/project.pbxproj b/camino/Chimera.pbproj/project.pbxproj index f789e40d443..7d26c0177ce 100644 --- a/camino/Chimera.pbproj/project.pbxproj +++ b/camino/Chimera.pbproj/project.pbxproj @@ -146,6 +146,7 @@ 4A9504CDFFE6A4B311CA0CBA, F593CA5E034EB88E01A967F3, ); + hasScannedForEncodings = 1; isa = PBXProject; knownRegions = ( English, @@ -200,6 +201,7 @@ refType = 4; }; 29B97316FDCFA39411CA2CEA = { + fileEncoding = 30; isa = PBXFileReference; name = main.m; path = src/application/main.m; @@ -495,7 +497,6 @@ "; - shouldUseHeadermap = 1; }; 29B97327FDCFA39411CA2CEA = { buildActionMask = 2147483647; @@ -541,7 +542,6 @@ F55C4DD402D2864E0130B065, F50D9DE402ECC2C601BB4219, F50D9DEF02EE0AB101BB4219, - F50D9DF302EE194001BB4219, F50D9DF702EE2B9B01BB4219, F5D33CBF02EF61AA01A967F3, F566BD1402EFA9AD01A967F3, @@ -565,6 +565,9 @@ F57BEDA003A1825001A9666E, F5C8D55303A2A42401A8016F, F5C8D55603A2A43301A8016F, + A7AEBEC603CB962500A967F8, + A7AEBEE003CB9CD700A967F8, + A7AEBEE903CB9DFB00A967F8, ); isa = PBXHeadersBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -643,6 +646,12 @@ F5566DC5038E075F01A80166, F5566DC6038E075F01A80166, F5566DC7038E075F01A80166, + A7AEBED103CB9BD000A967F8, + A7AEBED203CB9BD000A967F8, + A7AEBED303CB9BD000A967F8, + A7AEBEDB03CB9C2F00A967F8, + A7AEBEDC03CB9C2F00A967F8, + A7F01A4903CBBCA500A967F8, ); isa = PBXResourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -689,7 +698,6 @@ F59236C302C89ACA0100012B, F50D9DE502ECC2C601BB4219, F50D9DF002EE0AB101BB4219, - F50D9DF402EE194001BB4219, F50D9DF802EE2B9B01BB4219, F5D33CC002EF61AA01A967F3, F5D33CC102EF61AA01A967F3, @@ -712,6 +720,9 @@ F55EBC9D0383665201A80166, F57BED9803A1824001A9666E, F57BED9F03A1825001A9666E, + A7AEBEC903CB964000A967F8, + A7AEBEE303CB9CEC00A967F8, + A7AEBEE603CB9DDF00A967F8, ); isa = PBXSourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -752,12 +763,14 @@ //2E3 //2E4 2E2939FF027F33604B000102 = { + fileEncoding = 30; isa = PBXFileReference; name = PageProxyIcon.mm; path = src/browser/PageProxyIcon.mm; refType = 2; }; 2E293A00027F33604B000102 = { + fileEncoding = 30; isa = PBXFileReference; name = PageProxyIcon.h; path = src/browser/PageProxyIcon.h; @@ -776,12 +789,14 @@ }; }; 2E748B72029A448D4B000102 = { + fileEncoding = 30; isa = PBXFileReference; name = GoMenu.h; path = src/browser/GoMenu.h; refType = 2; }; 2E748B73029A448D4B000102 = { + fileEncoding = 30; isa = PBXFileReference; name = GoMenu.mm; path = src/browser/GoMenu.mm; @@ -800,12 +815,14 @@ }; }; 2EEC3E61028138714B000102 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksOutlineView.h; path = src/bookmarks/BookmarksOutlineView.h; refType = 2; }; 2EEC3E62028138714B000102 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksOutlineView.mm; path = src/bookmarks/BookmarksOutlineView.mm; @@ -881,6 +898,292 @@ //982 //983 //984 +//A70 +//A71 +//A72 +//A73 +//A74 + A7AEBEB103CB950400A967F8 = { + isa = PBXFileReference; + name = xmlextras.xpt; + path = ../dist/Embed/components/xmlextras.xpt; + refType = 2; + }; + A7AEBEB303CB954500A967F8 = { + fileRef = A7AEBEB103CB950400A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEB403CB955700A967F8 = { + fileRef = A7AEBEB103CB950400A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEC403CB962500A967F8 = { + fileEncoding = 30; + isa = PBXFileReference; + name = "NSView+Utils.h"; + path = "src/extensions/NSView+Utils.h"; + refType = 2; + }; + A7AEBEC503CB962500A967F8 = { + fileRef = A7AEBEC403CB962500A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEC603CB962500A967F8 = { + fileRef = A7AEBEC403CB962500A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEC703CB964000A967F8 = { + fileEncoding = 30; + isa = PBXFileReference; + name = "NSView+Utils.m"; + path = "src/extensions/NSView+Utils.m"; + refType = 2; + }; + A7AEBEC803CB964000A967F8 = { + fileRef = A7AEBEC703CB964000A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEC903CB964000A967F8 = { + fileRef = A7AEBEC703CB964000A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBECA03CB96D600A967F8 = { + isa = PBXFileReference; + name = nsProxyAutoConfig.js; + path = ../netwerk/base/src/nsProxyAutoConfig.js; + refType = 2; + }; + A7AEBECB03CB96E700A967F8 = { + fileRef = A7AEBECA03CB96D600A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBECC03CB96F900A967F8 = { + fileRef = A7AEBECA03CB96D600A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBECE03CB9BD000A967F8 = { + isa = PBXFileReference; + name = disclosureArrowDown.tiff; + path = resources/images/app/disclosureArrowDown.tiff; + refType = 2; + }; + A7AEBECF03CB9BD000A967F8 = { + isa = PBXFileReference; + name = disclosureArrowRight.tiff; + path = resources/images/app/disclosureArrowRight.tiff; + refType = 2; + }; + A7AEBED003CB9BD000A967F8 = { + isa = PBXFileReference; + name = small_close.tiff; + path = resources/images/app/small_close.tiff; + refType = 2; + }; + A7AEBED103CB9BD000A967F8 = { + fileRef = A7AEBECE03CB9BD000A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBED203CB9BD000A967F8 = { + fileRef = A7AEBECF03CB9BD000A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBED303CB9BD000A967F8 = { + fileRef = A7AEBED003CB9BD000A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBED403CB9BD000A967F8 = { + fileRef = A7AEBECE03CB9BD000A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBED503CB9BD000A967F8 = { + fileRef = A7AEBECF03CB9BD000A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBED603CB9BD000A967F8 = { + fileRef = A7AEBED003CB9BD000A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBED703CB9C2F00A967F8 = { + children = ( + A7AEBED803CB9C2F00A967F8, + ); + isa = PBXVariantGroup; + name = Keychain.nib; + path = ""; + refType = 2; + }; + A7AEBED803CB9C2F00A967F8 = { + isa = PBXFileReference; + name = English; + path = resources/localized/English.lproj/Keychain.nib; + refType = 4; + }; + A7AEBED903CB9C2F00A967F8 = { + children = ( + A7AEBEDA03CB9C2F00A967F8, + ); + isa = PBXVariantGroup; + name = ProgressView.nib; + path = ""; + refType = 2; + }; + A7AEBEDA03CB9C2F00A967F8 = { + isa = PBXFileReference; + name = English; + path = resources/localized/English.lproj/ProgressView.nib; + refType = 4; + }; + A7AEBEDB03CB9C2F00A967F8 = { + fileRef = A7AEBED703CB9C2F00A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEDC03CB9C2F00A967F8 = { + fileRef = A7AEBED903CB9C2F00A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEDD03CB9C2F00A967F8 = { + fileRef = A7AEBED703CB9C2F00A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEDE03CB9C2F00A967F8 = { + fileRef = A7AEBED903CB9C2F00A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEDF03CB9CD700A967F8 = { + fileEncoding = 30; + isa = PBXFileReference; + name = CHStackView.h; + path = src/extensions/CHStackView.h; + refType = 2; + }; + A7AEBEE003CB9CD700A967F8 = { + fileRef = A7AEBEDF03CB9CD700A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEE103CB9CD700A967F8 = { + fileRef = A7AEBEDF03CB9CD700A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEE203CB9CEC00A967F8 = { + fileEncoding = 30; + isa = PBXFileReference; + name = CHStackView.m; + path = src/extensions/CHStackView.m; + refType = 2; + }; + A7AEBEE303CB9CEC00A967F8 = { + fileRef = A7AEBEE203CB9CEC00A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEE403CB9CEC00A967F8 = { + fileRef = A7AEBEE203CB9CEC00A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEE503CB9DDF00A967F8 = { + fileEncoding = 30; + isa = PBXFileReference; + name = ProgressViewController.mm; + path = src/download/ProgressViewController.mm; + refType = 2; + }; + A7AEBEE603CB9DDF00A967F8 = { + fileRef = A7AEBEE503CB9DDF00A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEE703CB9DDF00A967F8 = { + fileRef = A7AEBEE503CB9DDF00A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEE803CB9DFB00A967F8 = { + fileEncoding = 30; + isa = PBXFileReference; + name = ProgressViewController.h; + path = src/download/ProgressViewController.h; + refType = 2; + }; + A7AEBEE903CB9DFB00A967F8 = { + fileRef = A7AEBEE803CB9DFB00A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEEA03CB9DFB00A967F8 = { + fileRef = A7AEBEE803CB9DFB00A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7F01A4803CBBCA500A967F8 = { + isa = PBXBundleReference; + name = PrintPDE.plugin; + path = ../dist/PrintPDE.plugin; + refType = 2; + }; + A7F01A4903CBBCA500A967F8 = { + fileRef = A7F01A4803CBBCA500A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7F01A4A03CBBCA500A967F8 = { + fileRef = A7F01A4803CBBCA500A967F8; + isa = PBXBuildFile; + settings = { + }; + }; +//A70 +//A71 +//A72 +//A73 +//A74 //F50 //F51 //F52 @@ -1169,6 +1472,7 @@ }; }; F507BA480213AD5F01D93544 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksService.h; path = src/bookmarks/BookmarksService.h; @@ -1181,6 +1485,7 @@ }; }; F507BA4C0213AFF701D93544 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksService.mm; path = src/bookmarks/BookmarksService.mm; @@ -1224,6 +1529,7 @@ refType = 4; }; F507BA540213C29E01D93544 = { + fileEncoding = 30; isa = PBXFileReference; name = bookmarks.xml; path = resources/application/bookmarks.xml; @@ -1243,18 +1549,23 @@ F540BD1C029ED17901026D5D, F5A112C902DF270F01026D5D, F55B6BF402EF1F7E01026D5D, + A7AEBECE03CB9BD000A967F8, + A7AEBECF03CB9BD000A967F8, + A7AEBED003CB9BD000A967F8, ); isa = PBXGroup; - name = Graphics; + name = images; refType = 4; }; F50D9DE202ECC2C601BB4219 = { + fileEncoding = 30; isa = PBXFileReference; name = nsDownloadListener.h; path = src/download/nsDownloadListener.h; refType = 2; }; F50D9DE302ECC2C601BB4219 = { + fileEncoding = 30; isa = PBXFileReference; name = nsDownloadListener.mm; path = src/download/nsDownloadListener.mm; @@ -1301,12 +1612,14 @@ }; }; F50D9DED02EE0AB101BB4219 = { + fileEncoding = 30; isa = PBXFileReference; name = CHDownloadProgressDisplay.h; path = src/embedding/CHDownloadProgressDisplay.h; refType = 2; }; F50D9DEE02EE0AB101BB4219 = { + fileEncoding = 30; isa = PBXFileReference; name = CHDownloadProgressDisplay.mm; path = src/embedding/CHDownloadProgressDisplay.mm; @@ -1324,37 +1637,15 @@ settings = { }; }; - F50D9DF102EE194001BB4219 = { - isa = PBXFileReference; - name = CHDownloadFactories.h; - path = src/embedding/CHDownloadFactories.h; - refType = 2; - }; - F50D9DF202EE194001BB4219 = { - isa = PBXFileReference; - name = CHDownloadFactories.mm; - path = src/embedding/CHDownloadFactories.mm; - refType = 2; - }; - F50D9DF302EE194001BB4219 = { - fileRef = F50D9DF102EE194001BB4219; - isa = PBXBuildFile; - settings = { - }; - }; - F50D9DF402EE194001BB4219 = { - fileRef = F50D9DF202EE194001BB4219; - isa = PBXBuildFile; - settings = { - }; - }; F50D9DF502EE2B9A01BB4219 = { + fileEncoding = 30; isa = PBXFileReference; name = SaveHeaderSniffer.h; path = src/download/SaveHeaderSniffer.h; refType = 2; }; F50D9DF602EE2B9A01BB4219 = { + fileEncoding = 30; isa = PBXFileReference; name = SaveHeaderSniffer.mm; path = src/download/SaveHeaderSniffer.mm; @@ -1374,8 +1665,6 @@ }; F50D9DF902EE2C1D01BB4219 = { children = ( - F50D9DF102EE194001BB4219, - F50D9DF202EE194001BB4219, F50D9DED02EE0AB101BB4219, F50D9DEE02EE0AB101BB4219, ); @@ -1387,8 +1676,9 @@ children = ( F50D9DF502EE2B9A01BB4219, F50D9DF602EE2B9A01BB4219, - F517395B020CE3740189DA0C, F50D9DE302ECC2C601BB4219, + A7AEBEE503CB9DDF00A967F8, + F517395B020CE3740189DA0C, ); isa = PBXGroup; name = Chimera; @@ -1549,6 +1839,7 @@ }; }; F5125A110202064D01FAFD9F = { + fileEncoding = 30; isa = PBXFileReference; name = BrowserWrapper.h; path = src/browser/BrowserWrapper.h; @@ -1682,6 +1973,7 @@ }; }; F5137A1102676B9101026D05 = { + fileEncoding = 30; isa = PBXFileReference; name = Find.h; path = src/find/Find.h; @@ -1768,7 +2060,6 @@ "; - shouldUseHeadermap = 0; }; F51704D3034A305B01026D5D = { buildActionMask = 2147483647; @@ -1898,12 +2189,14 @@ refType = 2; }; F51704E9034A30DF01026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = SecurityPane.h; path = PreferencePanes/Security/SecurityPane.h; refType = 2; }; F51704EA034A30DF01026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = SecurityPane.mm; path = PreferencePanes/Security/SecurityPane.mm; @@ -2037,7 +2330,6 @@ "; - shouldUseHeadermap = 0; }; F51704FE034A38FD01026D5D = { buildActionMask = 2147483647; @@ -2169,12 +2461,14 @@ target = F51704FD034A38FD01026D5D; }; F5170515034A398F01026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = WebFeatures.h; path = PreferencePanes/WebFeatures/WebFeatures.h; refType = 2; }; F5170516034A398F01026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = WebFeatures.mm; path = PreferencePanes/WebFeatures/WebFeatures.mm; @@ -2253,6 +2547,7 @@ refType = 2; }; F5170530034B5E9701026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = English; path = English.lproj/Localizable.strings; @@ -2271,12 +2566,14 @@ refType = 2; }; F517395A020CE3740189DA0C = { + fileEncoding = 30; isa = PBXFileReference; name = ProgressDlgController.h; path = src/download/ProgressDlgController.h; refType = 2; }; F517395B020CE3740189DA0C = { + fileEncoding = 30; isa = PBXFileReference; name = ProgressDlgController.mm; path = src/download/ProgressDlgController.mm; @@ -2320,6 +2617,7 @@ }; F51842F30206168101A966FE = { children = ( + F5C8D55203A2A42401A8016F, F5F94B900332532801026D5D, F5DE10E60209DC0601A967DF, F517395A020CE3740189DA0C, @@ -2363,6 +2661,7 @@ F53D36BD037843C201A80166, F58DB2D20381FD3301A9666E, F5C8D55503A2A43301A8016F, + A7AEBEE803CB9DFB00A967F8, ); isa = PBXGroup; name = Headers; @@ -2400,12 +2699,14 @@ }; }; F51B70B6026EC98B01A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = GetURLCommand.h; path = src/appleevents/GetURLCommand.h; refType = 2; }; F51B70B7026EC98B01A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = GetURLCommand.mm; path = src/appleevents/GetURLCommand.mm; @@ -2747,7 +3048,6 @@ "; - shouldUseHeadermap = 0; }; F52627CF027E976B01000102 = { buildActionMask = 2147483647; @@ -2796,6 +3096,7 @@ runOnlyForDeploymentPostprocessing = 0; }; F52627D4027E982201000102 = { + fileEncoding = 30; indentWidth = 2; isa = PBXFileReference; name = Navigation.h; @@ -2804,6 +3105,7 @@ tabWidth = 2; }; F52627D5027E982201000102 = { + fileEncoding = 30; indentWidth = 2; isa = PBXFileReference; name = Navigation.mm; @@ -2989,6 +3291,7 @@ refType = 2; }; F528E218020FD8400168DE43 = { + fileEncoding = 30; isa = PBXFileReference; name = FindDlgController.h; path = src/find/FindDlgController.h; @@ -3001,6 +3304,7 @@ }; }; F528E21A020FD9620168DE43 = { + fileEncoding = 30; isa = PBXFileReference; name = FindDlgController.mm; path = src/find/FindDlgController.mm; @@ -3013,12 +3317,14 @@ }; }; F529788A0371820B01026DCE = { + fileEncoding = 30; isa = PBXFileReference; name = CHClickListener.h; path = src/embedding/CHClickListener.h; refType = 2; }; F529788B0371820B01026DCE = { + fileEncoding = 30; isa = PBXFileReference; name = CHClickListener.mm; path = src/embedding/CHClickListener.mm; @@ -3049,6 +3355,7 @@ }; }; F52CE65902BFA88701026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = English; path = resources/localized/English.lproj/Localizable.strings; @@ -3094,12 +3401,14 @@ }; }; F52D5CCF027A887001A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = AutoCompleteTextField.h; path = src/browser/AutoCompleteTextField.h; refType = 2; }; F52D5CD0027A887001A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = AutoCompleteTextField.mm; path = src/browser/AutoCompleteTextField.mm; @@ -3118,12 +3427,14 @@ }; }; F52D5CD3027A88C601A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = AutoCompleteDataSource.h; path = src/browser/AutoCompleteDataSource.h; refType = 2; }; F52D5CD4027A88C601A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = AutoCompleteDataSource.mm; path = src/browser/AutoCompleteDataSource.mm; @@ -3142,12 +3453,14 @@ }; }; F52D5CD7027D3D5001A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = PreferenceManager.h; path = src/preferences/PreferenceManager.h; refType = 2; }; F52D5CD8027D3D5001A80166 = { + fileEncoding = 30; indentWidth = 2; isa = PBXFileReference; name = PreferenceManager.mm; @@ -3203,24 +3516,28 @@ }; }; F52F87CB027D75C301A80165 = { + fileEncoding = 30; isa = PBXFileReference; name = HistoryDataSource; path = src/history/HistoryDataSource.h; refType = 2; }; F52F87CC027D75C301A80165 = { + fileEncoding = 30; isa = PBXFileReference; name = RDFOutlineViewDataSource.h; path = src/extensions/RDFOutlineViewDataSource.h; refType = 2; }; F52F87CD027D75C301A80165 = { + fileEncoding = 30; isa = PBXFileReference; name = HistoryDataSource.mm; path = src/history/HistoryDataSource.mm; refType = 4; }; F52F87CE027D75C301A80165 = { + fileEncoding = 30; isa = PBXFileReference; name = RDFOutlineViewDataSource.mm; path = src/extensions/RDFOutlineViewDataSource.mm; @@ -3251,6 +3568,7 @@ }; }; F53849040349779901A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = Localizable.strings; path = English.lproj/Localizable.strings; @@ -3343,12 +3661,14 @@ }; }; F53C1CD6032FF3B301A96654 = { + fileEncoding = 30; isa = PBXFileReference; name = BrowserContentViews.h; path = src/browser/BrowserContentViews.h; refType = 2; }; F53C1CD7032FF3B301A96654 = { + fileEncoding = 30; isa = PBXFileReference; name = BrowserContentViews.mm; path = src/browser/BrowserContentViews.mm; @@ -3379,12 +3699,14 @@ }; }; F53D36BA037843B801A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksMenu.mm; path = src/bookmarks/BookmarksMenu.mm; refType = 2; }; F53D36BD037843C201A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksMenu.h; path = src/bookmarks/BookmarksMenu.h; @@ -3397,6 +3719,7 @@ }; }; F53E012902AEE91C01A967F3 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarkInfoController.h; path = src/bookmarks/BookmarkInfoController.h; @@ -3415,6 +3738,7 @@ }; }; F53E012C02AEE93601A967F3 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarkInfoController.mm; path = src/bookmarks/BookmarkInfoController.mm; @@ -3471,54 +3795,63 @@ refType = 2; }; F53F21EC022B7C77010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = MVPreferencePaneDefaults.plist; path = src/preferences/MVPreferencePaneDefaults.plist; refType = 2; }; F53F21ED022B7C77010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = MVPreferencePaneGroups.plist; path = src/preferences/MVPreferencePaneGroups.plist; refType = 2; }; F53F21EE022B7C77010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = English; path = resources/localized/English.lproj/MVPreferencePaneGroups.strings; refType = 2; }; F53F21EF022B7C77010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = MVPreferencesController.h; path = src/preferences/MVPreferencesController.h; refType = 2; }; F53F21F0022B7C77010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = MVPreferencesController.mm; path = src/preferences/MVPreferencesController.mm; refType = 2; }; F53F21F1022B7C77010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = MVPreferencesGroupedIconView.h; path = src/preferences/MVPreferencesGroupedIconView.h; refType = 2; }; F53F21F2022B7C77010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = MVPreferencesGroupedIconView.m; path = src/preferences/MVPreferencesGroupedIconView.m; refType = 2; }; F53F21F3022B7C77010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = MVPreferencesMultipleIconView.h; path = src/preferences/MVPreferencesMultipleIconView.h; refType = 2; }; F53F21F4022B7C77010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = MVPreferencesMultipleIconView.m; path = src/preferences/MVPreferencesMultipleIconView.m; @@ -3548,11 +3881,13 @@ refType = 4; }; F53F21FF022B7C77010001CA = { + fileEncoding = 30; isa = PBXFileReference; path = PersonalPane.h; refType = 4; }; F53F2200022B7C77010001CA = { + fileEncoding = 30; isa = PBXFileReference; path = PersonalPane.m; refType = 4; @@ -3666,12 +4001,14 @@ }; }; F541495A02711A8301A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = CHToolbarAdditions.h; path = src/extensions/ToolbarAdditions.h; refType = 2; }; F541495B02711A8301A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = CHToolbarAdditions.m; path = src/extensions/ToolbarAdditions.m; @@ -3690,12 +4027,14 @@ }; }; F541495E02711B0001A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = CHImageAdditions.h; path = src/extensions/ImageAdditions.h; refType = 2; }; F541495F02711B0001A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = CHImageAdditions.m; path = src/extensions/ImageAdditions.m; @@ -3744,12 +4083,14 @@ }; }; F549ACDE0302DE6001026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = ToolTip.mm; path = src/browser/ToolTip.mm; refType = 2; }; F549ACDF0302DE6001026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = "NSScreen+Utils.m"; path = "src/extensions/NSScreen+Utils.m"; @@ -3780,6 +4121,7 @@ }; }; F549ACE40302DEBB01026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = "NSScreen+Utils.h"; path = "src/extensions/NSScreen+Utils.h"; @@ -3798,6 +4140,7 @@ }; }; F549ACE70302DEF001026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = ToolTip.h; path = src/browser/ToolTip.h; @@ -4064,12 +4407,14 @@ }; }; F558099D02F22168015DF512 = { + fileEncoding = 30; isa = PBXFileReference; name = "NSString+Utils.h"; path = "src/extensions/NSString+Utils.h"; refType = 2; }; F558099E02F22168015DF512 = { + fileEncoding = 30; isa = PBXFileReference; name = "NSString+Utils.mm"; path = "src/extensions/NSString+Utils.mm"; @@ -4094,12 +4439,14 @@ }; }; F5581379030AEF9B0176F207 = { + fileEncoding = 30; isa = PBXFileReference; name = RemoteDataProvider.h; path = src/browser/RemoteDataProvider.h; refType = 2; }; F558137A030AEF9B0176F207 = { + fileEncoding = 30; isa = PBXFileReference; name = SiteIconProvider.h; path = src/browser/SiteIconProvider.h; @@ -4116,12 +4463,14 @@ refType = 4; }; F558137C030AEF9B0176F207 = { + fileEncoding = 30; isa = PBXFileReference; name = RemoteDataProvider.mm; path = src/browser/RemoteDataProvider.mm; refType = 2; }; F558137D030AEF9B0176F207 = { + fileEncoding = 30; isa = PBXFileReference; name = SiteIconProvider.mm; path = src/browser/SiteIconProvider.mm; @@ -4176,12 +4525,14 @@ }; }; F558B1F0030F6E470166970F = { + fileEncoding = 30; isa = PBXFileReference; name = CHBrowserListener.h; path = src/embedding/CHBrowserListener.h; refType = 2; }; F558B1F1030F6E470166970F = { + fileEncoding = 30; isa = PBXFileReference; name = CHBrowserListener.mm; path = src/embedding/CHBrowserListener.mm; @@ -4305,6 +4656,7 @@ }; }; F55C4DD302D2864D0130B065 = { + fileEncoding = 30; isa = PBXFileReference; name = UserDefaults.h; path = src/application/UserDefaults.h; @@ -4329,12 +4681,14 @@ }; }; F55EBC9A0383665201A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksExport.h; path = src/bookmarks/BookmarksExport.h; refType = 2; }; F55EBC9B0383665201A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksExport.mm; path = src/bookmarks/BookmarksExport.mm; @@ -4365,6 +4719,7 @@ }; }; F5607CB5023944AD01A967DF = { + fileEncoding = 30; isa = PBXFileReference; name = GeckoUtils.h; path = src/extensions/GeckoUtils.h; @@ -4434,12 +4789,14 @@ }; }; F5648739023C3857010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = IconTabViewItem.h; path = src/extensions/IconTabViewItem.h; refType = 2; }; F564873A023C3857010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = IconTabViewItem.mm; path = src/extensions/IconTabViewItem.mm; @@ -4464,6 +4821,7 @@ }; }; F56610A1039474CB01A9666E = { + fileEncoding = 30; isa = PBXFileReference; name = ChimeraVersion.r; path = resources/application/ChimeraVersion.r; @@ -4498,6 +4856,7 @@ F56610A40394767101A9666E = { children = ( F56610BC0394775201A9666E, + A7F01A4803CBBCA500A967F8, ); isa = PBXGroup; name = Plugins; @@ -4544,12 +4903,14 @@ }; }; F566BD1202EFA9AD01A967F3 = { + fileEncoding = 30; isa = PBXFileReference; name = CocoaPromptService.h; path = src/browser/CocoaPromptService.h; refType = 2; }; F566BD1302EFA9AD01A967F3 = { + fileEncoding = 30; isa = PBXFileReference; name = CocoaPromptService.mm; path = src/browser/CocoaPromptService.mm; @@ -4580,6 +4941,7 @@ }; }; F56769FB0208F74A010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = BrowserWindowController.mm; path = src/browser/BrowserWindowController.mm; @@ -4598,12 +4960,14 @@ refType = 2; }; F568C3CF023A4A5A010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = AboutBox.h; path = src/application/AboutBox.h; refType = 2; }; F568C3D0023A4A5A010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = AboutBox.m; path = src/application/AboutBox.m; @@ -4646,6 +5010,7 @@ }; }; F56F241F02AC6D0401A967F3 = { + fileEncoding = 30; isa = PBXFileReference; name = nsStaticComponents.cpp; path = src/application/nsStaticComponents.cpp; @@ -5250,6 +5615,7 @@ target = F5A8CE4702DFF039013CA8EC; }; F56F837202E47CCD01EF35C9 = { + fileEncoding = 30; isa = PBXFileReference; name = RegionNames.strings; path = PreferencePanes/Appearance/English.lproj/RegionNames.strings; @@ -5271,12 +5637,14 @@ }; }; F57074B5026BA85F01A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksToolbar.h; path = src/bookmarks/BookmarksToolbar.h; refType = 2; }; F57074B6026BA85F01A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksToolbar.mm; path = src/bookmarks/BookmarksToolbar.mm; @@ -5295,12 +5663,14 @@ }; }; F57074B9026BFD0101A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksButton.h; path = src/bookmarks/BookmarksButton.h; refType = 2; }; F57074BA026BFD0101A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksButton.mm; path = src/bookmarks/BookmarksButton.mm; @@ -5319,12 +5689,14 @@ }; }; F57074BD026D80DF01A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = LocationBar.h; path = src/browser/LocationBar.h; refType = 2; }; F57074BE026D80DF01A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = LocationBar.mm; path = src/browser/LocationBar.mm; @@ -5354,6 +5726,7 @@ refType = 4; }; F57BED9703A1824001A9666E = { + fileEncoding = 30; isa = PBXFileReference; name = NetworkServices.mm; path = src/rendezvous/NetworkServices.mm; @@ -5372,6 +5745,7 @@ }; }; F57BED9A03A1824801A9666E = { + fileEncoding = 30; isa = PBXFileReference; name = NetworkServices.h; path = src/rendezvous/NetworkServices.h; @@ -5390,12 +5764,14 @@ }; }; F57BED9D03A1825001A9666E = { + fileEncoding = 30; isa = PBXFileReference; name = DNSUtils.c; path = src/rendezvous/DNSUtils.c; refType = 2; }; F57BED9E03A1825001A9666E = { + fileEncoding = 30; isa = PBXFileReference; name = DNSUtils.h; path = src/rendezvous/DNSUtils.h; @@ -5506,7 +5882,6 @@ "; - shouldUseHeadermap = 0; }; F57F205D029997E701000106 = { children = ( @@ -5534,12 +5909,14 @@ refType = 2; }; F57F2060029997E701000106 = { + fileEncoding = 30; isa = PBXFileReference; name = PrivacyPane.h; path = PreferencePanes/Privacy/PrivacyPane.h; refType = 2; }; F57F2061029997E701000106 = { + fileEncoding = 30; isa = PBXFileReference; name = PrivacyPane.mm; path = PreferencePanes/Privacy/PrivacyPane.mm; @@ -5700,12 +6077,14 @@ refType = 4; }; F5807369023A1514010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = SplashScreenWindow.h; path = src/application/SplashScreenWindow.h; refType = 2; }; F580736A023A1514010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = SplashScreenWindow.mm; path = src/application/SplashScreenWindow.mm; @@ -5850,7 +6229,6 @@ "; - shouldUseHeadermap = 0; }; F58581AF022B8D62010001CA = { buildActionMask = 2147483647; @@ -5941,19 +6319,22 @@ F507A84A03116E6E01026D5D, F507A84D03116E7401026D5D, F507A85003116E7901026D5D, - F5C8D55203A2A42401A8016F, + A7AEBED703CB9C2F00A967F8, + A7AEBED903CB9C2F00A967F8, ); isa = PBXGroup; name = Nibs; refType = 4; }; F58DB2D20381FD3301A9666E = { + fileEncoding = 30; isa = PBXFileReference; name = JSConsole.h; path = src/application/JSConsole.h; refType = 2; }; F58DB2D30381FD3301A9666E = { + fileEncoding = 30; isa = PBXFileReference; name = JSConsole.mm; path = src/application/JSConsole.mm; @@ -5984,12 +6365,14 @@ }; }; F59236C002C89AC90100012B = { + fileEncoding = 30; isa = PBXFileReference; name = AppDirServiceProvider.cpp; path = src/application/AppDirServiceProvider.cpp; refType = 2; }; F59236C102C89AC90100012B = { + fileEncoding = 30; isa = PBXFileReference; name = AppDirServiceProvider.h; path = src/application/AppDirServiceProvider.h; @@ -6039,6 +6422,7 @@ refType = 2; }; F5949A47030D58A1014E8430 = { + fileEncoding = 30; isa = PBXFileReference; path = xhtml11.dtd; refType = 4; @@ -6106,6 +6490,7 @@ }; }; F59E9F3D0237E28401A967DF = { + fileEncoding = 30; isa = PBXFileReference; name = ContentClickListener.h; path = src/browser/ContentClickListener.h; @@ -6118,6 +6503,7 @@ }; }; F59E9F3F0237E43401A967DF = { + fileEncoding = 30; isa = PBXFileReference; name = ContentClickListener.mm; path = src/browser/ContentClickListener.mm; @@ -6154,6 +6540,7 @@ }; }; F5A3669302CCFAF601DC3354 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksDataSource.h; path = src/bookmarks/BookmarksDataSource.h; @@ -6176,6 +6563,7 @@ refType = 4; }; F5A3669502CCFAF601DC3354 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksDataSource.mm; path = src/bookmarks/BookmarksDataSource.mm; @@ -6542,12 +6930,14 @@ refType = 4; }; F5A8CE4102DFEF4C013CA8EC = { + fileEncoding = 30; isa = PBXFileReference; name = PreferencePaneBase.h; path = PreferencePanes/Shared/PreferencePaneBase.h; refType = 2; }; F5A8CE4202DFEF4C013CA8EC = { + fileEncoding = 30; isa = PBXFileReference; name = PreferencePaneBase.mm; path = PreferencePanes/Shared/PreferencePaneBase.mm; @@ -6632,7 +7022,6 @@ "; - shouldUseHeadermap = 0; }; F5A8CE4802DFF039013CA8EC = { buildActionMask = 2147483647; @@ -6698,12 +7087,14 @@ refType = 2; }; F5A8CE4E02DFF167013CA8EC = { + fileEncoding = 30; isa = PBXFileReference; name = Appearance.h; path = PreferencePanes/Appearance/Appearance.h; refType = 2; }; F5A8CE4F02DFF167013CA8EC = { + fileEncoding = 30; isa = PBXFileReference; name = Appearance.mm; path = PreferencePanes/Appearance/Appearance.mm; @@ -6782,6 +7173,7 @@ }; }; F5AE04B20206A34801A967DF = { + fileEncoding = 30; isa = PBXFileReference; name = BrowserWindowController.h; path = src/browser/BrowserWindowController.h; @@ -6794,6 +7186,7 @@ }; }; F5AE04B60206A37C01A967DF = { + fileEncoding = 30; isa = PBXFileReference; name = MainController.h; path = src/application/MainController.h; @@ -6806,6 +7199,7 @@ }; }; F5AE04BA0206A4FE01A967DF = { + fileEncoding = 30; isa = PBXFileReference; name = MainController.mm; path = src/application/MainController.mm; @@ -6818,12 +7212,14 @@ }; }; F5B34B01034A505F01A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = "NSPasteboard+Utils.mm"; path = "src/extensions/NSPasteboard+Utils.mm"; refType = 2; }; F5B34B04034A50C901A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = "NSPasteboard+Utils.h"; path = "src/extensions/NSPasteboard+Utils.h"; @@ -6876,10 +7272,12 @@ F5FDF166031AF47301DE816D, F5D98EBC031AC38601A96654, F558099D02F22168015DF512, + A7AEBEC403CB962500A967F8, F549ACE40302DEBB01026D5D, F5B34B04034A50C901A80166, F5648739023C3857010001CA, F5C3AB810270072A01A80166, + A7AEBEDF03CB9CD700A967F8, F541495A02711A8301A80166, F541495E02711B0001A80166, ); @@ -6892,9 +7290,11 @@ F5D98EB9031AC37801A96654, F558099E02F22168015DF512, F549ACDF0302DE6001026D5D, + A7AEBEC703CB964000A967F8, F5B34B01034A505F01A80166, F564873A023C3857010001CA, F5C3AB820270072A01A80166, + A7AEBEE203CB9CEC00A967F8, F541495B02711A8301A80166, F541495F02711B0001A80166, F5FDF167031AF47301DE816D, @@ -6905,12 +7305,14 @@ refType = 4; }; F5B950BC030C83B601A96654 = { + fileEncoding = 30; isa = PBXFileReference; name = BrowserTabViewItem.h; path = src/browser/BrowserTabViewItem.h; refType = 2; }; F5B950BD030C83B601A96654 = { + fileEncoding = 30; isa = PBXFileReference; name = BrowserTabViewItem.mm; path = src/browser/BrowserTabViewItem.mm; @@ -7184,7 +7586,6 @@ "; - shouldUseHeadermap = 0; }; F5BAAB1A02AC45D301A967F3 = { buildActionMask = 2147483647; @@ -7229,7 +7630,6 @@ F50D9DE702ECC36201BB4219, F50D9DE802ECC36201BB4219, F5E37B0C02EE959601A967F3, - F5E37B0D02EE95E201A967F3, F5E37B0E02EE95E201A967F3, F5E37B0F02EE95E201A967F3, F5D33CC202EF61AA01A967F3, @@ -7254,6 +7654,9 @@ F57BEDA203A1825001A9666E, F5C8D55403A2A42401A8016F, F5C8D55703A2A43301A8016F, + A7AEBEC503CB962500A967F8, + A7AEBEE103CB9CD700A967F8, + A7AEBEEA03CB9DFB00A967F8, ); isa = PBXHeadersBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -7343,6 +7746,12 @@ F5566DC9038E075F01A80166, F5566DCA038E075F01A80166, F5566DCB038E075F01A80166, + A7AEBED403CB9BD000A967F8, + A7AEBED503CB9BD000A967F8, + A7AEBED603CB9BD000A967F8, + A7AEBEDD03CB9C2F00A967F8, + A7AEBEDE03CB9C2F00A967F8, + A7F01A4A03CBBCA500A967F8, ); isa = PBXResourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -7389,7 +7798,6 @@ F5A3669B02CCFB7A01DC3354, F5A3669C02CCFB7A01DC3354, F50D9DE902ECC36201BB4219, - F5E37B1002EE95E201A967F3, F5E37B1102EE95E201A967F3, F5E37B1202EE95E201A967F3, F5D33CC302EF61AA01A967F3, @@ -7413,6 +7821,9 @@ F55EBC9F0383665201A80166, F57BED9903A1824001A9666E, F57BEDA103A1825001A9666E, + A7AEBEC803CB964000A967F8, + A7AEBEE403CB9CEC00A967F8, + A7AEBEE703CB9DDF00A967F8, ); isa = PBXSourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -8253,6 +8664,8 @@ F5BAAC0402AC693C01A967F3, F5BAAC0502AC693C01A967F3, F5BAAC0702AC693C01A967F3, + A7AEBEB403CB955700A967F8, + A7AEBECB03CB96E700A967F8, ); isa = PBXCopyFilesBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -8994,12 +9407,14 @@ }; }; F5BF71450231B8BC010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = BrowserTabView.h; path = src/browser/BrowserTabView.h; refType = 2; }; F5BF71460231B8BC010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = BrowserTabView.mm; path = src/browser/BrowserTabView.mm; @@ -9048,12 +9463,14 @@ }; }; F5C3AB810270072A01A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = ExtendedOutlineView.h; path = src/extensions/ExtendedOutlineView.h; refType = 2; }; F5C3AB820270072A01A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = ExtendedOutlineView.mm; path = src/extensions/ExtendedOutlineView.mm; @@ -9072,6 +9489,7 @@ }; }; F5C8D55203A2A42401A8016F = { + fileEncoding = 30; isa = PBXFileReference; name = ChimeraUIConstants.h; path = src/includes/ChimeraUIConstants.h; @@ -9090,6 +9508,7 @@ }; }; F5C8D55503A2A43301A8016F = { + fileEncoding = 30; isa = PBXFileReference; name = ChimeraUIConstants.h; path = src/includes/ChimeraUIConstants.h; @@ -9152,6 +9571,7 @@ refType = 4; }; F5D1421902BC88F801A967F3 = { + fileEncoding = 30; isa = PBXFileReference; name = "redo-prebinding.sh"; path = "src/scripts/redo-prebinding.sh"; @@ -9164,18 +9584,21 @@ }; }; F5D33CBC02EF61A901A967F3 = { + fileEncoding = 30; isa = PBXFileReference; name = SecurityDialogs.h; path = src/browser/SecurityDialogs.h; refType = 2; }; F5D33CBD02EF61A901A967F3 = { + fileEncoding = 30; isa = PBXFileReference; name = AppComponents.mm; path = src/application/AppComponents.mm; refType = 2; }; F5D33CBE02EF61A901A967F3 = { + fileEncoding = 30; isa = PBXFileReference; name = SecurityDialogs.mm; path = src/browser/SecurityDialogs.mm; @@ -9230,6 +9653,7 @@ }; }; F5D98EB9031AC37801A96654 = { + fileEncoding = 30; isa = PBXFileReference; name = "NSBezierPath+Utils.mm"; path = "src/extensions/NSBezierPath+Utils.mm"; @@ -9248,6 +9672,7 @@ }; }; F5D98EBC031AC38601A96654 = { + fileEncoding = 30; isa = PBXFileReference; name = "NSBezierPath+Utils.h"; path = "src/extensions/NSBezierPath+Utils.h"; @@ -9266,6 +9691,7 @@ }; }; F5DA444A027DD5AA01A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = "installed-chrome.txt"; path = "../dist/Embed/chrome/installed-chrome.txt"; @@ -9326,36 +9752,42 @@ }; }; F5DE10E60209DC0601A967DF = { + fileEncoding = 30; isa = PBXFileReference; name = nsAlertController.h; path = src/browser/nsAlertController.h; refType = 2; }; F5DE10E70209DC0601A967DF = { + fileEncoding = 30; isa = PBXFileReference; name = CHBrowserView.h; path = src/embedding/CHBrowserView.h; refType = 2; }; F5DE10E80209DC0601A967DF = { + fileEncoding = 30; isa = PBXFileReference; name = CHBrowserService.h; path = src/embedding/CHBrowserService.h; refType = 2; }; F5DE10E90209DC0601A967DF = { + fileEncoding = 30; isa = PBXFileReference; name = nsAlertController.mm; path = src/browser/nsAlertController.mm; refType = 2; }; F5DE10EA0209DC0601A967DF = { + fileEncoding = 30; isa = PBXFileReference; name = CHBrowserView.mm; path = src/embedding/CHBrowserView.mm; refType = 2; }; F5DE10EB0209DC0601A967DF = { + fileEncoding = 30; isa = PBXFileReference; name = CHBrowserService.mm; path = src/embedding/CHBrowserService.mm; @@ -9403,12 +9835,6 @@ settings = { }; }; - F5E37B0D02EE95E201A967F3 = { - fileRef = F50D9DF102EE194001BB4219; - isa = PBXBuildFile; - settings = { - }; - }; F5E37B0E02EE95E201A967F3 = { fileRef = F50D9DED02EE0AB101BB4219; isa = PBXBuildFile; @@ -9421,12 +9847,6 @@ settings = { }; }; - F5E37B1002EE95E201A967F3 = { - fileRef = F50D9DF202EE194001BB4219; - isa = PBXBuildFile; - settings = { - }; - }; F5E37B1102EE95E201A967F3 = { fileRef = F50D9DEE02EE0AB101BB4219; isa = PBXBuildFile; @@ -9506,6 +9926,7 @@ refType = 2; }; F5F190BB02D1F81A01026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = ToolbarDefaults.plist; path = resources/application/ToolbarDefaults.plist; @@ -9524,6 +9945,7 @@ }; }; F5F190BE02D217C201026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = WebsiteDefaults.strings; path = resources/application/WebsiteDefaults.strings; @@ -9569,12 +9991,14 @@ }; }; F5F94B900332532801026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = KeychainService.h; path = src/browser/KeychainService.h; refType = 4; }; F5F94B910332532801026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = KeychainService.mm; path = src/browser/KeychainService.mm; @@ -9633,6 +10057,7 @@ }; }; F5F9FBD902E13767012B5DB7 = { + fileEncoding = 30; isa = PBXFileReference; name = RegionMapping.plist; path = PreferencePanes/Appearance/RegionMapping.plist; @@ -9669,6 +10094,7 @@ }; }; F5FCDD5D03A035E001A9666E = { + fileEncoding = 30; isa = PBXFileReference; name = Localizable.strings; path = English.lproj/Localizable.strings; @@ -9689,12 +10115,14 @@ }; }; F5FDF166031AF47301DE816D = { + fileEncoding = 30; isa = PBXFileReference; name = DraggableImageAndTextCell.h; path = src/extensions/DraggableImageAndTextCell.h; refType = 4; }; F5FDF167031AF47301DE816D = { + fileEncoding = 30; isa = PBXFileReference; name = DraggableImageAndTextCell.mm; path = src/extensions/DraggableImageAndTextCell.mm; @@ -9747,12 +10175,14 @@ //F63 //F64 F632AF8302B9AEBB01000103 = { + fileEncoding = 30; isa = PBXFileReference; name = BrowserWindow.h; path = src/browser/BrowserWindow.h; refType = 2; }; F632AF8402B9AEBB01000103 = { + fileEncoding = 30; isa = PBXFileReference; name = BrowserWindow.mm; path = src/browser/BrowserWindow.mm; @@ -9771,6 +10201,7 @@ }; }; F6BA6D4E01B2F8A601A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = BrowserWrapper.mm; path = src/browser/BrowserWrapper.mm; @@ -9946,6 +10377,8 @@ F517941F027F3F2901A967DF, F53A902202C1127A01A967F3, 98590B3603A8938A45A2FA2A, + A7AEBEB103CB950400A967F8, + A7AEBECA03CB96D600A967F8, ); isa = PBXGroup; name = "Gecko Components"; @@ -10079,6 +10512,8 @@ F6BD64B601B3167601A962F7, F53A902402C1137901A967F3, 98E1988603A8A6F345B32312, + A7AEBEB303CB954500A967F8, + A7AEBECC03CB96F900A967F8, ); isa = PBXCopyFilesBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -11091,30 +11526,35 @@ runOnlyForDeploymentPostprocessing = 0; }; F6BD64B801B316DA01A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = charsetalias.properties; path = ../dist/Embed/res/charsetalias.properties; refType = 2; }; F6BD64B901B316DA01A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = charsetData.properties; path = ../dist/Embed/res/charsetData.properties; refType = 2; }; F6BD64BA01B316DA01A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = langGroups.properties; path = ../dist/Embed/res/langGroups.properties; refType = 2; }; F6BD64BB01B316DA01A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = language.properties; path = ../dist/Embed/res/language.properties; refType = 2; }; F6BD64BC01B316DA01A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = maccharset.properties; path = ../dist/Embed/res/maccharset.properties; @@ -11167,12 +11607,14 @@ refType = 2; }; F6BD64D301B3172601A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = htmlBindings.xml; path = ../dist/Embed/res/builtin/htmlBindings.xml; refType = 2; }; F6BD64D501B3172601A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = platformHTMLBindings.xml; path = ../dist/Embed/res/builtin/platformHTMLBindings.xml; @@ -11192,30 +11634,35 @@ refType = 2; }; F6BD64D801B3172601A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = html40Latin1.properties; path = ../dist/Embed/res/entityTables/html40Latin1.properties; refType = 2; }; F6BD64D901B3172601A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = html40Special.properties; path = ../dist/Embed/res/entityTables/html40Special.properties; refType = 2; }; F6BD64DA01B3172601A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = html40Symbols.properties; path = ../dist/Embed/res/entityTables/html40Symbols.properties; refType = 2; }; F6BD64DB01B3172601A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = htmlEntityVersions.properties; path = ../dist/Embed/res/entityTables/htmlEntityVersions.properties; refType = 2; }; F6BD64DC01B3172601A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = transliterate.properties; path = ../dist/Embed/res/entityTables/transliterate.properties; diff --git a/camino/PreferencePanes/Appearance/English.lproj/Appearance.nib/info.nib b/camino/PreferencePanes/Appearance/English.lproj/Appearance.nib/info.nib index 7734e3e1f0e..d089e644067 100644 --- a/camino/PreferencePanes/Appearance/English.lproj/Appearance.nib/info.nib +++ b/camino/PreferencePanes/Appearance/English.lproj/Appearance.nib/info.nib @@ -3,7 +3,7 @@ IBDocumentLocation - 646 106 458 263 0 0 1600 1002 + 674 107 458 263 0 0 1600 1002 IBEditorPositions 214 @@ -12,6 +12,6 @@ IBFramework Version 286.0 IBSystem Version - 6D52 + 6G30 diff --git a/camino/PreferencePanes/Appearance/English.lproj/Appearance.nib/objects.nib b/camino/PreferencePanes/Appearance/English.lproj/Appearance.nib/objects.nib index d46732370de..e69de29bb2d 100644 Binary files a/camino/PreferencePanes/Appearance/English.lproj/Appearance.nib/objects.nib and b/camino/PreferencePanes/Appearance/English.lproj/Appearance.nib/objects.nib differ diff --git a/camino/PreferencePanes/Navigation/English.lproj/Navigation.nib/info.nib b/camino/PreferencePanes/Navigation/English.lproj/Navigation.nib/info.nib index 7398ee93826..53d0766d0b8 100644 --- a/camino/PreferencePanes/Navigation/English.lproj/Navigation.nib/info.nib +++ b/camino/PreferencePanes/Navigation/English.lproj/Navigation.nib/info.nib @@ -17,11 +17,7 @@ IBLastGroupID 8 - IBOpenObjects - - 5 - IBSystem Version - 6F21 + 6G30 diff --git a/camino/PreferencePanes/Navigation/English.lproj/Navigation.nib/objects.nib b/camino/PreferencePanes/Navigation/English.lproj/Navigation.nib/objects.nib index 88d9df4efe6..2d20a0a2972 100644 Binary files a/camino/PreferencePanes/Navigation/English.lproj/Navigation.nib/objects.nib and b/camino/PreferencePanes/Navigation/English.lproj/Navigation.nib/objects.nib differ diff --git a/camino/resources/images/app/disclosureArrowDown.tiff b/camino/resources/images/app/disclosureArrowDown.tiff new file mode 100644 index 00000000000..fc9d9ee2497 Binary files /dev/null and b/camino/resources/images/app/disclosureArrowDown.tiff differ diff --git a/camino/resources/images/app/disclosureArrowRight.tiff b/camino/resources/images/app/disclosureArrowRight.tiff new file mode 100644 index 00000000000..95b3152ad82 Binary files /dev/null and b/camino/resources/images/app/disclosureArrowRight.tiff differ diff --git a/camino/resources/images/app/small_close.tiff b/camino/resources/images/app/small_close.tiff new file mode 100644 index 00000000000..e69de29bb2d diff --git a/camino/resources/localized/English.lproj/BrowserWindow.nib/classes.nib b/camino/resources/localized/English.lproj/BrowserWindow.nib/classes.nib index 8d9ef756813..8cb98c23986 100644 --- a/camino/resources/localized/English.lproj/BrowserWindow.nib/classes.nib +++ b/camino/resources/localized/English.lproj/BrowserWindow.nib/classes.nib @@ -68,6 +68,7 @@ closeCurrentTab = id; closeOtherTabs = id; closeSendersTab = id; + copyImage = id; copyImageLocation = id; copyLinkLocation = id; endAddBookmarkSheet = id; @@ -80,6 +81,7 @@ goToLocationFromToolbarURLField = id; home = id; manageBookmarks = id; + manageHistory = id; moveTabToNewWindow = id; newTab = id; nextTab = id; diff --git a/camino/resources/localized/English.lproj/BrowserWindow.nib/info.nib b/camino/resources/localized/English.lproj/BrowserWindow.nib/info.nib index ae6ff6280c5..2647aded841 100644 --- a/camino/resources/localized/English.lproj/BrowserWindow.nib/info.nib +++ b/camino/resources/localized/English.lproj/BrowserWindow.nib/info.nib @@ -3,7 +3,7 @@ IBDocumentLocation - 66 21 653 383 0 0 1152 848 + 65 36 653 383 0 0 1152 848 IBEditorPositions 124 @@ -15,17 +15,17 @@ 297 107 466 213 294 0 0 1600 1002 314 - 73 542 213 132 0 0 1600 1002 + 72 544 213 150 0 0 1600 1002 336 486 756 213 180 0 0 1600 1002 365 31 719 93 162 0 0 1600 1002 463 - 97 693 213 246 0 0 1600 1002 + 349 487 213 246 0 0 1600 1002 56 450 634 343 68 0 0 1280 1002 654 - 206 785 198 144 0 0 1600 1002 + 140 644 198 144 0 0 1152 848 IBFramework Version 286.0 @@ -42,6 +42,6 @@ IBLockedObjects IBSystem Version - 6F21 + 6G30 diff --git a/camino/resources/localized/English.lproj/BrowserWindow.nib/objects.nib b/camino/resources/localized/English.lproj/BrowserWindow.nib/objects.nib index 6ea50d4bb91..3a5bafda905 100644 Binary files a/camino/resources/localized/English.lproj/BrowserWindow.nib/objects.nib and b/camino/resources/localized/English.lproj/BrowserWindow.nib/objects.nib differ diff --git a/camino/resources/localized/English.lproj/Keychain.nib/classes.nib b/camino/resources/localized/English.lproj/Keychain.nib/classes.nib new file mode 100644 index 00000000000..97ccf33479a --- /dev/null +++ b/camino/resources/localized/English.lproj/Keychain.nib/classes.nib @@ -0,0 +1,14 @@ +{ + IBClasses = ( + {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, + {CLASS = KeychainBrowserListener; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, + { + ACTIONS = {hitButtonCancel = id; hitButtonOK = id; hitButtonOther = id; shutdown = id; }; + CLASS = KeychainService; + LANGUAGE = ObjC; + OUTLETS = {confirmChangePasswordPanel = id; confirmStorePasswordPanel = id; }; + SUPERCLASS = NSObject; + } + ); + IBVersion = 1; +} \ No newline at end of file diff --git a/camino/resources/localized/English.lproj/Keychain.nib/info.nib b/camino/resources/localized/English.lproj/Keychain.nib/info.nib new file mode 100644 index 00000000000..49f51184364 --- /dev/null +++ b/camino/resources/localized/English.lproj/Keychain.nib/info.nib @@ -0,0 +1,12 @@ + + + + + IBDocumentLocation + 240 146 356 240 0 0 1024 746 + IBFramework Version + 283.0 + IBSystem Version + 6F21 + + diff --git a/camino/resources/localized/English.lproj/Keychain.nib/objects.nib b/camino/resources/localized/English.lproj/Keychain.nib/objects.nib new file mode 100644 index 00000000000..e69de29bb2d diff --git a/camino/resources/localized/English.lproj/Localizable.strings b/camino/resources/localized/English.lproj/Localizable.strings index 6e0da7d528a..da2b9bebce2 100644 Binary files a/camino/resources/localized/English.lproj/Localizable.strings and b/camino/resources/localized/English.lproj/Localizable.strings differ diff --git a/camino/resources/localized/English.lproj/MainMenu.nib/classes.nib b/camino/resources/localized/English.lproj/MainMenu.nib/classes.nib index c8aaad9c499..a761cf8ecf8 100644 --- a/camino/resources/localized/English.lproj/MainMenu.nib/classes.nib +++ b/camino/resources/localized/English.lproj/MainMenu.nib/classes.nib @@ -20,6 +20,7 @@ doReload = id; doSearch = id; doStop = id; + downloadsWindow = id; exportBookmarks = id; feedbackLink = id; findAgain = id; @@ -61,7 +62,6 @@ mCreateBookmarksFolderMenuItem = NSMenuItem; mCreateBookmarksSeparatorMenuItem = NSMenuItem; mDockMenu = NSMenu; - mFilterList = NSPopUpButton; mFilterView = NSView; mGoMenu = NSMenu; mServersSubmenu = NSMenu; diff --git a/camino/resources/localized/English.lproj/MainMenu.nib/info.nib b/camino/resources/localized/English.lproj/MainMenu.nib/info.nib index 94276bd1461..515b3050c62 100644 --- a/camino/resources/localized/English.lproj/MainMenu.nib/info.nib +++ b/camino/resources/localized/English.lproj/MainMenu.nib/info.nib @@ -3,11 +3,11 @@ IBDocumentLocation - 237 33 482 372 0 0 1600 1002 + 105 33 482 372 0 0 1600 1002 IBEditorPositions 266 - 437 533 277 90 0 0 1152 848 + 644 623 277 90 0 0 1600 1002 29 11 957 446 44 0 0 1600 1002 494 @@ -31,7 +31,11 @@ IBLastGroupID 2 + IBOpenObjects + + 29 + IBSystem Version - 6F21 + 6G30 diff --git a/camino/resources/localized/English.lproj/MainMenu.nib/objects.nib b/camino/resources/localized/English.lproj/MainMenu.nib/objects.nib index 639e9548c05..9f05349791e 100644 Binary files a/camino/resources/localized/English.lproj/MainMenu.nib/objects.nib and b/camino/resources/localized/English.lproj/MainMenu.nib/objects.nib differ diff --git a/camino/resources/localized/English.lproj/ProgressDialog.nib/classes.nib b/camino/resources/localized/English.lproj/ProgressDialog.nib/classes.nib index fc624beb9c0..974a86d8f0c 100644 --- a/camino/resources/localized/English.lproj/ProgressDialog.nib/classes.nib +++ b/camino/resources/localized/English.lproj/ProgressDialog.nib/classes.nib @@ -1,18 +1,40 @@ { IBClasses = ( + { + CLASS = CHStackView; + LANGUAGE = ObjC; + OUTLETS = {mDataSource = id; }; + SUPERCLASS = NSView; + }, {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, + {CLASS = NSObject; LANGUAGE = ObjC; }, + {CLASS = NSView; LANGUAGE = ObjC; SUPERCLASS = NSResponder; }, { CLASS = ProgressDlgController; LANGUAGE = ObjC; OUTLETS = { - mElapsedTimeLabel = NSTextField; - mFromField = NSTextField; - mProgressBar = NSProgressIndicator; - mStatusLabel = NSTextField; - mTimeLeftLabel = NSTextField; - mToField = NSTextField; + mNoDownloadsText = NSTextField; + mScrollView = NSScrollView; + mStackView = CHStackView; }; SUPERCLASS = NSWindowController; + }, + { + ACTIONS = {stop = id; toggleDisclosure = id; }; + CLASS = ProgressViewController; + LANGUAGE = ObjC; + OUTLETS = { + mLocationsLabel = NSTextField; + mLocationsLabelCompact = NSTextField; + mProgressBar = NSProgressIndicator; + mProgressView = NSView; + mProgressViewCompact = NSView; + mServerLabel = NSTextField; + mStatusLabel = NSTextField; + mTimeLeftLabel = NSTextField; + mTimeLeftLabelCompact = NSTextField; + }; + SUPERCLASS = NSObject; } ); IBVersion = 1; diff --git a/camino/resources/localized/English.lproj/ProgressDialog.nib/info.nib b/camino/resources/localized/English.lproj/ProgressDialog.nib/info.nib index 0369fa65250..7285b197eda 100644 --- a/camino/resources/localized/English.lproj/ProgressDialog.nib/info.nib +++ b/camino/resources/localized/English.lproj/ProgressDialog.nib/info.nib @@ -1,12 +1,12 @@ - - + + IBDocumentLocation - 94 26 404 250 0 0 1152 746 + 24 42 592 284 0 0 1600 1002 IBFramework Version - 248.0 + 286.0 IBSystem Version - 5S60 + 6G30 diff --git a/camino/resources/localized/English.lproj/ProgressDialog.nib/objects.nib b/camino/resources/localized/English.lproj/ProgressDialog.nib/objects.nib index 6377ab6fd19..7e7c0487fc1 100644 Binary files a/camino/resources/localized/English.lproj/ProgressDialog.nib/objects.nib and b/camino/resources/localized/English.lproj/ProgressDialog.nib/objects.nib differ diff --git a/camino/resources/localized/English.lproj/ProgressView.nib/classes.nib b/camino/resources/localized/English.lproj/ProgressView.nib/classes.nib new file mode 100644 index 00000000000..522eba2b2ba --- /dev/null +++ b/camino/resources/localized/English.lproj/ProgressView.nib/classes.nib @@ -0,0 +1,22 @@ +{ + IBClasses = ( + {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, + { + ACTIONS = {close = id; open = id; reveal = id; stop = id; toggleDisclosure = id; }; + CLASS = ProgressViewController; + LANGUAGE = ObjC; + OUTLETS = { + mCompletedView = NSView; + mCompletedViewCompact = NSView; + mExpandedCancelButton = NSButton; + mExpandedOpenButton = NSButton; + mExpandedRevealButton = NSButton; + mProgressBar = NSProgressIndicator; + mProgressView = NSView; + mProgressViewCompact = NSView; + }; + SUPERCLASS = NSObject; + } + ); + IBVersion = 1; +} \ No newline at end of file diff --git a/camino/resources/localized/English.lproj/ProgressView.nib/info.nib b/camino/resources/localized/English.lproj/ProgressView.nib/info.nib new file mode 100644 index 00000000000..3d1f97eeb8b --- /dev/null +++ b/camino/resources/localized/English.lproj/ProgressView.nib/info.nib @@ -0,0 +1,27 @@ + + + + + IBDocumentLocation + 75 299 448 284 0 0 1600 1002 + IBEditorPositions + + 27 + 573 628 420 80 0 0 1600 1002 + 5 + 573 564 420 208 0 0 1600 1002 + 71 + 573 564 420 208 0 0 1600 1002 + 97 + 573 628 420 80 0 0 1600 1002 + + IBFramework Version + 286.0 + IBOpenObjects + + 5 + + IBSystem Version + 6G30 + + diff --git a/camino/resources/localized/English.lproj/ProgressView.nib/objects.nib b/camino/resources/localized/English.lproj/ProgressView.nib/objects.nib new file mode 100644 index 00000000000..3484f9a67df Binary files /dev/null and b/camino/resources/localized/English.lproj/ProgressView.nib/objects.nib differ diff --git a/camino/resources/localized/English.lproj/alert.nib/info.nib b/camino/resources/localized/English.lproj/alert.nib/info.nib index 1f32d25ff16..f8aa8787f47 100644 --- a/camino/resources/localized/English.lproj/alert.nib/info.nib +++ b/camino/resources/localized/English.lproj/alert.nib/info.nib @@ -3,13 +3,9 @@ IBDocumentLocation - 410 67 356 301 0 0 1152 848 + 325 55 356 301 0 0 1024 746 IBFramework Version - 286.0 - IBOpenObjects - - 251 - + 283.0 IBSystem Version 6F21 diff --git a/camino/resources/localized/English.lproj/alert.nib/objects.nib b/camino/resources/localized/English.lproj/alert.nib/objects.nib index 6a8f50daa6c..e69de29bb2d 100644 Binary files a/camino/resources/localized/English.lproj/alert.nib/objects.nib and b/camino/resources/localized/English.lproj/alert.nib/objects.nib differ diff --git a/camino/src/application/AppComponents.mm b/camino/src/application/AppComponents.mm index ebe8a06c200..d8cf7b31b10 100644 --- a/camino/src/application/AppComponents.mm +++ b/camino/src/application/AppComponents.mm @@ -37,10 +37,14 @@ * ***** END LICENSE BLOCK ***** */ #import + #import "SecurityDialogs.h" #import "CocoaPromptService.h" -#include "nsIGenericFactory.h" #import "KeychainService.h" +#import "nsDownloadListener.h" +#import "ProgressDlgController.h" + +#include "nsIGenericFactory.h" // {0ffd3880-7a1a-11d6-a384-975d1d5f86fc} #define NS_SECURITYDIALOGS_CID \ @@ -55,6 +59,27 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(SecurityDialogs); NS_GENERIC_FACTORY_CONSTRUCTOR(CocoaPromptService); NS_GENERIC_FACTORY_CONSTRUCTOR(KeychainPrompt); +//NS_GENERIC_FACTORY_CONSTRUCTOR(nsDownloadListener); + +static NS_IMETHODIMP +nsDownloadListenerConstructor(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + *aResult = NULL; + if (aOuter) + return NS_ERROR_NO_AGGREGATION; + + nsDownloadListener* inst; + NS_NEWXPCOM(inst, nsDownloadListener); + if (!inst) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(inst); + inst->SetDisplayFactory([ProgressDlgController sharedDownloadController]); + nsresult rv = inst->QueryInterface(aIID, aResult); + NS_RELEASE(inst); + return rv; +} + // used by MainController to register the components in which we want to override // with the Gecko embed layer. @@ -83,6 +108,12 @@ static const nsModuleComponentInfo gAppComponents[] = { NS_KEYCHAINPROMPT_CID, "@mozilla.org/wallet/single-sign-on-prompt;1", KeychainPromptConstructor + }, + { + "Download", + NS_DOWNLOAD_CID, + NS_DOWNLOAD_CONTRACTID, + nsDownloadListenerConstructor } }; diff --git a/camino/src/application/MainController.h b/camino/src/application/MainController.h index 2bf9fb1ce2b..33edbca4a3d 100644 --- a/camino/src/application/MainController.h +++ b/camino/src/application/MainController.h @@ -52,9 +52,8 @@ { IBOutlet NSApplication* mApplication; - // The following two items are used by the filter list when saving files. + // The following item is added to NSSavePanels as an accessory view IBOutlet NSView* mFilterView; - IBOutlet NSPopUpButton* mFilterList; // IBOutlet NSMenuItem* mOfflineMenuItem; IBOutlet NSMenuItem* mCloseWindowMenuItem; @@ -137,11 +136,12 @@ -(IBAction) addFolder:(id)aSender; -(IBAction) addSeparator:(id)aSender; -//Window menu actions +// Window menu actions -(IBAction) newTab:(id)aSender; -(IBAction) closeTab:(id)aSender; +-(IBAction) downloadsWindow:(id)aSender; -//Help menu actions +// Help menu actions -(IBAction) infoLink:(id)aSender; -(IBAction) feedbackLink:(id)aSender; @@ -154,7 +154,8 @@ - (void)adjustBookmarksMenuItemsEnabling:(BOOL)inBrowserWindowFrontmost; --(NSWindow*)getFrontmostBrowserWindow; +- (NSView*)getSavePanelView; +- (NSWindow*)getFrontmostBrowserWindow; - (MVPreferencesController *)preferencesController; - (void)displayPreferencesWindow:sender; diff --git a/camino/src/application/MainController.mm b/camino/src/application/MainController.mm index 9ef0177d9bf..e200d2f2e43 100644 --- a/camino/src/application/MainController.mm +++ b/camino/src/application/MainController.mm @@ -260,19 +260,7 @@ const int kReuseWindowOnAE = 2; - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { - if ([ProgressDlgController numDownloadInProgress] > 0) - { - NSString *alert = NSLocalizedString(@"QuitWithDownloadsMsg", @"Really Quit?"); - NSString *message = NSLocalizedString(@"QuitWithDownloadsExpl", @""); - NSString *okButton = NSLocalizedString(@"QuitWithdownloadsButtonDefault",@"Cancel"); - NSString *altButton = NSLocalizedString(@"QuitWithdownloadsButtonAlt",@"Quit"); - // while the panel is up, download dialogs won't update (no timers firing) but - // downloads continue (PLEvents being processed) - if (NSRunAlertPanel(alert, message, okButton, altButton, nil) == NSAlertDefaultReturn) - return NSTerminateCancel; - } - - return NSTerminateNow; + return [[ProgressDlgController sharedDownloadController] allowTerminate]; } -(void)applicationWillTerminate: (NSNotification*)aNotification @@ -439,7 +427,7 @@ const int kReuseWindowOnAE = 2; { BrowserWindowController* browserController = [self getMainWindowBrowserController]; if (browserController) - [browserController saveDocument:NO filterView:mFilterView filterList: mFilterList]; + [browserController saveDocument:NO filterView:mFilterView]; } -(IBAction) pageSetup:(id)aSender @@ -584,6 +572,11 @@ const int kReuseWindowOnAE = 2; } } +-(IBAction) downloadsWindow:(id)aSender +{ + [[ProgressDlgController sharedDownloadController] showWindow:aSender]; +} + - (void)adjustBookmarksMenuItemsEnabling:(BOOL)inBrowserWindowFrontmost; { [mAddBookmarkMenuItem setEnabled:inBrowserWindowFrontmost]; @@ -591,6 +584,11 @@ const int kReuseWindowOnAE = 2; [mCreateBookmarksSeparatorMenuItem setEnabled:NO]; // separators are not implemented yet } +- (NSView*)getSavePanelView +{ + return mFilterView; +} + -(NSWindow*)getFrontmostBrowserWindow { // for some reason, [NSApp mainWindow] doesn't always work, so we have to diff --git a/camino/src/application/nsStaticComponents.cpp b/camino/src/application/nsStaticComponents.cpp index 1065d7b5ed2..849cbfddf5d 100644 --- a/camino/src/application/nsStaticComponents.cpp +++ b/camino/src/application/nsStaticComponents.cpp @@ -47,7 +47,58 @@ NSGETMODULE(_name) (nsIComponentManager* aCompMgr, \ } // NSGetModule entry points -DECL_NSGETMODULE(UcharUtil) DECL_NSGETMODULE(nsUConvModule) DECL_NSGETMODULE(nsUCvJAModule) DECL_NSGETMODULE(nsUCvCnModule) DECL_NSGETMODULE(nsUCvLatinModule) DECL_NSGETMODULE(nsUCvTWModule) DECL_NSGETMODULE(nsUCvTW2Module) DECL_NSGETMODULE(nsUCvKoModule) DECL_NSGETMODULE(nsLocaleModule) DECL_NSGETMODULE(nsStringBundleModule) DECL_NSGETMODULE(nsLWBrkModule) DECL_NSGETMODULE(nsCharDetModule) DECL_NSGETMODULE(xpconnect) DECL_NSGETMODULE(cacheservice) DECL_NSGETMODULE(necko_core_and_primary_protocols) DECL_NSGETMODULE(necko_secondary_protocols) DECL_NSGETMODULE(nsURILoaderModule) DECL_NSGETMODULE(nsPrefModule) DECL_NSGETMODULE(nsCJVMManagerModule) DECL_NSGETMODULE(nsSecurityManagerModule) DECL_NSGETMODULE(nsChromeModule) DECL_NSGETMODULE(nsRDFModule) DECL_NSGETMODULE(nsParserModule) DECL_NSGETMODULE(nsGfxMacModule) DECL_NSGETMODULE(nsGfx2Module) DECL_NSGETMODULE(nsImageLib2Module) DECL_NSGETMODULE(nsPNGDecoderModule) DECL_NSGETMODULE(nsGIFModule2) DECL_NSGETMODULE(nsJPEGDecoderModule) DECL_NSGETMODULE(nsPluginModule) DECL_NSGETMODULE(javascript__protocol) DECL_NSGETMODULE(DOM_components) DECL_NSGETMODULE(nsViewModule) DECL_NSGETMODULE(nsWidgetMacModule) DECL_NSGETMODULE(nsContentModule) DECL_NSGETMODULE(nsLayoutModule) DECL_NSGETMODULE(nsMorkModule) DECL_NSGETMODULE(docshell_provider) DECL_NSGETMODULE(embedcomponents) DECL_NSGETMODULE(Browser_Embedding_Module) DECL_NSGETMODULE(nsEditorModule) DECL_NSGETMODULE(nsTransactionManagerModule) DECL_NSGETMODULE(nsTextServicesModule) DECL_NSGETMODULE(nsProfileModule) DECL_NSGETMODULE(Session_History_Module) DECL_NSGETMODULE(application) DECL_NSGETMODULE(nsCookieModule) DECL_NSGETMODULE(nsXMLExtrasModule) DECL_NSGETMODULE(nsUniversalCharDetModule) DECL_NSGETMODULE(BOOT) DECL_NSGETMODULE(NSS) +DECL_NSGETMODULE(UcharUtil) +DECL_NSGETMODULE(nsUConvModule) +DECL_NSGETMODULE(nsUCvJAModule) +DECL_NSGETMODULE(nsUCvCnModule) +DECL_NSGETMODULE(nsUCvLatinModule) +DECL_NSGETMODULE(nsUCvTWModule) +DECL_NSGETMODULE(nsUCvTW2Module) +DECL_NSGETMODULE(nsUCvKoModule) +DECL_NSGETMODULE(nsLocaleModule) +DECL_NSGETMODULE(nsStringBundleModule) +DECL_NSGETMODULE(nsLWBrkModule) +DECL_NSGETMODULE(nsCharDetModule) +DECL_NSGETMODULE(xpconnect) +DECL_NSGETMODULE(cacheservice) +DECL_NSGETMODULE(necko_core_and_primary_protocols) +DECL_NSGETMODULE(necko_secondary_protocols) +DECL_NSGETMODULE(nsURILoaderModule) +DECL_NSGETMODULE(nsPrefModule) +DECL_NSGETMODULE(nsCJVMManagerModule) +DECL_NSGETMODULE(nsSecurityManagerModule) +DECL_NSGETMODULE(nsChromeModule) +DECL_NSGETMODULE(nsRDFModule) +DECL_NSGETMODULE(nsParserModule) +DECL_NSGETMODULE(nsGfxMacModule) +DECL_NSGETMODULE(nsGfx2Module) +DECL_NSGETMODULE(nsImageLib2Module) +DECL_NSGETMODULE(nsPNGDecoderModule) +DECL_NSGETMODULE(nsGIFModule2) +DECL_NSGETMODULE(nsJPEGDecoderModule) +DECL_NSGETMODULE(nsPluginModule) +DECL_NSGETMODULE(javascript__protocol) +DECL_NSGETMODULE(JS_component_loader) +DECL_NSGETMODULE(DOM_components) +DECL_NSGETMODULE(nsViewModule) +DECL_NSGETMODULE(nsWidgetMacModule) +DECL_NSGETMODULE(nsContentModule) +DECL_NSGETMODULE(nsLayoutModule) +DECL_NSGETMODULE(nsMorkModule) +DECL_NSGETMODULE(docshell_provider) +DECL_NSGETMODULE(embedcomponents) +DECL_NSGETMODULE(Browser_Embedding_Module) +DECL_NSGETMODULE(nsEditorModule) +DECL_NSGETMODULE(nsTransactionManagerModule) +DECL_NSGETMODULE(nsTextServicesModule) +DECL_NSGETMODULE(nsProfileModule) +DECL_NSGETMODULE(Session_History_Module) +DECL_NSGETMODULE(application) +DECL_NSGETMODULE(nsCookieModule) +DECL_NSGETMODULE(nsXMLExtrasModule) +DECL_NSGETMODULE(nsUniversalCharDetModule) +DECL_NSGETMODULE(BOOT) +DECL_NSGETMODULE(NSS) #line 52 "nsStaticComponents.cpp.in" /** @@ -55,7 +106,58 @@ DECL_NSGETMODULE(UcharUtil) DECL_NSGETMODULE(nsUConvModule) DECL_NSGETMODULE(nsU */ static nsStaticModuleInfo gStaticModuleInfo[] = { #define MODULE(_name) { (#_name), NSGETMODULE(_name) } - MODULE(UcharUtil), MODULE(nsUConvModule), MODULE(nsUCvJAModule), MODULE(nsUCvCnModule), MODULE(nsUCvLatinModule), MODULE(nsUCvTWModule), MODULE(nsUCvTW2Module), MODULE(nsUCvKoModule), MODULE(nsLocaleModule), MODULE(nsStringBundleModule), MODULE(nsLWBrkModule), MODULE(nsCharDetModule), MODULE(xpconnect), MODULE(cacheservice), MODULE(necko_core_and_primary_protocols), MODULE(necko_secondary_protocols), MODULE(nsURILoaderModule), MODULE(nsPrefModule), MODULE(nsCJVMManagerModule), MODULE(nsSecurityManagerModule), MODULE(nsChromeModule), MODULE(nsRDFModule), MODULE(nsParserModule), MODULE(nsGfxMacModule), MODULE(nsGfx2Module), MODULE(nsImageLib2Module), MODULE(nsPNGDecoderModule), MODULE(nsGIFModule2), MODULE(nsJPEGDecoderModule), MODULE(nsPluginModule), MODULE(javascript__protocol), MODULE(DOM_components), MODULE(nsViewModule), MODULE(nsWidgetMacModule), MODULE(nsContentModule), MODULE(nsLayoutModule), MODULE(nsMorkModule), MODULE(docshell_provider), MODULE(embedcomponents), MODULE(Browser_Embedding_Module), MODULE(nsEditorModule), MODULE(nsTransactionManagerModule), MODULE(nsTextServicesModule), MODULE(nsProfileModule), MODULE(Session_History_Module), MODULE(application), MODULE(nsCookieModule), MODULE(nsXMLExtrasModule), MODULE(nsUniversalCharDetModule), MODULE(BOOT), MODULE(NSS), +MODULE(UcharUtil), +MODULE(nsUConvModule), +MODULE(nsUCvJAModule), +MODULE(nsUCvCnModule), +MODULE(nsUCvLatinModule), +MODULE(nsUCvTWModule), +MODULE(nsUCvTW2Module), +MODULE(nsUCvKoModule), +MODULE(nsLocaleModule), +MODULE(nsStringBundleModule), +MODULE(nsLWBrkModule), +MODULE(nsCharDetModule), +MODULE(xpconnect), +MODULE(cacheservice), +MODULE(necko_core_and_primary_protocols), +MODULE(necko_secondary_protocols), +MODULE(nsURILoaderModule), +MODULE(nsPrefModule), +MODULE(nsCJVMManagerModule), +MODULE(nsSecurityManagerModule), +MODULE(nsChromeModule), +MODULE(nsRDFModule), +MODULE(nsParserModule), +MODULE(nsGfxMacModule), +MODULE(nsGfx2Module), +MODULE(nsImageLib2Module), +MODULE(nsPNGDecoderModule), +MODULE(nsGIFModule2), +MODULE(nsJPEGDecoderModule), +MODULE(nsPluginModule), +MODULE(javascript__protocol), +MODULE(JS_component_loader), +MODULE(DOM_components), +MODULE(nsViewModule), +MODULE(nsWidgetMacModule), +MODULE(nsContentModule), +MODULE(nsLayoutModule), +MODULE(nsMorkModule), +MODULE(docshell_provider), +MODULE(embedcomponents), +MODULE(Browser_Embedding_Module), +MODULE(nsEditorModule), +MODULE(nsTransactionManagerModule), +MODULE(nsTextServicesModule), +MODULE(nsProfileModule), +MODULE(Session_History_Module), +MODULE(application), +MODULE(nsCookieModule), +MODULE(nsXMLExtrasModule), +MODULE(nsUniversalCharDetModule), +MODULE(BOOT), +MODULE(NSS), #line 60 "nsStaticComponents.cpp.in" }; diff --git a/camino/src/bookmarks/BookmarksDataSource.mm b/camino/src/bookmarks/BookmarksDataSource.mm index de6cf71b6ac..7d2eaa84935 100644 --- a/camino/src/bookmarks/BookmarksDataSource.mm +++ b/camino/src/bookmarks/BookmarksDataSource.mm @@ -601,7 +601,7 @@ const int kBookmarksRootItemTag = -2; //Set cell's textual contents //[cellValue replaceCharactersInRange:NSMakeRange(0, [cellValue length]) withString:[NSString stringWith_nsAString: nameAttr]]; - cellValue = [[NSMutableAttributedString alloc] initWithString:[NSString stringWith_nsAString: nameAttr]]; + cellValue = [[[NSMutableAttributedString alloc] initWithString:[NSString stringWith_nsAString: nameAttr]] autorelease]; //Create an attributed string to hold the empty attachment, then release the components. NSMutableAttributedString* attachmentAttrString = [NSMutableAttributedString attributedStringWithAttachment:textAttachment]; diff --git a/camino/src/browser/BrowserTabView.mm b/camino/src/browser/BrowserTabView.mm index f215b134dbe..a40bfd8ce33 100644 --- a/camino/src/browser/BrowserTabView.mm +++ b/camino/src/browser/BrowserTabView.mm @@ -100,6 +100,7 @@ - (BOOL)isOpaque { + // see http://developer.apple.com/qa/qa2001/qa1117.html if ( ([self tabViewType] == NSNoTabsBezelBorder) && (NSAppKitVersionNumber < 633) ) return NO; diff --git a/camino/src/browser/BrowserWindow.mm b/camino/src/browser/BrowserWindow.mm index 68592f4ae3a..faf2ff36dc8 100644 --- a/camino/src/browser/BrowserWindow.mm +++ b/camino/src/browser/BrowserWindow.mm @@ -54,6 +54,8 @@ static const int kEscapeKeyCode = 53; BOOL madeFirstResponder = [super makeFirstResponder:responder]; if (madeFirstResponder && oldResponder != [self firstResponder]) [(BrowserWindowController*)[self delegate] focusChangedFrom:oldResponder to:[self firstResponder]]; + + //NSLog(@"Old FR %@, new FR %@, responder %@, made %d", oldResponder, [self firstResponder], responder, madeFirstResponder); return madeFirstResponder; } diff --git a/camino/src/browser/BrowserWindowController.h b/camino/src/browser/BrowserWindowController.h index eb6789343dd..063a881b02a 100644 --- a/camino/src/browser/BrowserWindowController.h +++ b/camino/src/browser/BrowserWindowController.h @@ -109,12 +109,12 @@ typedef enum IBOutlet NSTextField* mLocationSheetURLField; IBOutlet NSView* mStatusBar; // contains the status text, progress bar, and lock IBOutlet PageProxyIcon* mProxyIcon; - IBOutlet BrowserContentView* mContentView; + IBOutlet BrowserContentView* mContentView; IBOutlet BookmarksDataSource* mSidebarBookmarksDataSource; - IBOutlet HistoryDataSource* mHistoryDataSource; + IBOutlet HistoryDataSource* mHistoryDataSource; - IBOutlet BookmarksToolbar* mPersonalToolbar; + IBOutlet BookmarksToolbar* mPersonalToolbar; IBOutlet NSWindow* mAddBookmarkSheetWindow; IBOutlet NSTextField* mAddBookmarkTitleField; @@ -191,6 +191,8 @@ typedef enum - (void)updateLocationFields:(NSString *)locationString; - (void)updateSiteIcons:(NSImage *)siteIconImage; - (void)updateToolbarItems; +- (void)loadingStarted; +- (void)loadingDone; - (void)focusURLBar; // call to update the image of the lock icon with a value from nsIWebProgressListener @@ -211,9 +213,9 @@ typedef enum - (IBAction)viewSource:(id)aSender; // focussed frame or page - (IBAction)viewPageSource:(id)aSender; // top-level page -- (void)saveDocument:(BOOL)focusedFrame filterView:(NSView*)aFilterView filterList: (NSPopUpButton*)aFilterList; -- (void)saveURL: (NSView*)aFilterView filterList: (NSPopUpButton*)aFilterList - url: (NSString*)aURLSpec suggestedFilename: (NSString*)aFilename; +- (void)saveDocument:(BOOL)focusedFrame filterView:(NSView*)aFilterView; +- (void)saveURL:(NSView*)aFilterView url: (NSString*)aURLSpec suggestedFilename: (NSString*)aFilename; + - (IBAction)printDocument:(id)aSender; - (IBAction)pageSetup:(id)aSender; - (IBAction)performSearch:(id)aSender; @@ -302,6 +304,7 @@ typedef enum - (IBAction)bookmarkLink: (id)aSender; - (IBAction)copyLinkLocation:(id)aSender; +- (IBAction)copyImage:(id)sender; - (IBAction)copyImageLocation:(id)sender; - (BookmarksToolbar*) bookmarksToolbar; diff --git a/camino/src/browser/BrowserWindowController.mm b/camino/src/browser/BrowserWindowController.mm index 979a03ef020..c36add4099a 100644 --- a/camino/src/browser/BrowserWindowController.mm +++ b/camino/src/browser/BrowserWindowController.mm @@ -816,6 +816,19 @@ static NSArray* sToolbarDefaults = nil; else return YES; } + +- (void)loadingStarted +{ + [self updateToolbarItems]; + [self startThrobber]; +} + +- (void)loadingDone +{ + [self updateToolbarItems]; + [self stopThrobber]; + [mHistoryDataSource refresh]; +} - (void)updateToolbarItems { @@ -960,16 +973,14 @@ static NSArray* sToolbarDefaults = nil; } } -- (void)saveDocument:(BOOL)focusedFrame filterView:(NSView*)aFilterView filterList: (NSPopUpButton*)aFilterList +- (void)saveDocument:(BOOL)focusedFrame filterView:(NSView*)aFilterView { - [[mBrowserView getBrowserView] saveDocument:focusedFrame filterView:aFilterView filterList:aFilterList]; + [[mBrowserView getBrowserView] saveDocument:focusedFrame filterView:aFilterView]; } -- (void)saveURL: (NSView*)aFilterView filterList: (NSPopUpButton*)aFilterList - url: (NSString*)aURLSpec suggestedFilename: (NSString*)aFilename +- (void)saveURL: (NSView*)aFilterView url: (NSString*)aURLSpec suggestedFilename: (NSString*)aFilename { - [[mBrowserView getBrowserView] saveURL: aFilterView filterList: aFilterList - url: aURLSpec suggestedFilename: aFilename]; + [[mBrowserView getBrowserView] saveURL: aFilterView url: aURLSpec suggestedFilename: aFilename]; } - (void)loadSourceOfURL:(NSString*)urlStr @@ -1890,12 +1901,14 @@ static NSArray* sToolbarDefaults = nil; - (IBAction)savePageAs:(id)aSender { - [self saveDocument:NO filterView:nil filterList: nil]; + NSView* accessoryView = [[NSApp delegate] getSavePanelView]; + [self saveDocument:NO filterView:accessoryView]; } - (IBAction)saveFrameAs:(id)aSender { - [self saveDocument:YES filterView:nil filterList: nil]; + NSView* accessoryView = [[NSApp delegate] getSavePanelView]; + [self saveDocument:YES filterView:accessoryView]; } - (IBAction)saveLinkAs:(id)aSender @@ -1915,8 +1928,7 @@ static NSArray* sToolbarDefaults = nil; nsAutoString text; GeckoUtils::GatherTextUnder(mContextMenuNode, text); - [self saveURL: nil filterList: nil - url: hrefStr suggestedFilename: [NSString stringWith_nsAString: text]]; + [self saveURL:nil url:hrefStr suggestedFilename:[NSString stringWith_nsAString:text]]; } - (IBAction)saveImageAs:(id)aSender @@ -1931,11 +1943,18 @@ static NSArray* sToolbarDefaults = nil; NSString* hrefStr = [NSString stringWith_nsAString: url]; - [self saveURL: nil filterList: nil - url: hrefStr suggestedFilename: [NSString stringWith_nsAString: text]]; + [self saveURL:nil url:hrefStr suggestedFilename: [NSString stringWith_nsAString: text]]; } } +- (IBAction)copyImage:(id)sender +{ + nsCOMPtr webBrowser = getter_AddRefs([[[self getBrowserWrapper] getBrowserView] getWebBrowser]); + nsCOMPtr clipboard(do_GetInterface(webBrowser)); + if (clipboard) + clipboard->CopyImageContents(); +} + - (IBAction)copyImageLocation:(id)sender { nsCOMPtr webBrowser = getter_AddRefs([[[self getBrowserWrapper] getBrowserView] getWebBrowser]); diff --git a/camino/src/browser/BrowserWrapper.mm b/camino/src/browser/BrowserWrapper.mm index c39050967c8..3f1a6120bc2 100644 --- a/camino/src/browser/BrowserWrapper.mm +++ b/camino/src/browser/BrowserWrapper.mm @@ -335,10 +335,8 @@ const NSString* kOfflineNotificationName = @"offlineModeChanged"; mTabTitle = [mLoadingStatusString retain]; [mTabItem setLabel:mTabTitle]; - if (mWindowController) { - [mWindowController updateToolbarItems]; - [mWindowController startThrobber]; - } + if (mWindowController) + [mWindowController loadingStarted]; } - (void)onLoadingCompleted:(BOOL)succeeded @@ -402,10 +400,8 @@ const NSString* kOfflineNotificationName = @"offlineModeChanged"; [self removeFromSuperview]; } - if (mWindowController) { - [mWindowController updateToolbarItems]; - [mWindowController stopThrobber]; - } + if (mWindowController) + [mWindowController loadingDone]; } - (void)onProgressChange:(int)currentBytes outOf:(int)maxBytes diff --git a/camino/src/browser/ContentClickListener.mm b/camino/src/browser/ContentClickListener.mm index bb18dd8fd91..57d8940282a 100644 --- a/camino/src/browser/ContentClickListener.mm +++ b/camino/src/browser/ContentClickListener.mm @@ -139,8 +139,7 @@ ContentClickListener::MouseClick(nsIDOMEvent* aEvent) nsAutoString text; GeckoUtils::GatherTextUnder(content, text); - [mBrowserController saveURL: nil filterList: nil - url: hrefStr suggestedFilename: [NSString stringWith_nsAString: text]]; + [mBrowserController saveURL:nil url:hrefStr suggestedFilename:[NSString stringWith_nsAString:text]]; } return NS_OK; diff --git a/camino/src/browser/KeychainService.h b/camino/src/browser/KeychainService.h index 3eeb9018fa1..2a167d7357a 100644 --- a/camino/src/browser/KeychainService.h +++ b/camino/src/browser/KeychainService.h @@ -51,10 +51,16 @@ class nsIPrefBranch; +enum KeychainPromptResult { kSave, kDontRemember, kNeverRemember } ; + @class CHBrowserView; + @interface KeychainService : NSObject { + IBOutlet id confirmStorePasswordPanel; + IBOutlet id confirmChangePasswordPanel; + BOOL mIsEnabled; BOOL mIsAutoFillEnabled; @@ -64,6 +70,13 @@ class nsIPrefBranch; + (KeychainService*) instance; - (void) shutdown:(id)sender; +- (IBAction)hitButtonOK:(id)sender; +- (IBAction)hitButtonCancel:(id)sender; +- (IBAction)hitButtonOther:(id)sender; + +- (KeychainPromptResult)confirmStorePassword:(NSWindow*)parent; +- (BOOL)confirmChangedPassword:(NSWindow*)parent; + - (BOOL) getUsernameAndPassword:(NSString*)realm port:(PRInt32)inPort user:(NSMutableString*)username password:(NSMutableString*)pwd item:(KCItemRef*)outItem; - (BOOL) findUsernameAndPassword:(NSString*)realm port:(PRInt32)inPort; - (void) storeUsernameAndPassword:(NSString*)realm port:(PRInt32)inPort user:(NSString*)username password:(NSString*)pwd; @@ -75,13 +88,43 @@ class nsIPrefBranch; - (BOOL) isEnabled; - (BOOL) isAutoFillEnabled; +// routines to manipulate the keychain deny list for which hosts we shouldn't +// ask about +- (void) addHostToDenyList:(NSString*)host; +- (BOOL) isHostInDenyList:(NSString*)host; + @end + +// +// KeychainDenyList +// +// A singleton object that maintains a list of sites where we should +// not prompt the user for saving in the keychain. This object also +// handles archiving the list in the user's profile dir. +// + +@interface KeychainDenyList : NSObject +{ + NSMutableArray* mDenyList; // the list + BOOL mIsDirty; // do we need to write the list to disk? +} + ++ (KeychainDenyList*) instance; +- (void) shutdown:(id)sender; + +- (BOOL) isHostPresent:(NSString*)host; +- (void) addHost:(NSString*)host; +- (void) removeHost:(NSString*)host; +- (void) writeToDisk; + +@end + + class KeychainPrompt : public nsIAuthPromptWrapper { public: KeychainPrompt(); - KeychainPrompt(KeychainService*); virtual ~KeychainPrompt(); NS_DECL_ISUPPORTS @@ -95,7 +138,6 @@ protected: static void ExtractHostAndPort(const PRUnichar* inRealm, NSString** outHost, PRInt32* outPort); nsCOMPtr mPrompt; - KeychainService* mKeychain; }; // @@ -105,7 +147,7 @@ class KeychainFormSubmitObserver : public nsIObserver, public nsIFormSubmitObserver { public: - KeychainFormSubmitObserver(KeychainService*); + KeychainFormSubmitObserver(); virtual ~KeychainFormSubmitObserver(); NS_DECL_ISUPPORTS @@ -116,12 +158,10 @@ public: private: - static BOOL CheckStorePasswordYN(nsIDOMWindowInternal*); + static KeychainPromptResult CheckStorePasswordYN(nsIDOMWindowInternal*); static BOOL CheckChangeDataYN(nsIDOMWindowInternal*); static NSWindow* GetNSWindow(nsIDOMWindowInternal* inWindow); - - KeychainService* mKeychain; }; // @@ -129,11 +169,10 @@ private: // @interface KeychainBrowserListener : NSObject { - KeychainService* mKeychain; CHBrowserView* mBrowserView; } -- (id)initWithBrowser:(KeychainService*)keychain browser:(CHBrowserView*)aBrowser; +- (id)initWithBrowser:(CHBrowserView*)aBrowser; @end diff --git a/camino/src/browser/KeychainService.mm b/camino/src/browser/KeychainService.mm index c20a16db4c8..94f514531c6 100644 --- a/camino/src/browser/KeychainService.mm +++ b/camino/src/browser/KeychainService.mm @@ -69,6 +69,9 @@ #include "nsIWindowWatcher.h" #include "nsIWebBrowserChrome.h" #include "nsIEmbeddingSiteWindow.h" +#include "nsAppDirectoryServiceDefs.h" + +extern NSString* XPCOMShutDownNotificationName; nsresult @@ -114,7 +117,7 @@ int KeychainPrefChangedCallback(const char* inPref, void* unused) // observer service uses a weakref. nsCOMPtr svc = do_GetService("@mozilla.org/observer-service;1"); NS_ASSERTION(svc, "Keychain can't get observer service"); - mFormSubmitObserver = new KeychainFormSubmitObserver(self); + mFormSubmitObserver = new KeychainFormSubmitObserver(); if ( mFormSubmitObserver && svc ) { NS_ADDREF(mFormSubmitObserver); svc->AddObserver(mFormSubmitObserver, NS_FORMSUBMIT_SUBJECT, PR_FALSE); @@ -122,7 +125,7 @@ int KeychainPrefChangedCallback(const char* inPref, void* unused) // register for the cocoa notification posted when XPCOM shutdown so we // can unregister the pref callbacks we register below - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(shutdown:) name:@"XPCOM Shutdown" + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(shutdown:) name:XPCOMShutDownNotificationName object:nil]; // cache the values of the prefs and register pref-changed callbacks. Yeah, I know @@ -139,6 +142,10 @@ int KeychainPrefChangedCallback(const char* inPref, void* unused) pref->RegisterCallback(gAutoFillEnabledPref, KeychainPrefChangedCallback, nsnull); } } + + // load the keychain.nib file with our dialogs in it + BOOL success = [NSBundle loadNibNamed:@"Keychain" owner:self]; + NS_ASSERTION(success, "can't load keychain prompt dialogs"); } return self; } @@ -168,6 +175,8 @@ int KeychainPrefChangedCallback(const char* inPref, void* unused) pref->UnregisterCallback(gUseKeychainPref, KeychainPrefChangedCallback, nsnull); pref->UnregisterCallback(gAutoFillEnabledPref, KeychainPrefChangedCallback, nsnull); } + + [sInstance release]; } @@ -324,7 +333,181 @@ int KeychainPrefChangedCallback(const char* inPref, void* unused) // - (void) addListenerToView:(CHBrowserView*)view { - [view addListener:[[[KeychainBrowserListener alloc] initWithBrowser:self browser:view] autorelease]]; + [view addListener:[[[KeychainBrowserListener alloc] initWithBrowser:view] autorelease]]; +} + +// +// hitButtonOK: +// hitButtonCancel: +// hitButtonOther: +// +// actions for the buttons of the keychain prompt dialogs. +// + +enum { kOKButton = 0, kCancelButton = 1, kOtherButton = 2 }; + +- (IBAction)hitButtonOK:(id)sender +{ + [NSApp stopModalWithCode:kOKButton]; +} + +- (IBAction)hitButtonCancel:(id)sender +{ + [NSApp stopModalWithCode:kCancelButton]; +} + +- (IBAction)hitButtonOther:(id)sender +{ + [NSApp stopModalWithCode:kOtherButton]; +} + +// +// confirmStorePassword: +// +// Puts up a dialog when the keychain doesn't yet have an entry from +// this site asking to store it, forget it this once, or mark the site +// on a deny list so we never ask again. +// +- (KeychainPromptResult)confirmStorePassword:(NSWindow*)parent +{ + int result = [NSApp runModalForWindow:confirmStorePasswordPanel relativeToWindow:parent]; + [confirmStorePasswordPanel close]; + + // the results of hitButtonXX: map to the corresponding values in the + // |KeychainPromptResult| enum so we can just cast and return + return NS_STATIC_CAST(KeychainPromptResult, result); +} + +// +// confirmChangedPassword: +// +// The password stored in the keychain differs from what the user typed +// in. Ask what they want to do to resolve the issue. +// +- (BOOL)confirmChangedPassword:(NSWindow*)parent +{ + int result = [NSApp runModalForWindow:confirmChangePasswordPanel relativeToWindow:parent]; + [confirmChangePasswordPanel close]; + return (result == kOKButton); +} + + +- (void) addHostToDenyList:(NSString*)host +{ + [[KeychainDenyList instance] addHost:host]; +} + +- (BOOL) isHostInDenyList:(NSString*)host +{ + return [[KeychainDenyList instance] isHostPresent:host]; +} + +@end + + +@interface KeychainDenyList (KeychainDenyListPrivate) +- (NSString*) pathToDenyListFile; +@end + + +@implementation KeychainDenyList + +static KeychainDenyList *sDenyListInstance = nil; + ++ (KeychainDenyList*) instance +{ + return sDenyListInstance ? sDenyListInstance : sDenyListInstance = [[self alloc] init]; +} + +- (id) init +{ + if ( (self = [super init]) ) { + mDenyList = [[NSUnarchiver unarchiveObjectWithFile:[self pathToDenyListFile]] retain]; + if ( !mDenyList ) + mDenyList = [[NSMutableArray alloc] init]; + + mIsDirty = NO; + + // register for the cocoa notification posted when XPCOM shutdown so we + // can release our singleton and flush the file + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(shutdown:) name:XPCOMShutDownNotificationName object:nil]; + } + return self; +} + +- (void) dealloc +{ + [self writeToDisk]; + [mDenyList release]; +} + +// +// shutdown: +// +// Called in response to the cocoa notification "XPCOM Shutdown" sent by the cocoa +// browser service before it terminates embedding and shuts down xpcom. Allows us +// to get rid of anything we're holding onto for the length of the app. +// +- (void) shutdown:(id)unused +{ + [sDenyListInstance release]; +} + +// +// writeToDisk +// +// flushes the deny list to the save file in the user's profile, but only +// if it has changed since we read it in. +// +- (void) writeToDisk +{ + if ( mIsDirty ) + [NSArchiver archiveRootObject:mDenyList toFile:[self pathToDenyListFile]]; + mIsDirty = NO; +} + +- (BOOL) isHostPresent:(NSString*)host +{ + return [mDenyList containsObject:host]; +} + +- (void) addHost:(NSString*)host +{ + if ( ![self isHostPresent:host] ) { + [mDenyList addObject:host]; + mIsDirty = YES; + } +} + +- (void) removeHost:(NSString*)host +{ + if ( [self isHostPresent:host] ) { + [mDenyList removeObject:host]; + mIsDirty = YES; + } +} + + +// +// pathToDenyListFile +// +// returns a path ('/' delimited) that cocoa can use to point to the +// deny list save file in the current user's profile +// +- (NSString*) pathToDenyListFile +{ + NSMutableString* path = [[[NSMutableString alloc] init] autorelease]; + + nsCOMPtr appProfileDir; + NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(appProfileDir)); + if ( appProfileDir ) { + nsAutoString profilePath; + appProfileDir->GetPath(profilePath); + [path setString:[NSString stringWith_nsAString:profilePath]]; + [path appendString:@"/Keychain Deny List"]; // |profilePath| is '/' delimited + } + + return path; } @end @@ -338,12 +521,6 @@ NS_IMPL_ISUPPORTS2(KeychainPrompt, nsIAuthPromptWrapper) KeychainPrompt::KeychainPrompt() - : mKeychain([KeychainService instance]) -{ - NS_INIT_ISUPPORTS(); -} - -KeychainPrompt::KeychainPrompt(KeychainService* keychain) : mKeychain(keychain) { NS_INIT_ISUPPORTS(); } @@ -391,7 +568,8 @@ KeychainPrompt::ExtractHostAndPort(const PRUnichar* inRealm, NSString** outHost, void KeychainPrompt::PreFill(const PRUnichar *realm, PRUnichar **user, PRUnichar **pwd) { - if(![mKeychain isEnabled] || ![mKeychain isAutoFillEnabled]) + KeychainService* keychain = [KeychainService instance]; + if(![keychain isEnabled] || ![keychain isAutoFillEnabled]) return; NSString* host = nil; @@ -409,7 +587,7 @@ KeychainPrompt::PreFill(const PRUnichar *realm, PRUnichar **user, PRUnichar **pw // Pre-fill user/password if found in the keychain. // KCItemRef ignore; - if([mKeychain getUsernameAndPassword:(NSString*)host port:port user:username password:password item:&ignore]) { + if([keychain getUsernameAndPassword:(NSString*)host port:port user:username password:password item:&ignore]) { if ( user ) *user = [username createNewUnicodeBuffer]; if ( pwd ) @@ -427,10 +605,12 @@ KeychainPrompt::ProcessPrompt(const PRUnichar* realm, bool checked, PRUnichar* u NSString* username = [NSString stringWithPRUnichars:user]; NSString* password = [NSString stringWithPRUnichars:pwd]; + KeychainService* keychain = [KeychainService instance]; + NSMutableString* origUsername = [NSMutableString string]; NSMutableString* origPwd = [NSMutableString string]; KCItemRef itemRef; - bool found = [mKeychain getUsernameAndPassword:(NSString*)host port:port user:origUsername password:origPwd item:&itemRef]; + bool found = [keychain getUsernameAndPassword:(NSString*)host port:port user:origUsername password:origPwd item:&itemRef]; // // Update, store or remove the user/password depending on the user @@ -438,11 +618,11 @@ KeychainPrompt::ProcessPrompt(const PRUnichar* realm, bool checked, PRUnichar* u // keychain. // if(checked && !found) - [mKeychain storeUsernameAndPassword:(NSString*)host port:port user:username password:password]; + [keychain storeUsernameAndPassword:(NSString*)host port:port user:username password:password]; else if(checked && found && (![origUsername isEqualToString:username] || ![origPwd isEqualToString:password])) - [mKeychain updateUsernameAndPassword:(NSString*)host port:port user:username password:password item:itemRef]; + [keychain updateUsernameAndPassword:(NSString*)host port:port user:username password:password item:itemRef]; else if(!checked && found) - [mKeychain removeUsernameAndPassword:(NSString*)host port:port item:itemRef]; + [keychain removeUsernameAndPassword:(NSString*)host port:port item:itemRef]; } // @@ -476,7 +656,7 @@ KeychainPrompt::PromptUsernameAndPassword(const PRUnichar *dialogTitle, { PreFill(realm, user, pwd); - PRBool checked = [mKeychain isEnabled]; + PRBool checked = [[KeychainService instance] isEnabled]; PRUnichar* checkTitle = [NSLocalizedString(@"KeychainCheckTitle", @"") createNewUnicodeBuffer]; nsresult rv = mPrompt->PromptUsernameAndPassword(dialogTitle, text, user, pwd, checkTitle, &checked, _retval); @@ -501,7 +681,7 @@ KeychainPrompt::PromptPassword(const PRUnichar *dialogTitle, { PreFill(realm, nsnull, pwd); - PRBool checked = [mKeychain isEnabled]; + PRBool checked = [[KeychainService instance] isEnabled]; PRUnichar* checkTitle = [NSLocalizedString(@"KeychainCheckTitle", @"") createNewUnicodeBuffer]; nsresult rv = mPrompt->PromptPassword(dialogTitle, text, pwd, checkTitle, &checked, _retval); @@ -530,7 +710,7 @@ NS_IMPL_ISUPPORTS2(KeychainFormSubmitObserver, nsIObserver, nsIFormSubmitObserver) -KeychainFormSubmitObserver::KeychainFormSubmitObserver(KeychainService* keychain) : mKeychain(keychain) +KeychainFormSubmitObserver::KeychainFormSubmitObserver() { NS_INIT_ISUPPORTS(); //NSLog(@"Keychain form submit observer created."); @@ -551,7 +731,8 @@ NS_IMETHODIMP KeychainFormSubmitObserver::Notify(nsIContent* node, nsIDOMWindowInternal* window, nsIURI* actionURL, PRBool* cancelSubmit) { - if (![mKeychain isEnabled]) + KeychainService* keychain = [KeychainService instance]; + if (![keychain isEnabled]) return NS_OK; nsCOMPtr formNode(do_QueryInterface(node)); @@ -590,25 +771,41 @@ KeychainFormSubmitObserver::Notify(nsIContent* node, nsIDOMWindowInternal* windo docURL->GetHost(host); docURL->GetPort(&port); + // is the host in the deny list? if yes, bail. otherwise check the keychain. + NSString* realm = [NSString stringWithCString:host.get()]; + if ( [keychain isHostInDenyList:realm] ) + return NS_OK; + // // If there's already an entry in the keychain, check if the username // and password match. If not, ask the user what they want to do and replace // it as necessary. If there's no entry, ask if they want to remember it // and then put it into the keychain // - NSString* realm = [NSString stringWithCString:host.get()]; NSString* existingUser = [NSMutableString string]; NSString* existingPassword = [NSMutableString string]; KCItemRef itemRef; - BOOL foundExistingPassword = [mKeychain getUsernameAndPassword:realm port:port user:existingUser password:existingPassword item:&itemRef]; + BOOL foundExistingPassword = [keychain getUsernameAndPassword:realm port:port user:existingUser password:existingPassword item:&itemRef]; if ( foundExistingPassword ) { if ( !([existingUser isEqualToString:username] && [existingPassword isEqualToString:password]) ) if ( CheckChangeDataYN(window) ) - [mKeychain updateUsernameAndPassword:realm port:port user:username password:password item:itemRef]; + [keychain updateUsernameAndPassword:realm port:port user:username password:password item:itemRef]; } else { - if (CheckStorePasswordYN(window)) - [mKeychain storeUsernameAndPassword:realm port:port user:username password:password]; + switch (CheckStorePasswordYN(window)) { + case kSave: + [keychain storeUsernameAndPassword:realm port:port user:username password:password]; + break; + + case kNeverRemember: + // tell the keychain we never want to be prompted about this host again + [keychain addHostToDenyList:realm]; + break; + + case kDontRemember: + // do nothing at all + break; + } } } @@ -644,12 +841,11 @@ KeychainFormSubmitObserver::GetNSWindow(nsIDOMWindowInternal* inWindow) return nswindow; } -BOOL +KeychainPromptResult KeychainFormSubmitObserver::CheckStorePasswordYN(nsIDOMWindowInternal* window) { NSWindow* nswindow = GetNSWindow(window); - nsAlertController* dialog = CHBrowserService::GetAlertController(); - return [dialog confirmStorePassword:nswindow]; + return [[KeychainService instance] confirmStorePassword:nswindow]; } @@ -657,16 +853,14 @@ BOOL KeychainFormSubmitObserver::CheckChangeDataYN(nsIDOMWindowInternal* window) { NSWindow* nswindow = GetNSWindow(window); - nsAlertController* dialog = CHBrowserService::GetAlertController(); - return [dialog confirmChangedPassword:nswindow]; + return [[KeychainService instance] confirmChangedPassword:nswindow]; } @implementation KeychainBrowserListener -- (id)initWithBrowser:(KeychainService*)keychain browser:(CHBrowserView*)aBrowser +- (id)initWithBrowser:(CHBrowserView*)aBrowser { if ( (self = [super init]) ) { - mKeychain = keychain; mBrowserView = aBrowser; } return self; @@ -683,7 +877,8 @@ KeychainFormSubmitObserver::CheckChangeDataYN(nsIDOMWindowInternal* window) if(!succeeded) return; - if(![mKeychain isEnabled] || ![mKeychain isAutoFillEnabled]) + KeychainService* keychain = [KeychainService instance]; + if(![keychain isEnabled] || ![keychain isAutoFillEnabled]) return; nsCOMPtr domWin = getter_AddRefs([mBrowserView getContentWindow]); @@ -750,7 +945,7 @@ KeychainFormSubmitObserver::CheckChangeDataYN(nsIDOMWindowInternal* window) docURL->GetPort(&port); KCItemRef ignore; - if ([mKeychain getUsernameAndPassword:hostStr port:port user:username password:password item:&ignore]) { + if ([keychain getUsernameAndPassword:hostStr port:port user:username password:password item:&ignore]) { nsAutoString user, pwd; [username assignTo_nsAString:user]; [password assignTo_nsAString:pwd]; diff --git a/camino/src/browser/SiteIconProvider.mm b/camino/src/browser/SiteIconProvider.mm index e6c1709218e..3cf26d6414c 100644 --- a/camino/src/browser/SiteIconProvider.mm +++ b/camino/src/browser/SiteIconProvider.mm @@ -286,7 +286,7 @@ static nsresult MakeFaviconURIFromURI(const nsAString& inURIString, nsAString& o NSImage* faviconImage = nil; NS_DURING - faviconImage = [[NSImage alloc] initWithData:data]; + faviconImage = [[[NSImage alloc] initWithData:data] autorelease]; NS_HANDLER NSLog(@"Exception \"%@ making\" favicon image for %@", localException, inURI); faviconImage = nil; diff --git a/camino/src/browser/nsAlertController.h b/camino/src/browser/nsAlertController.h index 1790fc2054d..91bdc274498 100644 --- a/camino/src/browser/nsAlertController.h +++ b/camino/src/browser/nsAlertController.h @@ -53,8 +53,6 @@ IBOutlet id confirmPanelText; IBOutlet id confirmPanelButton1; IBOutlet id confirmPanelButton2; - IBOutlet id confirmStorePasswordPanel; - IBOutlet id confirmChangePasswordPanel; IBOutlet id promptPanel; IBOutlet id promptPanelCheck; IBOutlet id promptPanelText; @@ -90,8 +88,6 @@ - (int)confirmCheckEx:(NSWindow*)parent title:(NSString*)title text:(NSString*)text button1:(NSString*)btn1 button2:(NSString*)btn2 button3:(NSString*)btn3 checkMsg:(NSString*)checkMsg checkValue:(BOOL*)checkValue; -- (BOOL)confirmStorePassword:(NSWindow*)parent; -- (BOOL)confirmChangedPassword:(NSWindow*)parent; - (BOOL)prompt:(NSWindow*)parent title:(NSString*)title text:(NSString*)text promptText:(NSMutableString*)promptText checkMsg:(NSString*)checkMsg checkValue:(BOOL*)checkValue doCheck:(BOOL)doCheck; - (BOOL)promptUserNameAndPassword:(NSWindow*)parent title:(NSString*)title text:(NSString*)text userNameText:(NSMutableString*)userNameText passwordText:(NSMutableString*)passwordText checkMsg:(NSString*)checkMsg checkValue:(BOOL*)checkValue doCheck:(BOOL)doCheck; diff --git a/camino/src/browser/nsAlertController.mm b/camino/src/browser/nsAlertController.mm index 8f1ac58cd80..326878cc28d 100644 --- a/camino/src/browser/nsAlertController.mm +++ b/camino/src/browser/nsAlertController.mm @@ -154,19 +154,6 @@ enum { kOKButton = 0, kCancelButton = 1, kOtherButton = 2 }; return result; } -- (BOOL)confirmStorePassword:(NSWindow*)parent -{ - int result = [NSApp runModalForWindow:confirmStorePasswordPanel relativeToWindow:parent]; - [confirmStorePasswordPanel close]; - return (result == kOKButton); -} - -- (BOOL)confirmChangedPassword:(NSWindow*)parent -{ - int result = [NSApp runModalForWindow:confirmChangePasswordPanel relativeToWindow:parent]; - [confirmChangePasswordPanel close]; - return (result == kOKButton); -} - (BOOL)prompt:(NSWindow*)parent title:(NSString*)title text:(NSString*)text promptText:(NSMutableString*)promptText checkMsg:(NSString*)checkMsg checkValue:(BOOL*)checkValue doCheck:(BOOL)doCheck { diff --git a/camino/src/download/ProgressDlgController.h b/camino/src/download/ProgressDlgController.h index 3b1b3a3a861..93496b25ab4 100644 --- a/camino/src/download/ProgressDlgController.h +++ b/camino/src/download/ProgressDlgController.h @@ -20,6 +20,8 @@ * the Initial Developer. All Rights Reserved. * * Contributor(s): + * Simon Fraser + * Calum Robinson * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -38,49 +40,72 @@ #import #import "CHDownloadProgressDisplay.h" +#import "CHStackView.h" -#include "nscore.h" +/* + How ProgressViewController and ProgressDlgController work. + + ProgressDlgController manages the window the the downloads are displayed in. + It contains a single CHStackView, a custom class that asks its datasource + for a list of views to display, in a similar fashion to the way NSTableView + asks its datasource for data to display. There is a single instance of + ProgressDlgController, returned by +sharedDownloadController. + + The ProgressDlgController is a subclass of CHDownloadController, which + means that it gets asked to create new objects conforming to the + CHDownloadProgressDisplay protocol, which are used to display + the progress of a single download. It does so by returning instances of + ProgressViewController, which manage an NSView that contains a progress + indicator, some text fields for status info and a cancel button. + + After a ProgressViewController is requested, the CHStackView is reloaded, + which causes it to ask the ProgressDlgController (it's datasource) to + provide it with a list of all the subviews to be diaplyed. It calculates + it's new frame, and arranges the subviews in a vertical list. + + The ProgressDlgController now needs to resize its window. It knows when + to do this because is watches for changes in the CHStackViews frame (using + NSViews built in NSNotification for this). + + + Expanding/contracting download progress views + + When a disclosure triangle is clicked, the ProgressViewController just swaps + the expanded view for a smaller one. It saves the new state as the users + preference for "browser.download.compactView". If the option key was held down, + a notification is posted (that all ProgressViewControllers listen for) that + makes all ProgressViewControllers change their state to the new state of the sender. -class nsIWebBrowserPersist; -class nsISupports; -class nsIInputStream; -class nsDownloadListener; +*/ +#import "CHDownloadProgressDisplay.h" -@interface ChimeraDownloadControllerFactory : DownloadControllerFactory -@end - - -@interface ProgressDlgController : NSWindowController +@interface ProgressDlgController : NSWindowController { - IBOutlet NSTextField *mElapsedTimeLabel; - IBOutlet NSTextField *mFromField; - IBOutlet NSTextField *mStatusLabel; - IBOutlet NSTextField *mTimeLeftLabel; - IBOutlet NSTextField *mToField; - IBOutlet NSProgressIndicator *mProgressBar; - - NSToolbarItem *leaveOpenToggleToolbarItem; - - BOOL mSaveFileDialogShouldStayOpen; - BOOL mDoingAutoFileDownload; - BOOL mIsFileSave; - BOOL mDownloadIsComplete; - long mCurrentProgress; // if progress bar is indeterminate, can still calc stats. - - CHDownloader *mDownloader; // we hold a ref to this - NSTimer *mDownloadTimer; + IBOutlet CHStackView *mStackView; + IBOutlet NSScrollView *mScrollView; + IBOutlet NSTextField *mNoDownloadsText; + + NSSize mDefaultWindowSize; + NSTimer *mDownloadTimer; + NSMutableArray *mProgressViewControllers; + int mNumActiveDownloads; } -+ (int)numDownloadInProgress; ++ (ProgressDlgController *)sharedDownloadController; --(void)autosaveWindowFrame; +- (int)numDownloadsInProgress; --(void) setupDownloadTimer; --(void) killDownloadTimer; --(void) setDownloadProgress:(NSTimer *)aTimer; --(NSString *) formatTime:(int)aSeconds; --(NSString *) formatFuzzyTime:(int)aSeconds; --(NSString *) formatBytes:(float)aBytes; +- (void)autosaveWindowFrame; + +- (void)setupDownloadTimer; +- (void)killDownloadTimer; +- (void)setDownloadProgress:(NSTimer *)aTimer; + +- (void)didStartDownload:(id )progressDisplay; +- (void)didEndDownload:(id )progressDisplay; +- (void)removeDownload:(id )progressDisplay; + +- (NSApplicationTerminateReply)allowTerminate; @end diff --git a/camino/src/download/ProgressDlgController.mm b/camino/src/download/ProgressDlgController.mm index f602e492d4c..9ce24f3576a 100644 --- a/camino/src/download/ProgressDlgController.mm +++ b/camino/src/download/ProgressDlgController.mm @@ -20,6 +20,7 @@ * the Initial Developer. All Rights Reserved. * * Contributor(s): + * Calum Robinson * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -35,504 +36,319 @@ * * ***** END LICENSE BLOCK ***** */ +#import "NSView+Utils.h" + #import "ProgressDlgController.h" -#include "nsCOMPtr.h" -#include "nsString.h" -#include "nsCRT.h" -#include "nsIWebBrowserPersist.h" -#include "nsIInputStream.h" -#include "nsIURL.h" -#include "nsILocalFile.h" -#include "nsIDOMHTMLDocument.h" -#include "nsIWebProgressListener.h" -#include "nsIDownload.h" -#include "nsIComponentManager.h" -#include "nsIPref.h" - -static NSString *SaveFileToolbarIdentifier = @"Save File Dialog Toolbar"; -static NSString *CancelToolbarItemIdentifier = @"Cancel Toolbar Item"; -static NSString *ShowFileToolbarItemIdentifier = @"Show File Toolbar Item"; -static NSString *OpenFileToolbarItemIdentifier = @"Open File Toolbar Item"; -static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar Item"; +#import "ProgressViewController.h" +#import "PreferenceManager.h" static NSString *ProgressWindowFrameSaveName = @"ProgressWindow"; -@implementation ChimeraDownloadControllerFactory : DownloadControllerFactory -- (NSWindowController *)createDownloadController -{ - NSWindowController* progressController = [[ProgressDlgController alloc] initWithWindowNibName: @"ProgressDialog"]; - NSAssert([progressController conformsToProtocol:@protocol(CHDownloadProgressDisplay)], - @"progressController should conform to CHDownloadProgressDisplay protocol"); - return progressController; -} + +@interface ProgressDlgController(PrivateProgressDlgController) + +- (void)resizeWindowToFit; +- (void)rebuildViews; +- (NSSize)windowSizeForStackSize:(NSSize)stackSize; @end -#pragma mark - -@interface ProgressDlgController(Private) --(void)setupToolbar; -@end - @implementation ProgressDlgController -static int gNumActiveDownloads = 0; +static id gSharedProgressController = nil; -+ (int)numDownloadInProgress ++ (ProgressDlgController *)sharedDownloadController; { - return gNumActiveDownloads; + if (gSharedProgressController == nil) + gSharedProgressController = [[ProgressDlgController alloc] init]; + + return gSharedProgressController; +} + +- (id)init +{ + if ((self == [super initWithWindowNibName:@"ProgressDialog"])) + { + // Register for notifications when the stack view changes size + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(stackViewResized:) + name:StackViewResizedNotificationName + object:nil]; + + mProgressViewControllers = [[NSMutableArray alloc] init]; + + mDefaultWindowSize = [[self window] frame].size; + // it would be nice if we could get the frame from the name, and then + // mess with it before setting it. + [[self window] setFrameUsingName:ProgressWindowFrameSaveName]; + // set the window to its default height + NSRect windowFrame = [[self window] frame]; + windowFrame.size.height = mDefaultWindowSize.height; + [[self window] setFrame:windowFrame display:NO]; + + // We provide the views for the stack view, from mProgressViewControllers + [mStackView setDataSource:self]; + + [mScrollView setDrawsBackground:NO]; + [mNoDownloadsText retain]; // so we can remove it from its superview + } + + return self; } - (void)dealloc { - // if we get here because we're quitting, the listener will still be alive - // yet we're going away. As a result, we need to tell the d/l listener to - // forget it ever met us and necko will clean it up on its own. - if ( mDownloader) - mDownloader->DetachDownloadDisplay(); - NS_IF_RELEASE(mDownloader); + if (self == gSharedProgressController) + gSharedProgressController = nil; + + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [mProgressViewControllers release]; + [mNoDownloadsText release]; + [self killDownloadTimer]; [super dealloc]; } -- (void)windowDidLoad +- (void)didStartDownload:(id )progressDisplay { - [super windowDidLoad]; - - mDownloadIsComplete = NO; - mDoingAutoFileDownload = NO; + [self showWindow:nil]; // make sure the window is visible - if (!mIsFileSave) { - nsCOMPtr prefs(do_GetService(NS_PREF_CONTRACTID)); - PRBool save = PR_FALSE; - prefs->GetBoolPref("browser.download.progressDnldDialog.keepAlive", &save); - mSaveFileDialogShouldStayOpen = save; - - PRBool autoHelperDispatch = PR_FALSE; - prefs->GetBoolPref("browser.download.autoDispatch", &autoHelperDispatch); - mDoingAutoFileDownload = autoHelperDispatch; + [self rebuildViews]; + [self setupDownloadTimer]; +} + +- (void)didEndDownload:(id )progressDisplay +{ + [self rebuildViews]; // to swap in the completed view +} + +- (void)removeDownload:(id )progressDisplay +{ + [mProgressViewControllers removeObject:progressDisplay]; + + if ([mProgressViewControllers count] == 0) + { + // Stop doing stuff if there aren't any downloads going on + [self killDownloadTimer]; } - [self setupToolbar]; - [mProgressBar setUsesThreadedAnimation:YES]; - [mProgressBar startAnimation:self]; // move to onStateChange + [self rebuildViews]; } -- (void)setupToolbar +- (void)stackViewResized:(NSNotification *)notification { - NSToolbar *toolbar = [[[NSToolbar alloc] initWithIdentifier:SaveFileToolbarIdentifier] autorelease]; - - [toolbar setDisplayMode:NSToolbarDisplayModeDefault]; - [toolbar setAllowsUserCustomization:YES]; - [toolbar setAutosavesConfiguration:YES]; - [toolbar setDelegate:self]; - [[self window] setToolbar:toolbar]; + NSDictionary* userInfo = [notification userInfo]; + NSSize oldStackSize = [[userInfo objectForKey:@"oldsize"] sizeValue]; + + // this code is used to auto-resize the downloads window when + // its contents change size, if the window is in its standard, "zoomed" + // state. This allows the user to choose between auto-resizing behavior, + // by leaving the window alone, or their own size, by resizing it. + + // get the size the window would have been if it had been in the + // standard state, given the old size of the contents + NSSize oldZoomedWindowSize = [self windowSizeForStackSize:oldStackSize]; + NSSize curWindowSize = [[self window] frame].size; + + // only resize if the window matches the stack size + if (CHCloseSizes(oldZoomedWindowSize, curWindowSize, 4.0)) + [self resizeWindowToFit]; } -- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar +// given the dimensions of our stack view, return the dimensions of the window, +// assuming the window is zoomed to show as much of the contents as possible. +- (NSSize)windowSizeForStackSize:(NSSize)stackSize { - return [NSArray arrayWithObjects: CancelToolbarItemIdentifier, - ShowFileToolbarItemIdentifier, - OpenFileToolbarItemIdentifier, - LeaveOpenToolbarItemIdentifier, - NSToolbarCustomizeToolbarItemIdentifier, - NSToolbarFlexibleSpaceItemIdentifier, - NSToolbarSpaceItemIdentifier, - NSToolbarSeparatorItemIdentifier, - nil]; + NSSize actualScrollFrame = [mScrollView frame].size; + NSSize scrollFrameSize = [NSScrollView frameSizeForContentSize:stackSize + hasHorizontalScroller:NO hasVerticalScroller:YES borderType:NSNoBorder]; + + // frameSizeForContentSize seems to return a width 1 pixel too narrow + scrollFrameSize.width += 1; + + NSRect contentRect = [[[self window] contentView] frame]; + contentRect.size.width += scrollFrameSize.width - actualScrollFrame.width; + contentRect.size.height += scrollFrameSize.height - actualScrollFrame.height; + contentRect.origin = [[self window] convertBaseToScreen:contentRect.origin]; // convert to screen + + NSRect advisoryWindowFrame = [NSWindow frameRectForContentRect:contentRect styleMask:[[self window] styleMask]]; + NSRect constrainedRect = [[self window] constrainFrameRect:advisoryWindowFrame toScreen:[[self window] screen]]; + return constrainedRect.size; } -- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar +- (void)resizeWindowToFit { - return [NSArray arrayWithObjects: CancelToolbarItemIdentifier, - NSToolbarFlexibleSpaceItemIdentifier, - LeaveOpenToolbarItemIdentifier, - NSToolbarFlexibleSpaceItemIdentifier, - ShowFileToolbarItemIdentifier, - OpenFileToolbarItemIdentifier, - nil]; + if ([mProgressViewControllers count] > 0) + { + NSSize scrollFrameSize = [NSScrollView frameSizeForContentSize:[mStackView bounds].size + hasHorizontalScroller:NO hasVerticalScroller:YES borderType:NSNoBorder]; + NSSize curScrollFrameSize = [mScrollView frame].size; + + NSRect windowFrame = [[self window] frame]; + + float frameDelta = (scrollFrameSize.height - curScrollFrameSize.height); + windowFrame.size.height += frameDelta; + windowFrame.origin.y -= frameDelta; // maintain top + + [[self window] setFrame:windowFrame display:YES]; + } } -- (BOOL)validateToolbarItem:(NSToolbarItem *)toolbarItem +- (void)rebuildViews { - if ([toolbarItem action] == @selector(cancel)) // cancel button - return (!mDownloadIsComplete); - if ([toolbarItem action] == @selector(pauseAndResumeDownload)) // pause/resume button - return (NO); // Hey - it hasn't been hooked up yet. !mDownloadIsComplete when it is. - if ([toolbarItem action] == @selector(showFile)) // show file - return (mDownloadIsComplete); - if ([toolbarItem action] == @selector(openFile)) // open file - return (mDownloadIsComplete); - return YES; // turn it on otherwise. + [mStackView reloadSubviews]; + + if ([mProgressViewControllers count] == 0) + { + [[[self window] contentView] addSubview:mNoDownloadsText]; + } + else + { + [mNoDownloadsText removeFromSuperview]; + } + +} + +- (int)numDownloadsInProgress +{ + unsigned int numViews = [mProgressViewControllers count]; + int numActive = 0; + + for (unsigned int i = 0; i < numViews; i++) + { + if ([[mProgressViewControllers objectAtIndex:i] isActive]) + ++numActive; + } + return numActive; } -(void)autosaveWindowFrame { - [[self window] saveFrameUsingName: ProgressWindowFrameSaveName]; -} - -- (NSToolbarItem *) toolbar:(NSToolbar *)toolbar - itemForItemIdentifier:(NSString *)itemIdent - willBeInsertedIntoToolbar:(BOOL)willBeInserted -{ - NSToolbarItem *toolbarItem = [[[NSToolbarItem alloc] initWithItemIdentifier:itemIdent] autorelease]; - - if ( [itemIdent isEqual:CancelToolbarItemIdentifier] ) - { - [toolbarItem setLabel:NSLocalizedString(@"Cancel",@"Cancel")]; - [toolbarItem setPaletteLabel:NSLocalizedString(@"CancelPaletteLabel",@"Cancel Download")]; - [toolbarItem setToolTip:NSLocalizedString(@"CancelToolTip",@"Cancel this file download")]; - [toolbarItem setImage:[NSImage imageNamed:@"saveCancel"]]; - [toolbarItem setTarget:self]; - [toolbarItem setAction:@selector(cancel)]; - } - else if ( [itemIdent isEqual:ShowFileToolbarItemIdentifier] ) - { - [toolbarItem setLabel:NSLocalizedString(@"Show File",@"Show File")]; - [toolbarItem setPaletteLabel:NSLocalizedString(@"Show File",@"Show File")]; - [toolbarItem setToolTip:NSLocalizedString(@"ShowToolTip",@"Show the saved file in the Finder")]; - [toolbarItem setImage:[NSImage imageNamed:@"saveShowFile"]]; - [toolbarItem setTarget:self]; - [toolbarItem setAction:@selector(showFile)]; - } - else if ( [itemIdent isEqual:OpenFileToolbarItemIdentifier] ) - { - [toolbarItem setLabel:NSLocalizedString(@"Open File",@"Open File")]; - [toolbarItem setPaletteLabel:NSLocalizedString(@"Open File",@"Open File")]; - [toolbarItem setToolTip:NSLocalizedString(@"OpenToolTip",@"Open the saved file in its default application.")]; - [toolbarItem setImage:[NSImage imageNamed:@"saveOpenFile"]]; - [toolbarItem setTarget:self]; - [toolbarItem setAction:@selector(openFile)]; - } - else if ( [itemIdent isEqual:LeaveOpenToolbarItemIdentifier] ) - { - if ( !mIsFileSave && !mDoingAutoFileDownload ) - { - if ( mSaveFileDialogShouldStayOpen ) - { - [toolbarItem setLabel:NSLocalizedString(@"Leave Open",@"Leave Open")]; - [toolbarItem setPaletteLabel:NSLocalizedString(@"Toggle Close Behavior",@"Toggle Close Behavior")]; - [toolbarItem setToolTip:NSLocalizedString(@"LeaveOpenToolTip",@"Window will stay open when download finishes.")]; - [toolbarItem setImage:[NSImage imageNamed:@"saveLeaveOpenYES"]]; - [toolbarItem setTarget:self]; - [toolbarItem setAction:@selector(toggleLeaveOpen)]; - } - else - { - [toolbarItem setLabel:NSLocalizedString(@"Close When Done",@"Close When Done")]; - [toolbarItem setPaletteLabel:NSLocalizedString(@"Toggle Close Behavior",@"Toggle Close Behavior")]; - [toolbarItem setToolTip:NSLocalizedString(@"CloseWhenDoneToolTip",@"Window will close automatically when download finishes.")]; - [toolbarItem setImage:[NSImage imageNamed:@"saveLeaveOpenNO"]]; - [toolbarItem setTarget:self]; - [toolbarItem setAction:@selector(toggleLeaveOpen)]; - } - if ( willBeInserted ) - { - leaveOpenToggleToolbarItem = toolbarItem; //establish reference - } - } - } else - { - toolbarItem = nil; - } - - return toolbarItem; -} - --(void)cancel -{ - if (mDownloader) // we should always have one - mDownloader->CancelDownload(); - - // clean up downloaded file. - do it here on in CancelDownload? - NSFileManager *fileManager = [NSFileManager defaultManager]; - NSString *thePath = [[mToField stringValue] stringByExpandingTildeInPath]; - if ([fileManager isDeletableFileAtPath:thePath]) - // if we delete it, fantastic. if not, oh well. better to move to trash instead? - [fileManager removeFileAtPath:thePath handler:nil]; - - // we can _not_ set the |mDownloadIsComplete| flag here because the download really - // isn't done yet. We'll probably continue to process more PLEvents that are already - // in the queue until we get a STATE_STOP state change. As a result, we just keep - // going until that comes in (and it will, because we called CancelDownload() above). - // Ensure that the window goes away when we get there by flipping the 'stay alive' - // flag. (bug 154913) - mSaveFileDialogShouldStayOpen = NO; -} - --(void)showFile -{ - NSString *theFile = [[mToField stringValue] stringByExpandingTildeInPath]; - if ([[NSWorkspace sharedWorkspace] selectFile:theFile - inFileViewerRootedAtPath:[theFile stringByDeletingLastPathComponent]]) - return; - // hmmm. it didn't work. that's odd. need localized error messages. for now, just beep. - NSBeep(); -} - --(void)openFile -{ - NSString *theFile = [[mToField stringValue] stringByExpandingTildeInPath]; - if ([[NSWorkspace sharedWorkspace] openFile:theFile]) - return; - // hmmm. it didn't work. that's odd. need localized error message. for now, just beep. - NSBeep(); - -} - --(void)toggleLeaveOpen -{ - if ( ! mSaveFileDialogShouldStayOpen ) { - mSaveFileDialogShouldStayOpen = YES; - [leaveOpenToggleToolbarItem setLabel:NSLocalizedString(@"Leave Open",@"Leave Open")]; - [leaveOpenToggleToolbarItem setPaletteLabel:NSLocalizedString(@"Toggle Close Behavior",@"Toggle Close Behavior")]; - [leaveOpenToggleToolbarItem setToolTip:NSLocalizedString(@"LeaveOpenToolTip",@"Window will stay open when download finishes.")]; - [leaveOpenToggleToolbarItem setImage:[NSImage imageNamed:@"saveLeaveOpenYES"]]; - } else { - mSaveFileDialogShouldStayOpen = NO; - [leaveOpenToggleToolbarItem setLabel:NSLocalizedString(@"Close When Done",@"Close When Done")]; - [leaveOpenToggleToolbarItem setPaletteLabel:NSLocalizedString(@"Toggle Close Behavior",@"Toggle Close Behavior")]; - [leaveOpenToggleToolbarItem setToolTip:NSLocalizedString(@"CloseWhenDoneToolTip",@"Window will close automatically when download finishes.")]; - [leaveOpenToggleToolbarItem setImage:[NSImage imageNamed:@"saveLeaveOpenNO"]]; - } - - nsCOMPtr prefs(do_GetService(NS_PREF_CONTRACTID)); - prefs->SetBoolPref("browser.download.progressDnldDialog.keepAlive", mSaveFileDialogShouldStayOpen); + [[self window] saveFrameUsingName:ProgressWindowFrameSaveName]; } - (void)windowWillClose:(NSNotification *)notification { [self autosaveWindowFrame]; - [self autorelease]; -} - -- (BOOL)windowShouldClose:(NSNotification *)notification -{ - [self killDownloadTimer]; - if (!mDownloadIsComplete) { //whoops. hard cancel. - [self cancel]; - return NO; // let setDownloadProgress handle the close. - } - return YES; } - (void)killDownloadTimer { - if (mDownloadTimer) { + if (mDownloadTimer) + { [mDownloadTimer invalidate]; [mDownloadTimer release]; mDownloadTimer = nil; - } + } } + - (void)setupDownloadTimer { [self killDownloadTimer]; - mDownloadTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0 - target:self - selector:@selector(setDownloadProgress:) - userInfo:nil - repeats:YES] retain]; -} - --(NSString *)formatTime:(int)seconds -{ - NSMutableString *theTime =[[[NSMutableString alloc] initWithCapacity:8] autorelease]; - [theTime setString:@""]; - NSString *padZero = [NSString stringWithString:@"0"]; - //write out new elapsed time - if (seconds >= 3600){ - [theTime appendFormat:@"%d:",(seconds / 3600)]; - seconds = seconds % 3600; - } - NSString *elapsedMin = [NSString stringWithFormat:@"%d:",(seconds / 60)]; - if ([elapsedMin length] == 2) - [theTime appendString:[padZero stringByAppendingString:elapsedMin]]; - else - [theTime appendString:elapsedMin]; - seconds = seconds % 60; - NSString *elapsedSec = [NSString stringWithFormat:@"%d",seconds]; - if ([elapsedSec length] == 2) - [theTime appendString:elapsedSec]; - else - [theTime appendString:[padZero stringByAppendingString:elapsedSec]]; - return theTime; -} -// fuzzy time gives back strings like "about 5 seconds" --(NSString *)formatFuzzyTime:(int)seconds -{ - // check for seconds first - if (seconds < 60) { - if (seconds < 7) - return [[[NSString alloc] initWithFormat:NSLocalizedString(@"UnderSec",@"Under %d seconds"),5] autorelease]; - if (seconds < 13) - return [[[NSString alloc] initWithFormat:NSLocalizedString(@"UnderSec",@"Under %d seconds"),10] autorelease]; - return [[[NSString alloc] initWithString:NSLocalizedString(@"UnderMin",@"Under a minute")] autorelease]; - } - // seconds becomes minutes and we keep checking. - seconds = seconds/60; - if (seconds < 60) { - if (seconds < 2) - return [[[NSString alloc] initWithString:NSLocalizedString(@"AboutMin",@"About a minute")] autorelease]; - // OK, tell the good people how much time we have left. - return [[[NSString alloc] initWithFormat:NSLocalizedString(@"AboutMins",@"About %d minutes"),seconds] autorelease]; - } - //this download will never seemingly never end. now seconds become hours. - seconds = seconds/60; - if (seconds < 2) - return [[[NSString alloc] initWithString:NSLocalizedString(@"AboutHour",@"Over an hour")] autorelease]; - return [[[NSString alloc] initWithFormat:NSLocalizedString(@"AboutHours",@"Over %d hours"),seconds] autorelease]; -} - - --(NSString *)formatBytes:(float)bytes -{ // this is simpler than my first try. I peaked at Omnigroup byte formatting code. - // if bytes are negative, we return question marks. - if (bytes < 0) - return [[[NSString alloc] initWithString:@"???"] autorelease]; - // bytes first. - if (bytes < 1024) - return [[[NSString alloc] initWithFormat:@"%.1f bytes",bytes] autorelease]; - // kb - bytes = bytes/1024; - if (bytes < 1024) - return [[[NSString alloc] initWithFormat:@"%.1f KB",bytes] autorelease]; - // mb - bytes = bytes/1024; - if (bytes < 1024) - return [[[NSString alloc] initWithFormat:@"%.1f MB",bytes] autorelease]; - // gb - bytes = bytes/1024; - return [[[NSString alloc] initWithFormat:@"%.1f GB",bytes] autorelease]; -} - -// this handles lots of things. -- (void)setDownloadProgress:(NSTimer *)downloadTimer; -{ - // XXX this logic needs cleaning up. - // Ack! we're closing the window with the download still running! - if (mDownloadIsComplete) + mDownloadTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0 + target:self + selector:@selector(setDownloadProgress:) + userInfo:nil + repeats:YES] retain]; +} + +// Called by our timer to refresh all the download stats +- (void)setDownloadProgress:(NSTimer *)aTimer +{ + [mProgressViewControllers makeObjectsPerformSelector:@selector(refreshDownloadInfo)]; + // if the window is minimized, we want to update the dock image here. But how? +} + +- (NSApplicationTerminateReply)allowTerminate +{ + if ([self numDownloadsInProgress] > 0) { - [[self window] performClose:self]; - return; + // make sure the window is visible + [self showWindow:self]; + + NSString *alert = NSLocalizedString(@"QuitWithDownloadsMsg", @"Really Quit?"); + NSString *message = NSLocalizedString(@"QuitWithDownloadsExpl", @""); + NSString *okButton = NSLocalizedString(@"QuitWithdownloadsButtonDefault",@"Cancel"); + NSString *altButton = NSLocalizedString(@"QuitWithdownloadsButtonAlt",@"Quit"); + + // while the panel is up, download dialogs won't update (no timers firing) but + // downloads continue (PLEvents being processed) + id panel = NSGetAlertPanel(alert, message, okButton, altButton, nil, message); + + [NSApp beginSheet:panel + modalForWindow:[self window] + modalDelegate:self + didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) + contextInfo:NULL]; + int sheetResult = [NSApp runModalForWindow: panel]; + [NSApp endSheet: panel]; + [panel orderOut: self]; + NSReleaseAlertPanel(panel); + + return (sheetResult == NSAlertDefaultReturn) ? NSTerminateCancel : NSTerminateNow; } - // get the elapsed time - NSArray *elapsedTimeArray = [[mElapsedTimeLabel stringValue] componentsSeparatedByString:@":"]; - int j = [elapsedTimeArray count]; - int elapsedSec = [[elapsedTimeArray objectAtIndex:(j-1)] intValue] + [[elapsedTimeArray objectAtIndex:(j-2)] intValue]*60; - if (j==3) // this download is taking forever. - elapsedSec += [[elapsedTimeArray objectAtIndex:0] intValue]*3600; - // update elapsed time - [mElapsedTimeLabel setStringValue:[self formatTime:(++elapsedSec)]]; - // for status field & time left - float maxBytes = ([mProgressBar maxValue]); - float byteSec = mCurrentProgress/elapsedSec; - // OK - if downloadTimer is nil, we're done - fix maxBytes value for status report. - if (!downloadTimer) - maxBytes = mCurrentProgress; - // update status field - NSString *labelString = NSLocalizedString(@"LabelString",@"%@ of %@ total (at %@/sec)"); - [mStatusLabel setStringValue: [NSString stringWithFormat:labelString, [self formatBytes:mCurrentProgress], [self formatBytes:maxBytes], [self formatBytes:byteSec]]]; - // updating estimated time left field - // if maxBytes < 0, can't calc time left. - // if !downloadTimer, download is finished. either way, make sure time left is 0. - if ((maxBytes > 0) && (downloadTimer)) - { - int secToGo = (int)ceil((elapsedSec*maxBytes/mCurrentProgress) - elapsedSec); - [mTimeLeftLabel setStringValue:[self formatFuzzyTime:secToGo]]; - } - else if (!downloadTimer) - { // download done. Set remaining time to 0, fix progress bar & cancel button - mDownloadIsComplete = YES; // all done. we got a STATE_STOP - [mTimeLeftLabel setStringValue:@""]; - [self setProgressTo:mCurrentProgress ofMax:mCurrentProgress]; - if (!mSaveFileDialogShouldStayOpen || mDoingAutoFileDownload) - [[self window] performClose:self]; // close window - else - [[self window] update]; // redraw window - } - else //maxBytes is undetermined. Set remaining time to question marks. - [mTimeLeftLabel setStringValue:@"???"]; + + return NSTerminateNow; +} + +- (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo +{ + [NSApp stopModalWithCode:returnCode]; } #pragma mark - -// CHDownloadProgressDisplay protocol methods - -- (void)onStartDownload:(BOOL)isFileSave; +// implement to zoom to a size that just fits the contents +- (NSRect)windowWillUseStandardFrame:(NSWindow *)sender defaultFrame:(NSRect)defaultFrame { - mIsFileSave = isFileSave; + NSSize scrollFrameSize = [NSScrollView frameSizeForContentSize:[mStackView bounds].size + hasHorizontalScroller:NO hasVerticalScroller:YES borderType:NSNoBorder]; - [self window]; // make the window - [[self window] setFrameUsingName: ProgressWindowFrameSaveName]; + NSSize curScrollFrameSize = [mScrollView frame].size; + float frameDelta = (scrollFrameSize.height - curScrollFrameSize.height); - [self showWindow: self]; - [self setupDownloadTimer]; - - gNumActiveDownloads++; + NSRect windowFrame = [[self window] frame]; + windowFrame.size.height += frameDelta; + windowFrame.origin.y -= frameDelta; // maintain top + + windowFrame.size.width = mDefaultWindowSize.width; + // cocoa will ensure that the window fits onscreen for us + return windowFrame; } -- (void)onEndDownload +#pragma mark - + +/* + CHStackView datasource methods +*/ + +- (int)subviewsForStackView:(CHStackView *)stackView { - gNumActiveDownloads --; + return [mProgressViewControllers count]; +} + +- (NSView *)viewForStackView:(CHStackView *)aResizingView atIndex:(int)index +{ + return [[mProgressViewControllers objectAtIndex:index] view]; +} + +#pragma mark - + +/* + Just create a progress view, but don't display it (otherwise the URL fields etc. + are just blank) +*/ +- (id )createProgressDisplay +{ + ProgressViewController *newController = [[ProgressViewController alloc] init]; + [newController setProgressWindowController:self]; + [mProgressViewControllers addObject:newController]; - // if we're quitting, our progress window is already gone and we're in the - // process of shutting down gecko and all the d/l listeners. The timer, at - // that point, is the only thing keeping us alive. Killing it will cause - // us to go away immediately, so kung-fu deathgrip it until we're done twiddling - // bits on ourself. - [self retain]; // Enter The Dragon! - [self killDownloadTimer]; - [self setDownloadProgress:nil]; - [self release]; -} - -- (void)setProgressTo:(long)aCurProgress ofMax:(long)aMaxProgress -{ - mCurrentProgress = aCurProgress; // fall back for stat calcs - - if (![mProgressBar isIndeterminate]) //most likely - just update value - { - if (aCurProgress == aMaxProgress) //handles little bug in FTP download size - [mProgressBar setMaxValue:aMaxProgress]; - - [mProgressBar setDoubleValue:aCurProgress]; - } - else if (aMaxProgress > 0) // ok, we're starting up with good max & cur values - { - [mProgressBar setIndeterminate:NO]; - [mProgressBar setMaxValue:aMaxProgress]; - [mProgressBar setDoubleValue:aCurProgress]; - } // if neither case was true, it's barber pole city. -} - --(void) setDownloadListener: (CHDownloader*)aDownloader -{ - if (mDownloader != aDownloader) - NS_IF_RELEASE(mDownloader); - - NS_IF_ADDREF(mDownloader = aDownloader); -} - -- (void)setSourceURL:(NSString*)aSourceURL -{ - [mFromField setStringValue: aSourceURL]; - [mFromField display]; // force an immmeditate update -} - -- (void)setDestinationPath:(NSString*)aDestPath -{ - [mToField setStringValue: [aDestPath stringByAbbreviatingWithTildeInPath]]; - [mToField display]; // force an immmeditate update - - // also set the window title - NSString* downloadFileName = [aDestPath lastPathComponent]; - if ([downloadFileName length] == 0) - downloadFileName = aDestPath; - - [[self window] setTitle:[NSString stringWithFormat:NSLocalizedString(@"DownloadingTitle", @""), downloadFileName]]; + return newController; } @end diff --git a/camino/src/download/ProgressViewController.h b/camino/src/download/ProgressViewController.h new file mode 100644 index 00000000000..13754722a45 --- /dev/null +++ b/camino/src/download/ProgressViewController.h @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Calum Robinson + * Simon Fraser + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the NPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#import "CHDownloadProgressDisplay.h" + +class CHDownloader; +@class ProgressDlgController; + +@interface ProgressViewController : NSObject +{ + // we share one progress bar between both views. It's in the expanded + // view by default + IBOutlet NSProgressIndicator *mProgressBar; + + // in-progress expanded view + IBOutlet NSView *mProgressView; + IBOutlet NSButton *mExpandedCancelButton; + + // in-progress collapsed view + IBOutlet NSView *mProgressViewCompact; + + // completed expanded view + IBOutlet NSView *mCompletedView; + IBOutlet NSButton *mExpandedRevealButton; + IBOutlet NSButton *mExpandedOpenButton; + + // completed collapsed view + IBOutlet NSView *mCompletedViewCompact; + + BOOL mViewIsCompact; + BOOL mIsFileSave; + BOOL mUserCancelled; + BOOL mDownloadingError; + BOOL mDownloadDone; + BOOL mRemoveWhenDone; + + NSTimeInterval mDownloadTime; // only set when done + + long mCurrentProgress; // if progress bar is indeterminate, can still calc stats. + long mDownloadSize; + + NSString *mSourceURL; + NSString *mDestPath; + NSDate *mStartTime; + + CHDownloader *mDownloader; // we hold a ref to this + + ProgressDlgController *mProgressWindowController; // not retained +} + ++ (NSString *)formatTime:(int)aSeconds; ++ (NSString *)formatFuzzyTime:(int)aSeconds; ++ (NSString *)formatBytes:(float)aBytes; + +- (NSView *)view; + +- (IBAction)close:(id)sender; + +- (IBAction)stop:(id)sender; +- (IBAction)toggleDisclosure:(id)sender; + +- (IBAction)reveal:(id)sender; +- (IBAction)open:(id)sender; + +- (BOOL)isActive; + +- (void)setProgressWindowController:(ProgressDlgController*)progressWindowController; + +@end diff --git a/camino/src/download/ProgressViewController.mm b/camino/src/download/ProgressViewController.mm new file mode 100644 index 00000000000..86f5fb302db --- /dev/null +++ b/camino/src/download/ProgressViewController.mm @@ -0,0 +1,544 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Calum Robinson + * Simon Fraser + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the NPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#import "NSView+Utils.h" + +#import "ProgressViewController.h" +#import "ProgressDlgController.h" +#import "PreferenceManager.h" + +enum +{ + kLabelTagFilename = 1000, + kLabelTagProgress, + kLabelTagSource, + kLabelTagDestination, + kLabelTagTimeRemaining, + kLabelTagStatus, // 1005 + kLabelTagTimeRemainingLabel +}; + + +// Notification sent when user holds option key and expands/contracts a progress view +static NSString *ProgressViewsShouldResize = @"ProgressViewsShouldResize"; + +@interface ProgressViewController(ProgressViewControllerPrivate) + +- (void)viewDidLoad; +- (void)refreshDownloadInfo; +- (void)moveProgressBarToCurrentView; +- (void)updateButtons; + +@end + +@implementation ProgressViewController + ++ (NSString *)formatTime:(int)seconds +{ + NSMutableString *theTime = [NSMutableString stringWithCapacity:8]; + + NSString *padZero = [NSString stringWithString:@"0"]; + //write out new elapsed time + if (seconds >= 3600) + { + [theTime appendFormat:@"%d:",(seconds / 3600)]; + seconds = seconds % 3600; + } + + NSString *elapsedMin = [NSString stringWithFormat:@"%d:",(seconds / 60)]; + if ([elapsedMin length] == 2) + [theTime appendString:[padZero stringByAppendingString:elapsedMin]]; + else + [theTime appendString:elapsedMin]; + + seconds = seconds % 60; + NSString *elapsedSec = [NSString stringWithFormat:@"%d",seconds]; + + if ([elapsedSec length] == 2) + [theTime appendString:elapsedSec]; + else + [theTime appendString:[padZero stringByAppendingString:elapsedSec]]; + + return theTime; +} + +// fuzzy time gives back strings like "about 5 seconds" ++ (NSString *)formatFuzzyTime:(int)seconds +{ + // check for seconds first + if (seconds < 60) { + if (seconds < 7) + return [NSString stringWithFormat:NSLocalizedString(@"UnderSec", @"Under %d seconds"), 5]; + if (seconds < 13) + return [NSString stringWithFormat:NSLocalizedString(@"UnderSec", @"Under %d seconds"), 10]; + return [NSString stringWithFormat:NSLocalizedString(@"UnderMin", @"Under a minute")]; + } + // seconds becomes minutes and we keep checking. + seconds = seconds/60; + if (seconds < 60) { + if (seconds < 2) + return [NSString stringWithFormat:NSLocalizedString(@"AboutMin",@"About a minute")]; + // OK, tell the good people how much time we have left. + return [NSString stringWithFormat:NSLocalizedString(@"AboutMins",@"About %d minutes"), seconds]; + } + //this download will never seemingly never end. now seconds become hours. + seconds = seconds/60; + if (seconds < 2) + return [NSString stringWithFormat:NSLocalizedString(@"AboutHour", @"Over an hour")]; + return [NSString stringWithFormat:NSLocalizedString(@"AboutHours", @"Over %d hours"), seconds]; +} + ++ (NSString *)formatBytes:(float)bytes +{ + // if bytes are negative, we return question marks. + if (bytes < 0) + return [NSString stringWithString:@"?"]; + // bytes first. + if (bytes < 1024) + return [NSString stringWithFormat:@"%.1f bytes",bytes]; + // kb + bytes = bytes/1024; + if (bytes < 1024) + return [NSString stringWithFormat:@"%.1f KB",bytes]; + // mb + bytes = bytes/1024; + if (bytes < 1024) + return [NSString stringWithFormat:@"%.1f MB",bytes]; + // gb + bytes = bytes/1024; + return [NSString stringWithFormat:@"%.1f GB",bytes]; +} + +#pragma mark - + +- (id)init +{ + if ((self = [super init])) + { + [NSBundle loadNibNamed:@"ProgressView" owner:self]; + + [self viewDidLoad]; + + // Register for notifications when one of the progress views is expanded/contracted + // whilst holding the option button + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(changeCollapsedStateNotification:) + name:ProgressViewsShouldResize + object:nil]; + + [mExpandedRevealButton setEnabled:NO]; + [mExpandedOpenButton setEnabled:NO]; + } + + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self + name:ProgressViewsShouldResize + object:nil]; + + // if we get here because we're quitting, the listener will still be alive + // yet we're going away. As a result, we need to tell the d/l listener to + // forget it ever met us and necko will clean it up on its own. + if (mDownloader) + mDownloader->DetachDownloadDisplay(); + NS_IF_RELEASE(mDownloader); + + [mStartTime release]; + [mSourceURL release]; + [mDestPath release]; + [mProgressBar release]; + + [super dealloc]; +} + +// Save the expand/contract view pref (called when the user clicks the dislosure triangle) +- (void)setCompactViewPref +{ + [[PreferenceManager sharedInstance] setPref:"browser.download.compactView" toBoolean:mViewIsCompact]; +} + +- (void)viewDidLoad +{ + mViewIsCompact = [[PreferenceManager sharedInstance] getBooleanPref:"browser.download.compactView" withSuccess:NULL]; + [mProgressBar retain]; // make sure it survives being moved between views + + if (mViewIsCompact) + [self moveProgressBarToCurrentView]; + + // this isn't necessarily better. Need to profile. + [mProgressBar setUsesThreadedAnimation:YES]; +} + +- (NSView *)view +{ + if (mViewIsCompact) + return (mDownloadDone ? mCompletedViewCompact : mProgressViewCompact); + else + return (mDownloadDone ? mCompletedView : mProgressView); +} + +- (IBAction)toggleDisclosure:(id)sender +{ + mViewIsCompact = !mViewIsCompact; + + [self moveProgressBarToCurrentView]; + + // Is option/alt held down? + if ([[[sender window] currentEvent] modifierFlags] & NSAlternateKeyMask) + { + // Get all progress views to look the same as self + [[NSNotificationCenter defaultCenter] postNotificationName:ProgressViewsShouldResize + object:[NSNumber numberWithBool:mViewIsCompact]]; + } + + // Set the pref only when the user clicks the disclosure triangle + [self setCompactViewPref]; + + // Re-calculate the new view & window sizes + [[NSNotificationCenter defaultCenter] postNotificationName:StackViewReloadNotificationName + object:self]; + [self refreshDownloadInfo]; +} + +- (void)changeCollapsedStateNotification:(NSNotification *)notification +{ + // note that this will get called on the view that is being clicked, as well + // as the other views. Don't do redundant work here, like redrawing. + mViewIsCompact = [[notification object] boolValue]; + // Don't call [enclosingStackView reloadSubviews]; here, because it will be done + // by the original view that was option-clicked, not us +} + +-(void)cancel +{ + mUserCancelled = YES; + + if (mDownloader) // we should always have one + mDownloader->CancelDownload(); + + // clean up downloaded file. - do it here or in CancelDownload? + NSFileManager *fileManager = [NSFileManager defaultManager]; + if ([fileManager isDeletableFileAtPath:mDestPath]) + { + // if we delete it, fantastic. if not, oh well. better to move to trash instead? + [fileManager removeFileAtPath:mDestPath handler:nil]; + } +} + +- (IBAction)close:(id)sender +{ + if (!mDownloadDone) + { + mRemoveWhenDone = YES; + [self cancel]; + } + else + { + [mProgressWindowController removeDownload:self]; + } +} + +- (IBAction)stop:(id)sender +{ + [self cancel]; +} + +- (IBAction)reveal:(id)sender +{ + if ([[NSWorkspace sharedWorkspace] selectFile:mDestPath + inFileViewerRootedAtPath:[mDestPath stringByDeletingLastPathComponent]]) + return; + // hmmm. it didn't work. that's odd. need localized error messages. for now, just beep. + NSBeep(); +} + +- (IBAction)open:(id)sender +{ + if ([[NSWorkspace sharedWorkspace] openFile:mDestPath]) + return; + // hmmm. it didn't work. that's odd. need localized error message. for now, just beep. + NSBeep(); +} + +// Called just before the view will be shown to the user +- (void)downloadDidStart +{ + mStartTime = [[NSDate alloc] init]; +// [mProgressBar startAnimation:self]; // moved to onStartDownload + [self refreshDownloadInfo]; +} + +- (void)downloadDidEnd +{ + mDownloadDone = YES; + mDownloadTime = -[mStartTime timeIntervalSinceNow]; + [mProgressBar stopAnimation:self]; + + [mExpandedCancelButton setEnabled:NO]; + [self refreshDownloadInfo]; +} + +// this handles lots of things. +- (void)refreshDownloadInfo +{ + NSView* curView = [self view]; + + NSString* filename = [mSourceURL lastPathComponent]; + NSString *destPath = [mDestPath stringByAbbreviatingWithTildeInPath]; + NSString* tooltipFormat = NSLocalizedString(mDownloadDone ? @"DownloadedTooltipFormat" : @"DownloadingTooltipFormat", @""); + + id filenameLabel = [curView viewWithTag:kLabelTagFilename]; + [filenameLabel setStringValue:filename]; + [filenameLabel setToolTip:[NSString stringWithFormat:tooltipFormat, [mSourceURL lastPathComponent], mSourceURL, destPath]]; + + id destLabel = [curView viewWithTag:kLabelTagDestination]; + [destLabel setStringValue:destPath]; + + id locationLabel = [curView viewWithTag:kLabelTagSource]; + [locationLabel setStringValue:mSourceURL]; + + if (mDownloadDone) + { + id statusLabel = [curView viewWithTag:kLabelTagStatus]; + if (statusLabel) + { + NSString* statusString; + if (mUserCancelled) + statusString = NSLocalizedString(@"DownloadCancelled", @"Cancelled"); + else if (mDownloadingError) + statusString = NSLocalizedString(@"DownloadInterrupted", @"Interrupted"); + else + statusString = NSLocalizedString(@"DownloadCompleted", @"Completed"); + + [statusLabel setStringValue: statusString]; + } + + // set progress label + id progressLabel = [curView viewWithTag:kLabelTagProgress]; + if (progressLabel) + { + float byteSec = mCurrentProgress / mDownloadTime; + // show how much we downloaded, become some types of disconnects make us think + // we finished successfully + [progressLabel setStringValue:[NSString stringWithFormat: + NSLocalizedString(@"DownloadDoneStatusString", @"%@ of %@ done (at %@/sec)"), + [[self class] formatBytes:mCurrentProgress], + [[self class] formatBytes:mDownloadSize], + [[self class] formatBytes:byteSec]]]; + } + + id timeLabel = [curView viewWithTag:kLabelTagTimeRemaining]; + if (timeLabel) + [timeLabel setStringValue:[[self class] formatTime:(int)mDownloadTime]]; + + id timeLabelLabel = [curView viewWithTag:kLabelTagTimeRemainingLabel]; + if (timeLabelLabel) + [timeLabelLabel setStringValue:NSLocalizedString(@"DownloadRemainingLabelDone", @"Time elapsed:")]; + + [self updateButtons]; + } + else + { + NSTimeInterval elapsedTime = -[mStartTime timeIntervalSinceNow]; + + // update status field + id progressLabel = [curView viewWithTag:kLabelTagProgress]; + if (progressLabel) + { + NSString *statusLabelString = NSLocalizedString(@"DownloadStatusString", @"%@ of %@ total (at %@/sec)"); + float byteSec = mCurrentProgress / elapsedTime; + [progressLabel setStringValue:[NSString stringWithFormat:statusLabelString, + [[self class] formatBytes:mCurrentProgress], + (mDownloadSize > 0 ? [[self class] formatBytes:mDownloadSize] : @"?"), + [[self class] formatBytes:byteSec]]]; + } + + id timeLabel = [curView viewWithTag:kLabelTagTimeRemaining]; + if (timeLabel) + { + if (mDownloadSize > 0) + { + int secToGo = (int)ceil((elapsedTime * mDownloadSize / mCurrentProgress) - elapsedTime); + [timeLabel setStringValue:[[self class] formatFuzzyTime:secToGo]]; + } + else // mDownloadSize is undetermined. Set remaining time to question marks. + { + NSString *calculatingString = NSLocalizedString(@"DownloadCalculatingString", @"Unknown"); + [timeLabel setStringValue:calculatingString]; + } + } + } +} + +- (void)updateButtons +{ + // note: this will stat every time, which will be expensive! We could use + // FNNotify/FNSubscribe to avoid this (writing a Cocoa wrapper around it). + if (mDownloadDone && !mDownloadingError) + { + BOOL destFileExists = [[NSFileManager defaultManager] fileExistsAtPath:mDestPath]; + [mExpandedRevealButton setEnabled:destFileExists]; + [mExpandedOpenButton setEnabled:destFileExists]; + } +} + +- (void)moveProgressBarToCurrentView +{ + [mProgressBar moveToView:(mViewIsCompact ? mProgressViewCompact : mProgressView) resize:YES]; + [mProgressBar startAnimation:self]; // this is necessary to keep it animating for some reason +} + +- (void)setProgressWindowController:(ProgressDlgController*)progressWindowController +{ + mProgressWindowController = progressWindowController; +} + +- (BOOL)isActive +{ + return !mDownloadDone; +} + +#pragma mark - + +- (void)onStartDownload:(BOOL)isFileSave +{ + mIsFileSave = isFileSave; + [self downloadDidStart]; + [mProgressWindowController didStartDownload:self]; + + // need to do this after the view as been put in the window, otherwise it doesn't work + [mProgressBar startAnimation:self]; +} + +- (void)onEndDownload:(BOOL)completedOK +{ + mDownloadingError = !completedOK; + + [self downloadDidEnd]; + [mProgressWindowController didEndDownload:self]; + if (mRemoveWhenDone) + [mProgressWindowController removeDownload:self]; +} + +- (void)setProgressTo:(long)aCurProgress ofMax:(long)aMaxProgress +{ + mCurrentProgress = aCurProgress; // fall back for stat calcs + mDownloadSize = aMaxProgress; + + if (![mProgressBar isIndeterminate]) //most likely - just update value + { + if (aCurProgress == aMaxProgress) //handles little bug in FTP download size + [mProgressBar setMaxValue:aMaxProgress]; + + [mProgressBar setDoubleValue:aCurProgress]; + } + else if (aMaxProgress > 0) // ok, we're starting up with good max & cur values + { + [mProgressBar setIndeterminate:NO]; + [mProgressBar setMaxValue:aMaxProgress]; + [mProgressBar setDoubleValue:aCurProgress]; + } // if neither case was true, it's barber pole city. +} + +-(void)setDownloadListener:(CHDownloader*)aDownloader +{ + if (mDownloader != aDownloader) + NS_IF_RELEASE(mDownloader); + + NS_IF_ADDREF(mDownloader = aDownloader); +} + +#if 0 +/* + This is kind of a hack. It should probably be done somewhere else so Mozilla can have + it too, but until Apple fixes the problems with the setting of comments without + reverting to Applescript, I have left it in. + + Turned off for now, until we find a better way to do this. Won't Carbon APIs work? +*/ +- (void)tryToSetFinderComments +{ + if (mDestPath && mSourceURL) + { + CFURLRef fileURL = CFURLCreateWithFileSystemPath( NULL, + (CFStringRef)mDestPath, + kCFURLPOSIXPathStyle, + NO); + + NSString *hfsPath = (NSString *)CFURLCopyFileSystemPath(fileURL, + kCFURLHFSPathStyle); + + CFRelease(fileURL); + + NSAppleScript *setCommentScript = [[NSAppleScript alloc] initWithSource: + [NSString stringWithFormat:@"tell application \"Finder\" to set comment of file \"%@\" to \"%@\"", hfsPath, mSourceURL]]; + NSDictionary *errorInfo = NULL; + + [setCommentScript executeAndReturnError:&errorInfo]; + + if (errorInfo) + { + NSLog(@"Get error when running AppleScript to set comments for '%@':\n %@", + mDestPath, + [errorInfo objectForKey:NSAppleScriptErrorMessage]); + } + } +} +#endif + +- (void)setSourceURL:(NSString*)aSourceURL +{ + [mSourceURL autorelease]; + mSourceURL = [aSourceURL copy]; + + //[self tryToSetFinderComments]; +} + +- (void)setDestinationPath:(NSString*)aDestPath +{ + [mDestPath autorelease]; + mDestPath = [aDestPath copy]; + //[self tryToSetFinderComments]; +} + +@end diff --git a/camino/src/download/SaveHeaderSniffer.h b/camino/src/download/SaveHeaderSniffer.h index 4147cce1507..4ae0c1c04bb 100644 --- a/camino/src/download/SaveHeaderSniffer.h +++ b/camino/src/download/SaveHeaderSniffer.h @@ -56,7 +56,7 @@ public: nsHeaderSniffer(nsIWebBrowserPersist* aPersist, nsIFile* aFile, nsIURI* aURL, nsIDOMDocument* aDocument, nsIInputStream* aPostData, const nsAString& aSuggestedFilename, PRBool aBypassCache, - NSView* aFilterView, NSPopUpButton* aFilterList); + NSView* aFilterView); virtual ~nsHeaderSniffer(); NS_DECL_ISUPPORTS @@ -79,6 +79,5 @@ private: nsCString mContentType; nsCString mContentDisposition; NSView* mFilterView; - NSPopUpButton* mFilterList; }; diff --git a/camino/src/download/SaveHeaderSniffer.mm b/camino/src/download/SaveHeaderSniffer.mm index 42827fa633c..77ccd5842d7 100644 --- a/camino/src/download/SaveHeaderSniffer.mm +++ b/camino/src/download/SaveHeaderSniffer.mm @@ -38,6 +38,8 @@ #import "NSString+Utils.h" +#import "ChimeraUIConstants.h" + #include "SaveHeaderSniffer.h" #include "netCore.h" @@ -56,7 +58,7 @@ const char* const persistContractID = "@mozilla.org/embedding/browser/nsWebBrows nsHeaderSniffer::nsHeaderSniffer(nsIWebBrowserPersist* aPersist, nsIFile* aFile, nsIURI* aURL, nsIDOMDocument* aDocument, nsIInputStream* aPostData, const nsAString& aSuggestedFilename, PRBool aBypassCache, - NSView* aFilterView, NSPopUpButton* aFilterList) + NSView* aFilterView) : mPersist(aPersist) , mTmpFile(aFile) , mURL(aURL) @@ -65,9 +67,8 @@ nsHeaderSniffer::nsHeaderSniffer(nsIWebBrowserPersist* aPersist, nsIFile* aFile, , mDefaultFilename(aSuggestedFilename) , mBypassCache(aBypassCache) , mFilterView(aFilterView) -, mFilterList(aFilterList) { - NS_INIT_ISUPPORTS(); + NS_INIT_ISUPPORTS(); } nsHeaderSniffer::~nsHeaderSniffer() @@ -183,14 +184,16 @@ nsresult nsHeaderSniffer::PerformSave(nsIURI* inOriginalURI) return rv; nsCOMPtr dirBranch; prefs->GetBranch("browser.download.", getter_AddRefs(dirBranch)); - PRInt32 filterIndex = 0; + PRInt32 filterIndex = eSaveFormatHTMLComplete; if (dirBranch) { nsresult rv = dirBranch->GetIntPref("save_converter_index", &filterIndex); if (NS_FAILED(rv)) - filterIndex = 0; + filterIndex = eSaveFormatHTMLComplete; } - if (mFilterList) - [mFilterList selectItemAtIndex: filterIndex]; + + NSPopUpButton* filterList = [mFilterView viewWithTag:kSaveFormatPopupTag]; + if (filterList) + [filterList selectItemAtIndex: filterIndex]; // We need to figure out what file name to use. nsAutoString defaultFileName; @@ -294,17 +297,17 @@ nsresult nsHeaderSniffer::PerformSave(nsIURI* inOriginalURI) return NS_OK; // Update the filter index. - if (isHTML && mFilterList) { - filterIndex = [mFilterList indexOfSelectedItem]; + if (isHTML && filterList) { + filterIndex = [filterList indexOfSelectedItem]; dirBranch->SetIntPref("save_converter_index", filterIndex); } // Convert the content type to text/plain if it was selected in the filter. - if (isHTML && filterIndex == 2) + if (isHTML && filterIndex == eSaveFormatPlainText) mContentType = "text/plain"; nsCOMPtr sourceData; - if (isHTML && filterIndex != 1) + if (isHTML && filterIndex != eSaveFormatHTMLSource) sourceData = do_QueryInterface(mDocument); else sourceData = do_QueryInterface(mURL); diff --git a/camino/src/download/nsDownloadListener.h b/camino/src/download/nsDownloadListener.h index c76874c71d9..d3dc4e47aa7 100644 --- a/camino/src/download/nsDownloadListener.h +++ b/camino/src/download/nsDownloadListener.h @@ -21,6 +21,7 @@ * * Contributor(s): * Simon Fraser + * Calum Robinson * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -49,6 +50,8 @@ #include "nsIWebBrowserPersist.h" #include "nsIURI.h" #include "nsILocalFile.h" +#include "nsITimer.h" + #include "nsExternalHelperAppService.h" @@ -56,24 +59,28 @@ class nsDownloadListener : public CHDownloader, public nsIDownload, - public nsIWebProgressListener + public nsIWebProgressListener, + public nsITimerCallback { public: - nsDownloadListener(DownloadControllerFactory* inDownloadControllerFactory); + nsDownloadListener(); virtual ~nsDownloadListener(); NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIDOWNLOAD NS_DECL_NSIWEBPROGRESSLISTENER + + // nsITimerCallback + NS_IMETHOD Notify(nsITimer *timer); public: - //void BeginDownload(); + void InitDialog(); virtual void PauseDownload(); virtual void ResumeDownload(); virtual void CancelDownload(); - virtual void DownloadDone(); + virtual void DownloadDone(nsresult aStatus); virtual void DetachDownloadDisplay(); private: @@ -84,10 +91,13 @@ private: nsCOMPtr mURI; // The URI of our source file. Null if we're saving a complete document. nsCOMPtr mDestination; // Our destination URL. + nsCOMPtr mEndRefreshTimer; // Timer used to update the status to done + nsresult mDownloadStatus; // status from last nofication PRInt64 mStartTime; // When the download started PRPackedBool mBypassCache; // Whether we should bypass the cache or not. PRPackedBool mNetworkTransfer; // true if the first OnStateChange has the NETWORK bit set PRPackedBool mGotFirstStateChange; // true after we've seen the first OnStateChange PRPackedBool mUserCanceled; // true if the user canceled the download + PRPackedBool mSentCancel; // true when we've notified the backend of the cancel }; diff --git a/camino/src/download/nsDownloadListener.mm b/camino/src/download/nsDownloadListener.mm index 8acb6b28c53..0fb52f20c6a 100644 --- a/camino/src/download/nsDownloadListener.mm +++ b/camino/src/download/nsDownloadListener.mm @@ -21,7 +21,7 @@ * * Contributor(s): * Simon Fraser - * + * Calum Robinson * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -46,20 +46,25 @@ #include "nsIURL.h" #include "netCore.h" -nsDownloadListener::nsDownloadListener(DownloadControllerFactory* inControllerFactory) -: CHDownloader(inControllerFactory) +nsDownloadListener::nsDownloadListener() +: mDownloadStatus(NS_OK) , mBypassCache(PR_FALSE) , mNetworkTransfer(PR_FALSE) , mGotFirstStateChange(PR_FALSE) , mUserCanceled(PR_FALSE) +, mSentCancel(PR_FALSE) { + mStartTime = LL_ZERO; } nsDownloadListener::~nsDownloadListener() { + // if we go away before the timer fires, cancel it + if (mEndRefreshTimer) + mEndRefreshTimer->Cancel(); } -NS_IMPL_ISUPPORTS_INHERITED2(nsDownloadListener, CHDownloader, nsIDownload, nsIWebProgressListener) +NS_IMPL_ISUPPORTS_INHERITED3(nsDownloadListener, CHDownloader, nsIDownload, nsIWebProgressListener, nsITimerCallback) #pragma mark - @@ -193,14 +198,14 @@ nsDownloadListener::OnProgressChange(nsIWebProgress *aWebProgress, PRInt32 aCurTotalProgress, PRInt32 aMaxTotalProgress) { - if (mUserCanceled) + if (mUserCanceled && !mSentCancel) { if (mHelperAppLauncher) mHelperAppLauncher->Cancel(); else if (aRequest) aRequest->Cancel(NS_BINDING_ABORTED); - mUserCanceled = false; + mSentCancel = PR_TRUE; } [mDownloadDisplay setProgressTo:aCurTotalProgress ofMax:aMaxTotalProgress]; @@ -236,7 +241,7 @@ nsDownloadListener::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *a // Implementation of nsIWebProgressListener /* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aStateFlags, in unsigned long aStatus); */ NS_IMETHODIMP -nsDownloadListener::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 aStateFlags, +nsDownloadListener::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 aStateFlags, PRUint32 aStatus) { // NSLog(@"State changed: state %u, status %u", aStateFlags, aStatus); @@ -250,29 +255,64 @@ nsDownloadListener::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRe // the window and controller. We will get this even in the event of a cancel, // so this is the only place in the listener where we should kill the download. if ((aStateFlags & STATE_STOP) && (!mNetworkTransfer || (aStateFlags & STATE_IS_NETWORK))) { - DownloadDone(); + DownloadDone(aStatus); } return NS_OK; } #pragma mark - +// nsITimerCallback implementation +NS_IMETHODIMP nsDownloadListener::Notify(nsITimer *timer) +{ + // resset the destination, since uniquifying the filename may have + // changed it + nsAutoString pathStr; + mDestination->GetPath(pathStr); + [mDownloadDisplay setDestinationPath: [NSString stringWith_nsAString:pathStr]]; + + // cancelling should give us a failure status + [mDownloadDisplay onEndDownload:(NS_SUCCEEDED(mDownloadStatus) && !mUserCanceled)]; + mEndRefreshTimer = NULL; + return NS_OK; +} + +#pragma mark - + void nsDownloadListener::InitDialog() { // dialog has to be shown before the outlets get hooked up - [mDownloadDisplay onStartDownload:(BOOL)IsFileSave()]; - if (mURI) { nsCAutoString spec; - mURI->GetSpec(spec); + + // we need to be careful not to show a password in the url + nsCAutoString userPassword; + mURI->GetUserPass(userPassword); + if (!userPassword.IsEmpty()) + { + // ugh, build it by hand + nsCAutoString hostport, path; + mURI->GetScheme(spec); + mURI->GetHostPort(hostport); + mURI->GetPath(path); + + spec.Append("://"); + spec.Append(hostport); + spec.Append(path); + } + else + mURI->GetSpec(spec); + [mDownloadDisplay setSourceURL: [NSString stringWithUTF8String:spec.get()]]; } nsAutoString pathStr; mDestination->GetPath(pathStr); [mDownloadDisplay setDestinationPath: [NSString stringWith_nsAString:pathStr]]; + + [mDownloadDisplay onStartDownload:IsFileSave()]; } void @@ -292,19 +332,19 @@ nsDownloadListener::CancelDownload() { mUserCanceled = PR_TRUE; - if (mWebPersist) + if (mWebPersist && !mSentCancel) { mWebPersist->CancelSave(); - mUserCanceled = PR_FALSE; + mSentCancel = PR_TRUE; } // delete any files we've created... - + // DownloadDone will get called (eventually) } void -nsDownloadListener::DownloadDone() +nsDownloadListener::DownloadDone(nsresult aStatus) { // break the reference cycle by removing ourselves as a listener if (mWebPersist) @@ -314,8 +354,23 @@ nsDownloadListener::DownloadDone() } mHelperAppLauncher = nsnull; - - [mDownloadDisplay onEndDownload]; + mDownloadStatus = aStatus; + + // hack alert! + // Our destination file gets uniquified after the OnStop notification is sent + // (in nsExternalAppHandler::ExecuteDesiredAction), so we never get a chance + // to figure out the final filename. To work around this, set a timer to fire + // in the near future, from which we'll send the done callback. + mEndRefreshTimer = do_CreateInstance("@mozilla.org/timer;1"); + if (mEndRefreshTimer) + { + nsresult rv = mEndRefreshTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT); // defaults to 1-shot, normal priority + if (NS_FAILED(rv)) + mEndRefreshTimer = NULL; + } + + if (!mEndRefreshTimer) // timer creation or init failed, so just do it now + [mDownloadDisplay onEndDownload:(NS_SUCCEEDED(aStatus) && !mUserCanceled)]; } // diff --git a/camino/src/embedding/CHBrowserService.mm b/camino/src/embedding/CHBrowserService.mm index 0026795c567..6c0133b34e2 100644 --- a/camino/src/embedding/CHBrowserService.mm +++ b/camino/src/embedding/CHBrowserService.mm @@ -38,7 +38,6 @@ #import "NSString+Utils.h" #import "CHBrowserService.h" -#import "CHDownloadFactories.h" #import "CHBrowserView.h" #include "nsIWindowWatcher.h" @@ -107,14 +106,6 @@ CHBrowserService::InitEmbedding() static NS_DEFINE_CID(kHelperDlgCID, NS_HELPERAPPLAUNCHERDIALOG_CID); nsresult rv = cr->RegisterFactory(kHelperDlgCID, NS_IHELPERAPPLAUNCHERDLG_CLASSNAME, NS_IHELPERAPPLAUNCHERDLG_CONTRACTID, sSingleton); - - // replace the downloader with our own which does not rely on the xpfe downlaod manager - nsCOMPtr downloadFactory; - rv = NewDownloadListenerFactory(getter_AddRefs(downloadFactory)); - if (NS_FAILED(rv)) return rv; - - static NS_DEFINE_CID(kDownloadCID, NS_DOWNLOAD_CID); - rv = cr->RegisterFactory(kDownloadCID, "Download", NS_DOWNLOAD_CONTRACTID, downloadFactory); return rv; } diff --git a/camino/src/embedding/CHBrowserView.h b/camino/src/embedding/CHBrowserView.h index c7f87ee2b90..ff000640c7e 100644 --- a/camino/src/embedding/CHBrowserView.h +++ b/camino/src/embedding/CHBrowserView.h @@ -163,9 +163,8 @@ enum { // nsIWebBrowserSetup methods - (void)setProperty:(unsigned int)property toValue:(unsigned int)value; -- (void)saveDocument:(BOOL)focusedFrame filterView:(NSView*)aFilterView filterList: (NSPopUpButton*)aFilterList; -- (void)saveURL: (NSView*)aFilterView filterList: (NSPopUpButton*)aFilterList - url: (NSString*)aURLSpec suggestedFilename: (NSString*)aFilename; +- (void)saveDocument:(BOOL)focusedFrame filterView:(NSView*)aFilterView; +- (void)saveURL:(NSView*)aFilterView url: (NSString*)aURLSpec suggestedFilename: (NSString*)aFilename; - (void)printDocument; - (void)pageSetup; diff --git a/camino/src/embedding/CHBrowserView.mm b/camino/src/embedding/CHBrowserView.mm index 43feb519bee..4179f8260eb 100644 --- a/camino/src/embedding/CHBrowserView.mm +++ b/camino/src/embedding/CHBrowserView.mm @@ -430,7 +430,6 @@ const char kDirServiceContractID[] = "@mozilla.org/file/directory_service;1"; suggestedFilename: (NSString*)aFileName bypassCache: (BOOL)aBypassCache filterView: (NSView*)aFilterView - filterList: (NSPopUpButton*)aFilterList { // Create our web browser persist object. This is the object that knows // how to actually perform the saving of the page (and of the images @@ -477,7 +476,7 @@ const char kDirServiceContractID[] = "@mozilla.org/file/directory_service;1"; [aFileName assignTo_nsAString:fileName]; nsHeaderSniffer* sniffer = new nsHeaderSniffer(webPersist, tmpFile, aURI, aDocument, postData, fileName, aBypassCache, - aFilterView, aFilterList); + aFilterView); if (!sniffer) return; webPersist->SetProgressListener(sniffer); // owned @@ -572,8 +571,7 @@ const char kDirServiceContractID[] = "@mozilla.org/file/directory_service;1"; return found; } -- (void)saveURL: (NSView*)aFilterView filterList: (NSPopUpButton*)aFilterList - url: (NSString*)aURLSpec suggestedFilename: (NSString*)aFilename +- (void)saveURL: (NSView*)aFilterView url: (NSString*)aURLSpec suggestedFilename: (NSString*)aFilename { nsCOMPtr url; nsresult rv = NS_NewURI(getter_AddRefs(url), [aURLSpec UTF8String]); @@ -584,8 +582,7 @@ const char kDirServiceContractID[] = "@mozilla.org/file/directory_service;1"; withDocument: nsnull suggestedFilename: aFilename bypassCache: YES - filterView: aFilterView - filterList: aFilterList]; + filterView: aFilterView]; } -(NSString*)getFocusedURLString @@ -616,7 +613,7 @@ const char kDirServiceContractID[] = "@mozilla.org/file/directory_service;1"; return [NSString stringWith_nsAString: urlStr]; } -- (void)saveDocument:(BOOL)focusedFrame filterView:(NSView*)aFilterView filterList: (NSPopUpButton*)aFilterList +- (void)saveDocument:(BOOL)focusedFrame filterView:(NSView*)aFilterView { if (!_webBrowser) return; @@ -656,8 +653,7 @@ const char kDirServiceContractID[] = "@mozilla.org/file/directory_service;1"; withDocument: domDocument suggestedFilename: @"" bypassCache: NO - filterView: aFilterView - filterList: aFilterList]; + filterView: aFilterView]; } -(void)doCommand:(const char*)commandName diff --git a/camino/src/embedding/CHDownloadProgressDisplay.h b/camino/src/embedding/CHDownloadProgressDisplay.h index 03b8e659354..f1912e1dd8b 100644 --- a/camino/src/embedding/CHDownloadProgressDisplay.h +++ b/camino/src/embedding/CHDownloadProgressDisplay.h @@ -20,6 +20,7 @@ * * Contributor(s): * Simon Fraser + * Calum Robinson * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -45,19 +46,17 @@ 1. The CHDownloadProgressDisplay protocol. This is a formal protocol that needs to be implemented by - a window controller for your progress window. Its methods - will be called by the underlying C++ downloading classes. + an object (eg. a window controller or a view controller) + for your progress window. Its methods will be called by the + underlying C++ downloading classes. - 2. The Obj-C DownloadControllerFactory class. - - This class should be subclassed by an embedder, with an - implementation of 'createDownloadController' that hands back - a new instance of an NSWindowController that implements the - protocol. - - The underlying C++ classes use this factory to create the - progress window controller. + 2. The CHDownloadDisplayFactory protocol + This is a formal protocol that can be implemented by + any object that can create objects that themselves + implement CHDownloadProgressDisplay. This would probably be + an NSWindowController. + 3. The CHDownloader C++ class This base class exists to hide the complextity of the download @@ -90,10 +89,10 @@ In both cases, creating the nsDownloadListener and calling its Init() method calls nsDownloder::CreateDownloadDisplay(). The nsDownloder has as a member - variable a DownloadControllerFactory (see above), which got passed to it - via our XPCOM factory for nsIDownload objects. It then uses that DownloadControllerFactory - to get an instance of the download progress window controller, which then - shows the download progress window. + variable an object that implements CHDownloadDisplayFactory (see above), which got set + on it via a call to SetDisplayFactory. It then uses that CHDownloadDisplayFactory + to create an instance of the download progress display, which then controls + something (like a view or window) that shows in the UI. Simple, eh? @@ -105,13 +104,13 @@ class CHDownloader; -// a formal protocol for something that implements progress display -// Embedders can make a window controller that conforms to this +// A formal protocol for something that implements progress display. +// Embedders can make a window or view controller that conforms to this // protocol, and reuse nsDownloadListener to get download UI. @protocol CHDownloadProgressDisplay - (void)onStartDownload:(BOOL)isFileSave; -- (void)onEndDownload; +- (void)onEndDownload:(BOOL)completedOK; - (void)setProgressTo:(long)aCurProgress ofMax:(long)aMaxProgress; @@ -121,35 +120,34 @@ class CHDownloader; @end -// subclass this, and have your subclass instantiate and return your window -// controller in createDownloadController -@interface DownloadControllerFactory : NSObject -{ -} +// A formal protocol which is implemented by a factory of progress UI. +@protocol CHDownloadDisplayFactory -- (NSWindowController *)createDownloadController; +- (id )createProgressDisplay; @end // Pure virtual base class for a generic downloader, that the progress UI can talk to. // It implements nsISupports so that it can be refcounted. This class insulates the -// UI code from having to know too much about the nsIDownloadListener. -// It is responsible for creating the download UI, via the DownloadControllerFactory +// UI code from having to know too much about the nsDownloadListener. +// It is responsible for creating the download UI, via the CHDownloadController // that it owns. class CHDownloader : public nsISupports { public: - CHDownloader(DownloadControllerFactory* inControllerFactory); + CHDownloader(); virtual ~CHDownloader(); NS_DECL_ISUPPORTS + virtual void SetDisplayFactory(id inDownloadDisplayFactory); // retains + virtual void PauseDownload() = 0; virtual void ResumeDownload() = 0; virtual void CancelDownload() = 0; - virtual void DownloadDone() = 0; - virtual void DetachDownloadDisplay() = 0; // tell downloader to forget about its display + virtual void DownloadDone(nsresult aStatus) = 0; + virtual void DetachDownloadDisplay() = 0; // tell downloader to forget about its display virtual void CreateDownloadDisplay(); @@ -160,8 +158,8 @@ protected: protected: - DownloadControllerFactory* mControllerFactory; - id mDownloadDisplay; // something that implements the CHDownloadProgressDisplay protocol - PRBool mIsFileSave; // true if we're doing a save, rather than a download + id mDisplayFactory; + id mDownloadDisplay; // something that implements the CHDownloadProgressDisplay protocol + PRBool mIsFileSave; // true if we're doing a save, rather than a download }; diff --git a/camino/src/embedding/CHDownloadProgressDisplay.mm b/camino/src/embedding/CHDownloadProgressDisplay.mm index 3f384b9fa90..18a7e3df922 100644 --- a/camino/src/embedding/CHDownloadProgressDisplay.mm +++ b/camino/src/embedding/CHDownloadProgressDisplay.mm @@ -20,6 +20,7 @@ * * Contributor(s): * Simon Fraser + * Calum Robinson * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -37,40 +38,34 @@ #import "CHDownloadProgressDisplay.h" +// CHDownloader is a simple class that that the download UI can talk to -@implementation DownloadControllerFactory - -- (NSWindowController *)createDownloadController -{ - // a dummy implementation. You should provide a subclass that - // returns an instance of your progress dialog controller. - return nil; -} - -@end - -#pragma mark - - -// see the header file for comments -CHDownloader::CHDownloader(DownloadControllerFactory* inControllerFactory) -: mControllerFactory(inControllerFactory) +CHDownloader::CHDownloader() +: mDisplayFactory(NULL) , mDownloadDisplay(nil) , mIsFileSave(PR_FALSE) { NS_INIT_ISUPPORTS(); - [mControllerFactory retain]; } CHDownloader::~CHDownloader() { - [mControllerFactory release]; + [mDisplayFactory release]; } NS_IMPL_ISUPPORTS1(CHDownloader, nsISupports); +void +CHDownloader::SetDisplayFactory(id inDownloadControllerFactory) +{ + mDisplayFactory = inDownloadControllerFactory; + [mDisplayFactory retain]; +} + void CHDownloader::CreateDownloadDisplay() { - mDownloadDisplay = [mControllerFactory createDownloadController]; + NS_ASSERTION(mDisplayFactory, "Should have a UI factory"); + mDownloadDisplay = [mDisplayFactory createProgressDisplay]; [mDownloadDisplay setDownloadListener:this]; } diff --git a/camino/src/extensions/CHStackView.h b/camino/src/extensions/CHStackView.h new file mode 100644 index 00000000000..34149ed253d --- /dev/null +++ b/camino/src/extensions/CHStackView.h @@ -0,0 +1,61 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Chimera code. + * + * The Initial Developer of the Original Code is + * Calum Robinson. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Calum Robinson + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the NPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#import + +// views contained in the stack should send this notification when they change size +extern NSString* StackViewReloadNotificationName; + +// the stack view sends this notification after it has adjusted to subview sizes +extern NSString* StackViewResizedNotificationName; + +@interface CHStackView : NSView +{ + IBOutlet id mDataSource; +} + +- (void)setDataSource:(id)aDataSource; +- (void)reloadSubviews; + +@end + +@protocol CHStackViewDataSource + +- (int)subviewsForStackView:(CHStackView *)stackView; +- (NSView *)viewForStackView:(CHStackView *)stackView atIndex:(int)index; + +@end diff --git a/camino/src/extensions/CHStackView.m b/camino/src/extensions/CHStackView.m new file mode 100644 index 00000000000..d14c0d87e86 --- /dev/null +++ b/camino/src/extensions/CHStackView.m @@ -0,0 +1,143 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Chimera code. + * + * The Initial Developer of the Original Code is + * Calum Robinson. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Calum Robinson + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the NPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + /* + This class was inspired by the OAStack view from OmniGroup, but not copied directly. This + implementation is a little simpler, which is fine. + + It's like NSTableView, except the data source returns views instead of strings/images etc. +*/ + +#import "CHStackView.h" + +NSString* StackViewReloadNotificationName = @"ReloadStackView"; +NSString* StackViewResizedNotificationName = @"StackViewResized"; + +@implementation CHStackView + +- (id)initWithFrame:(NSRect)frameRect +{ + if ((self = [super initWithFrame:frameRect])) + { + // Register for notifications when one of the subviews changes size + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(reloadNotification:) + name:StackViewReloadNotificationName + object:nil]; + + } + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [super dealloc]; +} + +- (void)setDataSource:(id)aDataSource +{ + mDataSource = aDataSource; // should this retain? + + [self reloadSubviews]; +} + +- (void)reloadNotification:(NSNotification *)notification +{ + [self reloadSubviews]; +} + +- (void)reloadSubviews +{ + NSRect newFrame = [self frame]; + NSSize oldSize = [self bounds].size; + int i, subviewCount = [mDataSource subviewsForStackView:self]; + + NSPoint nextOrigin = NSZeroPoint; + + // we'll maintain the width of the stack view, assuming that it's + // scaled by its superview. + newFrame.size.height = 0.0; + + [[self subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)]; + + for (i = 0; i < subviewCount; i++) + { + NSView *subview = [mDataSource viewForStackView:self atIndex:i]; + NSRect subviewFrame = [subview frame]; + + unsigned int autoResizeMask = [subview autoresizingMask]; + if (autoResizeMask & NSViewWidthSizable) + subviewFrame.size.width = newFrame.size.width; + + newFrame.size.height += NSHeight(subviewFrame); + + subviewFrame.origin = nextOrigin; + [subview setFrame:subviewFrame]; + nextOrigin.y += NSHeight(subviewFrame); + + [self addSubview:subview]; + + // If there are more subviews, add a separator + if (i + 1 < subviewCount) + { + NSBox *separator = [[NSBox alloc] initWithFrame: + NSMakeRect(nextOrigin.x, nextOrigin.y - 1.0, NSWidth([subview frame]), 1.0)]; + [separator setBoxType:NSBoxSeparator]; + [separator setAutoresizingMask:NSViewWidthSizable]; + [self addSubview:separator]; + [separator release]; + } + } + + NSRect newBounds = newFrame; + newBounds.origin = NSZeroPoint; + + [self setFrame:newFrame]; + [self setNeedsDisplay:YES]; + + [[NSNotificationCenter defaultCenter] postNotificationName:StackViewResizedNotificationName + object:self + userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSValue valueWithSize:oldSize], @"oldsize", nil]]; +} + +- (BOOL)isFlipped +{ + return YES; +} + +@end diff --git a/camino/src/extensions/NSView+Utils.h b/camino/src/extensions/NSView+Utils.h new file mode 100644 index 00000000000..c36e552813f --- /dev/null +++ b/camino/src/extensions/NSView+Utils.h @@ -0,0 +1,60 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Chimera code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Simon Fraser + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#import + +#ifdef __cplusplus +extern "C" { +#endif + +// utility routine; returns YES if the sizes are equal, with the given slop +BOOL CHCloseSizes(NSSize aSize, NSSize bSize, float slop); + +#ifdef __cplusplus +} +#endif + +// category on NSView to add utilities for easy view resizing etc. + +@interface NSView(CHViewUtils) + +// move the recipient view from its superview to the destView, +// maintaining the relative size and position of the view based +// on its autoresize flags. +- (void)moveToView:(NSView*)destView resize:(BOOL)resize; + +@end diff --git a/camino/src/extensions/NSView+Utils.m b/camino/src/extensions/NSView+Utils.m new file mode 100644 index 00000000000..21393098095 --- /dev/null +++ b/camino/src/extensions/NSView+Utils.m @@ -0,0 +1,154 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Chimera code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Simon Fraser + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#import "NSView+Utils.h" + +BOOL CHCloseSizes(NSSize aSize, NSSize bSize, float slop) +{ + return (fabs(aSize.width - bSize.width) <= slop) && + (fabs(aSize.height - bSize.height) <= slop); +} + +// mask has 3 bits: 0 = 1 scales, 1 = 2 scales, 2 = 3 scales. +static void RedistributeSpace(int resizeMask, float newWidth, /* in out */ float ioSpaces[3]) +{ + float oldWidth = ioSpaces[0] + ioSpaces[1] + ioSpaces[2]; + + if (resizeMask != 0) + { + switch (resizeMask) + { + // 1 scalable section + case 1: // first + ioSpaces[0] += newWidth - oldWidth; // it can go negative + break; + case 2: // middle + ioSpaces[1] += newWidth - oldWidth; // it can go negative + break; + case 4: // last + ioSpaces[2] += newWidth - oldWidth; // it can go negative + break; + + // 2 scalable sections + case 3: // last fixed + { + float oldScaledWidth = ioSpaces[0] + ioSpaces[1]; + float newScaledWidth = (newWidth - ioSpaces[2]); + ioSpaces[0] = newScaledWidth * (ioSpaces[0] / oldScaledWidth); + ioSpaces[1] = newScaledWidth * (ioSpaces[1] / oldScaledWidth); + break; + } + case 5: // middle fixed + { + float oldScaledWidth = ioSpaces[0] + ioSpaces[2]; + float newScaledWidth = (newWidth - ioSpaces[1]); + ioSpaces[0] = newScaledWidth * (ioSpaces[0] / oldScaledWidth); + ioSpaces[2] = newScaledWidth * (ioSpaces[2] / oldScaledWidth); + break; + } + case 6: // first fixed + { + float oldScaledWidth = ioSpaces[1] + ioSpaces[2]; + float newScaledWidth = (newWidth - ioSpaces[0]); + ioSpaces[1] = newScaledWidth * (ioSpaces[1] / oldScaledWidth); + ioSpaces[2] = newScaledWidth * (ioSpaces[2] / oldScaledWidth); + break; + } + + // all scalable + case 7: + ioSpaces[0] *= newWidth / oldWidth; + ioSpaces[1] *= newWidth / oldWidth; + ioSpaces[2] *= newWidth / oldWidth; + break; + } + } + // otherwise nothing changes +} + +@implementation NSView(CHViewUtils) + +- (void)moveToView:(NSView*)destView resize:(BOOL)resize +{ + //resize &= [destView autoresizesSubviews]; + + NSRect oldFrame = [self frame]; + NSRect oldSuperBounds = [[self superview] bounds]; + + [self retain]; + [self removeFromSuperview]; + + [destView addSubview:self]; + [self release]; + + [destView setAutoresizesSubviews:YES]; + + if (resize) + { + unsigned int resizeMask = [self autoresizingMask]; + NSRect newFrame = oldFrame; + + if (resizeMask != NSViewNotSizable && !NSEqualRects([destView bounds], oldSuperBounds)) + { + float spaces[3]; + // horizontal + float newWidth = NSWidth([destView bounds]); + spaces[0] = NSMinX(oldFrame); + spaces[1] = NSWidth(oldFrame); + spaces[2] = NSMaxX(oldSuperBounds) - NSMaxX(oldFrame); + + RedistributeSpace(resizeMask & 0x07, newWidth, spaces); + newFrame.origin.x = spaces[0]; + newFrame.size.width = spaces[1]; + + // vertical. we assume that the view should stick to the top of the destView here + float newHeight = NSHeight([destView bounds]); + spaces[0] = NSMinY(oldFrame); + spaces[1] = NSHeight(oldFrame); + spaces[2] = NSMaxY(oldSuperBounds) - NSMaxY(oldFrame); + + RedistributeSpace((resizeMask >> 3) & 0x07, newHeight, spaces); + newFrame.origin.y = spaces[0]; + newFrame.size.height = spaces[1]; + } + + [self setFrame:newFrame]; + [self setNeedsDisplay:YES]; + } +} + +@end diff --git a/camino/src/extensions/RDFOutlineViewDataSource.h b/camino/src/extensions/RDFOutlineViewDataSource.h index f75ab400132..81c6ce491ce 100644 --- a/camino/src/extensions/RDFOutlineViewDataSource.h +++ b/camino/src/extensions/RDFOutlineViewDataSource.h @@ -51,24 +51,31 @@ class nsIRDFService; @interface RDFOutlineViewItem : NSObject { nsIRDFResource* mResource; + unsigned int mCacheVersion; // if matches the cache version in the data source, + // cached values are valid + BOOL mExpandable; + int mNumChildren; + NSArray* mChildNodes; } -- (nsIRDFResource*) resource; -- (void) setResource: (nsIRDFResource*) aResource; +- (nsIRDFResource*)resource; // addRefs the result +- (void)setResource:(nsIRDFResource*) aResource; @end -@interface RDFOutlineViewDataSource : NSObject { - nsIRDFDataSource* mDataSource; - nsIRDFContainer* mContainer; - nsIRDFContainerUtils* mContainerUtils; - nsIRDFResource* mRootResource; - nsIRDFService* mRDFService; +@interface RDFOutlineViewDataSource : NSObject +{ + nsIRDFDataSource* mDataSource; + nsIRDFContainer* mContainer; + nsIRDFContainerUtils* mContainerUtils; + nsIRDFResource* mRootResource; + nsIRDFService* mRDFService; - IBOutlet ExtendedOutlineView* mOutlineView; + IBOutlet ExtendedOutlineView* mOutlineView; - NSMutableDictionary* mDictionary; + NSMutableDictionary* mDictionary; + unsigned int mCacheVersion; } // Initialization Methods @@ -85,7 +92,6 @@ class nsIRDFService; - (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item; - (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item; - (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item; -- (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item; // tooltip support from the ExtendedOutlineView. Override to provide a tooltip // other than the Name property for each item in the view. @@ -94,14 +100,14 @@ class nsIRDFService; - (void)reloadDataForItem:(id)item reloadChildren: (BOOL)aReloadChildren; // Implementation Methods -- (id) makeWrapperFor: (nsIRDFResource*) aRDFResource; +- (id)getWrapperFor:(nsIRDFResource*) aRDFResource; +- (void)invalidateCachedItems; // override to do something different with the cell data rather than just // return a string (add an icon in an attributed string, for example). --(id) createCellContents:(const nsAString&)inValue withColumn:(NSString*)inColumn byItem:(id) inItem; +- (id)createCellContents:(NSString*)inValue withColumn:(NSString*)inColumn byItem:(id)inItem; --(void) getPropertyString:(NSString*)inPropertyURI forItem:(RDFOutlineViewItem*)inItem - result:(PRUnichar**)outResult; +- (NSString*)getPropertyString:(NSString*)inPropertyURI forItem:(RDFOutlineViewItem*)inItem; @end diff --git a/camino/src/extensions/RDFOutlineViewDataSource.mm b/camino/src/extensions/RDFOutlineViewDataSource.mm index 9b5993d91d1..a293b6a23b2 100644 --- a/camino/src/extensions/RDFOutlineViewDataSource.mm +++ b/camino/src/extensions/RDFOutlineViewDataSource.mm @@ -41,6 +41,7 @@ #import "RDFOutlineViewDataSource.h" #import "CHBrowserService.h" +#include "nsCRT.h" #include "nsIRDFDataSource.h" #include "nsIRDFService.h" #include "nsIRDFLiteral.h" @@ -55,14 +56,116 @@ #include "nsXPIDLString.h" #include "nsString.h" -@interface RDFOutlineViewDataSource(Private); -- (void)registerForShutdownNotification; -- (void)cleanup; +@interface RDFOutlineViewItem(Private) + +- (unsigned int)cacheVersion; +- (void)setNumChildren:(int)numChildren isExpandable:(BOOL)expandable cacheVersion:(unsigned int)version; +- (void)setChildren:(NSArray*)childArray; +- (BOOL)cacheValid:(unsigned int)version needChildren:(BOOL)needChildren; +- (BOOL)cachedChildren; + +- (BOOL)isExpandable; +- (int)numChildren; +- (id)childAtIndex:(int)index; @end +@implementation RDFOutlineViewItem + +- (id)init +{ + if ((self = [super init])) + { + mCacheVersion = 0; + mExpandable = NO; + mNumChildren = 0; + } + return self; +} + +- (void)dealloc +{ + [mChildNodes release]; + NS_IF_RELEASE(mResource); + [super dealloc]; +} + +- (nsIRDFResource*)resource +{ + NS_IF_ADDREF(mResource); + return mResource; +} + +- (void)setResource:(nsIRDFResource*) aResource +{ + nsIRDFResource* oldResource = mResource; + NS_IF_ADDREF(mResource = aResource); + NS_IF_RELEASE(oldResource); +} + +- (unsigned int)cacheVersion +{ + return mCacheVersion; +} + +- (void)setNumChildren:(int)numChildren isExpandable:(BOOL)expandable cacheVersion:(unsigned int)version; +{ + mNumChildren = numChildren; + mExpandable = expandable; + mCacheVersion = version; +} + +- (void)setChildren:(NSArray*)childArray +{ + // childArray can legally be nil here. If it is, we're clearing the cached children + NSArray* oldChildren = mChildNodes; + mChildNodes = childArray; + [mChildNodes retain]; + [oldChildren release]; +} + +- (BOOL)cacheValid:(unsigned int)version needChildren:(BOOL)needChildren; +{ + return (mCacheVersion == version) && (needChildren ? (mChildNodes != nil) : 1); +} + +- (BOOL)cachedChildren +{ + return (mChildNodes != nil); +} + +- (BOOL)isExpandable +{ + return mExpandable; +} + +- (int)numChildren +{ + return mNumChildren; +} + +- (id)childAtIndex:(int)index +{ + if (mChildNodes) + return [mChildNodes objectAtIndex:index]; + + return nil; +} + +@end + +#pragma mark - + +@interface RDFOutlineViewDataSource(Private) + +- (void)registerForShutdownNotification; +- (void)cleanup; +- (void)updateItemProperties:(id)item enumerateChildren:(BOOL)doChildren; + +@end + @implementation RDFOutlineViewDataSource - (id)init @@ -70,6 +173,7 @@ if ((self = [super init])) { [self registerForShutdownNotification]; + mCacheVersion = 1; } return self; } @@ -78,7 +182,7 @@ { [[NSNotificationCenter defaultCenter] removeObserver:self]; - [self cleanup]; + [self cleanup]; [super dealloc]; } @@ -167,123 +271,62 @@ // XXX - For now, we'll just say that none of our items are editable, as we aren't using any // RDF datasources that are mutable. // -- (BOOL) outlineView: (NSOutlineView*) aOutlineView shouldEditTableColumn: (NSTableColumn*) aTableColumn +- (BOOL) outlineView: (NSOutlineView*)aOutlineView shouldEditTableColumn: (NSTableColumn*) aTableColumn item: (id) aItem { - return NO; + return NO; } -- (BOOL) outlineView: (NSOutlineView*) aOutlineView isItemExpandable: (id) aItem +- (BOOL) outlineView: (NSOutlineView*)aOutlineView isItemExpandable:(id)aItem { - if (!mDataSource) - return NO; - - if (!aItem) - return YES; // The root is always open - - nsCOMPtr itemResource = dont_AddRef([aItem resource]); - - PRBool isSeq = PR_FALSE; - mContainerUtils->IsSeq(mDataSource, itemResource, &isSeq); - if (isSeq) - return YES; - - nsCOMPtr childProperty; - mRDFService->GetResource("http://home.netscape.com/NC-rdf#child", getter_AddRefs(childProperty)); - - nsCOMPtr childNode; - mDataSource->GetTarget(itemResource, childProperty, PR_TRUE, getter_AddRefs(childNode)); - - return childNode != nsnull; + if (!mDataSource) + return NO; + + if (!aItem) + return YES; // The root is always open + + if (![aItem cacheValid:mCacheVersion needChildren:NO]) + [self updateItemProperties:aItem enumerateChildren:NO]; + + return [aItem isExpandable]; } -- (id) outlineView: (NSOutlineView*) aOutlineView child: (int) aIndex - ofItem: (id) aItem +- (id)outlineView:(NSOutlineView*)aOutlineView child:(int)aIndex ofItem:(id)aItem { - if (!mDataSource) - return nil; + if (!mDataSource) + return nil; + + if (!aItem) + { + nsCOMPtr rootResource = dont_AddRef([self rootResource]); + aItem = [self getWrapperFor:rootResource]; + } + + if (![aItem cacheValid:mCacheVersion needChildren:YES]) + [self updateItemProperties:aItem enumerateChildren:YES]; - nsCOMPtr resource = !aItem ? dont_AddRef([self rootResource]) : dont_AddRef([aItem resource]); - - nsCOMPtr ordinalResource; - mContainerUtils->IndexToOrdinalResource(aIndex + 1, getter_AddRefs(ordinalResource)); - - nsCOMPtr childNode; - mDataSource->GetTarget(resource, ordinalResource, PR_TRUE, getter_AddRefs(childNode)); - if (childNode) { - // Yay. A regular container. We don't need to count, we can go directly to - // our object. - nsCOMPtr childResource(do_QueryInterface(childNode)); - if (childResource) - return [self makeWrapperFor:childResource]; - } - else - { - // Oh well, not a regular container. We need to count, dagnabbit. - nsCOMPtr childProperty; - mRDFService->GetResource("http://home.netscape.com/NC-rdf#child", getter_AddRefs(childProperty)); - - nsCOMPtr childNodes; - mDataSource->GetTargets(resource, childProperty, PR_TRUE, getter_AddRefs(childNodes)); - - nsCOMPtr supp; - PRInt32 count = 0; - - PRBool hasMore = PR_FALSE; - while (NS_SUCCEEDED(childNodes->HasMoreElements(&hasMore)) && hasMore) - { - childNodes->GetNext(getter_AddRefs(supp)); - if (count == aIndex) - break; - count ++; - } - - nsCOMPtr childResource(do_QueryInterface(supp)); - if (childResource) { - return [self makeWrapperFor:childResource]; - } - } - - return nil; + return [aItem childAtIndex:aIndex]; } -- (int) outlineView: (NSOutlineView*) aOutlineView numberOfChildrenOfItem: (id) aItem; +- (int)outlineView:(NSOutlineView*)aOutlineView numberOfChildrenOfItem:(id) aItem; { - if (!mDataSource) - return 0; - - nsCOMPtr resource = dont_AddRef(aItem ? [aItem resource] : [self rootResource]); - - // XXX just assume NC:child is the only containment arc for now - nsCOMPtr childProperty; - mRDFService->GetResource("http://home.netscape.com/NC-rdf#child", getter_AddRefs(childProperty)); - - nsCOMPtr childNodes; - mDataSource->GetTargets(resource, childProperty, PR_TRUE, getter_AddRefs(childNodes)); - - PRBool hasMore = PR_FALSE; - PRInt32 count = 0; - - while (NS_SUCCEEDED(childNodes->HasMoreElements(&hasMore)) && hasMore) - { - nsCOMPtr supp; - childNodes->GetNext(getter_AddRefs(supp)); - count ++; - } - - if (count == 0) { - nsresult rv = mContainer->Init(mDataSource, resource); - if (NS_FAILED(rv)) - return 0; - - mContainer->GetCount(&count); - } - - return count; + if (!mDataSource) + return 0; + + if (!aItem) + { + nsCOMPtr rootResource = dont_AddRef([self rootResource]); + aItem = [self getWrapperFor:rootResource]; + } + + if (![aItem cacheValid:mCacheVersion needChildren:YES]) + [self updateItemProperties:aItem enumerateChildren:YES]; + + return [aItem numChildren]; } -- (id) outlineView: (NSOutlineView*) aOutlineView objectValueForTableColumn: (NSTableColumn*) aTableColumn - byItem: (id) aItem +- (id)outlineView:(NSOutlineView*)aOutlineView objectValueForTableColumn:(NSTableColumn*)aTableColumn + byItem:(id)aItem { if (!mDataSource || !aItem) return nil; @@ -291,25 +334,22 @@ // The table column's identifier is the RDF Resource URI of the property being displayed in // that column, e.g. "http://home.netscape.com/NC-rdf#Name" NSString* columnPropertyURI = [aTableColumn identifier]; - nsXPIDLString literalValue; - [self getPropertyString:columnPropertyURI forItem:aItem result:getter_Copies(literalValue)]; + NSString* propString = [self getPropertyString:columnPropertyURI forItem:aItem]; - return [self createCellContents:literalValue withColumn:columnPropertyURI byItem:aItem]; + return [self createCellContents:propString withColumn:columnPropertyURI byItem:aItem]; } - // // createCellContents:withColumn:byItem // // Constructs a NSString from the given string data for this item in the given column. // This should be overridden to do more fancy things, such as add an icon, etc. // --(id) createCellContents:(const nsAString&)inValue withColumn:(NSString*)inColumn byItem:(id) inItem +- (id)createCellContents:(NSString*)inValue withColumn:(NSString*)inColumn byItem:(id)inItem { - return [NSString stringWith_nsAString: inValue]; + return inValue; } - // // outlineView:tooltipForString // @@ -318,21 +358,9 @@ // - (NSString *)outlineView:(NSOutlineView *)outlineView tooltipStringForItem:(id)inItem { - nsXPIDLString literalValue; - [self getPropertyString:@"http://home.netscape.com/NC-rdf#Name" forItem:inItem result:getter_Copies(literalValue)]; - return [NSString stringWith_nsAString:literalValue]; + return [self getPropertyString:@"http://home.netscape.com/NC-rdf#Name" forItem:inItem]; } - -- (void) outlineView: (NSOutlineView*) aOutlineView setObjectValue: (id) aObject - forTableColumn: (NSTableColumn*) aTableColumn - byItem: (id) aItem -{ - -} - - - - (void) reloadDataForItem: (id) aItem reloadChildren: (BOOL) aReloadChildren { if (!aItem) @@ -341,7 +369,7 @@ [mOutlineView reloadItem: aItem reloadChildren: aReloadChildren]; } -- (id) makeWrapperFor: (nsIRDFResource*) aRDFResource +- (id)getWrapperFor:(nsIRDFResource*) aRDFResource { const char* k; aRDFResource->GetValueConst(&k); @@ -350,8 +378,9 @@ // see if we've created a wrapper already, if not, create a new wrapper object // and stash it in our dictionary RDFOutlineViewItem* item = [mDictionary objectForKey:key]; - if (!item) { - item = [[RDFOutlineViewItem alloc] init]; + if (!item) + { + item = [[[RDFOutlineViewItem alloc] init] autorelease]; [item setResource: aRDFResource]; [mDictionary setObject:item forKey:key]; // retains |item| } @@ -359,14 +388,56 @@ return item; } - --(void) getPropertyString:(NSString*)inPropertyURI forItem:(RDFOutlineViewItem*)inItem - result:(PRUnichar**)outResult +- (void)invalidateCachedItems { - if ( !outResult ) - return; - *outResult = nil; + mCacheVersion++; +} + +- (void)updateItemProperties:(id)item enumerateChildren:(BOOL)doChildren +{ + BOOL isExpandable = NO; + NSMutableArray* itemChildren = doChildren ? [[[NSMutableArray alloc] initWithCapacity:10] autorelease] : nil; + nsCOMPtr itemResource = dont_AddRef([item resource]); + + PRBool isSeq = PR_FALSE; + mContainerUtils->IsSeq(mDataSource, itemResource, &isSeq); + if (isSeq) + isExpandable = YES; + + nsCOMPtr childProperty; + mRDFService->GetResource("http://home.netscape.com/NC-rdf#child", getter_AddRefs(childProperty)); + + nsCOMPtr childNodes; + mDataSource->GetTargets(itemResource, childProperty, PR_TRUE, getter_AddRefs(childNodes)); + + PRBool hasMore = PR_FALSE; + while (NS_SUCCEEDED(childNodes->HasMoreElements(&hasMore)) && hasMore) + { + nsCOMPtr supp; + childNodes->GetNext(getter_AddRefs(supp)); + + nsCOMPtr childResource = do_QueryInterface(supp); + if (childResource) + { + id childItem = [self getWrapperFor:childResource]; + if (childItem) + { + isExpandable = YES; + if (!itemChildren) break; // know enough already + [itemChildren addObject:childItem]; + } + } + } + + // itemChildren will be nil here if we don't care about children, but that's OK. + // the setChildren call will clear the cached child list. + [item setNumChildren:[itemChildren count] isExpandable:isExpandable cacheVersion:mCacheVersion]; + [item setChildren:itemChildren]; +} + +- (NSString*)getPropertyString:(NSString*)inPropertyURI forItem:(RDFOutlineViewItem*)inItem +{ nsCOMPtr propertyResource; mRDFService->GetResource([inPropertyURI UTF8String], getter_AddRefs(propertyResource)); @@ -378,38 +449,20 @@ #if DEBUG NSLog(@"ValueNode is null in RDF objectValueForTableColumn"); #endif - return; + return @""; } nsCOMPtr valueLiteral(do_QueryInterface(valueNode)); if (!valueLiteral) - return; + return @""; - valueLiteral->GetValue(outResult); + const PRUnichar* value = NULL; + valueLiteral->GetValueConst(&value); + if (value) + return [NSString stringWithCharacters:value length:nsCRT::strlen(value)]; + + return @""; } -@end - -@implementation RDFOutlineViewItem - -- (void) dealloc -{ - NS_IF_RELEASE(mResource); - [super dealloc]; -} - -- (nsIRDFResource*) resource -{ - NS_IF_ADDREF(mResource); - return mResource; -} - -- (void) setResource: (nsIRDFResource*) aResource -{ - nsIRDFResource* oldResource = mResource; - NS_IF_ADDREF(mResource = aResource); - NS_IF_RELEASE(oldResource); -} - @end diff --git a/camino/src/history/HistoryDataSource.h b/camino/src/history/HistoryDataSource.h index ac3e29f437b..1fb186b4922 100644 --- a/camino/src/history/HistoryDataSource.h +++ b/camino/src/history/HistoryDataSource.h @@ -49,17 +49,23 @@ class HistoryDataSourceObserver; { HistoryDataSourceObserver* mObserver; // STRONG ref, should be nsCOMPtr but can't IBOutlet BrowserWindowController* mBrowserWindowController; + BOOL mUpdatesEnabled; + BOOL mNeedsRefresh; } // overridden to create a attributed string with icon --(id) createCellContents:(const nsAString&)inValue withColumn:(NSString*)inColumn byItem:(id) inItem; +- (id)createCellContents:(NSString*)inValue withColumn:(NSString*)inColumn byItem:(id) inItem; - (NSString *)outlineView:(NSOutlineView *)outlineView tooltipStringForItem:(id)inItem; --(void) enableObserver; --(void) disableObserver; +- (void)enableObserver; +- (void)disableObserver; --(IBAction)openHistoryItem: (id)aSender; --(IBAction)deleteHistoryItems: (id)aSender; +- (void)setNeedsRefresh:(BOOL)needsRefresh; +- (BOOL)needsRefresh; +- (void)refresh; + +- (IBAction)openHistoryItem: (id)aSender; +- (IBAction)deleteHistoryItems: (id)aSender; @end diff --git a/camino/src/history/HistoryDataSource.mm b/camino/src/history/HistoryDataSource.mm index f1d040f99df..52a7a4bf7c3 100644 --- a/camino/src/history/HistoryDataSource.mm +++ b/camino/src/history/HistoryDataSource.mm @@ -63,33 +63,29 @@ class HistoryDataSourceObserver : public nsIRDFObserver { public: - HistoryDataSourceObserver(NSOutlineView* outlineView) : - mOutlineView(outlineView), mEnabled(false) + HistoryDataSourceObserver(HistoryDataSource* dataSource) + : mHistoryDataSource(dataSource) { NS_INIT_ISUPPORTS(); } - virtual ~HistoryDataSourceObserver() { } ; + virtual ~HistoryDataSourceObserver() { } NS_DECL_ISUPPORTS - NS_IMETHODIMP OnAssert(nsIRDFDataSource*, nsIRDFResource*, nsIRDFResource*, nsIRDFNode*) ; - NS_IMETHODIMP OnUnassert(nsIRDFDataSource*, nsIRDFResource*, nsIRDFResource*, nsIRDFNode*) { return NS_OK; } + NS_IMETHOD OnAssert(nsIRDFDataSource*, nsIRDFResource*, nsIRDFResource*, nsIRDFNode*); + NS_IMETHOD OnUnassert(nsIRDFDataSource*, nsIRDFResource*, nsIRDFResource*, nsIRDFNode*); - NS_IMETHODIMP OnMove(nsIRDFDataSource*, nsIRDFResource*, nsIRDFResource*, nsIRDFResource*, nsIRDFNode*) + NS_IMETHOD OnMove(nsIRDFDataSource*, nsIRDFResource*, nsIRDFResource*, nsIRDFResource*, nsIRDFNode*) { return NS_OK; } - NS_IMETHODIMP OnChange(nsIRDFDataSource*, nsIRDFResource*, nsIRDFResource*, nsIRDFNode*, nsIRDFNode*); + NS_IMETHOD OnChange(nsIRDFDataSource*, nsIRDFResource*, nsIRDFResource*, nsIRDFNode*, nsIRDFNode*); - NS_IMETHODIMP BeginUpdateBatch(nsIRDFDataSource*) { return NS_OK; } - NS_IMETHODIMP EndUpdateBatch(nsIRDFDataSource*) { return NS_OK; } - - void Enable() { mEnabled = true; } - void Disable() { mEnabled = false; } + NS_IMETHOD BeginUpdateBatch(nsIRDFDataSource*) { return NS_OK; } + NS_IMETHOD EndUpdateBatch(nsIRDFDataSource*) { return NS_OK; } private: - NSOutlineView* mOutlineView; - bool mEnabled; + HistoryDataSource* mHistoryDataSource; }; NS_IMPL_ISUPPORTS1(HistoryDataSourceObserver, nsIRDFObserver) @@ -105,15 +101,30 @@ NS_IMETHODIMP HistoryDataSourceObserver::OnAssert(nsIRDFDataSource*, nsIRDFResource*, nsIRDFResource* aProperty, nsIRDFNode*) { - if(mEnabled) { - const char* p; - aProperty->GetValueConst(&p); - if (strcmp("http://home.netscape.com/NC-rdf#Date", p) == 0) - [mOutlineView reloadData]; - } + const char* p; + aProperty->GetValueConst(&p); + if (strcmp("http://home.netscape.com/NC-rdf#Date", p) == 0) + [mHistoryDataSource setNeedsRefresh:YES]; + return NS_OK; } +// +// OnUnassert +// +// This gets called on redirects, when nsGlobalHistory::RemovePage is called. +// +NS_IMETHODIMP +HistoryDataSourceObserver::OnUnassert(nsIRDFDataSource*, nsIRDFResource*, + nsIRDFResource* aProperty, nsIRDFNode*) +{ + const char* p; + aProperty->GetValueConst(&p); + if (strcmp("http://home.netscape.com/NC-rdf#Date", p) == 0) + [mHistoryDataSource setNeedsRefresh:YES]; + + return NS_OK; +} // // OnChange @@ -125,12 +136,12 @@ NS_IMETHODIMP HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*, nsIRDFResource* aProperty, nsIRDFNode*, nsIRDFNode*) { - if(mEnabled) { - const char* p; - aProperty->GetValueConst(&p); - if (strcmp("http://home.netscape.com/NC-rdf#Date", p) == 0) - [mOutlineView reloadData]; - } + const char* p; + aProperty->GetValueConst(&p); + + if (strcmp("http://home.netscape.com/NC-rdf#Date", p) == 0) + [mHistoryDataSource setNeedsRefresh:YES]; + return NS_OK; } @@ -138,7 +149,7 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*, @interface HistoryDataSource(Private) -- (void)cleanup; +- (void)cleanupHistory; @end @@ -146,12 +157,12 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*, - (void) dealloc { - [self cleanup]; + [self cleanupHistory]; [super dealloc]; } // "non-virtual" cleanup method -- safe to call from dealloc. -- (void)cleanup +- (void)cleanupHistory { if (mDataSource && mObserver) { @@ -163,7 +174,7 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*, // "virtual" method; called from superclass - (void)cleanupDataSource { - [self cleanup]; + [self cleanupHistory]; [super cleanupDataSource]; } @@ -181,7 +192,8 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*, NS_ASSERTION(mRDFService, "Uh oh, RDF service not loaded in parent class"); - if ( !mDataSource ) { + if ( !mDataSource ) + { // Get the Global History DataSource mRDFService->GetDataSource("rdf:history", &mDataSource); // Get the Date Folder Root @@ -191,14 +203,15 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*, [mOutlineView setDoubleAction: @selector(openHistoryItem:)]; [mOutlineView setDeleteAction: @selector(deleteHistoryItems:)]; - mObserver = new HistoryDataSourceObserver(mOutlineView); + mObserver = new HistoryDataSourceObserver(self); if ( mObserver ) { NS_ADDREF(mObserver); mDataSource->AddObserver(mObserver); } [mOutlineView reloadData]; } - else { + else + { // everything is loaded, but we have to refresh our tree otherwise // changes that took place while the drawer was closed won't be noticed [mOutlineView reloadData]; @@ -207,18 +220,41 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*, NS_ASSERTION(mDataSource, "Uh oh, History RDF Data source not created"); } -- (void) enableObserver +- (void)enableObserver { - if ( mObserver ) - mObserver->Enable(); + mUpdatesEnabled = YES; } --(void) disableObserver +-(void)disableObserver { - if ( mObserver ) - mObserver->Disable(); + mUpdatesEnabled = NO; } +- (void)setNeedsRefresh:(BOOL)needsRefresh +{ + mNeedsRefresh = needsRefresh; +} + +- (BOOL)needsRefresh +{ + return mNeedsRefresh; +} + +- (void)refresh +{ + if (mNeedsRefresh) + { + [self invalidateCachedItems]; + if (mUpdatesEnabled) + { + // this can be very slow! See bug 180109. + //NSLog(@"history reload started"); + [self reloadDataForItem:nil reloadChildren:NO]; + //NSLog(@"history reload done"); + } + mNeedsRefresh = NO; + } +} // // createCellContents:withColumn:byItem @@ -226,31 +262,29 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*, // override to create an NSAttributedString instead of just the string with the // given text. We add an icon and adjust the positioning of the text w/in the cell // --(id) createCellContents:(const nsAString&)inValue withColumn:(NSString*)inColumn byItem:(id) inItem +-(id) createCellContents:(NSString*)inValue withColumn:(NSString*)inColumn byItem:(id) inItem { - NSMutableAttributedString *cellValue = [[NSMutableAttributedString alloc] init]; - - //Set cell's textual contents - [cellValue replaceCharactersInRange:NSMakeRange(0, [cellValue length]) withString:[NSString stringWith_nsAString:inValue]]; + if ([inValue length] == 0) + inValue = [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:inItem]; - if ([inColumn isEqualToString: @"http://home.netscape.com/NC-rdf#Name"]) { - NSMutableAttributedString *attachmentAttrString = nil; - NSFileWrapper *fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents:nil]; - NSTextAttachment *textAttachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper]; - NSCell *attachmentAttrStringCell; + NSMutableAttributedString *cellValue = [[[NSMutableAttributedString alloc] initWithString:inValue] autorelease]; + + if ([inColumn isEqualToString:@"http://home.netscape.com/NC-rdf#Name"]) + { + NSFileWrapper *fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents:nil]; + NSTextAttachment *textAttachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper]; - //Create an attributed string to hold the empty attachment, then release the components. - attachmentAttrString = [[NSMutableAttributedString attributedStringWithAttachment:textAttachment] retain]; + // Create an attributed string to hold the empty attachment, then release the components. + NSMutableAttributedString *attachmentAttrString = [NSMutableAttributedString attributedStringWithAttachment:textAttachment]; [textAttachment release]; [fileWrapper release]; //Get the cell of the text attachment. - attachmentAttrStringCell = (NSCell *)[(NSTextAttachment *)[attachmentAttrString attribute: + NSCell* attachmentAttrStringCell = (NSCell *)[(NSTextAttachment *)[attachmentAttrString attribute: NSAttachmentAttributeName atIndex:0 effectiveRange:nil] attachmentCell]; - if ([self outlineView:mOutlineView isItemExpandable:inItem]) { + if ([self outlineView:mOutlineView isItemExpandable:inItem]) [attachmentAttrStringCell setImage:[NSImage imageNamed:@"folder"]]; - } else [attachmentAttrStringCell setImage:[NSImage imageNamed:@"smallbookmark"]]; @@ -298,11 +332,8 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*, id item = [toDrag objectAtIndex: 0]; // if we have just one item, we add some more flavours - nsXPIDLString urlLiteral, nameLiteral; - [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:item result:getter_Copies(urlLiteral)]; - [self getPropertyString:@"http://home.netscape.com/NC-rdf#Name" forItem:item result:getter_Copies(nameLiteral)]; - NSString* url = [NSString stringWith_nsAString: urlLiteral]; - NSString* title = [NSString stringWith_nsAString: nameLiteral]; + NSString* url = [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:item]; + NSString* title = [self getPropertyString:@"http://home.netscape.com/NC-rdf#Name" forItem:item]; NSString *cleanedTitle = [title stringByReplacingCharactersInSet:[NSCharacterSet controlCharacterSet] withString:@" "]; [pboard declareURLPasteboardWithAdditionalTypes:[NSArray array] owner:self]; @@ -340,11 +371,8 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*, return; } - nsXPIDLString urlLiteral; - [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:item result:getter_Copies(urlLiteral)]; - // get uri - NSString* url = [NSString stringWith_nsAString: urlLiteral]; + NSString* url = [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:item]; [[mBrowserWindowController getBrowserWrapper] loadURI: url referrer: nil flags: NSLoadFlagsNone activate:YES]; } @@ -376,14 +404,15 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*, index = [currIndex intValue]; RDFOutlineViewItem* item = [mOutlineView itemAtRow: index]; if (![mOutlineView isExpandable: item]) { - nsXPIDLString urlLiteral; - [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:item result:getter_Copies(urlLiteral)]; - history->RemovePage(NS_ConvertUCS2toUTF8(urlLiteral).get()); + NSString* urlString = [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:item]; + history->RemovePage([urlString UTF8String]); } } history->EndBatchUpdate(); if ( clearSelectionWhenDone ) [mOutlineView deselectAll:self]; + + [self invalidateCachedItems]; [mOutlineView reloadData]; // necessary or the outline is really horked } } @@ -402,9 +431,8 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*, NSString* pageTitle = [super outlineView:outlineView tooltipStringForItem:inItem]; // append url - nsXPIDLString literalValue; - [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:inItem result:getter_Copies(literalValue)]; - return [NSString stringWithFormat:@"%@\n%@", pageTitle, [NSString stringWith_nsAString:literalValue]]; + NSString* url = [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:inItem]; + return [NSString stringWithFormat:@"%@\n%@", pageTitle, [url stringByTruncatingTo:80 at:kTruncateAtEnd]]; } return nil; } diff --git a/camino/src/includes/ChimeraUIConstants.h b/camino/src/includes/ChimeraUIConstants.h index b96c6e40dd7..1f6045d0ab7 100644 --- a/camino/src/includes/ChimeraUIConstants.h +++ b/camino/src/includes/ChimeraUIConstants.h @@ -52,3 +52,13 @@ const int kDividerTag = 4000; // the tag of the separator after which to insert bookmark items const int kBookmarksDividerTag = -1; + +// Save file dialog +const int kSaveFormatPopupTag = 1000; + +enum +{ + eSaveFormatHTMLComplete = 0, + eSaveFormatHTMLSource, + eSaveFormatPlainText +}; diff --git a/camino/src/preferences/PreferenceManager.h b/camino/src/preferences/PreferenceManager.h index 8273aca7a71..baa09d1b417 100644 --- a/camino/src/preferences/PreferenceManager.h +++ b/camino/src/preferences/PreferenceManager.h @@ -45,6 +45,9 @@ class nsIPref; NSUserDefaults* mDefaults; ICInstance mInternetConfig; nsIPref* mPrefs; + + // proxies notification stuff + CFRunLoopSourceRef mRunLoopSource; } + (PreferenceManager *)sharedInstance; diff --git a/camino/src/preferences/PreferenceManager.mm b/camino/src/preferences/PreferenceManager.mm index 18cf20c5680..8378bd39d82 100644 --- a/camino/src/preferences/PreferenceManager.mm +++ b/camino/src/preferences/PreferenceManager.mm @@ -38,6 +38,7 @@ #import #import + #import "PreferenceManager.h" #import "UserDefaults.h" #import "CHBrowserService.h" @@ -60,11 +61,23 @@ app_getModuleInfo(nsStaticModuleInfo **info, PRUint32 *count); @interface PreferenceManager(PreferenceManagerPrivate) ++ (PreferenceManager *) sharedInstanceDontCreate; + - (void)registerNotificationListener; - (void)termEmbedding: (NSNotification*)aNotification; - (void)xpcomTerminate: (NSNotification*)aNotification; +- (void)configureProxies; +- (BOOL)updateOneProxy:(NSDictionary*)configDict + protocol:(NSString*)protocol + proxyEnableKey:(NSString*)enableKey + proxyURLKey:(NSString*)urlKey + proxyPortKey:(NSString*)portKey; + +- (void)registerForProxyChanges; +- (BOOL)readSystemProxySettings; + @end @@ -76,7 +89,7 @@ static PreferenceManager* gSharedInstance = nil; static BOOL gMadePrefManager; #endif -+ (PreferenceManager *) sharedInstance ++ (PreferenceManager *)sharedInstance { if (!gSharedInstance) { @@ -88,13 +101,20 @@ static BOOL gMadePrefManager; gSharedInstance = [[PreferenceManager alloc] init]; } - return gSharedInstance; + return gSharedInstance; +} + ++ (PreferenceManager *)sharedInstanceDontCreate +{ + return gSharedInstance; } - (id) init { if ((self = [super init])) { + mRunLoopSource = NULL; + [self registerNotificationListener]; if ([self initInternetConfig] == NO) { @@ -115,6 +135,8 @@ static BOOL gMadePrefManager; - (void) dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; + if (self == gSharedInstance) + gSharedInstance = nil; [super dealloc]; } @@ -123,6 +145,13 @@ static BOOL gMadePrefManager; ::ICStop(mInternetConfig); mInternetConfig = nil; NS_IF_RELEASE(mPrefs); + // remove our runloop observer + if (mRunLoopSource) + { + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), mRunLoopSource, kCFRunLoopCommonModes); + CFRelease(mRunLoopSource); + mRunLoopSource = NULL; + } } - (void)xpcomTerminate: (NSNotification*)aNotification @@ -145,14 +174,14 @@ static BOOL gMadePrefManager; object: nil]; } -- (void) savePrefsFile +- (void)savePrefsFile { nsCOMPtr prefsService = do_GetService(NS_PREF_CONTRACTID); if (prefsService) prefsService->SavePrefFile(nsnull); } -- (BOOL) initInternetConfig +- (BOOL)initInternetConfig { OSStatus error; error = ::ICStart(&mInternetConfig, 'CHIM'); @@ -164,7 +193,7 @@ static BOOL gMadePrefManager; return YES; } -- (BOOL) initMozillaPrefs +- (BOOL)initMozillaPrefs { #ifdef _BUILD_STATIC_BIN @@ -246,15 +275,8 @@ static BOOL gMadePrefManager; return YES; } -- (void) syncMozillaPrefs +- (void)syncMozillaPrefs { - CFArrayRef cfArray; - CFDictionaryRef cfDictionary; - CFNumberRef cfNumber; - CFStringRef cfString; - char strbuf[1024]; - int numbuf; - if (!mPrefs) { NSLog(@"Mozilla prefs not set up successfully"); return; @@ -268,19 +290,101 @@ static BOOL gMadePrefManager; // fix up the cookie prefs. If 'p3p' or 'accept foreign cookies' are on, remap them to // something that chimera can deal with. PRInt32 acceptCookies = 0; - static const char* kCookieBehaviorPref = "network.cookie.cookieBehavior"; + static const char* kCookieBehaviorPref = "network.cookie.cookieBehavior"; mPrefs->GetIntPref(kCookieBehaviorPref, &acceptCookies); - if ( acceptCookies == 1 ) { // accept foreign cookies, assume off + if ( acceptCookies == 1 ) { // accept foreign cookies, assume off acceptCookies = 2; - mPrefs->SetIntPref(kCookieBehaviorPref, acceptCookies); - } + mPrefs->SetIntPref(kCookieBehaviorPref, acceptCookies); + } else if ( acceptCookies == 3 ) { // p3p, assume all cookies on acceptCookies = 0; - mPrefs->SetIntPref(kCookieBehaviorPref, acceptCookies); + mPrefs->SetIntPref(kCookieBehaviorPref, acceptCookies); } - + + [self configureProxies]; +} + +#pragma mark - + +- (void)configureProxies +{ + [self readSystemProxySettings]; + [self registerForProxyChanges]; +} + +static void SCProxiesChangedCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void * /* info */) +{ + PreferenceManager* prefsManager = [PreferenceManager sharedInstanceDontCreate]; + [prefsManager readSystemProxySettings]; +#if DEBUG + NSLog(@"Updating proxies"); +#endif +} + +- (void)registerForProxyChanges +{ + if (mRunLoopSource) // don't register twice + return; + + SCDynamicStoreContext context = {0, NULL, NULL, NULL, NULL}; + + SCDynamicStoreRef dynamicStoreRef = SCDynamicStoreCreate(NULL, CFSTR("ChimeraProxiesNotification"), SCProxiesChangedCallback, &context); + if (dynamicStoreRef) + { + CFStringRef proxyIdentifier = SCDynamicStoreKeyCreateProxies(NULL); + CFArrayRef keyList = CFArrayCreate(NULL, (const void **)&proxyIdentifier, 1, &kCFTypeArrayCallBacks); + + Boolean set = SCDynamicStoreSetNotificationKeys(dynamicStoreRef, keyList, NULL); + if (set) + { + mRunLoopSource = SCDynamicStoreCreateRunLoopSource(NULL, dynamicStoreRef, 0); + if (mRunLoopSource) + { + CFRunLoopAddSource(CFRunLoopGetCurrent(), mRunLoopSource, kCFRunLoopCommonModes); + // we keep the ref to the source, so that we can remove it when the prefs manager is cleaned up. + } + } + + CFRelease(proxyIdentifier); + CFRelease(keyList); + CFRelease(dynamicStoreRef); + } +} + +- (BOOL)updateOneProxy:(NSDictionary*)configDict + protocol:(NSString*)protocol + proxyEnableKey:(NSString*)enableKey + proxyURLKey:(NSString*)urlKey + proxyPortKey:(NSString*)portKey +{ + BOOL gotProxy = NO; + + BOOL enabled = (BOOL)[[configDict objectForKey:enableKey] intValue]; + if (enabled) + { + NSString* protocolProxy = [configDict objectForKey:urlKey]; + int proxyPort = [[configDict objectForKey:portKey] intValue]; + if ([protocolProxy length] > 0 && proxyPort != 0) + { + [self setPref:[[NSString stringWithFormat:@"network.proxy.%@", protocol] cString] toString:protocolProxy]; + [self setPref:[[NSString stringWithFormat:@"network.proxy.%@_port", protocol] cString] toInt:proxyPort]; + gotProxy = YES; + } + } + + return gotProxy; +} + +- (BOOL)readSystemProxySettings +{ + BOOL usingProxies = NO; + + PRInt32 proxyType, newProxyType; + mPrefs->GetIntPref("network.proxy.type", &proxyType); + newProxyType = proxyType; + if (proxyType == 0 || proxyType == 1) + { // get proxies from SystemConfiguration - mPrefs->SetIntPref("network.proxy.type", 0); // 0 == no proxies mPrefs->ClearUserPref("network.proxy.http"); mPrefs->ClearUserPref("network.proxy.http_port"); mPrefs->ClearUserPref("network.proxy.ssl"); @@ -293,94 +397,66 @@ static BOOL gMadePrefManager; mPrefs->ClearUserPref("network.proxy.socks_port"); mPrefs->ClearUserPref("network.proxy.no_proxies_on"); - if ((cfDictionary = SCDynamicStoreCopyProxies (NULL)) != NULL) { - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesHTTPEnable, (const void **)&cfNumber) == TRUE) { - if (CFNumberGetValue (cfNumber, kCFNumberIntType, &numbuf) == TRUE && numbuf == 1) { - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesHTTPProxy, (const void **)&cfString) == TRUE) { - if (CFStringGetCString (cfString, strbuf, sizeof(strbuf)-1, kCFStringEncodingASCII) == TRUE) { - mPrefs->SetCharPref("network.proxy.http", strbuf); - } - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesHTTPPort, (const void **)&cfNumber) == TRUE) { - if (CFNumberGetValue (cfNumber, kCFNumberIntType, &numbuf) == TRUE) { - mPrefs->SetIntPref("network.proxy.http_port", numbuf); - } - mPrefs->SetIntPref("network.proxy.type", 1); - } - } - } + NSDictionary* proxyConfigDict = (NSDictionary*)SCDynamicStoreCopyProxies(NULL); + if (proxyConfigDict) + { + BOOL gotAProxy = NO; + + gotAProxy |= [self updateOneProxy:proxyConfigDict protocol:@"http" + proxyEnableKey:(NSString*)kSCPropNetProxiesHTTPEnable + proxyURLKey:(NSString*)kSCPropNetProxiesHTTPProxy + proxyPortKey:(NSString*)kSCPropNetProxiesHTTPPort]; + + gotAProxy |= [self updateOneProxy:proxyConfigDict protocol:@"ssl" + proxyEnableKey:(NSString*)kSCPropNetProxiesHTTPSEnable + proxyURLKey:(NSString*)kSCPropNetProxiesHTTPSProxy + proxyPortKey:(NSString*)kSCPropNetProxiesHTTPSPort]; + + gotAProxy |= [self updateOneProxy:proxyConfigDict protocol:@"ftp" + proxyEnableKey:(NSString*)kSCPropNetProxiesFTPEnable + proxyURLKey:(NSString*)kSCPropNetProxiesFTPProxy + proxyPortKey:(NSString*)kSCPropNetProxiesFTPPort]; + + gotAProxy |= [self updateOneProxy:proxyConfigDict protocol:@"gopher" + proxyEnableKey:(NSString*)kSCPropNetProxiesGopherEnable + proxyURLKey:(NSString*)kSCPropNetProxiesGopherProxy + proxyPortKey:(NSString*)kSCPropNetProxiesGopherPort]; + + gotAProxy |= [self updateOneProxy:proxyConfigDict protocol:@"socks" + proxyEnableKey:(NSString*)kSCPropNetProxiesSOCKSEnable + proxyURLKey:(NSString*)kSCPropNetProxiesSOCKSProxy + proxyPortKey:(NSString*)kSCPropNetProxiesSOCKSPort]; + + if (gotAProxy) + { + newProxyType = 1; + + NSArray* exceptions = [proxyConfigDict objectForKey:(NSString*)kSCPropNetProxiesExceptionsList]; + if (exceptions) + { + NSString* sitesList = [exceptions componentsJoinedByString:@", "]; + if ([sitesList length] > 0) + [self setPref:"network.proxy.no_proxies_on" toString:sitesList]; } - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesHTTPSEnable, (const void **)&cfNumber) == TRUE) { - if (CFNumberGetValue (cfNumber, kCFNumberIntType, &numbuf) == TRUE && numbuf == 1) { - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesHTTPSProxy, (const void **)&cfString) == TRUE) { - if (CFStringGetCString (cfString, strbuf, sizeof(strbuf)-1, kCFStringEncodingASCII) == TRUE) { - mPrefs->SetCharPref("network.proxy.ssl", strbuf); - } - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesHTTPSPort, (const void **)&cfNumber) == TRUE) { - if (CFNumberGetValue (cfNumber, kCFNumberIntType, &numbuf) == TRUE) { - mPrefs->SetIntPref("network.proxy.ssl_port", numbuf); - } - mPrefs->SetIntPref("network.proxy.type", 1); - } - } - } - } - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesFTPEnable, (const void **)&cfNumber) == TRUE) { - if (CFNumberGetValue (cfNumber, kCFNumberIntType, &numbuf) == TRUE && numbuf == 1) { - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesFTPProxy, (const void **)&cfString) == TRUE) { - if (CFStringGetCString (cfString, strbuf, sizeof(strbuf)-1, kCFStringEncodingASCII) == TRUE) { - mPrefs->SetCharPref("network.proxy.ftp", strbuf); - } - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesFTPPort, (const void **)&cfNumber) == TRUE) { - if (CFNumberGetValue (cfNumber, kCFNumberIntType, &numbuf) == TRUE) { - mPrefs->SetIntPref("network.proxy.ftp_port", numbuf); - } - mPrefs->SetIntPref("network.proxy.type", 1); - } - } - } - } - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesGopherEnable, (const void **)&cfNumber) == TRUE) { - if (CFNumberGetValue (cfNumber, kCFNumberIntType, &numbuf) == TRUE && numbuf == 1) { - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesGopherProxy, (const void **)&cfString) == TRUE) { - if (CFStringGetCString (cfString, strbuf, sizeof(strbuf)-1, kCFStringEncodingASCII) == TRUE) { - mPrefs->SetCharPref("network.proxy.gopher", strbuf); - } - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesGopherPort, (const void **)&cfNumber) == TRUE) { - if (CFNumberGetValue (cfNumber, kCFNumberIntType, &numbuf) == TRUE) { - mPrefs->SetIntPref("network.proxy.gopher_port", numbuf); - } - mPrefs->SetIntPref("network.proxy.type", 1); - } - } - } - } - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesSOCKSEnable, (const void **)&cfNumber) == TRUE) { - if (CFNumberGetValue (cfNumber, kCFNumberIntType, &numbuf) == TRUE && numbuf == 1) { - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesSOCKSProxy, (const void **)&cfString) == TRUE) { - if (CFStringGetCString (cfString, strbuf, sizeof(strbuf)-1, kCFStringEncodingASCII) == TRUE) { - mPrefs->SetCharPref("network.proxy.socks", strbuf); - } - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesSOCKSPort, (const void **)&cfNumber) == TRUE) { - if (CFNumberGetValue (cfNumber, kCFNumberIntType, &numbuf) == TRUE) { - mPrefs->SetIntPref("network.proxy.socks_port", numbuf); - } - mPrefs->SetIntPref("network.proxy.type", 1); - } - } - } - } - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesExceptionsList, (const void **)&cfArray) == TRUE) { - cfString = CFStringCreateByCombiningStrings (NULL, cfArray, CFSTR(", ")); - if (CFStringGetLength (cfString) > 0) { - if (CFStringGetCString (cfString, strbuf, sizeof(strbuf)-1, kCFStringEncodingASCII) == TRUE) { - mPrefs->SetCharPref("network.proxy.no_proxies_on", strbuf); - } - } - } - CFRelease (cfDictionary); + usingProxies = YES; + } + else + { + newProxyType = 0; + } + + [proxyConfigDict release]; } + + if (newProxyType != proxyType) + mPrefs->SetIntPref("network.proxy.type", 1); + } + + return usingProxies; } +#pragma mark - + - (NSString*)getStringPref: (const char*)prefName withSuccess:(BOOL*)outSuccess { NSString *prefValue = @""; @@ -406,16 +482,16 @@ static BOOL gMadePrefManager; { // colors are stored in HTML-like #FFFFFF strings NSString* colorString = [self getStringPref:prefName withSuccess:outSuccess]; - NSColor* returnColor = [NSColor blackColor]; + NSColor* returnColor = [NSColor blackColor]; if ([colorString hasPrefix:@"#"] && [colorString length] == 7) { unsigned int redInt, greenInt, blueInt; sscanf([colorString cString], "#%02x%02x%02x", &redInt, &greenInt, &blueInt); - float redFloat = ((float)redInt / 255.0); - float greenFloat = ((float)greenInt / 255.0); - float blueFloat = ((float)blueInt / 255.0); + float redFloat = ((float)redInt / 255.0); + float greenFloat = ((float)greenInt / 255.0); + float blueFloat = ((float)blueInt / 255.0); returnColor = [NSColor colorWithCalibratedRed:redFloat green:greenFloat blue:blueFloat alpha:1.0f]; } @@ -548,7 +624,7 @@ static BOOL gMadePrefManager; mPrefs->SetCharPref("browser.startup.homepage", [homepagePref UTF8String]); } else { - homepagePref = [self getStringPref:"browser.startup.homepage" withSuccess:NULL]; + homepagePref = [self getStringPref:"browser.startup.homepage" withSuccess:NULL]; } if (homepagePref && [homepagePref length] > 0 && ![homepagePref isEqualToString:@"HomePageDefault"]) diff --git a/chimera/Chimera.pbproj/project.pbxproj b/chimera/Chimera.pbproj/project.pbxproj index f789e40d443..7d26c0177ce 100644 --- a/chimera/Chimera.pbproj/project.pbxproj +++ b/chimera/Chimera.pbproj/project.pbxproj @@ -146,6 +146,7 @@ 4A9504CDFFE6A4B311CA0CBA, F593CA5E034EB88E01A967F3, ); + hasScannedForEncodings = 1; isa = PBXProject; knownRegions = ( English, @@ -200,6 +201,7 @@ refType = 4; }; 29B97316FDCFA39411CA2CEA = { + fileEncoding = 30; isa = PBXFileReference; name = main.m; path = src/application/main.m; @@ -495,7 +497,6 @@ "; - shouldUseHeadermap = 1; }; 29B97327FDCFA39411CA2CEA = { buildActionMask = 2147483647; @@ -541,7 +542,6 @@ F55C4DD402D2864E0130B065, F50D9DE402ECC2C601BB4219, F50D9DEF02EE0AB101BB4219, - F50D9DF302EE194001BB4219, F50D9DF702EE2B9B01BB4219, F5D33CBF02EF61AA01A967F3, F566BD1402EFA9AD01A967F3, @@ -565,6 +565,9 @@ F57BEDA003A1825001A9666E, F5C8D55303A2A42401A8016F, F5C8D55603A2A43301A8016F, + A7AEBEC603CB962500A967F8, + A7AEBEE003CB9CD700A967F8, + A7AEBEE903CB9DFB00A967F8, ); isa = PBXHeadersBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -643,6 +646,12 @@ F5566DC5038E075F01A80166, F5566DC6038E075F01A80166, F5566DC7038E075F01A80166, + A7AEBED103CB9BD000A967F8, + A7AEBED203CB9BD000A967F8, + A7AEBED303CB9BD000A967F8, + A7AEBEDB03CB9C2F00A967F8, + A7AEBEDC03CB9C2F00A967F8, + A7F01A4903CBBCA500A967F8, ); isa = PBXResourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -689,7 +698,6 @@ F59236C302C89ACA0100012B, F50D9DE502ECC2C601BB4219, F50D9DF002EE0AB101BB4219, - F50D9DF402EE194001BB4219, F50D9DF802EE2B9B01BB4219, F5D33CC002EF61AA01A967F3, F5D33CC102EF61AA01A967F3, @@ -712,6 +720,9 @@ F55EBC9D0383665201A80166, F57BED9803A1824001A9666E, F57BED9F03A1825001A9666E, + A7AEBEC903CB964000A967F8, + A7AEBEE303CB9CEC00A967F8, + A7AEBEE603CB9DDF00A967F8, ); isa = PBXSourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -752,12 +763,14 @@ //2E3 //2E4 2E2939FF027F33604B000102 = { + fileEncoding = 30; isa = PBXFileReference; name = PageProxyIcon.mm; path = src/browser/PageProxyIcon.mm; refType = 2; }; 2E293A00027F33604B000102 = { + fileEncoding = 30; isa = PBXFileReference; name = PageProxyIcon.h; path = src/browser/PageProxyIcon.h; @@ -776,12 +789,14 @@ }; }; 2E748B72029A448D4B000102 = { + fileEncoding = 30; isa = PBXFileReference; name = GoMenu.h; path = src/browser/GoMenu.h; refType = 2; }; 2E748B73029A448D4B000102 = { + fileEncoding = 30; isa = PBXFileReference; name = GoMenu.mm; path = src/browser/GoMenu.mm; @@ -800,12 +815,14 @@ }; }; 2EEC3E61028138714B000102 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksOutlineView.h; path = src/bookmarks/BookmarksOutlineView.h; refType = 2; }; 2EEC3E62028138714B000102 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksOutlineView.mm; path = src/bookmarks/BookmarksOutlineView.mm; @@ -881,6 +898,292 @@ //982 //983 //984 +//A70 +//A71 +//A72 +//A73 +//A74 + A7AEBEB103CB950400A967F8 = { + isa = PBXFileReference; + name = xmlextras.xpt; + path = ../dist/Embed/components/xmlextras.xpt; + refType = 2; + }; + A7AEBEB303CB954500A967F8 = { + fileRef = A7AEBEB103CB950400A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEB403CB955700A967F8 = { + fileRef = A7AEBEB103CB950400A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEC403CB962500A967F8 = { + fileEncoding = 30; + isa = PBXFileReference; + name = "NSView+Utils.h"; + path = "src/extensions/NSView+Utils.h"; + refType = 2; + }; + A7AEBEC503CB962500A967F8 = { + fileRef = A7AEBEC403CB962500A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEC603CB962500A967F8 = { + fileRef = A7AEBEC403CB962500A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEC703CB964000A967F8 = { + fileEncoding = 30; + isa = PBXFileReference; + name = "NSView+Utils.m"; + path = "src/extensions/NSView+Utils.m"; + refType = 2; + }; + A7AEBEC803CB964000A967F8 = { + fileRef = A7AEBEC703CB964000A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEC903CB964000A967F8 = { + fileRef = A7AEBEC703CB964000A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBECA03CB96D600A967F8 = { + isa = PBXFileReference; + name = nsProxyAutoConfig.js; + path = ../netwerk/base/src/nsProxyAutoConfig.js; + refType = 2; + }; + A7AEBECB03CB96E700A967F8 = { + fileRef = A7AEBECA03CB96D600A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBECC03CB96F900A967F8 = { + fileRef = A7AEBECA03CB96D600A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBECE03CB9BD000A967F8 = { + isa = PBXFileReference; + name = disclosureArrowDown.tiff; + path = resources/images/app/disclosureArrowDown.tiff; + refType = 2; + }; + A7AEBECF03CB9BD000A967F8 = { + isa = PBXFileReference; + name = disclosureArrowRight.tiff; + path = resources/images/app/disclosureArrowRight.tiff; + refType = 2; + }; + A7AEBED003CB9BD000A967F8 = { + isa = PBXFileReference; + name = small_close.tiff; + path = resources/images/app/small_close.tiff; + refType = 2; + }; + A7AEBED103CB9BD000A967F8 = { + fileRef = A7AEBECE03CB9BD000A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBED203CB9BD000A967F8 = { + fileRef = A7AEBECF03CB9BD000A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBED303CB9BD000A967F8 = { + fileRef = A7AEBED003CB9BD000A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBED403CB9BD000A967F8 = { + fileRef = A7AEBECE03CB9BD000A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBED503CB9BD000A967F8 = { + fileRef = A7AEBECF03CB9BD000A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBED603CB9BD000A967F8 = { + fileRef = A7AEBED003CB9BD000A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBED703CB9C2F00A967F8 = { + children = ( + A7AEBED803CB9C2F00A967F8, + ); + isa = PBXVariantGroup; + name = Keychain.nib; + path = ""; + refType = 2; + }; + A7AEBED803CB9C2F00A967F8 = { + isa = PBXFileReference; + name = English; + path = resources/localized/English.lproj/Keychain.nib; + refType = 4; + }; + A7AEBED903CB9C2F00A967F8 = { + children = ( + A7AEBEDA03CB9C2F00A967F8, + ); + isa = PBXVariantGroup; + name = ProgressView.nib; + path = ""; + refType = 2; + }; + A7AEBEDA03CB9C2F00A967F8 = { + isa = PBXFileReference; + name = English; + path = resources/localized/English.lproj/ProgressView.nib; + refType = 4; + }; + A7AEBEDB03CB9C2F00A967F8 = { + fileRef = A7AEBED703CB9C2F00A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEDC03CB9C2F00A967F8 = { + fileRef = A7AEBED903CB9C2F00A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEDD03CB9C2F00A967F8 = { + fileRef = A7AEBED703CB9C2F00A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEDE03CB9C2F00A967F8 = { + fileRef = A7AEBED903CB9C2F00A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEDF03CB9CD700A967F8 = { + fileEncoding = 30; + isa = PBXFileReference; + name = CHStackView.h; + path = src/extensions/CHStackView.h; + refType = 2; + }; + A7AEBEE003CB9CD700A967F8 = { + fileRef = A7AEBEDF03CB9CD700A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEE103CB9CD700A967F8 = { + fileRef = A7AEBEDF03CB9CD700A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEE203CB9CEC00A967F8 = { + fileEncoding = 30; + isa = PBXFileReference; + name = CHStackView.m; + path = src/extensions/CHStackView.m; + refType = 2; + }; + A7AEBEE303CB9CEC00A967F8 = { + fileRef = A7AEBEE203CB9CEC00A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEE403CB9CEC00A967F8 = { + fileRef = A7AEBEE203CB9CEC00A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEE503CB9DDF00A967F8 = { + fileEncoding = 30; + isa = PBXFileReference; + name = ProgressViewController.mm; + path = src/download/ProgressViewController.mm; + refType = 2; + }; + A7AEBEE603CB9DDF00A967F8 = { + fileRef = A7AEBEE503CB9DDF00A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEE703CB9DDF00A967F8 = { + fileRef = A7AEBEE503CB9DDF00A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEE803CB9DFB00A967F8 = { + fileEncoding = 30; + isa = PBXFileReference; + name = ProgressViewController.h; + path = src/download/ProgressViewController.h; + refType = 2; + }; + A7AEBEE903CB9DFB00A967F8 = { + fileRef = A7AEBEE803CB9DFB00A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7AEBEEA03CB9DFB00A967F8 = { + fileRef = A7AEBEE803CB9DFB00A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7F01A4803CBBCA500A967F8 = { + isa = PBXBundleReference; + name = PrintPDE.plugin; + path = ../dist/PrintPDE.plugin; + refType = 2; + }; + A7F01A4903CBBCA500A967F8 = { + fileRef = A7F01A4803CBBCA500A967F8; + isa = PBXBuildFile; + settings = { + }; + }; + A7F01A4A03CBBCA500A967F8 = { + fileRef = A7F01A4803CBBCA500A967F8; + isa = PBXBuildFile; + settings = { + }; + }; +//A70 +//A71 +//A72 +//A73 +//A74 //F50 //F51 //F52 @@ -1169,6 +1472,7 @@ }; }; F507BA480213AD5F01D93544 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksService.h; path = src/bookmarks/BookmarksService.h; @@ -1181,6 +1485,7 @@ }; }; F507BA4C0213AFF701D93544 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksService.mm; path = src/bookmarks/BookmarksService.mm; @@ -1224,6 +1529,7 @@ refType = 4; }; F507BA540213C29E01D93544 = { + fileEncoding = 30; isa = PBXFileReference; name = bookmarks.xml; path = resources/application/bookmarks.xml; @@ -1243,18 +1549,23 @@ F540BD1C029ED17901026D5D, F5A112C902DF270F01026D5D, F55B6BF402EF1F7E01026D5D, + A7AEBECE03CB9BD000A967F8, + A7AEBECF03CB9BD000A967F8, + A7AEBED003CB9BD000A967F8, ); isa = PBXGroup; - name = Graphics; + name = images; refType = 4; }; F50D9DE202ECC2C601BB4219 = { + fileEncoding = 30; isa = PBXFileReference; name = nsDownloadListener.h; path = src/download/nsDownloadListener.h; refType = 2; }; F50D9DE302ECC2C601BB4219 = { + fileEncoding = 30; isa = PBXFileReference; name = nsDownloadListener.mm; path = src/download/nsDownloadListener.mm; @@ -1301,12 +1612,14 @@ }; }; F50D9DED02EE0AB101BB4219 = { + fileEncoding = 30; isa = PBXFileReference; name = CHDownloadProgressDisplay.h; path = src/embedding/CHDownloadProgressDisplay.h; refType = 2; }; F50D9DEE02EE0AB101BB4219 = { + fileEncoding = 30; isa = PBXFileReference; name = CHDownloadProgressDisplay.mm; path = src/embedding/CHDownloadProgressDisplay.mm; @@ -1324,37 +1637,15 @@ settings = { }; }; - F50D9DF102EE194001BB4219 = { - isa = PBXFileReference; - name = CHDownloadFactories.h; - path = src/embedding/CHDownloadFactories.h; - refType = 2; - }; - F50D9DF202EE194001BB4219 = { - isa = PBXFileReference; - name = CHDownloadFactories.mm; - path = src/embedding/CHDownloadFactories.mm; - refType = 2; - }; - F50D9DF302EE194001BB4219 = { - fileRef = F50D9DF102EE194001BB4219; - isa = PBXBuildFile; - settings = { - }; - }; - F50D9DF402EE194001BB4219 = { - fileRef = F50D9DF202EE194001BB4219; - isa = PBXBuildFile; - settings = { - }; - }; F50D9DF502EE2B9A01BB4219 = { + fileEncoding = 30; isa = PBXFileReference; name = SaveHeaderSniffer.h; path = src/download/SaveHeaderSniffer.h; refType = 2; }; F50D9DF602EE2B9A01BB4219 = { + fileEncoding = 30; isa = PBXFileReference; name = SaveHeaderSniffer.mm; path = src/download/SaveHeaderSniffer.mm; @@ -1374,8 +1665,6 @@ }; F50D9DF902EE2C1D01BB4219 = { children = ( - F50D9DF102EE194001BB4219, - F50D9DF202EE194001BB4219, F50D9DED02EE0AB101BB4219, F50D9DEE02EE0AB101BB4219, ); @@ -1387,8 +1676,9 @@ children = ( F50D9DF502EE2B9A01BB4219, F50D9DF602EE2B9A01BB4219, - F517395B020CE3740189DA0C, F50D9DE302ECC2C601BB4219, + A7AEBEE503CB9DDF00A967F8, + F517395B020CE3740189DA0C, ); isa = PBXGroup; name = Chimera; @@ -1549,6 +1839,7 @@ }; }; F5125A110202064D01FAFD9F = { + fileEncoding = 30; isa = PBXFileReference; name = BrowserWrapper.h; path = src/browser/BrowserWrapper.h; @@ -1682,6 +1973,7 @@ }; }; F5137A1102676B9101026D05 = { + fileEncoding = 30; isa = PBXFileReference; name = Find.h; path = src/find/Find.h; @@ -1768,7 +2060,6 @@ "; - shouldUseHeadermap = 0; }; F51704D3034A305B01026D5D = { buildActionMask = 2147483647; @@ -1898,12 +2189,14 @@ refType = 2; }; F51704E9034A30DF01026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = SecurityPane.h; path = PreferencePanes/Security/SecurityPane.h; refType = 2; }; F51704EA034A30DF01026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = SecurityPane.mm; path = PreferencePanes/Security/SecurityPane.mm; @@ -2037,7 +2330,6 @@ "; - shouldUseHeadermap = 0; }; F51704FE034A38FD01026D5D = { buildActionMask = 2147483647; @@ -2169,12 +2461,14 @@ target = F51704FD034A38FD01026D5D; }; F5170515034A398F01026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = WebFeatures.h; path = PreferencePanes/WebFeatures/WebFeatures.h; refType = 2; }; F5170516034A398F01026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = WebFeatures.mm; path = PreferencePanes/WebFeatures/WebFeatures.mm; @@ -2253,6 +2547,7 @@ refType = 2; }; F5170530034B5E9701026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = English; path = English.lproj/Localizable.strings; @@ -2271,12 +2566,14 @@ refType = 2; }; F517395A020CE3740189DA0C = { + fileEncoding = 30; isa = PBXFileReference; name = ProgressDlgController.h; path = src/download/ProgressDlgController.h; refType = 2; }; F517395B020CE3740189DA0C = { + fileEncoding = 30; isa = PBXFileReference; name = ProgressDlgController.mm; path = src/download/ProgressDlgController.mm; @@ -2320,6 +2617,7 @@ }; F51842F30206168101A966FE = { children = ( + F5C8D55203A2A42401A8016F, F5F94B900332532801026D5D, F5DE10E60209DC0601A967DF, F517395A020CE3740189DA0C, @@ -2363,6 +2661,7 @@ F53D36BD037843C201A80166, F58DB2D20381FD3301A9666E, F5C8D55503A2A43301A8016F, + A7AEBEE803CB9DFB00A967F8, ); isa = PBXGroup; name = Headers; @@ -2400,12 +2699,14 @@ }; }; F51B70B6026EC98B01A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = GetURLCommand.h; path = src/appleevents/GetURLCommand.h; refType = 2; }; F51B70B7026EC98B01A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = GetURLCommand.mm; path = src/appleevents/GetURLCommand.mm; @@ -2747,7 +3048,6 @@ "; - shouldUseHeadermap = 0; }; F52627CF027E976B01000102 = { buildActionMask = 2147483647; @@ -2796,6 +3096,7 @@ runOnlyForDeploymentPostprocessing = 0; }; F52627D4027E982201000102 = { + fileEncoding = 30; indentWidth = 2; isa = PBXFileReference; name = Navigation.h; @@ -2804,6 +3105,7 @@ tabWidth = 2; }; F52627D5027E982201000102 = { + fileEncoding = 30; indentWidth = 2; isa = PBXFileReference; name = Navigation.mm; @@ -2989,6 +3291,7 @@ refType = 2; }; F528E218020FD8400168DE43 = { + fileEncoding = 30; isa = PBXFileReference; name = FindDlgController.h; path = src/find/FindDlgController.h; @@ -3001,6 +3304,7 @@ }; }; F528E21A020FD9620168DE43 = { + fileEncoding = 30; isa = PBXFileReference; name = FindDlgController.mm; path = src/find/FindDlgController.mm; @@ -3013,12 +3317,14 @@ }; }; F529788A0371820B01026DCE = { + fileEncoding = 30; isa = PBXFileReference; name = CHClickListener.h; path = src/embedding/CHClickListener.h; refType = 2; }; F529788B0371820B01026DCE = { + fileEncoding = 30; isa = PBXFileReference; name = CHClickListener.mm; path = src/embedding/CHClickListener.mm; @@ -3049,6 +3355,7 @@ }; }; F52CE65902BFA88701026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = English; path = resources/localized/English.lproj/Localizable.strings; @@ -3094,12 +3401,14 @@ }; }; F52D5CCF027A887001A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = AutoCompleteTextField.h; path = src/browser/AutoCompleteTextField.h; refType = 2; }; F52D5CD0027A887001A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = AutoCompleteTextField.mm; path = src/browser/AutoCompleteTextField.mm; @@ -3118,12 +3427,14 @@ }; }; F52D5CD3027A88C601A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = AutoCompleteDataSource.h; path = src/browser/AutoCompleteDataSource.h; refType = 2; }; F52D5CD4027A88C601A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = AutoCompleteDataSource.mm; path = src/browser/AutoCompleteDataSource.mm; @@ -3142,12 +3453,14 @@ }; }; F52D5CD7027D3D5001A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = PreferenceManager.h; path = src/preferences/PreferenceManager.h; refType = 2; }; F52D5CD8027D3D5001A80166 = { + fileEncoding = 30; indentWidth = 2; isa = PBXFileReference; name = PreferenceManager.mm; @@ -3203,24 +3516,28 @@ }; }; F52F87CB027D75C301A80165 = { + fileEncoding = 30; isa = PBXFileReference; name = HistoryDataSource; path = src/history/HistoryDataSource.h; refType = 2; }; F52F87CC027D75C301A80165 = { + fileEncoding = 30; isa = PBXFileReference; name = RDFOutlineViewDataSource.h; path = src/extensions/RDFOutlineViewDataSource.h; refType = 2; }; F52F87CD027D75C301A80165 = { + fileEncoding = 30; isa = PBXFileReference; name = HistoryDataSource.mm; path = src/history/HistoryDataSource.mm; refType = 4; }; F52F87CE027D75C301A80165 = { + fileEncoding = 30; isa = PBXFileReference; name = RDFOutlineViewDataSource.mm; path = src/extensions/RDFOutlineViewDataSource.mm; @@ -3251,6 +3568,7 @@ }; }; F53849040349779901A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = Localizable.strings; path = English.lproj/Localizable.strings; @@ -3343,12 +3661,14 @@ }; }; F53C1CD6032FF3B301A96654 = { + fileEncoding = 30; isa = PBXFileReference; name = BrowserContentViews.h; path = src/browser/BrowserContentViews.h; refType = 2; }; F53C1CD7032FF3B301A96654 = { + fileEncoding = 30; isa = PBXFileReference; name = BrowserContentViews.mm; path = src/browser/BrowserContentViews.mm; @@ -3379,12 +3699,14 @@ }; }; F53D36BA037843B801A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksMenu.mm; path = src/bookmarks/BookmarksMenu.mm; refType = 2; }; F53D36BD037843C201A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksMenu.h; path = src/bookmarks/BookmarksMenu.h; @@ -3397,6 +3719,7 @@ }; }; F53E012902AEE91C01A967F3 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarkInfoController.h; path = src/bookmarks/BookmarkInfoController.h; @@ -3415,6 +3738,7 @@ }; }; F53E012C02AEE93601A967F3 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarkInfoController.mm; path = src/bookmarks/BookmarkInfoController.mm; @@ -3471,54 +3795,63 @@ refType = 2; }; F53F21EC022B7C77010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = MVPreferencePaneDefaults.plist; path = src/preferences/MVPreferencePaneDefaults.plist; refType = 2; }; F53F21ED022B7C77010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = MVPreferencePaneGroups.plist; path = src/preferences/MVPreferencePaneGroups.plist; refType = 2; }; F53F21EE022B7C77010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = English; path = resources/localized/English.lproj/MVPreferencePaneGroups.strings; refType = 2; }; F53F21EF022B7C77010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = MVPreferencesController.h; path = src/preferences/MVPreferencesController.h; refType = 2; }; F53F21F0022B7C77010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = MVPreferencesController.mm; path = src/preferences/MVPreferencesController.mm; refType = 2; }; F53F21F1022B7C77010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = MVPreferencesGroupedIconView.h; path = src/preferences/MVPreferencesGroupedIconView.h; refType = 2; }; F53F21F2022B7C77010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = MVPreferencesGroupedIconView.m; path = src/preferences/MVPreferencesGroupedIconView.m; refType = 2; }; F53F21F3022B7C77010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = MVPreferencesMultipleIconView.h; path = src/preferences/MVPreferencesMultipleIconView.h; refType = 2; }; F53F21F4022B7C77010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = MVPreferencesMultipleIconView.m; path = src/preferences/MVPreferencesMultipleIconView.m; @@ -3548,11 +3881,13 @@ refType = 4; }; F53F21FF022B7C77010001CA = { + fileEncoding = 30; isa = PBXFileReference; path = PersonalPane.h; refType = 4; }; F53F2200022B7C77010001CA = { + fileEncoding = 30; isa = PBXFileReference; path = PersonalPane.m; refType = 4; @@ -3666,12 +4001,14 @@ }; }; F541495A02711A8301A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = CHToolbarAdditions.h; path = src/extensions/ToolbarAdditions.h; refType = 2; }; F541495B02711A8301A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = CHToolbarAdditions.m; path = src/extensions/ToolbarAdditions.m; @@ -3690,12 +4027,14 @@ }; }; F541495E02711B0001A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = CHImageAdditions.h; path = src/extensions/ImageAdditions.h; refType = 2; }; F541495F02711B0001A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = CHImageAdditions.m; path = src/extensions/ImageAdditions.m; @@ -3744,12 +4083,14 @@ }; }; F549ACDE0302DE6001026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = ToolTip.mm; path = src/browser/ToolTip.mm; refType = 2; }; F549ACDF0302DE6001026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = "NSScreen+Utils.m"; path = "src/extensions/NSScreen+Utils.m"; @@ -3780,6 +4121,7 @@ }; }; F549ACE40302DEBB01026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = "NSScreen+Utils.h"; path = "src/extensions/NSScreen+Utils.h"; @@ -3798,6 +4140,7 @@ }; }; F549ACE70302DEF001026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = ToolTip.h; path = src/browser/ToolTip.h; @@ -4064,12 +4407,14 @@ }; }; F558099D02F22168015DF512 = { + fileEncoding = 30; isa = PBXFileReference; name = "NSString+Utils.h"; path = "src/extensions/NSString+Utils.h"; refType = 2; }; F558099E02F22168015DF512 = { + fileEncoding = 30; isa = PBXFileReference; name = "NSString+Utils.mm"; path = "src/extensions/NSString+Utils.mm"; @@ -4094,12 +4439,14 @@ }; }; F5581379030AEF9B0176F207 = { + fileEncoding = 30; isa = PBXFileReference; name = RemoteDataProvider.h; path = src/browser/RemoteDataProvider.h; refType = 2; }; F558137A030AEF9B0176F207 = { + fileEncoding = 30; isa = PBXFileReference; name = SiteIconProvider.h; path = src/browser/SiteIconProvider.h; @@ -4116,12 +4463,14 @@ refType = 4; }; F558137C030AEF9B0176F207 = { + fileEncoding = 30; isa = PBXFileReference; name = RemoteDataProvider.mm; path = src/browser/RemoteDataProvider.mm; refType = 2; }; F558137D030AEF9B0176F207 = { + fileEncoding = 30; isa = PBXFileReference; name = SiteIconProvider.mm; path = src/browser/SiteIconProvider.mm; @@ -4176,12 +4525,14 @@ }; }; F558B1F0030F6E470166970F = { + fileEncoding = 30; isa = PBXFileReference; name = CHBrowserListener.h; path = src/embedding/CHBrowserListener.h; refType = 2; }; F558B1F1030F6E470166970F = { + fileEncoding = 30; isa = PBXFileReference; name = CHBrowserListener.mm; path = src/embedding/CHBrowserListener.mm; @@ -4305,6 +4656,7 @@ }; }; F55C4DD302D2864D0130B065 = { + fileEncoding = 30; isa = PBXFileReference; name = UserDefaults.h; path = src/application/UserDefaults.h; @@ -4329,12 +4681,14 @@ }; }; F55EBC9A0383665201A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksExport.h; path = src/bookmarks/BookmarksExport.h; refType = 2; }; F55EBC9B0383665201A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksExport.mm; path = src/bookmarks/BookmarksExport.mm; @@ -4365,6 +4719,7 @@ }; }; F5607CB5023944AD01A967DF = { + fileEncoding = 30; isa = PBXFileReference; name = GeckoUtils.h; path = src/extensions/GeckoUtils.h; @@ -4434,12 +4789,14 @@ }; }; F5648739023C3857010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = IconTabViewItem.h; path = src/extensions/IconTabViewItem.h; refType = 2; }; F564873A023C3857010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = IconTabViewItem.mm; path = src/extensions/IconTabViewItem.mm; @@ -4464,6 +4821,7 @@ }; }; F56610A1039474CB01A9666E = { + fileEncoding = 30; isa = PBXFileReference; name = ChimeraVersion.r; path = resources/application/ChimeraVersion.r; @@ -4498,6 +4856,7 @@ F56610A40394767101A9666E = { children = ( F56610BC0394775201A9666E, + A7F01A4803CBBCA500A967F8, ); isa = PBXGroup; name = Plugins; @@ -4544,12 +4903,14 @@ }; }; F566BD1202EFA9AD01A967F3 = { + fileEncoding = 30; isa = PBXFileReference; name = CocoaPromptService.h; path = src/browser/CocoaPromptService.h; refType = 2; }; F566BD1302EFA9AD01A967F3 = { + fileEncoding = 30; isa = PBXFileReference; name = CocoaPromptService.mm; path = src/browser/CocoaPromptService.mm; @@ -4580,6 +4941,7 @@ }; }; F56769FB0208F74A010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = BrowserWindowController.mm; path = src/browser/BrowserWindowController.mm; @@ -4598,12 +4960,14 @@ refType = 2; }; F568C3CF023A4A5A010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = AboutBox.h; path = src/application/AboutBox.h; refType = 2; }; F568C3D0023A4A5A010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = AboutBox.m; path = src/application/AboutBox.m; @@ -4646,6 +5010,7 @@ }; }; F56F241F02AC6D0401A967F3 = { + fileEncoding = 30; isa = PBXFileReference; name = nsStaticComponents.cpp; path = src/application/nsStaticComponents.cpp; @@ -5250,6 +5615,7 @@ target = F5A8CE4702DFF039013CA8EC; }; F56F837202E47CCD01EF35C9 = { + fileEncoding = 30; isa = PBXFileReference; name = RegionNames.strings; path = PreferencePanes/Appearance/English.lproj/RegionNames.strings; @@ -5271,12 +5637,14 @@ }; }; F57074B5026BA85F01A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksToolbar.h; path = src/bookmarks/BookmarksToolbar.h; refType = 2; }; F57074B6026BA85F01A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksToolbar.mm; path = src/bookmarks/BookmarksToolbar.mm; @@ -5295,12 +5663,14 @@ }; }; F57074B9026BFD0101A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksButton.h; path = src/bookmarks/BookmarksButton.h; refType = 2; }; F57074BA026BFD0101A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksButton.mm; path = src/bookmarks/BookmarksButton.mm; @@ -5319,12 +5689,14 @@ }; }; F57074BD026D80DF01A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = LocationBar.h; path = src/browser/LocationBar.h; refType = 2; }; F57074BE026D80DF01A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = LocationBar.mm; path = src/browser/LocationBar.mm; @@ -5354,6 +5726,7 @@ refType = 4; }; F57BED9703A1824001A9666E = { + fileEncoding = 30; isa = PBXFileReference; name = NetworkServices.mm; path = src/rendezvous/NetworkServices.mm; @@ -5372,6 +5745,7 @@ }; }; F57BED9A03A1824801A9666E = { + fileEncoding = 30; isa = PBXFileReference; name = NetworkServices.h; path = src/rendezvous/NetworkServices.h; @@ -5390,12 +5764,14 @@ }; }; F57BED9D03A1825001A9666E = { + fileEncoding = 30; isa = PBXFileReference; name = DNSUtils.c; path = src/rendezvous/DNSUtils.c; refType = 2; }; F57BED9E03A1825001A9666E = { + fileEncoding = 30; isa = PBXFileReference; name = DNSUtils.h; path = src/rendezvous/DNSUtils.h; @@ -5506,7 +5882,6 @@ "; - shouldUseHeadermap = 0; }; F57F205D029997E701000106 = { children = ( @@ -5534,12 +5909,14 @@ refType = 2; }; F57F2060029997E701000106 = { + fileEncoding = 30; isa = PBXFileReference; name = PrivacyPane.h; path = PreferencePanes/Privacy/PrivacyPane.h; refType = 2; }; F57F2061029997E701000106 = { + fileEncoding = 30; isa = PBXFileReference; name = PrivacyPane.mm; path = PreferencePanes/Privacy/PrivacyPane.mm; @@ -5700,12 +6077,14 @@ refType = 4; }; F5807369023A1514010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = SplashScreenWindow.h; path = src/application/SplashScreenWindow.h; refType = 2; }; F580736A023A1514010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = SplashScreenWindow.mm; path = src/application/SplashScreenWindow.mm; @@ -5850,7 +6229,6 @@ "; - shouldUseHeadermap = 0; }; F58581AF022B8D62010001CA = { buildActionMask = 2147483647; @@ -5941,19 +6319,22 @@ F507A84A03116E6E01026D5D, F507A84D03116E7401026D5D, F507A85003116E7901026D5D, - F5C8D55203A2A42401A8016F, + A7AEBED703CB9C2F00A967F8, + A7AEBED903CB9C2F00A967F8, ); isa = PBXGroup; name = Nibs; refType = 4; }; F58DB2D20381FD3301A9666E = { + fileEncoding = 30; isa = PBXFileReference; name = JSConsole.h; path = src/application/JSConsole.h; refType = 2; }; F58DB2D30381FD3301A9666E = { + fileEncoding = 30; isa = PBXFileReference; name = JSConsole.mm; path = src/application/JSConsole.mm; @@ -5984,12 +6365,14 @@ }; }; F59236C002C89AC90100012B = { + fileEncoding = 30; isa = PBXFileReference; name = AppDirServiceProvider.cpp; path = src/application/AppDirServiceProvider.cpp; refType = 2; }; F59236C102C89AC90100012B = { + fileEncoding = 30; isa = PBXFileReference; name = AppDirServiceProvider.h; path = src/application/AppDirServiceProvider.h; @@ -6039,6 +6422,7 @@ refType = 2; }; F5949A47030D58A1014E8430 = { + fileEncoding = 30; isa = PBXFileReference; path = xhtml11.dtd; refType = 4; @@ -6106,6 +6490,7 @@ }; }; F59E9F3D0237E28401A967DF = { + fileEncoding = 30; isa = PBXFileReference; name = ContentClickListener.h; path = src/browser/ContentClickListener.h; @@ -6118,6 +6503,7 @@ }; }; F59E9F3F0237E43401A967DF = { + fileEncoding = 30; isa = PBXFileReference; name = ContentClickListener.mm; path = src/browser/ContentClickListener.mm; @@ -6154,6 +6540,7 @@ }; }; F5A3669302CCFAF601DC3354 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksDataSource.h; path = src/bookmarks/BookmarksDataSource.h; @@ -6176,6 +6563,7 @@ refType = 4; }; F5A3669502CCFAF601DC3354 = { + fileEncoding = 30; isa = PBXFileReference; name = BookmarksDataSource.mm; path = src/bookmarks/BookmarksDataSource.mm; @@ -6542,12 +6930,14 @@ refType = 4; }; F5A8CE4102DFEF4C013CA8EC = { + fileEncoding = 30; isa = PBXFileReference; name = PreferencePaneBase.h; path = PreferencePanes/Shared/PreferencePaneBase.h; refType = 2; }; F5A8CE4202DFEF4C013CA8EC = { + fileEncoding = 30; isa = PBXFileReference; name = PreferencePaneBase.mm; path = PreferencePanes/Shared/PreferencePaneBase.mm; @@ -6632,7 +7022,6 @@ "; - shouldUseHeadermap = 0; }; F5A8CE4802DFF039013CA8EC = { buildActionMask = 2147483647; @@ -6698,12 +7087,14 @@ refType = 2; }; F5A8CE4E02DFF167013CA8EC = { + fileEncoding = 30; isa = PBXFileReference; name = Appearance.h; path = PreferencePanes/Appearance/Appearance.h; refType = 2; }; F5A8CE4F02DFF167013CA8EC = { + fileEncoding = 30; isa = PBXFileReference; name = Appearance.mm; path = PreferencePanes/Appearance/Appearance.mm; @@ -6782,6 +7173,7 @@ }; }; F5AE04B20206A34801A967DF = { + fileEncoding = 30; isa = PBXFileReference; name = BrowserWindowController.h; path = src/browser/BrowserWindowController.h; @@ -6794,6 +7186,7 @@ }; }; F5AE04B60206A37C01A967DF = { + fileEncoding = 30; isa = PBXFileReference; name = MainController.h; path = src/application/MainController.h; @@ -6806,6 +7199,7 @@ }; }; F5AE04BA0206A4FE01A967DF = { + fileEncoding = 30; isa = PBXFileReference; name = MainController.mm; path = src/application/MainController.mm; @@ -6818,12 +7212,14 @@ }; }; F5B34B01034A505F01A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = "NSPasteboard+Utils.mm"; path = "src/extensions/NSPasteboard+Utils.mm"; refType = 2; }; F5B34B04034A50C901A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = "NSPasteboard+Utils.h"; path = "src/extensions/NSPasteboard+Utils.h"; @@ -6876,10 +7272,12 @@ F5FDF166031AF47301DE816D, F5D98EBC031AC38601A96654, F558099D02F22168015DF512, + A7AEBEC403CB962500A967F8, F549ACE40302DEBB01026D5D, F5B34B04034A50C901A80166, F5648739023C3857010001CA, F5C3AB810270072A01A80166, + A7AEBEDF03CB9CD700A967F8, F541495A02711A8301A80166, F541495E02711B0001A80166, ); @@ -6892,9 +7290,11 @@ F5D98EB9031AC37801A96654, F558099E02F22168015DF512, F549ACDF0302DE6001026D5D, + A7AEBEC703CB964000A967F8, F5B34B01034A505F01A80166, F564873A023C3857010001CA, F5C3AB820270072A01A80166, + A7AEBEE203CB9CEC00A967F8, F541495B02711A8301A80166, F541495F02711B0001A80166, F5FDF167031AF47301DE816D, @@ -6905,12 +7305,14 @@ refType = 4; }; F5B950BC030C83B601A96654 = { + fileEncoding = 30; isa = PBXFileReference; name = BrowserTabViewItem.h; path = src/browser/BrowserTabViewItem.h; refType = 2; }; F5B950BD030C83B601A96654 = { + fileEncoding = 30; isa = PBXFileReference; name = BrowserTabViewItem.mm; path = src/browser/BrowserTabViewItem.mm; @@ -7184,7 +7586,6 @@ "; - shouldUseHeadermap = 0; }; F5BAAB1A02AC45D301A967F3 = { buildActionMask = 2147483647; @@ -7229,7 +7630,6 @@ F50D9DE702ECC36201BB4219, F50D9DE802ECC36201BB4219, F5E37B0C02EE959601A967F3, - F5E37B0D02EE95E201A967F3, F5E37B0E02EE95E201A967F3, F5E37B0F02EE95E201A967F3, F5D33CC202EF61AA01A967F3, @@ -7254,6 +7654,9 @@ F57BEDA203A1825001A9666E, F5C8D55403A2A42401A8016F, F5C8D55703A2A43301A8016F, + A7AEBEC503CB962500A967F8, + A7AEBEE103CB9CD700A967F8, + A7AEBEEA03CB9DFB00A967F8, ); isa = PBXHeadersBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -7343,6 +7746,12 @@ F5566DC9038E075F01A80166, F5566DCA038E075F01A80166, F5566DCB038E075F01A80166, + A7AEBED403CB9BD000A967F8, + A7AEBED503CB9BD000A967F8, + A7AEBED603CB9BD000A967F8, + A7AEBEDD03CB9C2F00A967F8, + A7AEBEDE03CB9C2F00A967F8, + A7F01A4A03CBBCA500A967F8, ); isa = PBXResourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -7389,7 +7798,6 @@ F5A3669B02CCFB7A01DC3354, F5A3669C02CCFB7A01DC3354, F50D9DE902ECC36201BB4219, - F5E37B1002EE95E201A967F3, F5E37B1102EE95E201A967F3, F5E37B1202EE95E201A967F3, F5D33CC302EF61AA01A967F3, @@ -7413,6 +7821,9 @@ F55EBC9F0383665201A80166, F57BED9903A1824001A9666E, F57BEDA103A1825001A9666E, + A7AEBEC803CB964000A967F8, + A7AEBEE403CB9CEC00A967F8, + A7AEBEE703CB9DDF00A967F8, ); isa = PBXSourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -8253,6 +8664,8 @@ F5BAAC0402AC693C01A967F3, F5BAAC0502AC693C01A967F3, F5BAAC0702AC693C01A967F3, + A7AEBEB403CB955700A967F8, + A7AEBECB03CB96E700A967F8, ); isa = PBXCopyFilesBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -8994,12 +9407,14 @@ }; }; F5BF71450231B8BC010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = BrowserTabView.h; path = src/browser/BrowserTabView.h; refType = 2; }; F5BF71460231B8BC010001CA = { + fileEncoding = 30; isa = PBXFileReference; name = BrowserTabView.mm; path = src/browser/BrowserTabView.mm; @@ -9048,12 +9463,14 @@ }; }; F5C3AB810270072A01A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = ExtendedOutlineView.h; path = src/extensions/ExtendedOutlineView.h; refType = 2; }; F5C3AB820270072A01A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = ExtendedOutlineView.mm; path = src/extensions/ExtendedOutlineView.mm; @@ -9072,6 +9489,7 @@ }; }; F5C8D55203A2A42401A8016F = { + fileEncoding = 30; isa = PBXFileReference; name = ChimeraUIConstants.h; path = src/includes/ChimeraUIConstants.h; @@ -9090,6 +9508,7 @@ }; }; F5C8D55503A2A43301A8016F = { + fileEncoding = 30; isa = PBXFileReference; name = ChimeraUIConstants.h; path = src/includes/ChimeraUIConstants.h; @@ -9152,6 +9571,7 @@ refType = 4; }; F5D1421902BC88F801A967F3 = { + fileEncoding = 30; isa = PBXFileReference; name = "redo-prebinding.sh"; path = "src/scripts/redo-prebinding.sh"; @@ -9164,18 +9584,21 @@ }; }; F5D33CBC02EF61A901A967F3 = { + fileEncoding = 30; isa = PBXFileReference; name = SecurityDialogs.h; path = src/browser/SecurityDialogs.h; refType = 2; }; F5D33CBD02EF61A901A967F3 = { + fileEncoding = 30; isa = PBXFileReference; name = AppComponents.mm; path = src/application/AppComponents.mm; refType = 2; }; F5D33CBE02EF61A901A967F3 = { + fileEncoding = 30; isa = PBXFileReference; name = SecurityDialogs.mm; path = src/browser/SecurityDialogs.mm; @@ -9230,6 +9653,7 @@ }; }; F5D98EB9031AC37801A96654 = { + fileEncoding = 30; isa = PBXFileReference; name = "NSBezierPath+Utils.mm"; path = "src/extensions/NSBezierPath+Utils.mm"; @@ -9248,6 +9672,7 @@ }; }; F5D98EBC031AC38601A96654 = { + fileEncoding = 30; isa = PBXFileReference; name = "NSBezierPath+Utils.h"; path = "src/extensions/NSBezierPath+Utils.h"; @@ -9266,6 +9691,7 @@ }; }; F5DA444A027DD5AA01A80166 = { + fileEncoding = 30; isa = PBXFileReference; name = "installed-chrome.txt"; path = "../dist/Embed/chrome/installed-chrome.txt"; @@ -9326,36 +9752,42 @@ }; }; F5DE10E60209DC0601A967DF = { + fileEncoding = 30; isa = PBXFileReference; name = nsAlertController.h; path = src/browser/nsAlertController.h; refType = 2; }; F5DE10E70209DC0601A967DF = { + fileEncoding = 30; isa = PBXFileReference; name = CHBrowserView.h; path = src/embedding/CHBrowserView.h; refType = 2; }; F5DE10E80209DC0601A967DF = { + fileEncoding = 30; isa = PBXFileReference; name = CHBrowserService.h; path = src/embedding/CHBrowserService.h; refType = 2; }; F5DE10E90209DC0601A967DF = { + fileEncoding = 30; isa = PBXFileReference; name = nsAlertController.mm; path = src/browser/nsAlertController.mm; refType = 2; }; F5DE10EA0209DC0601A967DF = { + fileEncoding = 30; isa = PBXFileReference; name = CHBrowserView.mm; path = src/embedding/CHBrowserView.mm; refType = 2; }; F5DE10EB0209DC0601A967DF = { + fileEncoding = 30; isa = PBXFileReference; name = CHBrowserService.mm; path = src/embedding/CHBrowserService.mm; @@ -9403,12 +9835,6 @@ settings = { }; }; - F5E37B0D02EE95E201A967F3 = { - fileRef = F50D9DF102EE194001BB4219; - isa = PBXBuildFile; - settings = { - }; - }; F5E37B0E02EE95E201A967F3 = { fileRef = F50D9DED02EE0AB101BB4219; isa = PBXBuildFile; @@ -9421,12 +9847,6 @@ settings = { }; }; - F5E37B1002EE95E201A967F3 = { - fileRef = F50D9DF202EE194001BB4219; - isa = PBXBuildFile; - settings = { - }; - }; F5E37B1102EE95E201A967F3 = { fileRef = F50D9DEE02EE0AB101BB4219; isa = PBXBuildFile; @@ -9506,6 +9926,7 @@ refType = 2; }; F5F190BB02D1F81A01026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = ToolbarDefaults.plist; path = resources/application/ToolbarDefaults.plist; @@ -9524,6 +9945,7 @@ }; }; F5F190BE02D217C201026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = WebsiteDefaults.strings; path = resources/application/WebsiteDefaults.strings; @@ -9569,12 +9991,14 @@ }; }; F5F94B900332532801026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = KeychainService.h; path = src/browser/KeychainService.h; refType = 4; }; F5F94B910332532801026D5D = { + fileEncoding = 30; isa = PBXFileReference; name = KeychainService.mm; path = src/browser/KeychainService.mm; @@ -9633,6 +10057,7 @@ }; }; F5F9FBD902E13767012B5DB7 = { + fileEncoding = 30; isa = PBXFileReference; name = RegionMapping.plist; path = PreferencePanes/Appearance/RegionMapping.plist; @@ -9669,6 +10094,7 @@ }; }; F5FCDD5D03A035E001A9666E = { + fileEncoding = 30; isa = PBXFileReference; name = Localizable.strings; path = English.lproj/Localizable.strings; @@ -9689,12 +10115,14 @@ }; }; F5FDF166031AF47301DE816D = { + fileEncoding = 30; isa = PBXFileReference; name = DraggableImageAndTextCell.h; path = src/extensions/DraggableImageAndTextCell.h; refType = 4; }; F5FDF167031AF47301DE816D = { + fileEncoding = 30; isa = PBXFileReference; name = DraggableImageAndTextCell.mm; path = src/extensions/DraggableImageAndTextCell.mm; @@ -9747,12 +10175,14 @@ //F63 //F64 F632AF8302B9AEBB01000103 = { + fileEncoding = 30; isa = PBXFileReference; name = BrowserWindow.h; path = src/browser/BrowserWindow.h; refType = 2; }; F632AF8402B9AEBB01000103 = { + fileEncoding = 30; isa = PBXFileReference; name = BrowserWindow.mm; path = src/browser/BrowserWindow.mm; @@ -9771,6 +10201,7 @@ }; }; F6BA6D4E01B2F8A601A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = BrowserWrapper.mm; path = src/browser/BrowserWrapper.mm; @@ -9946,6 +10377,8 @@ F517941F027F3F2901A967DF, F53A902202C1127A01A967F3, 98590B3603A8938A45A2FA2A, + A7AEBEB103CB950400A967F8, + A7AEBECA03CB96D600A967F8, ); isa = PBXGroup; name = "Gecko Components"; @@ -10079,6 +10512,8 @@ F6BD64B601B3167601A962F7, F53A902402C1137901A967F3, 98E1988603A8A6F345B32312, + A7AEBEB303CB954500A967F8, + A7AEBECC03CB96F900A967F8, ); isa = PBXCopyFilesBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -11091,30 +11526,35 @@ runOnlyForDeploymentPostprocessing = 0; }; F6BD64B801B316DA01A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = charsetalias.properties; path = ../dist/Embed/res/charsetalias.properties; refType = 2; }; F6BD64B901B316DA01A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = charsetData.properties; path = ../dist/Embed/res/charsetData.properties; refType = 2; }; F6BD64BA01B316DA01A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = langGroups.properties; path = ../dist/Embed/res/langGroups.properties; refType = 2; }; F6BD64BB01B316DA01A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = language.properties; path = ../dist/Embed/res/language.properties; refType = 2; }; F6BD64BC01B316DA01A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = maccharset.properties; path = ../dist/Embed/res/maccharset.properties; @@ -11167,12 +11607,14 @@ refType = 2; }; F6BD64D301B3172601A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = htmlBindings.xml; path = ../dist/Embed/res/builtin/htmlBindings.xml; refType = 2; }; F6BD64D501B3172601A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = platformHTMLBindings.xml; path = ../dist/Embed/res/builtin/platformHTMLBindings.xml; @@ -11192,30 +11634,35 @@ refType = 2; }; F6BD64D801B3172601A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = html40Latin1.properties; path = ../dist/Embed/res/entityTables/html40Latin1.properties; refType = 2; }; F6BD64D901B3172601A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = html40Special.properties; path = ../dist/Embed/res/entityTables/html40Special.properties; refType = 2; }; F6BD64DA01B3172601A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = html40Symbols.properties; path = ../dist/Embed/res/entityTables/html40Symbols.properties; refType = 2; }; F6BD64DB01B3172601A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = htmlEntityVersions.properties; path = ../dist/Embed/res/entityTables/htmlEntityVersions.properties; refType = 2; }; F6BD64DC01B3172601A962F7 = { + fileEncoding = 30; isa = PBXFileReference; name = transliterate.properties; path = ../dist/Embed/res/entityTables/transliterate.properties; diff --git a/chimera/PreferencePanes/Appearance/English.lproj/Appearance.nib/info.nib b/chimera/PreferencePanes/Appearance/English.lproj/Appearance.nib/info.nib index 7734e3e1f0e..e69de29bb2d 100644 --- a/chimera/PreferencePanes/Appearance/English.lproj/Appearance.nib/info.nib +++ b/chimera/PreferencePanes/Appearance/English.lproj/Appearance.nib/info.nib @@ -1,17 +0,0 @@ - - - - - IBDocumentLocation - 646 106 458 263 0 0 1600 1002 - IBEditorPositions - - 214 - 70 395 152 96 0 0 1152 746 - - IBFramework Version - 286.0 - IBSystem Version - 6D52 - - diff --git a/chimera/PreferencePanes/Appearance/English.lproj/Appearance.nib/objects.nib b/chimera/PreferencePanes/Appearance/English.lproj/Appearance.nib/objects.nib index d46732370de..e69de29bb2d 100644 Binary files a/chimera/PreferencePanes/Appearance/English.lproj/Appearance.nib/objects.nib and b/chimera/PreferencePanes/Appearance/English.lproj/Appearance.nib/objects.nib differ diff --git a/chimera/PreferencePanes/Navigation/English.lproj/Navigation.nib/info.nib b/chimera/PreferencePanes/Navigation/English.lproj/Navigation.nib/info.nib index 7398ee93826..e69de29bb2d 100644 --- a/chimera/PreferencePanes/Navigation/English.lproj/Navigation.nib/info.nib +++ b/chimera/PreferencePanes/Navigation/English.lproj/Navigation.nib/info.nib @@ -1,27 +0,0 @@ - - - - - IBDocumentLocation - 140 56 522 320 0 0 1280 1002 - IBFramework Version - 286.0 - IBGroupedObjects - - 5 - - 12 - 24 - 56 - - - IBLastGroupID - 8 - IBOpenObjects - - 5 - - IBSystem Version - 6F21 - - diff --git a/chimera/PreferencePanes/Navigation/English.lproj/Navigation.nib/objects.nib b/chimera/PreferencePanes/Navigation/English.lproj/Navigation.nib/objects.nib index 88d9df4efe6..e69de29bb2d 100644 Binary files a/chimera/PreferencePanes/Navigation/English.lproj/Navigation.nib/objects.nib and b/chimera/PreferencePanes/Navigation/English.lproj/Navigation.nib/objects.nib differ diff --git a/chimera/resources/images/app/disclosureArrowDown.tiff b/chimera/resources/images/app/disclosureArrowDown.tiff new file mode 100644 index 00000000000..e69de29bb2d diff --git a/chimera/resources/images/app/disclosureArrowRight.tiff b/chimera/resources/images/app/disclosureArrowRight.tiff new file mode 100644 index 00000000000..e69de29bb2d diff --git a/chimera/resources/images/app/small_close.tiff b/chimera/resources/images/app/small_close.tiff new file mode 100644 index 00000000000..e69de29bb2d diff --git a/chimera/resources/localized/English.lproj/BrowserWindow.nib/classes.nib b/chimera/resources/localized/English.lproj/BrowserWindow.nib/classes.nib index 8d9ef756813..e69de29bb2d 100644 --- a/chimera/resources/localized/English.lproj/BrowserWindow.nib/classes.nib +++ b/chimera/resources/localized/English.lproj/BrowserWindow.nib/classes.nib @@ -1,177 +0,0 @@ -{ - IBClasses = ( - {CLASS = AutoCompleteDataSource; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, - { - ACTIONS = {onBlur = id; onResize = id; }; - CLASS = AutoCompleteTextField; - LANGUAGE = ObjC; - OUTLETS = {mProxyIcon = PageProxyIcon; }; - SUPERCLASS = NSTextField; - }, - {CLASS = BookmarkItem; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, - { - ACTIONS = { - addBookmark = id; - addFolder = id; - deleteBookmarks = id; - openBookmarkInNewTab = id; - openBookmarkInNewWindow = id; - showBookmarkInfo = id; - }; - CLASS = BookmarksDataSource; - LANGUAGE = ObjC; - OUTLETS = { - mBrowserWindowController = id; - mDeleteBookmarkButton = id; - mEditBookmarkButton = id; - mOutlineView = id; - }; - SUPERCLASS = NSObject; - }, - { - CLASS = BookmarksOutlineView; - LANGUAGE = ObjC; - SUPERCLASS = ExtendedOutlineView; - }, - { - ACTIONS = {addFolder = id; }; - CLASS = BookmarksToolbar; - LANGUAGE = ObjC; - SUPERCLASS = NSView; - }, - {CLASS = BrowserContainerView; LANGUAGE = ObjC; SUPERCLASS = NSView; }, - { - CLASS = BrowserContentView; - LANGUAGE = ObjC; - OUTLETS = { - mBookmarksToolbar = BookmarksToolbar; - mBrowserContainerView = NSView; - mStatusBar = NSView; - }; - SUPERCLASS = NSView; - }, - {CLASS = BrowserTabView; LANGUAGE = ObjC; SUPERCLASS = NSTabView; }, - { - CLASS = BrowserWindow; - LANGUAGE = ObjC; - OUTLETS = {mAutoCompleteTextField = id; }; - SUPERCLASS = NSWindow; - }, - { - ACTIONS = { - back = id; - biggerTextSize = id; - bookmarkLink = id; - bookmarkPage = id; - cancelAddBookmarkSheet = id; - cancelLocationSheet = id; - closeCurrentTab = id; - closeOtherTabs = id; - closeSendersTab = id; - copyImageLocation = id; - copyLinkLocation = id; - endAddBookmarkSheet = id; - endLocationSheet = id; - forward = id; - frameToNewTab = id; - frameToNewWindow = id; - frameToThisWindow = id; - getInfo = id; - goToLocationFromToolbarURLField = id; - home = id; - manageBookmarks = id; - moveTabToNewWindow = id; - newTab = id; - nextTab = id; - openLinkInNewTab = id; - openLinkInNewWindow = id; - pageSetup = id; - performSearch = id; - previousTab = id; - printDocument = id; - reload = id; - reloadSendersTab = id; - saveFrameAs = id; - saveImageAs = id; - saveLinkAs = id; - savePageAs = id; - sendURL = id; - smallerTextSize = id; - stop = id; - toggleSidebar = id; - viewOnlyThisImage = id; - viewPageSource = id; - viewSource = id; - }; - CLASS = BrowserWindowController; - LANGUAGE = ObjC; - OUTLETS = { - mAddBookmarkCheckbox = NSButton; - mAddBookmarkFolderField = NSPopUpButton; - mAddBookmarkSheetWindow = NSWindow; - mAddBookmarkTitleField = NSTextField; - mBackItem = NSMenuItem; - mContentView = BrowserContentView; - mCopyItem = NSMenuItem; - mForwardItem = NSMenuItem; - mHistoryDataSource = HistoryDataSource; - mImageLinkMenu = NSMenu; - mImageMenu = NSMenu; - mInputMenu = NSMenu; - mLinkMenu = NSMenu; - mLocationSheetURLField = NSTextField; - mLocationSheetWindow = NSWindow; - mLocationToolbarView = NSView; - mLock = NSImageView; - mPageMenu = NSMenu; - mPersonalToolbar = BookmarksToolbar; - mProgress = NSProgressIndicator; - mProxyIcon = PageProxyIcon; - mSidebarBookmarksDataSource = BookmarksDataSource; - mSidebarDrawer = NSDrawer; - mSidebarSourceTabView = NSTabView; - mSidebarTabView = NSTabView; - mStatus = NSTextField; - mStatusBar = NSView; - mTabBrowser = BrowserTabView; - mTabMenu = NSMenu; - mURLBar = NSTextField; - }; - SUPERCLASS = NSWindowController; - }, - { - ACTIONS = {load = id; }; - CLASS = BrowserWrapper; - LANGUAGE = ObjC; - OUTLETS = { - mLockIcon = id; - mWindowController = id; - progress = id; - progressSuper = id; - status = id; - urlbar = id; - }; - SUPERCLASS = NSView; - }, - {CLASS = ExtendedOutlineView; LANGUAGE = ObjC; SUPERCLASS = NSOutlineView; }, - {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, - { - CLASS = HistoryDataSource; - LANGUAGE = ObjC; - OUTLETS = {mBrowserWindowController = id; }; - SUPERCLASS = RDFOutlineViewDataSource; - }, - {CLASS = LocationBar; LANGUAGE = ObjC; SUPERCLASS = NSView; }, - {CLASS = MainController; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, - {CLASS = PageProxyIcon; LANGUAGE = ObjC; SUPERCLASS = NSImageView; }, - { - CLASS = RDFOutlineViewDataSource; - LANGUAGE = ObjC; - OUTLETS = {mOutlineView = id; }; - SUPERCLASS = NSObject; - }, - {CLASS = RDFOutlineViewItem; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, - {CLASS = ThrobberHandler; LANGUAGE = ObjC; SUPERCLASS = NSObject; } - ); - IBVersion = 1; -} \ No newline at end of file diff --git a/chimera/resources/localized/English.lproj/BrowserWindow.nib/info.nib b/chimera/resources/localized/English.lproj/BrowserWindow.nib/info.nib index ae6ff6280c5..2647aded841 100644 --- a/chimera/resources/localized/English.lproj/BrowserWindow.nib/info.nib +++ b/chimera/resources/localized/English.lproj/BrowserWindow.nib/info.nib @@ -3,7 +3,7 @@ IBDocumentLocation - 66 21 653 383 0 0 1152 848 + 65 36 653 383 0 0 1152 848 IBEditorPositions 124 @@ -15,17 +15,17 @@ 297 107 466 213 294 0 0 1600 1002 314 - 73 542 213 132 0 0 1600 1002 + 72 544 213 150 0 0 1600 1002 336 486 756 213 180 0 0 1600 1002 365 31 719 93 162 0 0 1600 1002 463 - 97 693 213 246 0 0 1600 1002 + 349 487 213 246 0 0 1600 1002 56 450 634 343 68 0 0 1280 1002 654 - 206 785 198 144 0 0 1600 1002 + 140 644 198 144 0 0 1152 848 IBFramework Version 286.0 @@ -42,6 +42,6 @@ IBLockedObjects IBSystem Version - 6F21 + 6G30 diff --git a/chimera/resources/localized/English.lproj/BrowserWindow.nib/objects.nib b/chimera/resources/localized/English.lproj/BrowserWindow.nib/objects.nib index 6ea50d4bb91..3a5bafda905 100644 Binary files a/chimera/resources/localized/English.lproj/BrowserWindow.nib/objects.nib and b/chimera/resources/localized/English.lproj/BrowserWindow.nib/objects.nib differ diff --git a/chimera/resources/localized/English.lproj/Keychain.nib/classes.nib b/chimera/resources/localized/English.lproj/Keychain.nib/classes.nib new file mode 100644 index 00000000000..e69de29bb2d diff --git a/chimera/resources/localized/English.lproj/Keychain.nib/info.nib b/chimera/resources/localized/English.lproj/Keychain.nib/info.nib new file mode 100644 index 00000000000..e69de29bb2d diff --git a/chimera/resources/localized/English.lproj/Keychain.nib/objects.nib b/chimera/resources/localized/English.lproj/Keychain.nib/objects.nib new file mode 100644 index 00000000000..e69de29bb2d diff --git a/chimera/resources/localized/English.lproj/Localizable.strings b/chimera/resources/localized/English.lproj/Localizable.strings index 6e0da7d528a..da2b9bebce2 100644 Binary files a/chimera/resources/localized/English.lproj/Localizable.strings and b/chimera/resources/localized/English.lproj/Localizable.strings differ diff --git a/chimera/resources/localized/English.lproj/MainMenu.nib/classes.nib b/chimera/resources/localized/English.lproj/MainMenu.nib/classes.nib index c8aaad9c499..a761cf8ecf8 100644 --- a/chimera/resources/localized/English.lproj/MainMenu.nib/classes.nib +++ b/chimera/resources/localized/English.lproj/MainMenu.nib/classes.nib @@ -20,6 +20,7 @@ doReload = id; doSearch = id; doStop = id; + downloadsWindow = id; exportBookmarks = id; feedbackLink = id; findAgain = id; @@ -61,7 +62,6 @@ mCreateBookmarksFolderMenuItem = NSMenuItem; mCreateBookmarksSeparatorMenuItem = NSMenuItem; mDockMenu = NSMenu; - mFilterList = NSPopUpButton; mFilterView = NSView; mGoMenu = NSMenu; mServersSubmenu = NSMenu; diff --git a/chimera/resources/localized/English.lproj/MainMenu.nib/info.nib b/chimera/resources/localized/English.lproj/MainMenu.nib/info.nib index 94276bd1461..515b3050c62 100644 --- a/chimera/resources/localized/English.lproj/MainMenu.nib/info.nib +++ b/chimera/resources/localized/English.lproj/MainMenu.nib/info.nib @@ -3,11 +3,11 @@ IBDocumentLocation - 237 33 482 372 0 0 1600 1002 + 105 33 482 372 0 0 1600 1002 IBEditorPositions 266 - 437 533 277 90 0 0 1152 848 + 644 623 277 90 0 0 1600 1002 29 11 957 446 44 0 0 1600 1002 494 @@ -31,7 +31,11 @@ IBLastGroupID 2 + IBOpenObjects + + 29 + IBSystem Version - 6F21 + 6G30 diff --git a/chimera/resources/localized/English.lproj/MainMenu.nib/objects.nib b/chimera/resources/localized/English.lproj/MainMenu.nib/objects.nib index 639e9548c05..9f05349791e 100644 Binary files a/chimera/resources/localized/English.lproj/MainMenu.nib/objects.nib and b/chimera/resources/localized/English.lproj/MainMenu.nib/objects.nib differ diff --git a/chimera/resources/localized/English.lproj/ProgressDialog.nib/classes.nib b/chimera/resources/localized/English.lproj/ProgressDialog.nib/classes.nib index fc624beb9c0..e69de29bb2d 100644 --- a/chimera/resources/localized/English.lproj/ProgressDialog.nib/classes.nib +++ b/chimera/resources/localized/English.lproj/ProgressDialog.nib/classes.nib @@ -1,19 +0,0 @@ -{ - IBClasses = ( - {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, - { - CLASS = ProgressDlgController; - LANGUAGE = ObjC; - OUTLETS = { - mElapsedTimeLabel = NSTextField; - mFromField = NSTextField; - mProgressBar = NSProgressIndicator; - mStatusLabel = NSTextField; - mTimeLeftLabel = NSTextField; - mToField = NSTextField; - }; - SUPERCLASS = NSWindowController; - } - ); - IBVersion = 1; -} \ No newline at end of file diff --git a/chimera/resources/localized/English.lproj/ProgressDialog.nib/info.nib b/chimera/resources/localized/English.lproj/ProgressDialog.nib/info.nib index 0369fa65250..e69de29bb2d 100644 --- a/chimera/resources/localized/English.lproj/ProgressDialog.nib/info.nib +++ b/chimera/resources/localized/English.lproj/ProgressDialog.nib/info.nib @@ -1,12 +0,0 @@ - - - - - IBDocumentLocation - 94 26 404 250 0 0 1152 746 - IBFramework Version - 248.0 - IBSystem Version - 5S60 - - diff --git a/chimera/resources/localized/English.lproj/ProgressDialog.nib/objects.nib b/chimera/resources/localized/English.lproj/ProgressDialog.nib/objects.nib index 6377ab6fd19..e69de29bb2d 100644 Binary files a/chimera/resources/localized/English.lproj/ProgressDialog.nib/objects.nib and b/chimera/resources/localized/English.lproj/ProgressDialog.nib/objects.nib differ diff --git a/chimera/resources/localized/English.lproj/ProgressView.nib/classes.nib b/chimera/resources/localized/English.lproj/ProgressView.nib/classes.nib new file mode 100644 index 00000000000..e69de29bb2d diff --git a/chimera/resources/localized/English.lproj/ProgressView.nib/info.nib b/chimera/resources/localized/English.lproj/ProgressView.nib/info.nib new file mode 100644 index 00000000000..e69de29bb2d diff --git a/chimera/resources/localized/English.lproj/ProgressView.nib/objects.nib b/chimera/resources/localized/English.lproj/ProgressView.nib/objects.nib new file mode 100644 index 00000000000..e69de29bb2d diff --git a/chimera/resources/localized/English.lproj/alert.nib/info.nib b/chimera/resources/localized/English.lproj/alert.nib/info.nib index 1f32d25ff16..e69de29bb2d 100644 --- a/chimera/resources/localized/English.lproj/alert.nib/info.nib +++ b/chimera/resources/localized/English.lproj/alert.nib/info.nib @@ -1,16 +0,0 @@ - - - - - IBDocumentLocation - 410 67 356 301 0 0 1152 848 - IBFramework Version - 286.0 - IBOpenObjects - - 251 - - IBSystem Version - 6F21 - - diff --git a/chimera/resources/localized/English.lproj/alert.nib/objects.nib b/chimera/resources/localized/English.lproj/alert.nib/objects.nib index 6a8f50daa6c..e69de29bb2d 100644 Binary files a/chimera/resources/localized/English.lproj/alert.nib/objects.nib and b/chimera/resources/localized/English.lproj/alert.nib/objects.nib differ diff --git a/chimera/src/application/AppComponents.mm b/chimera/src/application/AppComponents.mm index ebe8a06c200..d8cf7b31b10 100644 --- a/chimera/src/application/AppComponents.mm +++ b/chimera/src/application/AppComponents.mm @@ -37,10 +37,14 @@ * ***** END LICENSE BLOCK ***** */ #import + #import "SecurityDialogs.h" #import "CocoaPromptService.h" -#include "nsIGenericFactory.h" #import "KeychainService.h" +#import "nsDownloadListener.h" +#import "ProgressDlgController.h" + +#include "nsIGenericFactory.h" // {0ffd3880-7a1a-11d6-a384-975d1d5f86fc} #define NS_SECURITYDIALOGS_CID \ @@ -55,6 +59,27 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(SecurityDialogs); NS_GENERIC_FACTORY_CONSTRUCTOR(CocoaPromptService); NS_GENERIC_FACTORY_CONSTRUCTOR(KeychainPrompt); +//NS_GENERIC_FACTORY_CONSTRUCTOR(nsDownloadListener); + +static NS_IMETHODIMP +nsDownloadListenerConstructor(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + *aResult = NULL; + if (aOuter) + return NS_ERROR_NO_AGGREGATION; + + nsDownloadListener* inst; + NS_NEWXPCOM(inst, nsDownloadListener); + if (!inst) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(inst); + inst->SetDisplayFactory([ProgressDlgController sharedDownloadController]); + nsresult rv = inst->QueryInterface(aIID, aResult); + NS_RELEASE(inst); + return rv; +} + // used by MainController to register the components in which we want to override // with the Gecko embed layer. @@ -83,6 +108,12 @@ static const nsModuleComponentInfo gAppComponents[] = { NS_KEYCHAINPROMPT_CID, "@mozilla.org/wallet/single-sign-on-prompt;1", KeychainPromptConstructor + }, + { + "Download", + NS_DOWNLOAD_CID, + NS_DOWNLOAD_CONTRACTID, + nsDownloadListenerConstructor } }; diff --git a/chimera/src/application/MainController.h b/chimera/src/application/MainController.h index 2bf9fb1ce2b..33edbca4a3d 100644 --- a/chimera/src/application/MainController.h +++ b/chimera/src/application/MainController.h @@ -52,9 +52,8 @@ { IBOutlet NSApplication* mApplication; - // The following two items are used by the filter list when saving files. + // The following item is added to NSSavePanels as an accessory view IBOutlet NSView* mFilterView; - IBOutlet NSPopUpButton* mFilterList; // IBOutlet NSMenuItem* mOfflineMenuItem; IBOutlet NSMenuItem* mCloseWindowMenuItem; @@ -137,11 +136,12 @@ -(IBAction) addFolder:(id)aSender; -(IBAction) addSeparator:(id)aSender; -//Window menu actions +// Window menu actions -(IBAction) newTab:(id)aSender; -(IBAction) closeTab:(id)aSender; +-(IBAction) downloadsWindow:(id)aSender; -//Help menu actions +// Help menu actions -(IBAction) infoLink:(id)aSender; -(IBAction) feedbackLink:(id)aSender; @@ -154,7 +154,8 @@ - (void)adjustBookmarksMenuItemsEnabling:(BOOL)inBrowserWindowFrontmost; --(NSWindow*)getFrontmostBrowserWindow; +- (NSView*)getSavePanelView; +- (NSWindow*)getFrontmostBrowserWindow; - (MVPreferencesController *)preferencesController; - (void)displayPreferencesWindow:sender; diff --git a/chimera/src/application/MainController.mm b/chimera/src/application/MainController.mm index 9ef0177d9bf..e200d2f2e43 100644 --- a/chimera/src/application/MainController.mm +++ b/chimera/src/application/MainController.mm @@ -260,19 +260,7 @@ const int kReuseWindowOnAE = 2; - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { - if ([ProgressDlgController numDownloadInProgress] > 0) - { - NSString *alert = NSLocalizedString(@"QuitWithDownloadsMsg", @"Really Quit?"); - NSString *message = NSLocalizedString(@"QuitWithDownloadsExpl", @""); - NSString *okButton = NSLocalizedString(@"QuitWithdownloadsButtonDefault",@"Cancel"); - NSString *altButton = NSLocalizedString(@"QuitWithdownloadsButtonAlt",@"Quit"); - // while the panel is up, download dialogs won't update (no timers firing) but - // downloads continue (PLEvents being processed) - if (NSRunAlertPanel(alert, message, okButton, altButton, nil) == NSAlertDefaultReturn) - return NSTerminateCancel; - } - - return NSTerminateNow; + return [[ProgressDlgController sharedDownloadController] allowTerminate]; } -(void)applicationWillTerminate: (NSNotification*)aNotification @@ -439,7 +427,7 @@ const int kReuseWindowOnAE = 2; { BrowserWindowController* browserController = [self getMainWindowBrowserController]; if (browserController) - [browserController saveDocument:NO filterView:mFilterView filterList: mFilterList]; + [browserController saveDocument:NO filterView:mFilterView]; } -(IBAction) pageSetup:(id)aSender @@ -584,6 +572,11 @@ const int kReuseWindowOnAE = 2; } } +-(IBAction) downloadsWindow:(id)aSender +{ + [[ProgressDlgController sharedDownloadController] showWindow:aSender]; +} + - (void)adjustBookmarksMenuItemsEnabling:(BOOL)inBrowserWindowFrontmost; { [mAddBookmarkMenuItem setEnabled:inBrowserWindowFrontmost]; @@ -591,6 +584,11 @@ const int kReuseWindowOnAE = 2; [mCreateBookmarksSeparatorMenuItem setEnabled:NO]; // separators are not implemented yet } +- (NSView*)getSavePanelView +{ + return mFilterView; +} + -(NSWindow*)getFrontmostBrowserWindow { // for some reason, [NSApp mainWindow] doesn't always work, so we have to diff --git a/chimera/src/application/nsStaticComponents.cpp b/chimera/src/application/nsStaticComponents.cpp index 1065d7b5ed2..849cbfddf5d 100644 --- a/chimera/src/application/nsStaticComponents.cpp +++ b/chimera/src/application/nsStaticComponents.cpp @@ -47,7 +47,58 @@ NSGETMODULE(_name) (nsIComponentManager* aCompMgr, \ } // NSGetModule entry points -DECL_NSGETMODULE(UcharUtil) DECL_NSGETMODULE(nsUConvModule) DECL_NSGETMODULE(nsUCvJAModule) DECL_NSGETMODULE(nsUCvCnModule) DECL_NSGETMODULE(nsUCvLatinModule) DECL_NSGETMODULE(nsUCvTWModule) DECL_NSGETMODULE(nsUCvTW2Module) DECL_NSGETMODULE(nsUCvKoModule) DECL_NSGETMODULE(nsLocaleModule) DECL_NSGETMODULE(nsStringBundleModule) DECL_NSGETMODULE(nsLWBrkModule) DECL_NSGETMODULE(nsCharDetModule) DECL_NSGETMODULE(xpconnect) DECL_NSGETMODULE(cacheservice) DECL_NSGETMODULE(necko_core_and_primary_protocols) DECL_NSGETMODULE(necko_secondary_protocols) DECL_NSGETMODULE(nsURILoaderModule) DECL_NSGETMODULE(nsPrefModule) DECL_NSGETMODULE(nsCJVMManagerModule) DECL_NSGETMODULE(nsSecurityManagerModule) DECL_NSGETMODULE(nsChromeModule) DECL_NSGETMODULE(nsRDFModule) DECL_NSGETMODULE(nsParserModule) DECL_NSGETMODULE(nsGfxMacModule) DECL_NSGETMODULE(nsGfx2Module) DECL_NSGETMODULE(nsImageLib2Module) DECL_NSGETMODULE(nsPNGDecoderModule) DECL_NSGETMODULE(nsGIFModule2) DECL_NSGETMODULE(nsJPEGDecoderModule) DECL_NSGETMODULE(nsPluginModule) DECL_NSGETMODULE(javascript__protocol) DECL_NSGETMODULE(DOM_components) DECL_NSGETMODULE(nsViewModule) DECL_NSGETMODULE(nsWidgetMacModule) DECL_NSGETMODULE(nsContentModule) DECL_NSGETMODULE(nsLayoutModule) DECL_NSGETMODULE(nsMorkModule) DECL_NSGETMODULE(docshell_provider) DECL_NSGETMODULE(embedcomponents) DECL_NSGETMODULE(Browser_Embedding_Module) DECL_NSGETMODULE(nsEditorModule) DECL_NSGETMODULE(nsTransactionManagerModule) DECL_NSGETMODULE(nsTextServicesModule) DECL_NSGETMODULE(nsProfileModule) DECL_NSGETMODULE(Session_History_Module) DECL_NSGETMODULE(application) DECL_NSGETMODULE(nsCookieModule) DECL_NSGETMODULE(nsXMLExtrasModule) DECL_NSGETMODULE(nsUniversalCharDetModule) DECL_NSGETMODULE(BOOT) DECL_NSGETMODULE(NSS) +DECL_NSGETMODULE(UcharUtil) +DECL_NSGETMODULE(nsUConvModule) +DECL_NSGETMODULE(nsUCvJAModule) +DECL_NSGETMODULE(nsUCvCnModule) +DECL_NSGETMODULE(nsUCvLatinModule) +DECL_NSGETMODULE(nsUCvTWModule) +DECL_NSGETMODULE(nsUCvTW2Module) +DECL_NSGETMODULE(nsUCvKoModule) +DECL_NSGETMODULE(nsLocaleModule) +DECL_NSGETMODULE(nsStringBundleModule) +DECL_NSGETMODULE(nsLWBrkModule) +DECL_NSGETMODULE(nsCharDetModule) +DECL_NSGETMODULE(xpconnect) +DECL_NSGETMODULE(cacheservice) +DECL_NSGETMODULE(necko_core_and_primary_protocols) +DECL_NSGETMODULE(necko_secondary_protocols) +DECL_NSGETMODULE(nsURILoaderModule) +DECL_NSGETMODULE(nsPrefModule) +DECL_NSGETMODULE(nsCJVMManagerModule) +DECL_NSGETMODULE(nsSecurityManagerModule) +DECL_NSGETMODULE(nsChromeModule) +DECL_NSGETMODULE(nsRDFModule) +DECL_NSGETMODULE(nsParserModule) +DECL_NSGETMODULE(nsGfxMacModule) +DECL_NSGETMODULE(nsGfx2Module) +DECL_NSGETMODULE(nsImageLib2Module) +DECL_NSGETMODULE(nsPNGDecoderModule) +DECL_NSGETMODULE(nsGIFModule2) +DECL_NSGETMODULE(nsJPEGDecoderModule) +DECL_NSGETMODULE(nsPluginModule) +DECL_NSGETMODULE(javascript__protocol) +DECL_NSGETMODULE(JS_component_loader) +DECL_NSGETMODULE(DOM_components) +DECL_NSGETMODULE(nsViewModule) +DECL_NSGETMODULE(nsWidgetMacModule) +DECL_NSGETMODULE(nsContentModule) +DECL_NSGETMODULE(nsLayoutModule) +DECL_NSGETMODULE(nsMorkModule) +DECL_NSGETMODULE(docshell_provider) +DECL_NSGETMODULE(embedcomponents) +DECL_NSGETMODULE(Browser_Embedding_Module) +DECL_NSGETMODULE(nsEditorModule) +DECL_NSGETMODULE(nsTransactionManagerModule) +DECL_NSGETMODULE(nsTextServicesModule) +DECL_NSGETMODULE(nsProfileModule) +DECL_NSGETMODULE(Session_History_Module) +DECL_NSGETMODULE(application) +DECL_NSGETMODULE(nsCookieModule) +DECL_NSGETMODULE(nsXMLExtrasModule) +DECL_NSGETMODULE(nsUniversalCharDetModule) +DECL_NSGETMODULE(BOOT) +DECL_NSGETMODULE(NSS) #line 52 "nsStaticComponents.cpp.in" /** @@ -55,7 +106,58 @@ DECL_NSGETMODULE(UcharUtil) DECL_NSGETMODULE(nsUConvModule) DECL_NSGETMODULE(nsU */ static nsStaticModuleInfo gStaticModuleInfo[] = { #define MODULE(_name) { (#_name), NSGETMODULE(_name) } - MODULE(UcharUtil), MODULE(nsUConvModule), MODULE(nsUCvJAModule), MODULE(nsUCvCnModule), MODULE(nsUCvLatinModule), MODULE(nsUCvTWModule), MODULE(nsUCvTW2Module), MODULE(nsUCvKoModule), MODULE(nsLocaleModule), MODULE(nsStringBundleModule), MODULE(nsLWBrkModule), MODULE(nsCharDetModule), MODULE(xpconnect), MODULE(cacheservice), MODULE(necko_core_and_primary_protocols), MODULE(necko_secondary_protocols), MODULE(nsURILoaderModule), MODULE(nsPrefModule), MODULE(nsCJVMManagerModule), MODULE(nsSecurityManagerModule), MODULE(nsChromeModule), MODULE(nsRDFModule), MODULE(nsParserModule), MODULE(nsGfxMacModule), MODULE(nsGfx2Module), MODULE(nsImageLib2Module), MODULE(nsPNGDecoderModule), MODULE(nsGIFModule2), MODULE(nsJPEGDecoderModule), MODULE(nsPluginModule), MODULE(javascript__protocol), MODULE(DOM_components), MODULE(nsViewModule), MODULE(nsWidgetMacModule), MODULE(nsContentModule), MODULE(nsLayoutModule), MODULE(nsMorkModule), MODULE(docshell_provider), MODULE(embedcomponents), MODULE(Browser_Embedding_Module), MODULE(nsEditorModule), MODULE(nsTransactionManagerModule), MODULE(nsTextServicesModule), MODULE(nsProfileModule), MODULE(Session_History_Module), MODULE(application), MODULE(nsCookieModule), MODULE(nsXMLExtrasModule), MODULE(nsUniversalCharDetModule), MODULE(BOOT), MODULE(NSS), +MODULE(UcharUtil), +MODULE(nsUConvModule), +MODULE(nsUCvJAModule), +MODULE(nsUCvCnModule), +MODULE(nsUCvLatinModule), +MODULE(nsUCvTWModule), +MODULE(nsUCvTW2Module), +MODULE(nsUCvKoModule), +MODULE(nsLocaleModule), +MODULE(nsStringBundleModule), +MODULE(nsLWBrkModule), +MODULE(nsCharDetModule), +MODULE(xpconnect), +MODULE(cacheservice), +MODULE(necko_core_and_primary_protocols), +MODULE(necko_secondary_protocols), +MODULE(nsURILoaderModule), +MODULE(nsPrefModule), +MODULE(nsCJVMManagerModule), +MODULE(nsSecurityManagerModule), +MODULE(nsChromeModule), +MODULE(nsRDFModule), +MODULE(nsParserModule), +MODULE(nsGfxMacModule), +MODULE(nsGfx2Module), +MODULE(nsImageLib2Module), +MODULE(nsPNGDecoderModule), +MODULE(nsGIFModule2), +MODULE(nsJPEGDecoderModule), +MODULE(nsPluginModule), +MODULE(javascript__protocol), +MODULE(JS_component_loader), +MODULE(DOM_components), +MODULE(nsViewModule), +MODULE(nsWidgetMacModule), +MODULE(nsContentModule), +MODULE(nsLayoutModule), +MODULE(nsMorkModule), +MODULE(docshell_provider), +MODULE(embedcomponents), +MODULE(Browser_Embedding_Module), +MODULE(nsEditorModule), +MODULE(nsTransactionManagerModule), +MODULE(nsTextServicesModule), +MODULE(nsProfileModule), +MODULE(Session_History_Module), +MODULE(application), +MODULE(nsCookieModule), +MODULE(nsXMLExtrasModule), +MODULE(nsUniversalCharDetModule), +MODULE(BOOT), +MODULE(NSS), #line 60 "nsStaticComponents.cpp.in" }; diff --git a/chimera/src/bookmarks/BookmarksDataSource.mm b/chimera/src/bookmarks/BookmarksDataSource.mm index de6cf71b6ac..e69de29bb2d 100644 --- a/chimera/src/bookmarks/BookmarksDataSource.mm +++ b/chimera/src/bookmarks/BookmarksDataSource.mm @@ -1,883 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: NPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Netscape Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 2002 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Simon Fraser - * - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the NPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the NPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#import "NSString+Utils.h" - -#import "BookmarksDataSource.h" -#import "BookmarkInfoController.h" -#import "SiteIconProvider.h" - -#include "nsCOMPtr.h" -#include "nsIContent.h" -#include "nsIDocument.h" -#include "nsIDocumentObserver.h" -#include "nsIDOMDocument.h" -#include "nsIDOMElement.h" -#include "nsINamespaceManager.h" - -#include "nsVoidArray.h" - -#import "BookmarksService.h" - -@interface BookmarksDataSource(Private) - -- (void)restoreFolderExpandedStates; -- (void)refreshChildrenOfItem:(nsIContent*)item; - -@end - -const int kBookmarksRootItemTag = -2; - -@implementation BookmarksDataSource - --(id) init -{ - if ( (self = [super init]) ) - { - mCachedHref = nil; - } - return self; -} - -- (void)dealloc -{ -// NSLog(@"BookmarksDataSource dealloc"); - [super dealloc]; -} - --(void) awakeFromNib -{ - // make sure these are disabled at the start since the outliner - // starts off with no selection. - [mEditBookmarkButton setEnabled:NO]; - [mDeleteBookmarkButton setEnabled:NO]; -} - --(void) windowClosing -{ - BookmarksManager* bmManager = [BookmarksManager sharedBookmarksManagerDontAlloc]; - [bmManager removeBookmarksClient:self]; -} - --(void) ensureBookmarks -{ - if (mRegisteredClient) - return; - - BookmarksManager* bmManager = [BookmarksManager sharedBookmarksManager]; - [bmManager addBookmarksClient:self]; - mRegisteredClient = YES; - - [mOutlineView setTarget: self]; - [mOutlineView setDoubleAction: @selector(openBookmark:)]; - [mOutlineView setDeleteAction: @selector(deleteBookmarks:)]; - [mOutlineView reloadData]; - [self restoreFolderExpandedStates]; -} - --(IBAction)addBookmark:(id)aSender -{ - [self addBookmark: aSender useSelection: YES isFolder: NO URL:nil title:nil]; -} - --(IBAction)addFolder:(id)aSender -{ - [self addBookmark: aSender useSelection: YES isFolder: YES URL:nil title:nil]; -} - --(void)addBookmark:(id)aSender useSelection:(BOOL)aUseSel isFolder:(BOOL)aIsFolder URL:(NSString*)aURL title:(NSString*)aTitle -{ - // We use the selected item to determine the parent only if aUseSel is YES. - BookmarkItem* item = nil; - if (aUseSel && ([mOutlineView numberOfSelectedRows] == 1)) - { - // There is only one selected row. If it is a folder, use it as our parent. - // Otherwise, use our parent, - int index = [mOutlineView selectedRow]; - item = [mOutlineView itemAtRow: index]; - if (![mOutlineView isExpandable: item]) { - // We can't be used as the parent. Try our parent. - nsIContent* content = [item contentNode]; - if (!content) - return; - - nsCOMPtr parentContent; - content->GetParent(*getter_AddRefs(parentContent)); - nsCOMPtr root; - BookmarksService::GetRootContent(getter_AddRefs(root)); - - // The root has no item, so we don't need to do a lookup unless we - // aren't the root. - if (parentContent != root) { - PRUint32 contentID; - parentContent->GetContentID(&contentID); - item = BookmarksService::GetWrapperFor(contentID); - } - } - } - - [self addBookmark:aSender withParent:item isFolder:aIsFolder URL:aURL title:aTitle]; -} - --(void)addBookmark:(id)aSender withParent:(BookmarkItem*)bmItem isFolder:(BOOL)aIsFolder URL:(NSString*)aURL title:(NSString*)aTitle -{ - NSString* titleString = aTitle; - NSString* urlString = aURL; - - if (!aIsFolder) - { - // If no URL and title were specified, get them from the current page. - if (!aURL || !aTitle) - [[mBrowserWindowController getBrowserWrapper] getTitle:&titleString andHref:&urlString]; - - mCachedHref = [NSString stringWithString:urlString]; - [mCachedHref retain]; - - } else { // Folder - mCachedHref = nil; - titleString = NSLocalizedString(@"NewBookmarkFolder", @""); - } - - NSTextField* textField = [mBrowserWindowController getAddBookmarkTitle]; - NSString* bookmarkTitle = titleString; - NSString* cleanedTitle = [bookmarkTitle stringByReplacingCharactersInSet:[NSCharacterSet controlCharacterSet] withString:@" "]; - - [textField setStringValue: cleanedTitle]; - - [mBrowserWindowController cacheBookmarkDS: self]; - - // Show/hide the bookmark all tabs checkbox as appropriate. - NSTabView* tabView = [mBrowserWindowController getTabBrowser]; - id checkbox = [mBrowserWindowController getAddBookmarkCheckbox]; - BOOL hasSuperview = [checkbox superview] != nil; - if (aIsFolder && hasSuperview) { - // Just don't show it at all. - [checkbox removeFromSuperview]; - [checkbox retain]; - } - else if (!aIsFolder && !hasSuperview) { - // Put it back in. - [[[mBrowserWindowController getAddBookmarkSheetWindow] contentView] addSubview: checkbox]; - [checkbox autorelease]; - } - - // Enable the bookmark all tabs checkbox if appropriate. - if (!aIsFolder) - [[mBrowserWindowController getAddBookmarkCheckbox] setEnabled: ([tabView numberOfTabViewItems] > 1)]; - - // Build up the folder list. - NSPopUpButton* popup = [mBrowserWindowController getAddBookmarkFolder]; - [popup removeAllItems]; - [popup addItemWithTitle: NSLocalizedString(@"BookmarksRootName", @"")]; - [[popup lastItem] setTag:kBookmarksRootItemTag]; - - BookmarksManager* bmManager = [BookmarksManager sharedBookmarksManager]; - [bmManager buildFlatFolderList:[popup menu] fromRoot:NULL]; - - int itemIndex = [popup indexOfItemWithTag:[bmItem intContentID]]; - if (itemIndex != -1) - [popup selectItemAtIndex:itemIndex]; - - [popup synchronizeTitleAndSelectedItem]; - - [NSApp beginSheet: [mBrowserWindowController getAddBookmarkSheetWindow] - modalForWindow: [mBrowserWindowController window] - modalDelegate: nil //self - didEndSelector: nil //@selector(sheetDidEnd:) - contextInfo: nil]; -} - --(void)endAddBookmark: (int)aCode -{ - if (aCode == 0) - return; - - BOOL isGroup = NO; - id checkbox = [mBrowserWindowController getAddBookmarkCheckbox]; - if (([checkbox superview] != nil) && [checkbox isEnabled] && ([checkbox state] == NSOnState)) - { - [mCachedHref release]; - mCachedHref = nil; - isGroup = YES; - } - - BookmarksManager* bmManager = [BookmarksManager sharedBookmarksManager]; - NSString* titleString = [[mBrowserWindowController getAddBookmarkTitle] stringValue]; - - // Figure out the parent element. - nsCOMPtr parentContent; - - NSPopUpButton* popup = [mBrowserWindowController getAddBookmarkFolder]; - NSMenuItem* selectedItem = [popup selectedItem]; - int tag = [selectedItem tag]; - if (tag != kBookmarksRootItemTag) - { - BookmarkItem* item = BookmarksService::GetWrapperFor(tag); - // Get the content node. - parentContent = [item contentNode]; - } - - if (isGroup) - { - id tabBrowser = [mBrowserWindowController getTabBrowser]; - int count = [tabBrowser numberOfTabViewItems]; - - NSMutableArray* itemsArray = [[NSMutableArray alloc] initWithCapacity:count]; - - for (int i = 0; i < count; i++) - { - BrowserWrapper* browserWrapper = (BrowserWrapper*)[[tabBrowser tabViewItemAtIndex: i] view]; - - NSString* titleString = nil; - NSString* hrefString = nil; - [browserWrapper getTitle:&titleString andHref:&hrefString]; - - NSDictionary* itemDict = [NSDictionary dictionaryWithObjectsAndKeys: - titleString, @"title", - hrefString, @"href", - nil]; - [itemsArray addObject:itemDict]; - } - - [bmManager addNewBookmarkGroup:titleString items:itemsArray withParent:parentContent]; - } - else - { - if (mCachedHref) - { - [bmManager addNewBookmark:mCachedHref title:titleString withParent:parentContent]; - [mCachedHref release]; - mCachedHref = nil; - } - else - [bmManager addNewBookmarkFolder:titleString withParent:parentContent]; - } -} - --(IBAction)deleteBookmarks: (id)aSender -{ - int index = [mOutlineView selectedRow]; - if (index == -1) - return; - - // first, see how many items are selected - BOOL haveBookmarks = NO; - - NSEnumerator* testSelRows = [mOutlineView selectedRowEnumerator]; - for (NSNumber* currIndex = [testSelRows nextObject]; - currIndex != nil; - currIndex = [testSelRows nextObject]) - { - index = [currIndex intValue]; - BookmarkItem* item = [mOutlineView itemAtRow: index]; - if ([mOutlineView isExpandable: item]) { - // dumb check to see if we're deleting an empty folder. Should really - // recurse down - if ([self outlineView:mOutlineView numberOfChildrenOfItem: item] > 0) - haveBookmarks = YES; - } else - haveBookmarks = YES; - } - - // ideally, we should count the number of doomed bookmarks and tell the user - if (haveBookmarks) { - NSString *alert = NSLocalizedString(@"DeteleBookmarksAlert",@""); - NSString *message = NSLocalizedString(@"DeteleBookmarksMsg",@""); - NSString *okButton = NSLocalizedString(@"DeteleBookmarksOKButton",@""); - NSString *cancelButton = NSLocalizedString(@"DeteleBookmarksCancelButton",@""); - if (NSRunAlertPanel(alert, message, okButton, cancelButton, nil) != NSAlertDefaultReturn) - return; - } - - // The alert panel was the key window. As soon as we dismissed it, Cocoa will - // pick a new one for us. Ideally, it'll be the window we were using when - // we clicked the delete button. However, if by chance the BookmarkInfoController - // is visible, it will become the key window since it's a panel. If we then delete - // the bookmark and try to close the window before we've setup a new bookmark, - // we'll trigger the windowDidResignKey message, which will try to update the bookmark - // we just deleted, and things will crash. So, we'll trigger windowDidResignKey now - // and avoid the unpleasentness of a crash log. - - if (![[mBrowserWindowController window] isKeyWindow]) - [[mBrowserWindowController window] makeKeyWindow]; - - // we'll run into problems if a parent item and one if its children are both selected. - // A cheap way of having to avoid scanning the list to remove children is to have the - // outliner collapse all items that are being deleted. This will cull the selection - // for us and eliminate any children that happened to be selected. - NSEnumerator* selRows = [mOutlineView selectedRowEnumerator]; - for (NSNumber* currIndex = [selRows nextObject]; - currIndex != nil; - currIndex = [selRows nextObject]) { - index = [currIndex intValue]; - BookmarkItem* item = [mOutlineView itemAtRow: index]; - [mOutlineView collapseItem: item]; - } - - // create array of items we need to delete. Deleting items out of of the - // selection array is problematic for some reason. - NSMutableArray* itemsToDelete = [[[NSMutableArray alloc] init] autorelease]; - selRows = [mOutlineView selectedRowEnumerator]; - for (NSNumber* currIndex = [selRows nextObject]; - currIndex != nil; - currIndex = [selRows nextObject]) { - index = [currIndex intValue]; - BookmarkItem* item = [mOutlineView itemAtRow: index]; - [itemsToDelete addObject: item]; - } - - // delete all bookmarks that are in our array - int count = [itemsToDelete count]; - for (int i = 0; i < count; i++) { - BookmarkItem* item = [itemsToDelete objectAtIndex: i]; - [self deleteBookmark: item]; - } - - // restore selection to location near last item deleted or last item - int total = [mOutlineView numberOfRows]; - if (index >= total) - index = total - 1; - [mOutlineView selectRow: index byExtendingSelection: NO]; - // lame, but makes sure we catch all delete events in Info Panel - [[NSNotificationCenter defaultCenter] postNotificationName:@"NSOutlineViewSelectionDidChangeNotification" object:mOutlineView]; -} - --(void)deleteBookmark:(id)aItem -{ - [aItem remove]; -} - --(IBAction)openBookmark: (id)aSender -{ - int index = [mOutlineView selectedRow]; - if (index == -1) - return; - - id item = [mOutlineView itemAtRow: index]; - if (!item) - return; - - if ([item isGroup]) - { - NSArray* groupURLs = [[BookmarksManager sharedBookmarksManager] getBookmarkGroupURIs:item]; - [mBrowserWindowController openTabGroup:groupURLs replaceExistingTabs:YES]; - } - else if ([mOutlineView isExpandable: item]) - { - if ([mOutlineView isItemExpanded: item]) - [mOutlineView collapseItem: item]; - else - [mOutlineView expandItem: item]; - } - else - { - // if the command key is down, follow the command-click pref - if (([[NSApp currentEvent] modifierFlags] & NSCommandKeyMask) && - [[PreferenceManager sharedInstance] getBooleanPref:"browser.tabs.opentabfor.middleclick" withSuccess:NULL]) - { - BOOL loadInBackground = [[PreferenceManager sharedInstance] getBooleanPref:"browser.tabs.loadInBackground" withSuccess:NULL]; - [mBrowserWindowController openNewTabWithURL:[item url] referrer:nil loadInBackground: loadInBackground]; - } - else - [[mBrowserWindowController getBrowserWrapper] loadURI:[item url] referrer:nil flags:NSLoadFlagsNone activate:YES]; - } -} - --(IBAction)openBookmarkInNewTab:(id)aSender -{ - int index = [mOutlineView selectedRow]; - if (index == -1) - return; - - if ([mOutlineView numberOfSelectedRows] == 1) - { - BookmarkItem* item = [mOutlineView itemAtRow: index]; - BOOL loadInBackground = [[PreferenceManager sharedInstance] getBooleanPref:"browser.tabs.loadInBackground" withSuccess:NULL]; - [mBrowserWindowController openNewTabWithURL:[item url] referrer:nil loadInBackground: loadInBackground]; - } -} - --(IBAction)openBookmarkInNewWindow:(id)aSender -{ - int index = [mOutlineView selectedRow]; - if (index == -1) - return; - if ([mOutlineView numberOfSelectedRows] == 1) - { - BookmarkItem* item = [mOutlineView itemAtRow: index]; - - BOOL loadInBackground = [[PreferenceManager sharedInstance] getBooleanPref:"browser.tabs.loadInBackground" withSuccess:NULL]; - - if ([item isGroup]) - [mBrowserWindowController openNewWindowWithGroup:[item contentNode] loadInBackground:loadInBackground]; - else - [mBrowserWindowController openNewWindowWithURL:[item url] referrer: nil loadInBackground: loadInBackground]; - } -} - --(IBAction)showBookmarkInfo:(id)aSender -{ - BookmarkInfoController *bic = [BookmarkInfoController sharedBookmarkInfoController]; - - int index = [mOutlineView selectedRow]; - BookmarkItem* item = [mOutlineView itemAtRow: index]; - [bic setBookmark:item]; - - [bic showWindow:bic]; -} - -- (void)restoreFolderExpandedStates -{ - int curRow = 0; - - while (curRow < [mOutlineView numberOfRows]) - { - id item = [mOutlineView itemAtRow:curRow]; - - if (item) - { - nsCOMPtr content; - content = [item contentNode]; - - PRBool isOpen = content && content->HasAttr(kNameSpaceID_None, BookmarksService::gOpenAtom); - if (isOpen) - [mOutlineView expandItem: item]; - else - [mOutlineView collapseItem: item]; - } - - curRow ++; - } -} - -- (void)refreshChildrenOfItem:(nsIContent*)item -{ - BookmarkItem* bmItem = nil; - - nsCOMPtr parent; - if (item) - item->GetParent(*getter_AddRefs(parent)); - if (parent) // we're not the root - bmItem = [[BookmarksManager sharedBookmarksManager] getWrapperForContent:item]; - - [self reloadDataForItem:bmItem reloadChildren:YES]; -} - -#pragma mark - - -// BookmarksClient protocol - -- (void)bookmarkAdded:(nsIContent*)bookmark inContainer:(nsIContent*)container isChangedRoot:(BOOL)isRoot -{ - [self refreshChildrenOfItem:container]; -} - -- (void)bookmarkRemoved:(nsIContent*)bookmark inContainer:(nsIContent*)container isChangedRoot:(BOOL)isRoot -{ - [self refreshChildrenOfItem:container]; -} - -- (void)bookmarkChanged:(nsIContent*)bookmark -{ - BookmarkItem* item = [[BookmarksManager sharedBookmarksManager] getWrapperForContent:bookmark]; - [self reloadDataForItem:item reloadChildren:NO]; -} - -- (void)specialFolder:(EBookmarksFolderType)folderType changedTo:(nsIContent*)newFolderContent -{ - // change the icons - - -} - -#pragma mark - - -// -// outlineView:shouldEditTableColumn:item: (delegate method) -// -// Called by the outliner to determine whether or not we should allow the -// user to edit this item. We're leaving it off for now, becaue there are -// some usability issues with inline editing (no undo, Escape doesn't work). -- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item -{ - return NO; //([[tableColumn identifier] isEqualToString:@"name"]); -} - -- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item -{ - if (!mRegisteredClient) return nil; - - nsCOMPtr content; - if (!item) - BookmarksService::GetRootContent(getter_AddRefs(content)); - else - content = [item contentNode]; - - nsCOMPtr child; - content->ChildAt(index, *getter_AddRefs(child)); - if ( child ) - return BookmarksService::GetWrapperFor(child); - - return nil; -} - -- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item -{ - if (!mRegisteredClient) return NO; - - if (!item) - return YES; // The root node is always open. - - return [item isFolder]; -} - -- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item -{ - if (!mRegisteredClient) return 0; - - nsCOMPtr content; - if (!item) - BookmarksService::GetRootContent(getter_AddRefs(content)); - else - content = [item contentNode]; - - PRInt32 childCount; - content->ChildCount(childCount); - - return childCount; -} - -- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item -{ - if (!mRegisteredClient) return nil; - - NSString *columnName = [tableColumn identifier]; - NSMutableAttributedString *cellValue = nil; - - if ([columnName isEqualToString: @"name"]) - { - NSFileWrapper *fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents:nil]; - NSTextAttachment *textAttachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper]; - - nsIContent* content = [item contentNode]; - nsAutoString nameAttr; - content->GetAttr(kNameSpaceID_None, BookmarksService::gNameAtom, nameAttr); - - //Set cell's textual contents - //[cellValue replaceCharactersInRange:NSMakeRange(0, [cellValue length]) withString:[NSString stringWith_nsAString: nameAttr]]; - cellValue = [[NSMutableAttributedString alloc] initWithString:[NSString stringWith_nsAString: nameAttr]]; - - //Create an attributed string to hold the empty attachment, then release the components. - NSMutableAttributedString* attachmentAttrString = [NSMutableAttributedString attributedStringWithAttachment:textAttachment]; - [textAttachment release]; - [fileWrapper release]; - - //Get the cell of the text attachment. - NSCell* attachmentAttrStringCell = (NSCell *)[(NSTextAttachment *)[attachmentAttrString attribute:NSAttachmentAttributeName atIndex:0 effectiveRange:nil] attachmentCell]; - - nsCOMPtr elt(do_QueryInterface(content)); - NSImage* bookmarkImage = BookmarksService::CreateIconForBookmark(elt); - [attachmentAttrStringCell setImage:bookmarkImage]; - - //Insert the image - [cellValue replaceCharactersInRange:NSMakeRange(0, 0) withAttributedString:attachmentAttrString]; - - //Tweak the baseline to vertically center the text. - [cellValue addAttribute:NSBaselineOffsetAttributeName - value:[NSNumber numberWithFloat:-3.0] - range:NSMakeRange(0, 1)]; - } - return cellValue; -} - -- (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item -{ - // object is really an NSString, even though objectValueForTableColumn returns NSAttributedStrings. - NSString *columnName = [tableColumn identifier]; - if ( [columnName isEqualTo:@"name"] ) - { - const unichar kAttachmentCharacter = NSAttachmentCharacter; - - NSMutableString* mutableString = [NSMutableString stringWithString:object]; - [mutableString replaceOccurrencesOfString:[NSString stringWithCharacters:&kAttachmentCharacter length:1] withString:@"" options:0 range:NSMakeRange(0, [mutableString length])]; - - nsAutoString nameAttr; - [mutableString assignTo_nsAString:nameAttr]; - - // stash it into the DOM - BookmarkItem* bmItem = (BookmarkItem*)item; - nsIContent* content = [bmItem contentNode]; - if (content) - content->SetAttr(kNameSpaceID_None, BookmarksService::gNameAtom, nameAttr, PR_TRUE); - - [bmItem itemChanged:YES]; - } -} - -- (BOOL)outlineView:(NSOutlineView *)ov writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard -{ - if (!mRegisteredClient) return NO; - -#ifdef FILTER_DESCENDANT_ON_DRAG - NSArray *toDrag = BookmarksService::FilterOutDescendantsForDrag(items); -#else - NSArray *toDrag = items; -#endif - int count = [toDrag count]; - if (count > 0) { - // Create Pasteboard Data - NSMutableArray *draggedIDs = [NSMutableArray arrayWithCapacity: count]; - - for (int i = 0; i < count; i++) - [draggedIDs addObject: [[toDrag objectAtIndex: i] contentID]]; - - if (count == 1) { - // if we have just one item, we add some more flavours - [pboard declareTypes: [NSArray arrayWithObjects: - @"MozBookmarkType", NSURLPboardType, NSStringPboardType, nil] owner: self]; - [pboard setPropertyList: draggedIDs forType: @"MozBookmarkType"]; - - NSString* itemURL = [[toDrag objectAtIndex: 0] url]; - [pboard setString:itemURL forType: NSStringPboardType]; - [[NSURL URLWithString:itemURL] writeToPasteboard: pboard]; - // maybe construct the @"MozURLType" type here also - } - else { - // multiple bookmarks. Arrays of strings or NSURLs seem to - // confuse receivers. Not sure what the correct way is. - [pboard declareTypes: [NSArray arrayWithObject: @"MozBookmarkType"] owner: self]; - [pboard setPropertyList: draggedIDs forType: @"MozBookmarkType"]; - } - - return YES; - } - - return NO; -} - - -- (NSDragOperation)outlineView:(NSOutlineView*)ov validateDrop:(id )info proposedItem:(id)item proposedChildIndex:(int)index -{ - if (!mRegisteredClient) return NSDragOperationNone; - - NSArray* types = [[info draggingPasteboard] types]; - BOOL isCopy = ([info draggingSourceOperationMask] == NSDragOperationCopy); - - // if the index is -1, deny the drop - if (index == NSOutlineViewDropOnItemIndex) - return NSDragOperationNone; - - if ([types containsObject: @"MozBookmarkType"]) - { - NSArray *draggedIDs = [[info draggingPasteboard] propertyListForType: @"MozBookmarkType"]; - - BookmarkItem* parent = (item) ? item : BookmarksService::GetRootItem(); - return (BookmarksService::IsBookmarkDropValid(parent, index, draggedIDs, isCopy)) ? NSDragOperationGeneric : NSDragOperationNone; - } - - if ([types containsObject: @"MozURLType"]) - return NSDragOperationGeneric; - - if ([types containsObject: NSStringPboardType]) - return NSDragOperationGeneric; - - if ([types containsObject: NSURLPboardType]) - return NSDragOperationGeneric; - - return NSDragOperationNone; -} - -- (BOOL)outlineView:(NSOutlineView*)ov acceptDrop:(id )info item:(id)item childIndex:(int)index -{ - if (!mRegisteredClient) return NO; - - NSArray* types = [[info draggingPasteboard] types]; - BookmarkItem* parent = (item) ? item : BookmarksService::GetRootItem(); - BOOL isCopy = ([info draggingSourceOperationMask] == NSDragOperationCopy); - - BookmarkItem* beforeItem = [self outlineView:ov child:index ofItem:item]; - if ([types containsObject: @"MozBookmarkType"]) - { - NSArray *draggedItems = [[info draggingPasteboard] propertyListForType: @"MozBookmarkType"]; - return BookmarksService::PerformBookmarkDrop(parent, beforeItem, index, draggedItems, isCopy); - } - else if ([types containsObject: @"MozURLType"]) - { - NSDictionary* proxy = [[info draggingPasteboard] propertyListForType: @"MozURLType"]; - return BookmarksService::PerformProxyDrop(parent, beforeItem, proxy); - } - else if ([types containsObject: NSStringPboardType]) - { - NSString* draggedText = [[info draggingPasteboard] stringForType:NSStringPboardType]; - return BookmarksService::PerformURLDrop(parent, beforeItem, draggedText, draggedText); - } - else if ([types containsObject: NSURLPboardType]) - { - NSURL* urlData = [NSURL URLFromPasteboard:[info draggingPasteboard]]; - return BookmarksService::PerformURLDrop(parent, beforeItem, [urlData absoluteString], [urlData absoluteString]); - } - - return NO; -} - -- (NSString *)outlineView:(NSOutlineView *)outlineView tooltipStringForItem:(id)item -{ - if (!mRegisteredClient) return @""; - - NSString* descStr = nil; - NSString* hrefStr = nil; - nsIContent* content = [item contentNode]; - nsAutoString value; - - content->GetAttr(kNameSpaceID_None, BookmarksService::gDescriptionAtom, value); - if (value.Length()) - descStr = [NSString stringWith_nsAString:value]; - - // Only description for folders - if ([item isFolder]) - return descStr; - - // Extract the URL from the item - content->GetAttr(kNameSpaceID_None, BookmarksService::gHrefAtom, value); - if (value.Length()) - hrefStr = [NSString stringWith_nsAString:value]; - - if (!hrefStr) - return descStr; - else if (!descStr) - return hrefStr; - - // Display both URL and description - return [NSString stringWithFormat:@"%@\n%@", hrefStr, descStr]; -} - -/* -- (NSMenu *)outlineView:(NSOutlineView *)outlineView contextMenuForItem:(id)item -{ - // TODO - return (custom?) context menu for item here. - // Note that according to HIG, there should never be disabled items in - // a context menu - instead, items that do not apply should be removed. - // We could nicely do that here. -} -*/ - -- (void)reloadDataForItem:(id)item reloadChildren: (BOOL)aReloadChildren -{ - if (!item) - [mOutlineView reloadData]; - else - [mOutlineView reloadItem: item reloadChildren: aReloadChildren]; -} - -- (BOOL)haveSelectedRow -{ - return ([mOutlineView selectedRow] != -1); -} - --(void)outlineViewSelectionDidChange: (NSNotification*) aNotification -{ - BookmarkInfoController *bic = [BookmarkInfoController sharedBookmarkInfoController]; - int index = [mOutlineView selectedRow]; - if (index == -1) - { - [mEditBookmarkButton setEnabled:NO]; - [mDeleteBookmarkButton setEnabled:NO]; - [bic close]; - } - else - { - BookmarkItem* item = [mOutlineView itemAtRow: index]; - - [mEditBookmarkButton setEnabled:YES]; - [mDeleteBookmarkButton setEnabled:![item isToobarRoot]]; - if ([[bic window] isVisible]) - [bic setBookmark:[mOutlineView itemAtRow:index]]; - } -} - --(BOOL)validateMenuItem:(NSMenuItem*)aMenuItem -{ - int index = [mOutlineView selectedRow]; - BOOL haveSelection = (index != -1); - BOOL isBookmark = NO; - BOOL isGroup = NO; - - BookmarkItem* item = nil; - - if (haveSelection) - { - item = [mOutlineView itemAtRow: index]; - isBookmark = ([mOutlineView isExpandable:item] == NO); - isGroup = [item isGroup]; - } - - // Bookmarks and Bookmark Groups can be opened in a new window - if (([aMenuItem action] == @selector(openBookmarkInNewWindow:))) - return (isBookmark || isGroup); - - // Only Bookmarks can be opened in new tabs - if (([aMenuItem action] == @selector(openBookmarkInNewTab:))) - return isBookmark && [mBrowserWindowController newTabsAllowed]; - - if (([aMenuItem action] == @selector(showBookmarkInfo:))) - return haveSelection; - - if (([aMenuItem action] == @selector(deleteBookmarks:))) - return haveSelection && ![item isToobarRoot]; // should deal with multiple selections - - if (([aMenuItem action] == @selector(addFolder:))) - return YES; - - return YES; -} - -- (void)outlineViewItemWillExpand:(NSNotification *)notification -{ - BookmarkItem* item = [[notification userInfo] objectForKey:[[[notification userInfo] allKeys] objectAtIndex: 0]]; - [item contentNode]->SetAttr(kNameSpaceID_None, BookmarksService::gOpenAtom, NS_LITERAL_STRING("true"), PR_FALSE); -} - -- (void)outlineViewItemWillCollapse:(NSNotification *)notification -{ - BookmarkItem* item = [[notification userInfo] objectForKey:[[[notification userInfo] allKeys] objectAtIndex: 0]]; - [item contentNode]->UnsetAttr(kNameSpaceID_None, BookmarksService::gOpenAtom, PR_FALSE); -} - -@end - diff --git a/chimera/src/browser/BrowserTabView.mm b/chimera/src/browser/BrowserTabView.mm index f215b134dbe..a40bfd8ce33 100644 --- a/chimera/src/browser/BrowserTabView.mm +++ b/chimera/src/browser/BrowserTabView.mm @@ -100,6 +100,7 @@ - (BOOL)isOpaque { + // see http://developer.apple.com/qa/qa2001/qa1117.html if ( ([self tabViewType] == NSNoTabsBezelBorder) && (NSAppKitVersionNumber < 633) ) return NO; diff --git a/chimera/src/browser/BrowserWindow.mm b/chimera/src/browser/BrowserWindow.mm index 68592f4ae3a..e69de29bb2d 100644 --- a/chimera/src/browser/BrowserWindow.mm +++ b/chimera/src/browser/BrowserWindow.mm @@ -1,94 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Chimera code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 2002 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Simon Fraser - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#import "BrowserWindow.h" -#import "BrowserWindowController.h" -#import "AutoCompleteTextField.h" - -static const int kEscapeKeyCode = 53; - -@implementation BrowserWindow - -- (void)dealloc -{ - [super dealloc]; -} - -- (BOOL)makeFirstResponder:(NSResponder*)responder -{ - NSResponder* oldResponder = [self firstResponder]; - BOOL madeFirstResponder = [super makeFirstResponder:responder]; - if (madeFirstResponder && oldResponder != [self firstResponder]) - [(BrowserWindowController*)[self delegate] focusChangedFrom:oldResponder to:[self firstResponder]]; - return madeFirstResponder; -} - -- (void)sendEvent:(NSEvent *)theEvent -{ - // We need this hack because NSWindow::sendEvent will eat the escape key - // and won't pass it down to the key handler of responders in the window. - // We have to override sendEvent for all of our escape key needs. - if ([theEvent type] == NSKeyDown && - [theEvent keyCode] == kEscapeKeyCode && [self firstResponder] == [mAutoCompleteTextField fieldEditor]) - [mAutoCompleteTextField revertText]; - else - [super sendEvent:theEvent]; -} - -- (BOOL)suppressMakeKeyFront -{ - return mSuppressMakeKeyFront; -} - -- (void)setSuppressMakeKeyFront:(BOOL)inSuppress -{ - mSuppressMakeKeyFront = inSuppress; -} - -// accessor for the 'URL' Apple Event attribute -- (NSString*)getURL -{ - BrowserWindowController* windowController = (BrowserWindowController*)[self delegate]; - - NSString* titleString = nil; - NSString* urlString = nil; - - [[windowController getBrowserWrapper] getTitle:&titleString andHref:&urlString]; - return urlString; -} - -@end diff --git a/chimera/src/browser/BrowserWindowController.h b/chimera/src/browser/BrowserWindowController.h index eb6789343dd..063a881b02a 100644 --- a/chimera/src/browser/BrowserWindowController.h +++ b/chimera/src/browser/BrowserWindowController.h @@ -109,12 +109,12 @@ typedef enum IBOutlet NSTextField* mLocationSheetURLField; IBOutlet NSView* mStatusBar; // contains the status text, progress bar, and lock IBOutlet PageProxyIcon* mProxyIcon; - IBOutlet BrowserContentView* mContentView; + IBOutlet BrowserContentView* mContentView; IBOutlet BookmarksDataSource* mSidebarBookmarksDataSource; - IBOutlet HistoryDataSource* mHistoryDataSource; + IBOutlet HistoryDataSource* mHistoryDataSource; - IBOutlet BookmarksToolbar* mPersonalToolbar; + IBOutlet BookmarksToolbar* mPersonalToolbar; IBOutlet NSWindow* mAddBookmarkSheetWindow; IBOutlet NSTextField* mAddBookmarkTitleField; @@ -191,6 +191,8 @@ typedef enum - (void)updateLocationFields:(NSString *)locationString; - (void)updateSiteIcons:(NSImage *)siteIconImage; - (void)updateToolbarItems; +- (void)loadingStarted; +- (void)loadingDone; - (void)focusURLBar; // call to update the image of the lock icon with a value from nsIWebProgressListener @@ -211,9 +213,9 @@ typedef enum - (IBAction)viewSource:(id)aSender; // focussed frame or page - (IBAction)viewPageSource:(id)aSender; // top-level page -- (void)saveDocument:(BOOL)focusedFrame filterView:(NSView*)aFilterView filterList: (NSPopUpButton*)aFilterList; -- (void)saveURL: (NSView*)aFilterView filterList: (NSPopUpButton*)aFilterList - url: (NSString*)aURLSpec suggestedFilename: (NSString*)aFilename; +- (void)saveDocument:(BOOL)focusedFrame filterView:(NSView*)aFilterView; +- (void)saveURL:(NSView*)aFilterView url: (NSString*)aURLSpec suggestedFilename: (NSString*)aFilename; + - (IBAction)printDocument:(id)aSender; - (IBAction)pageSetup:(id)aSender; - (IBAction)performSearch:(id)aSender; @@ -302,6 +304,7 @@ typedef enum - (IBAction)bookmarkLink: (id)aSender; - (IBAction)copyLinkLocation:(id)aSender; +- (IBAction)copyImage:(id)sender; - (IBAction)copyImageLocation:(id)sender; - (BookmarksToolbar*) bookmarksToolbar; diff --git a/chimera/src/browser/BrowserWindowController.mm b/chimera/src/browser/BrowserWindowController.mm index 979a03ef020..c36add4099a 100644 --- a/chimera/src/browser/BrowserWindowController.mm +++ b/chimera/src/browser/BrowserWindowController.mm @@ -816,6 +816,19 @@ static NSArray* sToolbarDefaults = nil; else return YES; } + +- (void)loadingStarted +{ + [self updateToolbarItems]; + [self startThrobber]; +} + +- (void)loadingDone +{ + [self updateToolbarItems]; + [self stopThrobber]; + [mHistoryDataSource refresh]; +} - (void)updateToolbarItems { @@ -960,16 +973,14 @@ static NSArray* sToolbarDefaults = nil; } } -- (void)saveDocument:(BOOL)focusedFrame filterView:(NSView*)aFilterView filterList: (NSPopUpButton*)aFilterList +- (void)saveDocument:(BOOL)focusedFrame filterView:(NSView*)aFilterView { - [[mBrowserView getBrowserView] saveDocument:focusedFrame filterView:aFilterView filterList:aFilterList]; + [[mBrowserView getBrowserView] saveDocument:focusedFrame filterView:aFilterView]; } -- (void)saveURL: (NSView*)aFilterView filterList: (NSPopUpButton*)aFilterList - url: (NSString*)aURLSpec suggestedFilename: (NSString*)aFilename +- (void)saveURL: (NSView*)aFilterView url: (NSString*)aURLSpec suggestedFilename: (NSString*)aFilename { - [[mBrowserView getBrowserView] saveURL: aFilterView filterList: aFilterList - url: aURLSpec suggestedFilename: aFilename]; + [[mBrowserView getBrowserView] saveURL: aFilterView url: aURLSpec suggestedFilename: aFilename]; } - (void)loadSourceOfURL:(NSString*)urlStr @@ -1890,12 +1901,14 @@ static NSArray* sToolbarDefaults = nil; - (IBAction)savePageAs:(id)aSender { - [self saveDocument:NO filterView:nil filterList: nil]; + NSView* accessoryView = [[NSApp delegate] getSavePanelView]; + [self saveDocument:NO filterView:accessoryView]; } - (IBAction)saveFrameAs:(id)aSender { - [self saveDocument:YES filterView:nil filterList: nil]; + NSView* accessoryView = [[NSApp delegate] getSavePanelView]; + [self saveDocument:YES filterView:accessoryView]; } - (IBAction)saveLinkAs:(id)aSender @@ -1915,8 +1928,7 @@ static NSArray* sToolbarDefaults = nil; nsAutoString text; GeckoUtils::GatherTextUnder(mContextMenuNode, text); - [self saveURL: nil filterList: nil - url: hrefStr suggestedFilename: [NSString stringWith_nsAString: text]]; + [self saveURL:nil url:hrefStr suggestedFilename:[NSString stringWith_nsAString:text]]; } - (IBAction)saveImageAs:(id)aSender @@ -1931,11 +1943,18 @@ static NSArray* sToolbarDefaults = nil; NSString* hrefStr = [NSString stringWith_nsAString: url]; - [self saveURL: nil filterList: nil - url: hrefStr suggestedFilename: [NSString stringWith_nsAString: text]]; + [self saveURL:nil url:hrefStr suggestedFilename: [NSString stringWith_nsAString: text]]; } } +- (IBAction)copyImage:(id)sender +{ + nsCOMPtr webBrowser = getter_AddRefs([[[self getBrowserWrapper] getBrowserView] getWebBrowser]); + nsCOMPtr clipboard(do_GetInterface(webBrowser)); + if (clipboard) + clipboard->CopyImageContents(); +} + - (IBAction)copyImageLocation:(id)sender { nsCOMPtr webBrowser = getter_AddRefs([[[self getBrowserWrapper] getBrowserView] getWebBrowser]); diff --git a/chimera/src/browser/BrowserWrapper.mm b/chimera/src/browser/BrowserWrapper.mm index c39050967c8..3f1a6120bc2 100644 --- a/chimera/src/browser/BrowserWrapper.mm +++ b/chimera/src/browser/BrowserWrapper.mm @@ -335,10 +335,8 @@ const NSString* kOfflineNotificationName = @"offlineModeChanged"; mTabTitle = [mLoadingStatusString retain]; [mTabItem setLabel:mTabTitle]; - if (mWindowController) { - [mWindowController updateToolbarItems]; - [mWindowController startThrobber]; - } + if (mWindowController) + [mWindowController loadingStarted]; } - (void)onLoadingCompleted:(BOOL)succeeded @@ -402,10 +400,8 @@ const NSString* kOfflineNotificationName = @"offlineModeChanged"; [self removeFromSuperview]; } - if (mWindowController) { - [mWindowController updateToolbarItems]; - [mWindowController stopThrobber]; - } + if (mWindowController) + [mWindowController loadingDone]; } - (void)onProgressChange:(int)currentBytes outOf:(int)maxBytes diff --git a/chimera/src/browser/ContentClickListener.mm b/chimera/src/browser/ContentClickListener.mm index bb18dd8fd91..e69de29bb2d 100644 --- a/chimera/src/browser/ContentClickListener.mm +++ b/chimera/src/browser/ContentClickListener.mm @@ -1,147 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: NPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Netscape Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 2002 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * David Hyatt (Original Author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the NPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the NPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#import "NSString+Utils.h" - -#include "nsCOMPtr.h" -#include "ContentClickListener.h" -#include "nsIDOMEventTarget.h" -#include "nsIContent.h" -#include "nsIAtom.h" -#include "nsIDOMElement.h" -#include "nsString.h" -#include "nsUnicharUtils.h" -#include "nsIPrefBranch.h" -#include "nsIDOMMouseEvent.h" -#include "nsEmbedAPI.h" -#include "nsIDOMDocument.h" -#include "nsIDOMDocumentEvent.h" -#include "nsIDOMEventTarget.h" -#include "nsIDOMNSHTMLElement.h" -#include "nsIDOMHTMLSelectElement.h" -#include "nsIDOMHTMLOptionElement.h" -#include "nsIDOMHTMLCollection.h" -#include "nsIDOMWindow.h" -#include "nsIScriptGlobalObject.h" -#include "nsIDocument.h" -#include "nsIPresShell.h" -#include "nsIPresContext.h" -#include "nsIFrame.h" -#include "nsIView.h" -#include "nsIWidget.h" -#include "nsIURI.h" -#include "nsIProtocolHandler.h" -#include "nsNetUtil.h" - -// Common helper routines (also used by the context menu code) -#include "GeckoUtils.h" - -#import "CHBrowserView.h" - -NS_IMPL_ISUPPORTS2(ContentClickListener, nsIDOMMouseListener, nsIDOMEventListener); - -ContentClickListener::ContentClickListener(id aBrowserController) -:mBrowserController(aBrowserController) -{ - NS_INIT_ISUPPORTS(); -} - -ContentClickListener::~ContentClickListener() -{ - -} - -NS_IMETHODIMP -ContentClickListener::MouseClick(nsIDOMEvent* aEvent) -{ - nsCOMPtr target; - aEvent->GetTarget(getter_AddRefs(target)); - if (!target) - return NS_OK; - nsCOMPtr content(do_QueryInterface(target)); - - nsCOMPtr linkContent; - nsAutoString href; - GeckoUtils::GetEnclosingLinkElementAndHref(content, getter_AddRefs(linkContent), href); - - // XXXdwh Handle simple XLINKs if we want to be compatible with Mozilla, but who - // really uses these anyway? :) - if (!linkContent || href.IsEmpty()) - return NS_OK; - - nsCOMPtr pref(do_GetService("@mozilla.org/preferences-service;1")); - if (!pref) - return NS_OK; // Something bad happened if we can't get prefs. - - PRUint16 button; - nsCOMPtr mouseEvent(do_QueryInterface(aEvent)); - mouseEvent->GetButton(&button); - - PRBool metaKey, shiftKey, altKey; - mouseEvent->GetMetaKey(&metaKey); - mouseEvent->GetShiftKey(&shiftKey); - mouseEvent->GetAltKey(&altKey); - - NSString* hrefStr = [NSString stringWith_nsAString: href]; - - if ((metaKey && button == 0) || button == 1) { - // The command key is down or we got a middle click. Open the link in a new window or tab. - PRBool useTab; - pref->GetBoolPref("browser.tabs.opentabfor.middleclick", &useTab); - PRBool loadInBackground; - pref->GetBoolPref("browser.tabs.loadInBackground", &loadInBackground); - NSString* referrer = [[[mBrowserController getBrowserWrapper] getBrowserView] getFocusedURLString]; - - if (shiftKey) - loadInBackground = !loadInBackground; - if (useTab && [mBrowserController newTabsAllowed]) - [mBrowserController openNewTabWithURL: hrefStr referrer:referrer loadInBackground: loadInBackground]; - else - [mBrowserController openNewWindowWithURL: hrefStr referrer:referrer loadInBackground: loadInBackground]; - } - else if (altKey) { - // The user wants to save this link. - nsAutoString text; - GeckoUtils::GatherTextUnder(content, text); - - [mBrowserController saveURL: nil filterList: nil - url: hrefStr suggestedFilename: [NSString stringWith_nsAString: text]]; - } - - return NS_OK; -} diff --git a/chimera/src/browser/KeychainService.h b/chimera/src/browser/KeychainService.h index 3eeb9018fa1..e69de29bb2d 100644 --- a/chimera/src/browser/KeychainService.h +++ b/chimera/src/browser/KeychainService.h @@ -1,140 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: NPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Netscape Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 2002 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the NPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the NPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef __KeychainService_h__ -#define __KeychainService_h__ - -#include - -#include "CHBrowserView.h" - -#include "nsEmbedAPI.h" -#include "nsIFactory.h" -#include "nsIPrompt.h" -#include "nsIAuthPromptWrapper.h" -#include "nsIObserver.h" -#include "nsIFormSubmitObserver.h" - -class nsIPrefBranch; - -@class CHBrowserView; - -@interface KeychainService : NSObject -{ - BOOL mIsEnabled; - BOOL mIsAutoFillEnabled; - - nsIObserver* mFormSubmitObserver; -} - -+ (KeychainService*) instance; -- (void) shutdown:(id)sender; - -- (BOOL) getUsernameAndPassword:(NSString*)realm port:(PRInt32)inPort user:(NSMutableString*)username password:(NSMutableString*)pwd item:(KCItemRef*)outItem; -- (BOOL) findUsernameAndPassword:(NSString*)realm port:(PRInt32)inPort; -- (void) storeUsernameAndPassword:(NSString*)realm port:(PRInt32)inPort user:(NSString*)username password:(NSString*)pwd; -- (void) removeUsernameAndPassword:(NSString*)realm port:(PRInt32)inPort item:(KCItemRef)item; -- (void) updateUsernameAndPassword:(NSString*)realm port:(PRInt32)inPort user:(NSString*)username password:(NSString*)pwd item:(KCItemRef)item; - -- (void) addListenerToView:(CHBrowserView*)view; - -- (BOOL) isEnabled; -- (BOOL) isAutoFillEnabled; - -@end - -class KeychainPrompt : public nsIAuthPromptWrapper -{ -public: - KeychainPrompt(); - KeychainPrompt(KeychainService*); - virtual ~KeychainPrompt(); - - NS_DECL_ISUPPORTS - NS_DECL_NSIAUTHPROMPT - NS_DECL_NSIAUTHPROMPTWRAPPER - -protected: - - void PreFill(const PRUnichar *, PRUnichar **, PRUnichar **); - void ProcessPrompt(const PRUnichar *, bool, PRUnichar *, PRUnichar *); - static void ExtractHostAndPort(const PRUnichar* inRealm, NSString** outHost, PRInt32* outPort); - - nsCOMPtr mPrompt; - KeychainService* mKeychain; -}; - -// -// Keychain form submit observer -// -class KeychainFormSubmitObserver : public nsIObserver, - public nsIFormSubmitObserver -{ -public: - KeychainFormSubmitObserver(KeychainService*); - virtual ~KeychainFormSubmitObserver(); - - NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER - - // NS_DECL_NSIFORMSUBMITOBSERVER - NS_IMETHOD Notify(nsIContent* formNode, nsIDOMWindowInternal* window, nsIURI* actionURL, PRBool* cancelSubmit); - -private: - - static BOOL CheckStorePasswordYN(nsIDOMWindowInternal*); - static BOOL CheckChangeDataYN(nsIDOMWindowInternal*); - - static NSWindow* GetNSWindow(nsIDOMWindowInternal* inWindow); - - KeychainService* mKeychain; -}; - -// -// Keychain browser listener to auto fill username/passwords. -// -@interface KeychainBrowserListener : NSObject -{ - KeychainService* mKeychain; - CHBrowserView* mBrowserView; -} - -- (id)initWithBrowser:(KeychainService*)keychain browser:(CHBrowserView*)aBrowser; - -@end - -#endif diff --git a/chimera/src/browser/KeychainService.mm b/chimera/src/browser/KeychainService.mm index c20a16db4c8..94f514531c6 100644 --- a/chimera/src/browser/KeychainService.mm +++ b/chimera/src/browser/KeychainService.mm @@ -69,6 +69,9 @@ #include "nsIWindowWatcher.h" #include "nsIWebBrowserChrome.h" #include "nsIEmbeddingSiteWindow.h" +#include "nsAppDirectoryServiceDefs.h" + +extern NSString* XPCOMShutDownNotificationName; nsresult @@ -114,7 +117,7 @@ int KeychainPrefChangedCallback(const char* inPref, void* unused) // observer service uses a weakref. nsCOMPtr svc = do_GetService("@mozilla.org/observer-service;1"); NS_ASSERTION(svc, "Keychain can't get observer service"); - mFormSubmitObserver = new KeychainFormSubmitObserver(self); + mFormSubmitObserver = new KeychainFormSubmitObserver(); if ( mFormSubmitObserver && svc ) { NS_ADDREF(mFormSubmitObserver); svc->AddObserver(mFormSubmitObserver, NS_FORMSUBMIT_SUBJECT, PR_FALSE); @@ -122,7 +125,7 @@ int KeychainPrefChangedCallback(const char* inPref, void* unused) // register for the cocoa notification posted when XPCOM shutdown so we // can unregister the pref callbacks we register below - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(shutdown:) name:@"XPCOM Shutdown" + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(shutdown:) name:XPCOMShutDownNotificationName object:nil]; // cache the values of the prefs and register pref-changed callbacks. Yeah, I know @@ -139,6 +142,10 @@ int KeychainPrefChangedCallback(const char* inPref, void* unused) pref->RegisterCallback(gAutoFillEnabledPref, KeychainPrefChangedCallback, nsnull); } } + + // load the keychain.nib file with our dialogs in it + BOOL success = [NSBundle loadNibNamed:@"Keychain" owner:self]; + NS_ASSERTION(success, "can't load keychain prompt dialogs"); } return self; } @@ -168,6 +175,8 @@ int KeychainPrefChangedCallback(const char* inPref, void* unused) pref->UnregisterCallback(gUseKeychainPref, KeychainPrefChangedCallback, nsnull); pref->UnregisterCallback(gAutoFillEnabledPref, KeychainPrefChangedCallback, nsnull); } + + [sInstance release]; } @@ -324,7 +333,181 @@ int KeychainPrefChangedCallback(const char* inPref, void* unused) // - (void) addListenerToView:(CHBrowserView*)view { - [view addListener:[[[KeychainBrowserListener alloc] initWithBrowser:self browser:view] autorelease]]; + [view addListener:[[[KeychainBrowserListener alloc] initWithBrowser:view] autorelease]]; +} + +// +// hitButtonOK: +// hitButtonCancel: +// hitButtonOther: +// +// actions for the buttons of the keychain prompt dialogs. +// + +enum { kOKButton = 0, kCancelButton = 1, kOtherButton = 2 }; + +- (IBAction)hitButtonOK:(id)sender +{ + [NSApp stopModalWithCode:kOKButton]; +} + +- (IBAction)hitButtonCancel:(id)sender +{ + [NSApp stopModalWithCode:kCancelButton]; +} + +- (IBAction)hitButtonOther:(id)sender +{ + [NSApp stopModalWithCode:kOtherButton]; +} + +// +// confirmStorePassword: +// +// Puts up a dialog when the keychain doesn't yet have an entry from +// this site asking to store it, forget it this once, or mark the site +// on a deny list so we never ask again. +// +- (KeychainPromptResult)confirmStorePassword:(NSWindow*)parent +{ + int result = [NSApp runModalForWindow:confirmStorePasswordPanel relativeToWindow:parent]; + [confirmStorePasswordPanel close]; + + // the results of hitButtonXX: map to the corresponding values in the + // |KeychainPromptResult| enum so we can just cast and return + return NS_STATIC_CAST(KeychainPromptResult, result); +} + +// +// confirmChangedPassword: +// +// The password stored in the keychain differs from what the user typed +// in. Ask what they want to do to resolve the issue. +// +- (BOOL)confirmChangedPassword:(NSWindow*)parent +{ + int result = [NSApp runModalForWindow:confirmChangePasswordPanel relativeToWindow:parent]; + [confirmChangePasswordPanel close]; + return (result == kOKButton); +} + + +- (void) addHostToDenyList:(NSString*)host +{ + [[KeychainDenyList instance] addHost:host]; +} + +- (BOOL) isHostInDenyList:(NSString*)host +{ + return [[KeychainDenyList instance] isHostPresent:host]; +} + +@end + + +@interface KeychainDenyList (KeychainDenyListPrivate) +- (NSString*) pathToDenyListFile; +@end + + +@implementation KeychainDenyList + +static KeychainDenyList *sDenyListInstance = nil; + ++ (KeychainDenyList*) instance +{ + return sDenyListInstance ? sDenyListInstance : sDenyListInstance = [[self alloc] init]; +} + +- (id) init +{ + if ( (self = [super init]) ) { + mDenyList = [[NSUnarchiver unarchiveObjectWithFile:[self pathToDenyListFile]] retain]; + if ( !mDenyList ) + mDenyList = [[NSMutableArray alloc] init]; + + mIsDirty = NO; + + // register for the cocoa notification posted when XPCOM shutdown so we + // can release our singleton and flush the file + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(shutdown:) name:XPCOMShutDownNotificationName object:nil]; + } + return self; +} + +- (void) dealloc +{ + [self writeToDisk]; + [mDenyList release]; +} + +// +// shutdown: +// +// Called in response to the cocoa notification "XPCOM Shutdown" sent by the cocoa +// browser service before it terminates embedding and shuts down xpcom. Allows us +// to get rid of anything we're holding onto for the length of the app. +// +- (void) shutdown:(id)unused +{ + [sDenyListInstance release]; +} + +// +// writeToDisk +// +// flushes the deny list to the save file in the user's profile, but only +// if it has changed since we read it in. +// +- (void) writeToDisk +{ + if ( mIsDirty ) + [NSArchiver archiveRootObject:mDenyList toFile:[self pathToDenyListFile]]; + mIsDirty = NO; +} + +- (BOOL) isHostPresent:(NSString*)host +{ + return [mDenyList containsObject:host]; +} + +- (void) addHost:(NSString*)host +{ + if ( ![self isHostPresent:host] ) { + [mDenyList addObject:host]; + mIsDirty = YES; + } +} + +- (void) removeHost:(NSString*)host +{ + if ( [self isHostPresent:host] ) { + [mDenyList removeObject:host]; + mIsDirty = YES; + } +} + + +// +// pathToDenyListFile +// +// returns a path ('/' delimited) that cocoa can use to point to the +// deny list save file in the current user's profile +// +- (NSString*) pathToDenyListFile +{ + NSMutableString* path = [[[NSMutableString alloc] init] autorelease]; + + nsCOMPtr appProfileDir; + NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(appProfileDir)); + if ( appProfileDir ) { + nsAutoString profilePath; + appProfileDir->GetPath(profilePath); + [path setString:[NSString stringWith_nsAString:profilePath]]; + [path appendString:@"/Keychain Deny List"]; // |profilePath| is '/' delimited + } + + return path; } @end @@ -338,12 +521,6 @@ NS_IMPL_ISUPPORTS2(KeychainPrompt, nsIAuthPromptWrapper) KeychainPrompt::KeychainPrompt() - : mKeychain([KeychainService instance]) -{ - NS_INIT_ISUPPORTS(); -} - -KeychainPrompt::KeychainPrompt(KeychainService* keychain) : mKeychain(keychain) { NS_INIT_ISUPPORTS(); } @@ -391,7 +568,8 @@ KeychainPrompt::ExtractHostAndPort(const PRUnichar* inRealm, NSString** outHost, void KeychainPrompt::PreFill(const PRUnichar *realm, PRUnichar **user, PRUnichar **pwd) { - if(![mKeychain isEnabled] || ![mKeychain isAutoFillEnabled]) + KeychainService* keychain = [KeychainService instance]; + if(![keychain isEnabled] || ![keychain isAutoFillEnabled]) return; NSString* host = nil; @@ -409,7 +587,7 @@ KeychainPrompt::PreFill(const PRUnichar *realm, PRUnichar **user, PRUnichar **pw // Pre-fill user/password if found in the keychain. // KCItemRef ignore; - if([mKeychain getUsernameAndPassword:(NSString*)host port:port user:username password:password item:&ignore]) { + if([keychain getUsernameAndPassword:(NSString*)host port:port user:username password:password item:&ignore]) { if ( user ) *user = [username createNewUnicodeBuffer]; if ( pwd ) @@ -427,10 +605,12 @@ KeychainPrompt::ProcessPrompt(const PRUnichar* realm, bool checked, PRUnichar* u NSString* username = [NSString stringWithPRUnichars:user]; NSString* password = [NSString stringWithPRUnichars:pwd]; + KeychainService* keychain = [KeychainService instance]; + NSMutableString* origUsername = [NSMutableString string]; NSMutableString* origPwd = [NSMutableString string]; KCItemRef itemRef; - bool found = [mKeychain getUsernameAndPassword:(NSString*)host port:port user:origUsername password:origPwd item:&itemRef]; + bool found = [keychain getUsernameAndPassword:(NSString*)host port:port user:origUsername password:origPwd item:&itemRef]; // // Update, store or remove the user/password depending on the user @@ -438,11 +618,11 @@ KeychainPrompt::ProcessPrompt(const PRUnichar* realm, bool checked, PRUnichar* u // keychain. // if(checked && !found) - [mKeychain storeUsernameAndPassword:(NSString*)host port:port user:username password:password]; + [keychain storeUsernameAndPassword:(NSString*)host port:port user:username password:password]; else if(checked && found && (![origUsername isEqualToString:username] || ![origPwd isEqualToString:password])) - [mKeychain updateUsernameAndPassword:(NSString*)host port:port user:username password:password item:itemRef]; + [keychain updateUsernameAndPassword:(NSString*)host port:port user:username password:password item:itemRef]; else if(!checked && found) - [mKeychain removeUsernameAndPassword:(NSString*)host port:port item:itemRef]; + [keychain removeUsernameAndPassword:(NSString*)host port:port item:itemRef]; } // @@ -476,7 +656,7 @@ KeychainPrompt::PromptUsernameAndPassword(const PRUnichar *dialogTitle, { PreFill(realm, user, pwd); - PRBool checked = [mKeychain isEnabled]; + PRBool checked = [[KeychainService instance] isEnabled]; PRUnichar* checkTitle = [NSLocalizedString(@"KeychainCheckTitle", @"") createNewUnicodeBuffer]; nsresult rv = mPrompt->PromptUsernameAndPassword(dialogTitle, text, user, pwd, checkTitle, &checked, _retval); @@ -501,7 +681,7 @@ KeychainPrompt::PromptPassword(const PRUnichar *dialogTitle, { PreFill(realm, nsnull, pwd); - PRBool checked = [mKeychain isEnabled]; + PRBool checked = [[KeychainService instance] isEnabled]; PRUnichar* checkTitle = [NSLocalizedString(@"KeychainCheckTitle", @"") createNewUnicodeBuffer]; nsresult rv = mPrompt->PromptPassword(dialogTitle, text, pwd, checkTitle, &checked, _retval); @@ -530,7 +710,7 @@ NS_IMPL_ISUPPORTS2(KeychainFormSubmitObserver, nsIObserver, nsIFormSubmitObserver) -KeychainFormSubmitObserver::KeychainFormSubmitObserver(KeychainService* keychain) : mKeychain(keychain) +KeychainFormSubmitObserver::KeychainFormSubmitObserver() { NS_INIT_ISUPPORTS(); //NSLog(@"Keychain form submit observer created."); @@ -551,7 +731,8 @@ NS_IMETHODIMP KeychainFormSubmitObserver::Notify(nsIContent* node, nsIDOMWindowInternal* window, nsIURI* actionURL, PRBool* cancelSubmit) { - if (![mKeychain isEnabled]) + KeychainService* keychain = [KeychainService instance]; + if (![keychain isEnabled]) return NS_OK; nsCOMPtr formNode(do_QueryInterface(node)); @@ -590,25 +771,41 @@ KeychainFormSubmitObserver::Notify(nsIContent* node, nsIDOMWindowInternal* windo docURL->GetHost(host); docURL->GetPort(&port); + // is the host in the deny list? if yes, bail. otherwise check the keychain. + NSString* realm = [NSString stringWithCString:host.get()]; + if ( [keychain isHostInDenyList:realm] ) + return NS_OK; + // // If there's already an entry in the keychain, check if the username // and password match. If not, ask the user what they want to do and replace // it as necessary. If there's no entry, ask if they want to remember it // and then put it into the keychain // - NSString* realm = [NSString stringWithCString:host.get()]; NSString* existingUser = [NSMutableString string]; NSString* existingPassword = [NSMutableString string]; KCItemRef itemRef; - BOOL foundExistingPassword = [mKeychain getUsernameAndPassword:realm port:port user:existingUser password:existingPassword item:&itemRef]; + BOOL foundExistingPassword = [keychain getUsernameAndPassword:realm port:port user:existingUser password:existingPassword item:&itemRef]; if ( foundExistingPassword ) { if ( !([existingUser isEqualToString:username] && [existingPassword isEqualToString:password]) ) if ( CheckChangeDataYN(window) ) - [mKeychain updateUsernameAndPassword:realm port:port user:username password:password item:itemRef]; + [keychain updateUsernameAndPassword:realm port:port user:username password:password item:itemRef]; } else { - if (CheckStorePasswordYN(window)) - [mKeychain storeUsernameAndPassword:realm port:port user:username password:password]; + switch (CheckStorePasswordYN(window)) { + case kSave: + [keychain storeUsernameAndPassword:realm port:port user:username password:password]; + break; + + case kNeverRemember: + // tell the keychain we never want to be prompted about this host again + [keychain addHostToDenyList:realm]; + break; + + case kDontRemember: + // do nothing at all + break; + } } } @@ -644,12 +841,11 @@ KeychainFormSubmitObserver::GetNSWindow(nsIDOMWindowInternal* inWindow) return nswindow; } -BOOL +KeychainPromptResult KeychainFormSubmitObserver::CheckStorePasswordYN(nsIDOMWindowInternal* window) { NSWindow* nswindow = GetNSWindow(window); - nsAlertController* dialog = CHBrowserService::GetAlertController(); - return [dialog confirmStorePassword:nswindow]; + return [[KeychainService instance] confirmStorePassword:nswindow]; } @@ -657,16 +853,14 @@ BOOL KeychainFormSubmitObserver::CheckChangeDataYN(nsIDOMWindowInternal* window) { NSWindow* nswindow = GetNSWindow(window); - nsAlertController* dialog = CHBrowserService::GetAlertController(); - return [dialog confirmChangedPassword:nswindow]; + return [[KeychainService instance] confirmChangedPassword:nswindow]; } @implementation KeychainBrowserListener -- (id)initWithBrowser:(KeychainService*)keychain browser:(CHBrowserView*)aBrowser +- (id)initWithBrowser:(CHBrowserView*)aBrowser { if ( (self = [super init]) ) { - mKeychain = keychain; mBrowserView = aBrowser; } return self; @@ -683,7 +877,8 @@ KeychainFormSubmitObserver::CheckChangeDataYN(nsIDOMWindowInternal* window) if(!succeeded) return; - if(![mKeychain isEnabled] || ![mKeychain isAutoFillEnabled]) + KeychainService* keychain = [KeychainService instance]; + if(![keychain isEnabled] || ![keychain isAutoFillEnabled]) return; nsCOMPtr domWin = getter_AddRefs([mBrowserView getContentWindow]); @@ -750,7 +945,7 @@ KeychainFormSubmitObserver::CheckChangeDataYN(nsIDOMWindowInternal* window) docURL->GetPort(&port); KCItemRef ignore; - if ([mKeychain getUsernameAndPassword:hostStr port:port user:username password:password item:&ignore]) { + if ([keychain getUsernameAndPassword:hostStr port:port user:username password:password item:&ignore]) { nsAutoString user, pwd; [username assignTo_nsAString:user]; [password assignTo_nsAString:pwd]; diff --git a/chimera/src/browser/SiteIconProvider.mm b/chimera/src/browser/SiteIconProvider.mm index e6c1709218e..e69de29bb2d 100644 --- a/chimera/src/browser/SiteIconProvider.mm +++ b/chimera/src/browser/SiteIconProvider.mm @@ -1,344 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Chimera code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 2002 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Simon Fraser - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#import "NSString+Utils.h" - -#import "SiteIconProvider.h" - -#include "prtime.h" -#include "nsString.h" -#include "nsISupports.h" -#include "nsNetUtil.h" -#include "nsICacheSession.h" -#include "nsICacheService.h" -#include "nsICacheEntryDescriptor.h" - - -NSString* SiteIconLoadNotificationName = @"siteicon_load_notification"; -NSString* SiteIconLoadImageKey = @"siteicon_load_image"; -NSString* SiteIconLoadURIKey = @"siteicon_load_uri"; -NSString* SiteIconLoadUserDataKey = @"siteicon_load_user_data"; - - -static inline PRUint32 PRTimeToSeconds(PRTime t_usec) -{ - PRTime usec_per_sec; - PRUint32 t_sec; - LL_I2L(usec_per_sec, PR_USEC_PER_SEC); - LL_DIV(t_usec, t_usec, usec_per_sec); - LL_L2I(t_sec, t_usec); - return t_sec; -} - -class NeckoCacheHelper -{ -public: - - NeckoCacheHelper(const char* inMetaElement, const char* inMetaValue); - ~NeckoCacheHelper() {} - - nsresult Init(const char* inCacheSessionName); - nsresult ExistsInCache(const nsACString& inURI, PRBool* outExists); - nsresult PutInCache(const nsACString& inURI, PRUint32 inExpirationTimeSeconds); - - nsresult ClearCache(); - -protected: - - const char* mMetaElement; - const char* mMetaValue; - nsCOMPtr mCacheSession; - -}; - -static NS_DEFINE_CID(kCacheServiceCID, NS_CACHESERVICE_CID); - -NeckoCacheHelper::NeckoCacheHelper(const char* inMetaElement, const char* inMetaValue) -: mMetaElement(inMetaElement) -, mMetaValue(inMetaValue) -{ -} - -nsresult NeckoCacheHelper::Init(const char* inCacheSessionName) -{ - nsresult rv; - - nsCOMPtr cacheService = do_GetService(kCacheServiceCID, &rv); - if (NS_FAILED(rv)) - return rv; - - rv = cacheService->CreateSession(inCacheSessionName, - nsICache::STORE_ANYWHERE, nsICache::STREAM_BASED, - getter_AddRefs(mCacheSession)); - if (NS_FAILED(rv)) - return rv; - - return NS_OK; -} - - -nsresult NeckoCacheHelper::ExistsInCache(const nsACString& inURI, PRBool* outExists) -{ - NS_ASSERTION(mCacheSession, "No cache session"); - - nsCOMPtr entryDesc; - nsresult rv = mCacheSession->OpenCacheEntry(PromiseFlatCString(inURI).get(), nsICache::ACCESS_READ, nsICache::NON_BLOCKING, getter_AddRefs(entryDesc)); - - *outExists = NS_SUCCEEDED(rv) && (entryDesc != NULL); - return NS_OK; -} - -nsresult NeckoCacheHelper::PutInCache(const nsACString& inURI, PRUint32 inExpirationTimeSeconds) -{ - NS_ASSERTION(mCacheSession, "No cache session"); - - nsCOMPtr entryDesc; - nsresult rv = mCacheSession->OpenCacheEntry(PromiseFlatCString(inURI).get(), nsICache::ACCESS_WRITE, nsICache::NON_BLOCKING, getter_AddRefs(entryDesc)); - if (NS_FAILED(rv) || !entryDesc) return rv; - - nsCacheAccessMode accessMode; - rv = entryDesc->GetAccessGranted(&accessMode); - if (NS_FAILED(rv)) - return rv; - - if (accessMode != nsICache::ACCESS_WRITE) - return NS_ERROR_FAILURE; - - entryDesc->SetMetaDataElement(mMetaElement, mMetaValue); // just set a bit of meta data. - entryDesc->SetExpirationTime(PRTimeToSeconds(PR_Now()) + inExpirationTimeSeconds); - - entryDesc->MarkValid(); - entryDesc->Close(); - - return NS_OK; -} - -nsresult NeckoCacheHelper::ClearCache() -{ - NS_ASSERTION(mCacheSession, "No cache session"); - - return mCacheSession->EvictEntries(); -} - - -#pragma mark - - -static nsresult MakeFaviconURIFromURI(const nsAString& inURIString, nsAString& outFaviconURI) -{ - outFaviconURI.Truncate(0); - - nsCOMPtr uri; - nsresult rv = NS_NewURI(getter_AddRefs(uri), inURIString); - if (NS_FAILED(rv)) - return rv; - - // check for http/https - PRBool isHTTP = PR_FALSE, isHTTPS = PR_FALSE; - uri->SchemeIs("http", &isHTTP); - uri->SchemeIs("https", &isHTTPS); - if (!isHTTP && !isHTTPS) - return NS_OK; - - PRInt32 port; - uri->GetPort(&port); - - nsCAutoString scheme; - uri->GetScheme(scheme); - - nsCAutoString host; - uri->GetHost(host); - - nsCAutoString faviconURI(scheme); - faviconURI.Append("://"); - faviconURI.Append(host); - if (port != -1) { - faviconURI.Append(':'); - faviconURI.AppendInt(port); - } - faviconURI.Append("/favicon.ico"); - - outFaviconURI.Assign(NS_ConvertUTF8toUCS2(faviconURI)); - return NS_OK; -} - - -@interface SiteIconProvider(Private) - -- (void)addToMissedIconsCache:(const nsAString&)inURI withExpirationSeconds:(unsigned int)inExpSeconds; -- (BOOL)inMissedIconsCache:(const nsAString&)inURI; - -@end - - -@implementation SiteIconProvider - -- (id)init -{ - if ((self = [super init])) - { - mMissedIconsCacheHelper = new NeckoCacheHelper("Favicon", "Missed"); - nsresult rv = mMissedIconsCacheHelper->Init("MissedIconsCache"); - if (NS_FAILED(rv)) { - delete mMissedIconsCacheHelper; - mMissedIconsCacheHelper = NULL; - } - } - - return self; -} - -- (void)dealloc -{ - delete mMissedIconsCacheHelper; - [super dealloc]; -} - -- (void)addToMissedIconsCache:(const nsAString&)inURI withExpirationSeconds:(unsigned int)inExpSeconds -{ - if (mMissedIconsCacheHelper) - { - nsresult rv = mMissedIconsCacheHelper->PutInCache(NS_ConvertUCS2toUTF8(inURI), inExpSeconds); - } - -} - -- (BOOL)inMissedIconsCache:(const nsAString&)inURI -{ - PRBool inCache = PR_FALSE; - - if (mMissedIconsCacheHelper) - mMissedIconsCacheHelper->ExistsInCache(NS_ConvertUCS2toUTF8(inURI), &inCache); - - return inCache; -} - -- (BOOL)loadFavoriteIcon:(id)sender forURI:(NSString *)inURI withUserData:(id)userData allowNetwork:(BOOL)inAllowNetwork -{ - // look for a favicon - nsAutoString uriString; - [inURI assignTo_nsAString:uriString]; - - nsAutoString faviconURIString; - MakeFaviconURIFromURI(uriString, faviconURIString); - if (faviconURIString.Length() == 0) - return NO; - - NSString* faviconString = [NSString stringWith_nsAString:faviconURIString]; - - // is this uri already in the missing icons cache? - if ([self inMissedIconsCache:faviconURIString]) - { - return NO; - } - - RemoteDataProvider* dataProvider = [RemoteDataProvider sharedRemoteDataProvider]; - return [dataProvider loadURI:faviconString forTarget:sender withListener:self withUserData:userData allowNetworking:inAllowNetwork]; -} - -#define SITE_ICON_EXPIRATION_SECONDS (60 * 60 * 24 * 7) // 1 week - -// this is called on the main thread -- (void)doneRemoteLoad:(NSString*)inURI forTarget:(id)target withUserData:(id)userData data:(NSData*)data status:(nsresult)status -{ - nsAutoString uriString; - [inURI assignTo_nsAString:uriString]; - - BOOL loadOK = NS_SUCCEEDED(status) && (data != nil); - - // it's hard to tell if the favicon load succeeded or not. Even if the file - // does not exist, servers will send back a 404 page with a 0 status. - // So we just go ahead and try to make the image; it will return nil on - // failure. - NSImage* faviconImage = nil; - - NS_DURING - faviconImage = [[NSImage alloc] initWithData:data]; - NS_HANDLER - NSLog(@"Exception \"%@ making\" favicon image for %@", localException, inURI); - faviconImage = nil; - NS_ENDHANDLER - - BOOL gotImageData = loadOK && (faviconImage != nil); - if (NS_SUCCEEDED(status) && !gotImageData) // error status indicates that load was attempted from cache - { - [self addToMissedIconsCache:uriString withExpirationSeconds:SITE_ICON_EXPIRATION_SECONDS]; - } - - if (gotImageData) - { - [faviconImage setDataRetained:YES]; - [faviconImage setScalesWhenResized:YES]; - [faviconImage setSize:NSMakeSize(16, 16)]; - } - - // we always send out the notification, so that clients know - // about failed requests - NSDictionary* notificationData = [NSDictionary dictionaryWithObjectsAndKeys: - inURI, SiteIconLoadURIKey, - faviconImage, SiteIconLoadImageKey, // may be nil - userData, SiteIconLoadUserDataKey, - nil]; - - [[NSNotificationCenter defaultCenter] postNotificationName: SiteIconLoadNotificationName - object:target userInfo:notificationData]; -} - -#pragma mark - - -+ (SiteIconProvider*)sharedFavoriteIconProvider -{ - static SiteIconProvider* sIconProvider = nil; - if (!sIconProvider) - { - sIconProvider = [[SiteIconProvider alloc] init]; - } - - return sIconProvider; -} - - -+ (NSString*)faviconLocationStringFromURI:(NSString*)inURI -{ - nsAutoString uriString; - [inURI assignTo_nsAString:uriString]; - - nsAutoString faviconURIString; - MakeFaviconURIFromURI(uriString, faviconURIString); - return [NSString stringWith_nsAString:faviconURIString]; -} - -@end diff --git a/chimera/src/browser/nsAlertController.h b/chimera/src/browser/nsAlertController.h index 1790fc2054d..91bdc274498 100644 --- a/chimera/src/browser/nsAlertController.h +++ b/chimera/src/browser/nsAlertController.h @@ -53,8 +53,6 @@ IBOutlet id confirmPanelText; IBOutlet id confirmPanelButton1; IBOutlet id confirmPanelButton2; - IBOutlet id confirmStorePasswordPanel; - IBOutlet id confirmChangePasswordPanel; IBOutlet id promptPanel; IBOutlet id promptPanelCheck; IBOutlet id promptPanelText; @@ -90,8 +88,6 @@ - (int)confirmCheckEx:(NSWindow*)parent title:(NSString*)title text:(NSString*)text button1:(NSString*)btn1 button2:(NSString*)btn2 button3:(NSString*)btn3 checkMsg:(NSString*)checkMsg checkValue:(BOOL*)checkValue; -- (BOOL)confirmStorePassword:(NSWindow*)parent; -- (BOOL)confirmChangedPassword:(NSWindow*)parent; - (BOOL)prompt:(NSWindow*)parent title:(NSString*)title text:(NSString*)text promptText:(NSMutableString*)promptText checkMsg:(NSString*)checkMsg checkValue:(BOOL*)checkValue doCheck:(BOOL)doCheck; - (BOOL)promptUserNameAndPassword:(NSWindow*)parent title:(NSString*)title text:(NSString*)text userNameText:(NSMutableString*)userNameText passwordText:(NSMutableString*)passwordText checkMsg:(NSString*)checkMsg checkValue:(BOOL*)checkValue doCheck:(BOOL)doCheck; diff --git a/chimera/src/browser/nsAlertController.mm b/chimera/src/browser/nsAlertController.mm index 8f1ac58cd80..326878cc28d 100644 --- a/chimera/src/browser/nsAlertController.mm +++ b/chimera/src/browser/nsAlertController.mm @@ -154,19 +154,6 @@ enum { kOKButton = 0, kCancelButton = 1, kOtherButton = 2 }; return result; } -- (BOOL)confirmStorePassword:(NSWindow*)parent -{ - int result = [NSApp runModalForWindow:confirmStorePasswordPanel relativeToWindow:parent]; - [confirmStorePasswordPanel close]; - return (result == kOKButton); -} - -- (BOOL)confirmChangedPassword:(NSWindow*)parent -{ - int result = [NSApp runModalForWindow:confirmChangePasswordPanel relativeToWindow:parent]; - [confirmChangePasswordPanel close]; - return (result == kOKButton); -} - (BOOL)prompt:(NSWindow*)parent title:(NSString*)title text:(NSString*)text promptText:(NSMutableString*)promptText checkMsg:(NSString*)checkMsg checkValue:(BOOL*)checkValue doCheck:(BOOL)doCheck { diff --git a/chimera/src/download/ProgressDlgController.h b/chimera/src/download/ProgressDlgController.h index 3b1b3a3a861..e69de29bb2d 100644 --- a/chimera/src/download/ProgressDlgController.h +++ b/chimera/src/download/ProgressDlgController.h @@ -1,86 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: NPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Netscape Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 2002 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the NPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the NPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#import - -#import "CHDownloadProgressDisplay.h" - -#include "nscore.h" - -class nsIWebBrowserPersist; -class nsISupports; -class nsIInputStream; -class nsDownloadListener; - - -@interface ChimeraDownloadControllerFactory : DownloadControllerFactory -@end - - -@interface ProgressDlgController : NSWindowController -{ - IBOutlet NSTextField *mElapsedTimeLabel; - IBOutlet NSTextField *mFromField; - IBOutlet NSTextField *mStatusLabel; - IBOutlet NSTextField *mTimeLeftLabel; - IBOutlet NSTextField *mToField; - IBOutlet NSProgressIndicator *mProgressBar; - - NSToolbarItem *leaveOpenToggleToolbarItem; - - BOOL mSaveFileDialogShouldStayOpen; - BOOL mDoingAutoFileDownload; - BOOL mIsFileSave; - BOOL mDownloadIsComplete; - long mCurrentProgress; // if progress bar is indeterminate, can still calc stats. - - CHDownloader *mDownloader; // we hold a ref to this - NSTimer *mDownloadTimer; -} - -+ (int)numDownloadInProgress; - --(void)autosaveWindowFrame; - --(void) setupDownloadTimer; --(void) killDownloadTimer; --(void) setDownloadProgress:(NSTimer *)aTimer; --(NSString *) formatTime:(int)aSeconds; --(NSString *) formatFuzzyTime:(int)aSeconds; --(NSString *) formatBytes:(float)aBytes; - -@end diff --git a/chimera/src/download/ProgressDlgController.mm b/chimera/src/download/ProgressDlgController.mm index f602e492d4c..9ce24f3576a 100644 --- a/chimera/src/download/ProgressDlgController.mm +++ b/chimera/src/download/ProgressDlgController.mm @@ -20,6 +20,7 @@ * the Initial Developer. All Rights Reserved. * * Contributor(s): + * Calum Robinson * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -35,504 +36,319 @@ * * ***** END LICENSE BLOCK ***** */ +#import "NSView+Utils.h" + #import "ProgressDlgController.h" -#include "nsCOMPtr.h" -#include "nsString.h" -#include "nsCRT.h" -#include "nsIWebBrowserPersist.h" -#include "nsIInputStream.h" -#include "nsIURL.h" -#include "nsILocalFile.h" -#include "nsIDOMHTMLDocument.h" -#include "nsIWebProgressListener.h" -#include "nsIDownload.h" -#include "nsIComponentManager.h" -#include "nsIPref.h" - -static NSString *SaveFileToolbarIdentifier = @"Save File Dialog Toolbar"; -static NSString *CancelToolbarItemIdentifier = @"Cancel Toolbar Item"; -static NSString *ShowFileToolbarItemIdentifier = @"Show File Toolbar Item"; -static NSString *OpenFileToolbarItemIdentifier = @"Open File Toolbar Item"; -static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar Item"; +#import "ProgressViewController.h" +#import "PreferenceManager.h" static NSString *ProgressWindowFrameSaveName = @"ProgressWindow"; -@implementation ChimeraDownloadControllerFactory : DownloadControllerFactory -- (NSWindowController *)createDownloadController -{ - NSWindowController* progressController = [[ProgressDlgController alloc] initWithWindowNibName: @"ProgressDialog"]; - NSAssert([progressController conformsToProtocol:@protocol(CHDownloadProgressDisplay)], - @"progressController should conform to CHDownloadProgressDisplay protocol"); - return progressController; -} + +@interface ProgressDlgController(PrivateProgressDlgController) + +- (void)resizeWindowToFit; +- (void)rebuildViews; +- (NSSize)windowSizeForStackSize:(NSSize)stackSize; @end -#pragma mark - -@interface ProgressDlgController(Private) --(void)setupToolbar; -@end - @implementation ProgressDlgController -static int gNumActiveDownloads = 0; +static id gSharedProgressController = nil; -+ (int)numDownloadInProgress ++ (ProgressDlgController *)sharedDownloadController; { - return gNumActiveDownloads; + if (gSharedProgressController == nil) + gSharedProgressController = [[ProgressDlgController alloc] init]; + + return gSharedProgressController; +} + +- (id)init +{ + if ((self == [super initWithWindowNibName:@"ProgressDialog"])) + { + // Register for notifications when the stack view changes size + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(stackViewResized:) + name:StackViewResizedNotificationName + object:nil]; + + mProgressViewControllers = [[NSMutableArray alloc] init]; + + mDefaultWindowSize = [[self window] frame].size; + // it would be nice if we could get the frame from the name, and then + // mess with it before setting it. + [[self window] setFrameUsingName:ProgressWindowFrameSaveName]; + // set the window to its default height + NSRect windowFrame = [[self window] frame]; + windowFrame.size.height = mDefaultWindowSize.height; + [[self window] setFrame:windowFrame display:NO]; + + // We provide the views for the stack view, from mProgressViewControllers + [mStackView setDataSource:self]; + + [mScrollView setDrawsBackground:NO]; + [mNoDownloadsText retain]; // so we can remove it from its superview + } + + return self; } - (void)dealloc { - // if we get here because we're quitting, the listener will still be alive - // yet we're going away. As a result, we need to tell the d/l listener to - // forget it ever met us and necko will clean it up on its own. - if ( mDownloader) - mDownloader->DetachDownloadDisplay(); - NS_IF_RELEASE(mDownloader); + if (self == gSharedProgressController) + gSharedProgressController = nil; + + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [mProgressViewControllers release]; + [mNoDownloadsText release]; + [self killDownloadTimer]; [super dealloc]; } -- (void)windowDidLoad +- (void)didStartDownload:(id )progressDisplay { - [super windowDidLoad]; - - mDownloadIsComplete = NO; - mDoingAutoFileDownload = NO; + [self showWindow:nil]; // make sure the window is visible - if (!mIsFileSave) { - nsCOMPtr prefs(do_GetService(NS_PREF_CONTRACTID)); - PRBool save = PR_FALSE; - prefs->GetBoolPref("browser.download.progressDnldDialog.keepAlive", &save); - mSaveFileDialogShouldStayOpen = save; - - PRBool autoHelperDispatch = PR_FALSE; - prefs->GetBoolPref("browser.download.autoDispatch", &autoHelperDispatch); - mDoingAutoFileDownload = autoHelperDispatch; + [self rebuildViews]; + [self setupDownloadTimer]; +} + +- (void)didEndDownload:(id )progressDisplay +{ + [self rebuildViews]; // to swap in the completed view +} + +- (void)removeDownload:(id )progressDisplay +{ + [mProgressViewControllers removeObject:progressDisplay]; + + if ([mProgressViewControllers count] == 0) + { + // Stop doing stuff if there aren't any downloads going on + [self killDownloadTimer]; } - [self setupToolbar]; - [mProgressBar setUsesThreadedAnimation:YES]; - [mProgressBar startAnimation:self]; // move to onStateChange + [self rebuildViews]; } -- (void)setupToolbar +- (void)stackViewResized:(NSNotification *)notification { - NSToolbar *toolbar = [[[NSToolbar alloc] initWithIdentifier:SaveFileToolbarIdentifier] autorelease]; - - [toolbar setDisplayMode:NSToolbarDisplayModeDefault]; - [toolbar setAllowsUserCustomization:YES]; - [toolbar setAutosavesConfiguration:YES]; - [toolbar setDelegate:self]; - [[self window] setToolbar:toolbar]; + NSDictionary* userInfo = [notification userInfo]; + NSSize oldStackSize = [[userInfo objectForKey:@"oldsize"] sizeValue]; + + // this code is used to auto-resize the downloads window when + // its contents change size, if the window is in its standard, "zoomed" + // state. This allows the user to choose between auto-resizing behavior, + // by leaving the window alone, or their own size, by resizing it. + + // get the size the window would have been if it had been in the + // standard state, given the old size of the contents + NSSize oldZoomedWindowSize = [self windowSizeForStackSize:oldStackSize]; + NSSize curWindowSize = [[self window] frame].size; + + // only resize if the window matches the stack size + if (CHCloseSizes(oldZoomedWindowSize, curWindowSize, 4.0)) + [self resizeWindowToFit]; } -- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar +// given the dimensions of our stack view, return the dimensions of the window, +// assuming the window is zoomed to show as much of the contents as possible. +- (NSSize)windowSizeForStackSize:(NSSize)stackSize { - return [NSArray arrayWithObjects: CancelToolbarItemIdentifier, - ShowFileToolbarItemIdentifier, - OpenFileToolbarItemIdentifier, - LeaveOpenToolbarItemIdentifier, - NSToolbarCustomizeToolbarItemIdentifier, - NSToolbarFlexibleSpaceItemIdentifier, - NSToolbarSpaceItemIdentifier, - NSToolbarSeparatorItemIdentifier, - nil]; + NSSize actualScrollFrame = [mScrollView frame].size; + NSSize scrollFrameSize = [NSScrollView frameSizeForContentSize:stackSize + hasHorizontalScroller:NO hasVerticalScroller:YES borderType:NSNoBorder]; + + // frameSizeForContentSize seems to return a width 1 pixel too narrow + scrollFrameSize.width += 1; + + NSRect contentRect = [[[self window] contentView] frame]; + contentRect.size.width += scrollFrameSize.width - actualScrollFrame.width; + contentRect.size.height += scrollFrameSize.height - actualScrollFrame.height; + contentRect.origin = [[self window] convertBaseToScreen:contentRect.origin]; // convert to screen + + NSRect advisoryWindowFrame = [NSWindow frameRectForContentRect:contentRect styleMask:[[self window] styleMask]]; + NSRect constrainedRect = [[self window] constrainFrameRect:advisoryWindowFrame toScreen:[[self window] screen]]; + return constrainedRect.size; } -- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar +- (void)resizeWindowToFit { - return [NSArray arrayWithObjects: CancelToolbarItemIdentifier, - NSToolbarFlexibleSpaceItemIdentifier, - LeaveOpenToolbarItemIdentifier, - NSToolbarFlexibleSpaceItemIdentifier, - ShowFileToolbarItemIdentifier, - OpenFileToolbarItemIdentifier, - nil]; + if ([mProgressViewControllers count] > 0) + { + NSSize scrollFrameSize = [NSScrollView frameSizeForContentSize:[mStackView bounds].size + hasHorizontalScroller:NO hasVerticalScroller:YES borderType:NSNoBorder]; + NSSize curScrollFrameSize = [mScrollView frame].size; + + NSRect windowFrame = [[self window] frame]; + + float frameDelta = (scrollFrameSize.height - curScrollFrameSize.height); + windowFrame.size.height += frameDelta; + windowFrame.origin.y -= frameDelta; // maintain top + + [[self window] setFrame:windowFrame display:YES]; + } } -- (BOOL)validateToolbarItem:(NSToolbarItem *)toolbarItem +- (void)rebuildViews { - if ([toolbarItem action] == @selector(cancel)) // cancel button - return (!mDownloadIsComplete); - if ([toolbarItem action] == @selector(pauseAndResumeDownload)) // pause/resume button - return (NO); // Hey - it hasn't been hooked up yet. !mDownloadIsComplete when it is. - if ([toolbarItem action] == @selector(showFile)) // show file - return (mDownloadIsComplete); - if ([toolbarItem action] == @selector(openFile)) // open file - return (mDownloadIsComplete); - return YES; // turn it on otherwise. + [mStackView reloadSubviews]; + + if ([mProgressViewControllers count] == 0) + { + [[[self window] contentView] addSubview:mNoDownloadsText]; + } + else + { + [mNoDownloadsText removeFromSuperview]; + } + +} + +- (int)numDownloadsInProgress +{ + unsigned int numViews = [mProgressViewControllers count]; + int numActive = 0; + + for (unsigned int i = 0; i < numViews; i++) + { + if ([[mProgressViewControllers objectAtIndex:i] isActive]) + ++numActive; + } + return numActive; } -(void)autosaveWindowFrame { - [[self window] saveFrameUsingName: ProgressWindowFrameSaveName]; -} - -- (NSToolbarItem *) toolbar:(NSToolbar *)toolbar - itemForItemIdentifier:(NSString *)itemIdent - willBeInsertedIntoToolbar:(BOOL)willBeInserted -{ - NSToolbarItem *toolbarItem = [[[NSToolbarItem alloc] initWithItemIdentifier:itemIdent] autorelease]; - - if ( [itemIdent isEqual:CancelToolbarItemIdentifier] ) - { - [toolbarItem setLabel:NSLocalizedString(@"Cancel",@"Cancel")]; - [toolbarItem setPaletteLabel:NSLocalizedString(@"CancelPaletteLabel",@"Cancel Download")]; - [toolbarItem setToolTip:NSLocalizedString(@"CancelToolTip",@"Cancel this file download")]; - [toolbarItem setImage:[NSImage imageNamed:@"saveCancel"]]; - [toolbarItem setTarget:self]; - [toolbarItem setAction:@selector(cancel)]; - } - else if ( [itemIdent isEqual:ShowFileToolbarItemIdentifier] ) - { - [toolbarItem setLabel:NSLocalizedString(@"Show File",@"Show File")]; - [toolbarItem setPaletteLabel:NSLocalizedString(@"Show File",@"Show File")]; - [toolbarItem setToolTip:NSLocalizedString(@"ShowToolTip",@"Show the saved file in the Finder")]; - [toolbarItem setImage:[NSImage imageNamed:@"saveShowFile"]]; - [toolbarItem setTarget:self]; - [toolbarItem setAction:@selector(showFile)]; - } - else if ( [itemIdent isEqual:OpenFileToolbarItemIdentifier] ) - { - [toolbarItem setLabel:NSLocalizedString(@"Open File",@"Open File")]; - [toolbarItem setPaletteLabel:NSLocalizedString(@"Open File",@"Open File")]; - [toolbarItem setToolTip:NSLocalizedString(@"OpenToolTip",@"Open the saved file in its default application.")]; - [toolbarItem setImage:[NSImage imageNamed:@"saveOpenFile"]]; - [toolbarItem setTarget:self]; - [toolbarItem setAction:@selector(openFile)]; - } - else if ( [itemIdent isEqual:LeaveOpenToolbarItemIdentifier] ) - { - if ( !mIsFileSave && !mDoingAutoFileDownload ) - { - if ( mSaveFileDialogShouldStayOpen ) - { - [toolbarItem setLabel:NSLocalizedString(@"Leave Open",@"Leave Open")]; - [toolbarItem setPaletteLabel:NSLocalizedString(@"Toggle Close Behavior",@"Toggle Close Behavior")]; - [toolbarItem setToolTip:NSLocalizedString(@"LeaveOpenToolTip",@"Window will stay open when download finishes.")]; - [toolbarItem setImage:[NSImage imageNamed:@"saveLeaveOpenYES"]]; - [toolbarItem setTarget:self]; - [toolbarItem setAction:@selector(toggleLeaveOpen)]; - } - else - { - [toolbarItem setLabel:NSLocalizedString(@"Close When Done",@"Close When Done")]; - [toolbarItem setPaletteLabel:NSLocalizedString(@"Toggle Close Behavior",@"Toggle Close Behavior")]; - [toolbarItem setToolTip:NSLocalizedString(@"CloseWhenDoneToolTip",@"Window will close automatically when download finishes.")]; - [toolbarItem setImage:[NSImage imageNamed:@"saveLeaveOpenNO"]]; - [toolbarItem setTarget:self]; - [toolbarItem setAction:@selector(toggleLeaveOpen)]; - } - if ( willBeInserted ) - { - leaveOpenToggleToolbarItem = toolbarItem; //establish reference - } - } - } else - { - toolbarItem = nil; - } - - return toolbarItem; -} - --(void)cancel -{ - if (mDownloader) // we should always have one - mDownloader->CancelDownload(); - - // clean up downloaded file. - do it here on in CancelDownload? - NSFileManager *fileManager = [NSFileManager defaultManager]; - NSString *thePath = [[mToField stringValue] stringByExpandingTildeInPath]; - if ([fileManager isDeletableFileAtPath:thePath]) - // if we delete it, fantastic. if not, oh well. better to move to trash instead? - [fileManager removeFileAtPath:thePath handler:nil]; - - // we can _not_ set the |mDownloadIsComplete| flag here because the download really - // isn't done yet. We'll probably continue to process more PLEvents that are already - // in the queue until we get a STATE_STOP state change. As a result, we just keep - // going until that comes in (and it will, because we called CancelDownload() above). - // Ensure that the window goes away when we get there by flipping the 'stay alive' - // flag. (bug 154913) - mSaveFileDialogShouldStayOpen = NO; -} - --(void)showFile -{ - NSString *theFile = [[mToField stringValue] stringByExpandingTildeInPath]; - if ([[NSWorkspace sharedWorkspace] selectFile:theFile - inFileViewerRootedAtPath:[theFile stringByDeletingLastPathComponent]]) - return; - // hmmm. it didn't work. that's odd. need localized error messages. for now, just beep. - NSBeep(); -} - --(void)openFile -{ - NSString *theFile = [[mToField stringValue] stringByExpandingTildeInPath]; - if ([[NSWorkspace sharedWorkspace] openFile:theFile]) - return; - // hmmm. it didn't work. that's odd. need localized error message. for now, just beep. - NSBeep(); - -} - --(void)toggleLeaveOpen -{ - if ( ! mSaveFileDialogShouldStayOpen ) { - mSaveFileDialogShouldStayOpen = YES; - [leaveOpenToggleToolbarItem setLabel:NSLocalizedString(@"Leave Open",@"Leave Open")]; - [leaveOpenToggleToolbarItem setPaletteLabel:NSLocalizedString(@"Toggle Close Behavior",@"Toggle Close Behavior")]; - [leaveOpenToggleToolbarItem setToolTip:NSLocalizedString(@"LeaveOpenToolTip",@"Window will stay open when download finishes.")]; - [leaveOpenToggleToolbarItem setImage:[NSImage imageNamed:@"saveLeaveOpenYES"]]; - } else { - mSaveFileDialogShouldStayOpen = NO; - [leaveOpenToggleToolbarItem setLabel:NSLocalizedString(@"Close When Done",@"Close When Done")]; - [leaveOpenToggleToolbarItem setPaletteLabel:NSLocalizedString(@"Toggle Close Behavior",@"Toggle Close Behavior")]; - [leaveOpenToggleToolbarItem setToolTip:NSLocalizedString(@"CloseWhenDoneToolTip",@"Window will close automatically when download finishes.")]; - [leaveOpenToggleToolbarItem setImage:[NSImage imageNamed:@"saveLeaveOpenNO"]]; - } - - nsCOMPtr prefs(do_GetService(NS_PREF_CONTRACTID)); - prefs->SetBoolPref("browser.download.progressDnldDialog.keepAlive", mSaveFileDialogShouldStayOpen); + [[self window] saveFrameUsingName:ProgressWindowFrameSaveName]; } - (void)windowWillClose:(NSNotification *)notification { [self autosaveWindowFrame]; - [self autorelease]; -} - -- (BOOL)windowShouldClose:(NSNotification *)notification -{ - [self killDownloadTimer]; - if (!mDownloadIsComplete) { //whoops. hard cancel. - [self cancel]; - return NO; // let setDownloadProgress handle the close. - } - return YES; } - (void)killDownloadTimer { - if (mDownloadTimer) { + if (mDownloadTimer) + { [mDownloadTimer invalidate]; [mDownloadTimer release]; mDownloadTimer = nil; - } + } } + - (void)setupDownloadTimer { [self killDownloadTimer]; - mDownloadTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0 - target:self - selector:@selector(setDownloadProgress:) - userInfo:nil - repeats:YES] retain]; -} - --(NSString *)formatTime:(int)seconds -{ - NSMutableString *theTime =[[[NSMutableString alloc] initWithCapacity:8] autorelease]; - [theTime setString:@""]; - NSString *padZero = [NSString stringWithString:@"0"]; - //write out new elapsed time - if (seconds >= 3600){ - [theTime appendFormat:@"%d:",(seconds / 3600)]; - seconds = seconds % 3600; - } - NSString *elapsedMin = [NSString stringWithFormat:@"%d:",(seconds / 60)]; - if ([elapsedMin length] == 2) - [theTime appendString:[padZero stringByAppendingString:elapsedMin]]; - else - [theTime appendString:elapsedMin]; - seconds = seconds % 60; - NSString *elapsedSec = [NSString stringWithFormat:@"%d",seconds]; - if ([elapsedSec length] == 2) - [theTime appendString:elapsedSec]; - else - [theTime appendString:[padZero stringByAppendingString:elapsedSec]]; - return theTime; -} -// fuzzy time gives back strings like "about 5 seconds" --(NSString *)formatFuzzyTime:(int)seconds -{ - // check for seconds first - if (seconds < 60) { - if (seconds < 7) - return [[[NSString alloc] initWithFormat:NSLocalizedString(@"UnderSec",@"Under %d seconds"),5] autorelease]; - if (seconds < 13) - return [[[NSString alloc] initWithFormat:NSLocalizedString(@"UnderSec",@"Under %d seconds"),10] autorelease]; - return [[[NSString alloc] initWithString:NSLocalizedString(@"UnderMin",@"Under a minute")] autorelease]; - } - // seconds becomes minutes and we keep checking. - seconds = seconds/60; - if (seconds < 60) { - if (seconds < 2) - return [[[NSString alloc] initWithString:NSLocalizedString(@"AboutMin",@"About a minute")] autorelease]; - // OK, tell the good people how much time we have left. - return [[[NSString alloc] initWithFormat:NSLocalizedString(@"AboutMins",@"About %d minutes"),seconds] autorelease]; - } - //this download will never seemingly never end. now seconds become hours. - seconds = seconds/60; - if (seconds < 2) - return [[[NSString alloc] initWithString:NSLocalizedString(@"AboutHour",@"Over an hour")] autorelease]; - return [[[NSString alloc] initWithFormat:NSLocalizedString(@"AboutHours",@"Over %d hours"),seconds] autorelease]; -} - - --(NSString *)formatBytes:(float)bytes -{ // this is simpler than my first try. I peaked at Omnigroup byte formatting code. - // if bytes are negative, we return question marks. - if (bytes < 0) - return [[[NSString alloc] initWithString:@"???"] autorelease]; - // bytes first. - if (bytes < 1024) - return [[[NSString alloc] initWithFormat:@"%.1f bytes",bytes] autorelease]; - // kb - bytes = bytes/1024; - if (bytes < 1024) - return [[[NSString alloc] initWithFormat:@"%.1f KB",bytes] autorelease]; - // mb - bytes = bytes/1024; - if (bytes < 1024) - return [[[NSString alloc] initWithFormat:@"%.1f MB",bytes] autorelease]; - // gb - bytes = bytes/1024; - return [[[NSString alloc] initWithFormat:@"%.1f GB",bytes] autorelease]; -} - -// this handles lots of things. -- (void)setDownloadProgress:(NSTimer *)downloadTimer; -{ - // XXX this logic needs cleaning up. - // Ack! we're closing the window with the download still running! - if (mDownloadIsComplete) + mDownloadTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0 + target:self + selector:@selector(setDownloadProgress:) + userInfo:nil + repeats:YES] retain]; +} + +// Called by our timer to refresh all the download stats +- (void)setDownloadProgress:(NSTimer *)aTimer +{ + [mProgressViewControllers makeObjectsPerformSelector:@selector(refreshDownloadInfo)]; + // if the window is minimized, we want to update the dock image here. But how? +} + +- (NSApplicationTerminateReply)allowTerminate +{ + if ([self numDownloadsInProgress] > 0) { - [[self window] performClose:self]; - return; + // make sure the window is visible + [self showWindow:self]; + + NSString *alert = NSLocalizedString(@"QuitWithDownloadsMsg", @"Really Quit?"); + NSString *message = NSLocalizedString(@"QuitWithDownloadsExpl", @""); + NSString *okButton = NSLocalizedString(@"QuitWithdownloadsButtonDefault",@"Cancel"); + NSString *altButton = NSLocalizedString(@"QuitWithdownloadsButtonAlt",@"Quit"); + + // while the panel is up, download dialogs won't update (no timers firing) but + // downloads continue (PLEvents being processed) + id panel = NSGetAlertPanel(alert, message, okButton, altButton, nil, message); + + [NSApp beginSheet:panel + modalForWindow:[self window] + modalDelegate:self + didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) + contextInfo:NULL]; + int sheetResult = [NSApp runModalForWindow: panel]; + [NSApp endSheet: panel]; + [panel orderOut: self]; + NSReleaseAlertPanel(panel); + + return (sheetResult == NSAlertDefaultReturn) ? NSTerminateCancel : NSTerminateNow; } - // get the elapsed time - NSArray *elapsedTimeArray = [[mElapsedTimeLabel stringValue] componentsSeparatedByString:@":"]; - int j = [elapsedTimeArray count]; - int elapsedSec = [[elapsedTimeArray objectAtIndex:(j-1)] intValue] + [[elapsedTimeArray objectAtIndex:(j-2)] intValue]*60; - if (j==3) // this download is taking forever. - elapsedSec += [[elapsedTimeArray objectAtIndex:0] intValue]*3600; - // update elapsed time - [mElapsedTimeLabel setStringValue:[self formatTime:(++elapsedSec)]]; - // for status field & time left - float maxBytes = ([mProgressBar maxValue]); - float byteSec = mCurrentProgress/elapsedSec; - // OK - if downloadTimer is nil, we're done - fix maxBytes value for status report. - if (!downloadTimer) - maxBytes = mCurrentProgress; - // update status field - NSString *labelString = NSLocalizedString(@"LabelString",@"%@ of %@ total (at %@/sec)"); - [mStatusLabel setStringValue: [NSString stringWithFormat:labelString, [self formatBytes:mCurrentProgress], [self formatBytes:maxBytes], [self formatBytes:byteSec]]]; - // updating estimated time left field - // if maxBytes < 0, can't calc time left. - // if !downloadTimer, download is finished. either way, make sure time left is 0. - if ((maxBytes > 0) && (downloadTimer)) - { - int secToGo = (int)ceil((elapsedSec*maxBytes/mCurrentProgress) - elapsedSec); - [mTimeLeftLabel setStringValue:[self formatFuzzyTime:secToGo]]; - } - else if (!downloadTimer) - { // download done. Set remaining time to 0, fix progress bar & cancel button - mDownloadIsComplete = YES; // all done. we got a STATE_STOP - [mTimeLeftLabel setStringValue:@""]; - [self setProgressTo:mCurrentProgress ofMax:mCurrentProgress]; - if (!mSaveFileDialogShouldStayOpen || mDoingAutoFileDownload) - [[self window] performClose:self]; // close window - else - [[self window] update]; // redraw window - } - else //maxBytes is undetermined. Set remaining time to question marks. - [mTimeLeftLabel setStringValue:@"???"]; + + return NSTerminateNow; +} + +- (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo +{ + [NSApp stopModalWithCode:returnCode]; } #pragma mark - -// CHDownloadProgressDisplay protocol methods - -- (void)onStartDownload:(BOOL)isFileSave; +// implement to zoom to a size that just fits the contents +- (NSRect)windowWillUseStandardFrame:(NSWindow *)sender defaultFrame:(NSRect)defaultFrame { - mIsFileSave = isFileSave; + NSSize scrollFrameSize = [NSScrollView frameSizeForContentSize:[mStackView bounds].size + hasHorizontalScroller:NO hasVerticalScroller:YES borderType:NSNoBorder]; - [self window]; // make the window - [[self window] setFrameUsingName: ProgressWindowFrameSaveName]; + NSSize curScrollFrameSize = [mScrollView frame].size; + float frameDelta = (scrollFrameSize.height - curScrollFrameSize.height); - [self showWindow: self]; - [self setupDownloadTimer]; - - gNumActiveDownloads++; + NSRect windowFrame = [[self window] frame]; + windowFrame.size.height += frameDelta; + windowFrame.origin.y -= frameDelta; // maintain top + + windowFrame.size.width = mDefaultWindowSize.width; + // cocoa will ensure that the window fits onscreen for us + return windowFrame; } -- (void)onEndDownload +#pragma mark - + +/* + CHStackView datasource methods +*/ + +- (int)subviewsForStackView:(CHStackView *)stackView { - gNumActiveDownloads --; + return [mProgressViewControllers count]; +} + +- (NSView *)viewForStackView:(CHStackView *)aResizingView atIndex:(int)index +{ + return [[mProgressViewControllers objectAtIndex:index] view]; +} + +#pragma mark - + +/* + Just create a progress view, but don't display it (otherwise the URL fields etc. + are just blank) +*/ +- (id )createProgressDisplay +{ + ProgressViewController *newController = [[ProgressViewController alloc] init]; + [newController setProgressWindowController:self]; + [mProgressViewControllers addObject:newController]; - // if we're quitting, our progress window is already gone and we're in the - // process of shutting down gecko and all the d/l listeners. The timer, at - // that point, is the only thing keeping us alive. Killing it will cause - // us to go away immediately, so kung-fu deathgrip it until we're done twiddling - // bits on ourself. - [self retain]; // Enter The Dragon! - [self killDownloadTimer]; - [self setDownloadProgress:nil]; - [self release]; -} - -- (void)setProgressTo:(long)aCurProgress ofMax:(long)aMaxProgress -{ - mCurrentProgress = aCurProgress; // fall back for stat calcs - - if (![mProgressBar isIndeterminate]) //most likely - just update value - { - if (aCurProgress == aMaxProgress) //handles little bug in FTP download size - [mProgressBar setMaxValue:aMaxProgress]; - - [mProgressBar setDoubleValue:aCurProgress]; - } - else if (aMaxProgress > 0) // ok, we're starting up with good max & cur values - { - [mProgressBar setIndeterminate:NO]; - [mProgressBar setMaxValue:aMaxProgress]; - [mProgressBar setDoubleValue:aCurProgress]; - } // if neither case was true, it's barber pole city. -} - --(void) setDownloadListener: (CHDownloader*)aDownloader -{ - if (mDownloader != aDownloader) - NS_IF_RELEASE(mDownloader); - - NS_IF_ADDREF(mDownloader = aDownloader); -} - -- (void)setSourceURL:(NSString*)aSourceURL -{ - [mFromField setStringValue: aSourceURL]; - [mFromField display]; // force an immmeditate update -} - -- (void)setDestinationPath:(NSString*)aDestPath -{ - [mToField setStringValue: [aDestPath stringByAbbreviatingWithTildeInPath]]; - [mToField display]; // force an immmeditate update - - // also set the window title - NSString* downloadFileName = [aDestPath lastPathComponent]; - if ([downloadFileName length] == 0) - downloadFileName = aDestPath; - - [[self window] setTitle:[NSString stringWithFormat:NSLocalizedString(@"DownloadingTitle", @""), downloadFileName]]; + return newController; } @end diff --git a/chimera/src/download/ProgressViewController.h b/chimera/src/download/ProgressViewController.h new file mode 100644 index 00000000000..e69de29bb2d diff --git a/chimera/src/download/ProgressViewController.mm b/chimera/src/download/ProgressViewController.mm new file mode 100644 index 00000000000..86f5fb302db --- /dev/null +++ b/chimera/src/download/ProgressViewController.mm @@ -0,0 +1,544 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Calum Robinson + * Simon Fraser + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the NPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#import "NSView+Utils.h" + +#import "ProgressViewController.h" +#import "ProgressDlgController.h" +#import "PreferenceManager.h" + +enum +{ + kLabelTagFilename = 1000, + kLabelTagProgress, + kLabelTagSource, + kLabelTagDestination, + kLabelTagTimeRemaining, + kLabelTagStatus, // 1005 + kLabelTagTimeRemainingLabel +}; + + +// Notification sent when user holds option key and expands/contracts a progress view +static NSString *ProgressViewsShouldResize = @"ProgressViewsShouldResize"; + +@interface ProgressViewController(ProgressViewControllerPrivate) + +- (void)viewDidLoad; +- (void)refreshDownloadInfo; +- (void)moveProgressBarToCurrentView; +- (void)updateButtons; + +@end + +@implementation ProgressViewController + ++ (NSString *)formatTime:(int)seconds +{ + NSMutableString *theTime = [NSMutableString stringWithCapacity:8]; + + NSString *padZero = [NSString stringWithString:@"0"]; + //write out new elapsed time + if (seconds >= 3600) + { + [theTime appendFormat:@"%d:",(seconds / 3600)]; + seconds = seconds % 3600; + } + + NSString *elapsedMin = [NSString stringWithFormat:@"%d:",(seconds / 60)]; + if ([elapsedMin length] == 2) + [theTime appendString:[padZero stringByAppendingString:elapsedMin]]; + else + [theTime appendString:elapsedMin]; + + seconds = seconds % 60; + NSString *elapsedSec = [NSString stringWithFormat:@"%d",seconds]; + + if ([elapsedSec length] == 2) + [theTime appendString:elapsedSec]; + else + [theTime appendString:[padZero stringByAppendingString:elapsedSec]]; + + return theTime; +} + +// fuzzy time gives back strings like "about 5 seconds" ++ (NSString *)formatFuzzyTime:(int)seconds +{ + // check for seconds first + if (seconds < 60) { + if (seconds < 7) + return [NSString stringWithFormat:NSLocalizedString(@"UnderSec", @"Under %d seconds"), 5]; + if (seconds < 13) + return [NSString stringWithFormat:NSLocalizedString(@"UnderSec", @"Under %d seconds"), 10]; + return [NSString stringWithFormat:NSLocalizedString(@"UnderMin", @"Under a minute")]; + } + // seconds becomes minutes and we keep checking. + seconds = seconds/60; + if (seconds < 60) { + if (seconds < 2) + return [NSString stringWithFormat:NSLocalizedString(@"AboutMin",@"About a minute")]; + // OK, tell the good people how much time we have left. + return [NSString stringWithFormat:NSLocalizedString(@"AboutMins",@"About %d minutes"), seconds]; + } + //this download will never seemingly never end. now seconds become hours. + seconds = seconds/60; + if (seconds < 2) + return [NSString stringWithFormat:NSLocalizedString(@"AboutHour", @"Over an hour")]; + return [NSString stringWithFormat:NSLocalizedString(@"AboutHours", @"Over %d hours"), seconds]; +} + ++ (NSString *)formatBytes:(float)bytes +{ + // if bytes are negative, we return question marks. + if (bytes < 0) + return [NSString stringWithString:@"?"]; + // bytes first. + if (bytes < 1024) + return [NSString stringWithFormat:@"%.1f bytes",bytes]; + // kb + bytes = bytes/1024; + if (bytes < 1024) + return [NSString stringWithFormat:@"%.1f KB",bytes]; + // mb + bytes = bytes/1024; + if (bytes < 1024) + return [NSString stringWithFormat:@"%.1f MB",bytes]; + // gb + bytes = bytes/1024; + return [NSString stringWithFormat:@"%.1f GB",bytes]; +} + +#pragma mark - + +- (id)init +{ + if ((self = [super init])) + { + [NSBundle loadNibNamed:@"ProgressView" owner:self]; + + [self viewDidLoad]; + + // Register for notifications when one of the progress views is expanded/contracted + // whilst holding the option button + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(changeCollapsedStateNotification:) + name:ProgressViewsShouldResize + object:nil]; + + [mExpandedRevealButton setEnabled:NO]; + [mExpandedOpenButton setEnabled:NO]; + } + + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self + name:ProgressViewsShouldResize + object:nil]; + + // if we get here because we're quitting, the listener will still be alive + // yet we're going away. As a result, we need to tell the d/l listener to + // forget it ever met us and necko will clean it up on its own. + if (mDownloader) + mDownloader->DetachDownloadDisplay(); + NS_IF_RELEASE(mDownloader); + + [mStartTime release]; + [mSourceURL release]; + [mDestPath release]; + [mProgressBar release]; + + [super dealloc]; +} + +// Save the expand/contract view pref (called when the user clicks the dislosure triangle) +- (void)setCompactViewPref +{ + [[PreferenceManager sharedInstance] setPref:"browser.download.compactView" toBoolean:mViewIsCompact]; +} + +- (void)viewDidLoad +{ + mViewIsCompact = [[PreferenceManager sharedInstance] getBooleanPref:"browser.download.compactView" withSuccess:NULL]; + [mProgressBar retain]; // make sure it survives being moved between views + + if (mViewIsCompact) + [self moveProgressBarToCurrentView]; + + // this isn't necessarily better. Need to profile. + [mProgressBar setUsesThreadedAnimation:YES]; +} + +- (NSView *)view +{ + if (mViewIsCompact) + return (mDownloadDone ? mCompletedViewCompact : mProgressViewCompact); + else + return (mDownloadDone ? mCompletedView : mProgressView); +} + +- (IBAction)toggleDisclosure:(id)sender +{ + mViewIsCompact = !mViewIsCompact; + + [self moveProgressBarToCurrentView]; + + // Is option/alt held down? + if ([[[sender window] currentEvent] modifierFlags] & NSAlternateKeyMask) + { + // Get all progress views to look the same as self + [[NSNotificationCenter defaultCenter] postNotificationName:ProgressViewsShouldResize + object:[NSNumber numberWithBool:mViewIsCompact]]; + } + + // Set the pref only when the user clicks the disclosure triangle + [self setCompactViewPref]; + + // Re-calculate the new view & window sizes + [[NSNotificationCenter defaultCenter] postNotificationName:StackViewReloadNotificationName + object:self]; + [self refreshDownloadInfo]; +} + +- (void)changeCollapsedStateNotification:(NSNotification *)notification +{ + // note that this will get called on the view that is being clicked, as well + // as the other views. Don't do redundant work here, like redrawing. + mViewIsCompact = [[notification object] boolValue]; + // Don't call [enclosingStackView reloadSubviews]; here, because it will be done + // by the original view that was option-clicked, not us +} + +-(void)cancel +{ + mUserCancelled = YES; + + if (mDownloader) // we should always have one + mDownloader->CancelDownload(); + + // clean up downloaded file. - do it here or in CancelDownload? + NSFileManager *fileManager = [NSFileManager defaultManager]; + if ([fileManager isDeletableFileAtPath:mDestPath]) + { + // if we delete it, fantastic. if not, oh well. better to move to trash instead? + [fileManager removeFileAtPath:mDestPath handler:nil]; + } +} + +- (IBAction)close:(id)sender +{ + if (!mDownloadDone) + { + mRemoveWhenDone = YES; + [self cancel]; + } + else + { + [mProgressWindowController removeDownload:self]; + } +} + +- (IBAction)stop:(id)sender +{ + [self cancel]; +} + +- (IBAction)reveal:(id)sender +{ + if ([[NSWorkspace sharedWorkspace] selectFile:mDestPath + inFileViewerRootedAtPath:[mDestPath stringByDeletingLastPathComponent]]) + return; + // hmmm. it didn't work. that's odd. need localized error messages. for now, just beep. + NSBeep(); +} + +- (IBAction)open:(id)sender +{ + if ([[NSWorkspace sharedWorkspace] openFile:mDestPath]) + return; + // hmmm. it didn't work. that's odd. need localized error message. for now, just beep. + NSBeep(); +} + +// Called just before the view will be shown to the user +- (void)downloadDidStart +{ + mStartTime = [[NSDate alloc] init]; +// [mProgressBar startAnimation:self]; // moved to onStartDownload + [self refreshDownloadInfo]; +} + +- (void)downloadDidEnd +{ + mDownloadDone = YES; + mDownloadTime = -[mStartTime timeIntervalSinceNow]; + [mProgressBar stopAnimation:self]; + + [mExpandedCancelButton setEnabled:NO]; + [self refreshDownloadInfo]; +} + +// this handles lots of things. +- (void)refreshDownloadInfo +{ + NSView* curView = [self view]; + + NSString* filename = [mSourceURL lastPathComponent]; + NSString *destPath = [mDestPath stringByAbbreviatingWithTildeInPath]; + NSString* tooltipFormat = NSLocalizedString(mDownloadDone ? @"DownloadedTooltipFormat" : @"DownloadingTooltipFormat", @""); + + id filenameLabel = [curView viewWithTag:kLabelTagFilename]; + [filenameLabel setStringValue:filename]; + [filenameLabel setToolTip:[NSString stringWithFormat:tooltipFormat, [mSourceURL lastPathComponent], mSourceURL, destPath]]; + + id destLabel = [curView viewWithTag:kLabelTagDestination]; + [destLabel setStringValue:destPath]; + + id locationLabel = [curView viewWithTag:kLabelTagSource]; + [locationLabel setStringValue:mSourceURL]; + + if (mDownloadDone) + { + id statusLabel = [curView viewWithTag:kLabelTagStatus]; + if (statusLabel) + { + NSString* statusString; + if (mUserCancelled) + statusString = NSLocalizedString(@"DownloadCancelled", @"Cancelled"); + else if (mDownloadingError) + statusString = NSLocalizedString(@"DownloadInterrupted", @"Interrupted"); + else + statusString = NSLocalizedString(@"DownloadCompleted", @"Completed"); + + [statusLabel setStringValue: statusString]; + } + + // set progress label + id progressLabel = [curView viewWithTag:kLabelTagProgress]; + if (progressLabel) + { + float byteSec = mCurrentProgress / mDownloadTime; + // show how much we downloaded, become some types of disconnects make us think + // we finished successfully + [progressLabel setStringValue:[NSString stringWithFormat: + NSLocalizedString(@"DownloadDoneStatusString", @"%@ of %@ done (at %@/sec)"), + [[self class] formatBytes:mCurrentProgress], + [[self class] formatBytes:mDownloadSize], + [[self class] formatBytes:byteSec]]]; + } + + id timeLabel = [curView viewWithTag:kLabelTagTimeRemaining]; + if (timeLabel) + [timeLabel setStringValue:[[self class] formatTime:(int)mDownloadTime]]; + + id timeLabelLabel = [curView viewWithTag:kLabelTagTimeRemainingLabel]; + if (timeLabelLabel) + [timeLabelLabel setStringValue:NSLocalizedString(@"DownloadRemainingLabelDone", @"Time elapsed:")]; + + [self updateButtons]; + } + else + { + NSTimeInterval elapsedTime = -[mStartTime timeIntervalSinceNow]; + + // update status field + id progressLabel = [curView viewWithTag:kLabelTagProgress]; + if (progressLabel) + { + NSString *statusLabelString = NSLocalizedString(@"DownloadStatusString", @"%@ of %@ total (at %@/sec)"); + float byteSec = mCurrentProgress / elapsedTime; + [progressLabel setStringValue:[NSString stringWithFormat:statusLabelString, + [[self class] formatBytes:mCurrentProgress], + (mDownloadSize > 0 ? [[self class] formatBytes:mDownloadSize] : @"?"), + [[self class] formatBytes:byteSec]]]; + } + + id timeLabel = [curView viewWithTag:kLabelTagTimeRemaining]; + if (timeLabel) + { + if (mDownloadSize > 0) + { + int secToGo = (int)ceil((elapsedTime * mDownloadSize / mCurrentProgress) - elapsedTime); + [timeLabel setStringValue:[[self class] formatFuzzyTime:secToGo]]; + } + else // mDownloadSize is undetermined. Set remaining time to question marks. + { + NSString *calculatingString = NSLocalizedString(@"DownloadCalculatingString", @"Unknown"); + [timeLabel setStringValue:calculatingString]; + } + } + } +} + +- (void)updateButtons +{ + // note: this will stat every time, which will be expensive! We could use + // FNNotify/FNSubscribe to avoid this (writing a Cocoa wrapper around it). + if (mDownloadDone && !mDownloadingError) + { + BOOL destFileExists = [[NSFileManager defaultManager] fileExistsAtPath:mDestPath]; + [mExpandedRevealButton setEnabled:destFileExists]; + [mExpandedOpenButton setEnabled:destFileExists]; + } +} + +- (void)moveProgressBarToCurrentView +{ + [mProgressBar moveToView:(mViewIsCompact ? mProgressViewCompact : mProgressView) resize:YES]; + [mProgressBar startAnimation:self]; // this is necessary to keep it animating for some reason +} + +- (void)setProgressWindowController:(ProgressDlgController*)progressWindowController +{ + mProgressWindowController = progressWindowController; +} + +- (BOOL)isActive +{ + return !mDownloadDone; +} + +#pragma mark - + +- (void)onStartDownload:(BOOL)isFileSave +{ + mIsFileSave = isFileSave; + [self downloadDidStart]; + [mProgressWindowController didStartDownload:self]; + + // need to do this after the view as been put in the window, otherwise it doesn't work + [mProgressBar startAnimation:self]; +} + +- (void)onEndDownload:(BOOL)completedOK +{ + mDownloadingError = !completedOK; + + [self downloadDidEnd]; + [mProgressWindowController didEndDownload:self]; + if (mRemoveWhenDone) + [mProgressWindowController removeDownload:self]; +} + +- (void)setProgressTo:(long)aCurProgress ofMax:(long)aMaxProgress +{ + mCurrentProgress = aCurProgress; // fall back for stat calcs + mDownloadSize = aMaxProgress; + + if (![mProgressBar isIndeterminate]) //most likely - just update value + { + if (aCurProgress == aMaxProgress) //handles little bug in FTP download size + [mProgressBar setMaxValue:aMaxProgress]; + + [mProgressBar setDoubleValue:aCurProgress]; + } + else if (aMaxProgress > 0) // ok, we're starting up with good max & cur values + { + [mProgressBar setIndeterminate:NO]; + [mProgressBar setMaxValue:aMaxProgress]; + [mProgressBar setDoubleValue:aCurProgress]; + } // if neither case was true, it's barber pole city. +} + +-(void)setDownloadListener:(CHDownloader*)aDownloader +{ + if (mDownloader != aDownloader) + NS_IF_RELEASE(mDownloader); + + NS_IF_ADDREF(mDownloader = aDownloader); +} + +#if 0 +/* + This is kind of a hack. It should probably be done somewhere else so Mozilla can have + it too, but until Apple fixes the problems with the setting of comments without + reverting to Applescript, I have left it in. + + Turned off for now, until we find a better way to do this. Won't Carbon APIs work? +*/ +- (void)tryToSetFinderComments +{ + if (mDestPath && mSourceURL) + { + CFURLRef fileURL = CFURLCreateWithFileSystemPath( NULL, + (CFStringRef)mDestPath, + kCFURLPOSIXPathStyle, + NO); + + NSString *hfsPath = (NSString *)CFURLCopyFileSystemPath(fileURL, + kCFURLHFSPathStyle); + + CFRelease(fileURL); + + NSAppleScript *setCommentScript = [[NSAppleScript alloc] initWithSource: + [NSString stringWithFormat:@"tell application \"Finder\" to set comment of file \"%@\" to \"%@\"", hfsPath, mSourceURL]]; + NSDictionary *errorInfo = NULL; + + [setCommentScript executeAndReturnError:&errorInfo]; + + if (errorInfo) + { + NSLog(@"Get error when running AppleScript to set comments for '%@':\n %@", + mDestPath, + [errorInfo objectForKey:NSAppleScriptErrorMessage]); + } + } +} +#endif + +- (void)setSourceURL:(NSString*)aSourceURL +{ + [mSourceURL autorelease]; + mSourceURL = [aSourceURL copy]; + + //[self tryToSetFinderComments]; +} + +- (void)setDestinationPath:(NSString*)aDestPath +{ + [mDestPath autorelease]; + mDestPath = [aDestPath copy]; + //[self tryToSetFinderComments]; +} + +@end diff --git a/chimera/src/download/SaveHeaderSniffer.h b/chimera/src/download/SaveHeaderSniffer.h index 4147cce1507..e69de29bb2d 100644 --- a/chimera/src/download/SaveHeaderSniffer.h +++ b/chimera/src/download/SaveHeaderSniffer.h @@ -1,84 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Chimera code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 2002 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * David Hyatt - * Simon Fraser - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - - -#import -#import - -#include "nsString.h" -#include "nsIWebProgressListener.h" -#include "nsIWebBrowserPersist.h" -#include "nsIURI.h" -#include "nsILocalFile.h" -#include "nsIInputStream.h" -#include "nsIDOMDocument.h" - - -// Implementation of a header sniffer class that is used when saving Web pages and images. -class nsHeaderSniffer : public nsIWebProgressListener -{ -public: - nsHeaderSniffer(nsIWebBrowserPersist* aPersist, nsIFile* aFile, nsIURI* aURL, - nsIDOMDocument* aDocument, nsIInputStream* aPostData, - const nsAString& aSuggestedFilename, PRBool aBypassCache, - NSView* aFilterView, NSPopUpButton* aFilterList); - virtual ~nsHeaderSniffer(); - - NS_DECL_ISUPPORTS - NS_DECL_NSIWEBPROGRESSLISTENER - -protected: - - nsresult PerformSave(nsIURI* inOriginalURI); - nsresult InitiateDownload(nsISupports* inSourceData, nsString& inFileName, nsIURI* inOriginalURI); - -private: - - nsIWebBrowserPersist* mPersist; // Weak. It owns us as a listener. - nsCOMPtr mTmpFile; - nsCOMPtr mURL; - nsCOMPtr mDocument; - nsCOMPtr mPostData; - nsString mDefaultFilename; - PRBool mBypassCache; - nsCString mContentType; - nsCString mContentDisposition; - NSView* mFilterView; - NSPopUpButton* mFilterList; -}; - diff --git a/chimera/src/download/SaveHeaderSniffer.mm b/chimera/src/download/SaveHeaderSniffer.mm index 42827fa633c..77ccd5842d7 100644 --- a/chimera/src/download/SaveHeaderSniffer.mm +++ b/chimera/src/download/SaveHeaderSniffer.mm @@ -38,6 +38,8 @@ #import "NSString+Utils.h" +#import "ChimeraUIConstants.h" + #include "SaveHeaderSniffer.h" #include "netCore.h" @@ -56,7 +58,7 @@ const char* const persistContractID = "@mozilla.org/embedding/browser/nsWebBrows nsHeaderSniffer::nsHeaderSniffer(nsIWebBrowserPersist* aPersist, nsIFile* aFile, nsIURI* aURL, nsIDOMDocument* aDocument, nsIInputStream* aPostData, const nsAString& aSuggestedFilename, PRBool aBypassCache, - NSView* aFilterView, NSPopUpButton* aFilterList) + NSView* aFilterView) : mPersist(aPersist) , mTmpFile(aFile) , mURL(aURL) @@ -65,9 +67,8 @@ nsHeaderSniffer::nsHeaderSniffer(nsIWebBrowserPersist* aPersist, nsIFile* aFile, , mDefaultFilename(aSuggestedFilename) , mBypassCache(aBypassCache) , mFilterView(aFilterView) -, mFilterList(aFilterList) { - NS_INIT_ISUPPORTS(); + NS_INIT_ISUPPORTS(); } nsHeaderSniffer::~nsHeaderSniffer() @@ -183,14 +184,16 @@ nsresult nsHeaderSniffer::PerformSave(nsIURI* inOriginalURI) return rv; nsCOMPtr dirBranch; prefs->GetBranch("browser.download.", getter_AddRefs(dirBranch)); - PRInt32 filterIndex = 0; + PRInt32 filterIndex = eSaveFormatHTMLComplete; if (dirBranch) { nsresult rv = dirBranch->GetIntPref("save_converter_index", &filterIndex); if (NS_FAILED(rv)) - filterIndex = 0; + filterIndex = eSaveFormatHTMLComplete; } - if (mFilterList) - [mFilterList selectItemAtIndex: filterIndex]; + + NSPopUpButton* filterList = [mFilterView viewWithTag:kSaveFormatPopupTag]; + if (filterList) + [filterList selectItemAtIndex: filterIndex]; // We need to figure out what file name to use. nsAutoString defaultFileName; @@ -294,17 +297,17 @@ nsresult nsHeaderSniffer::PerformSave(nsIURI* inOriginalURI) return NS_OK; // Update the filter index. - if (isHTML && mFilterList) { - filterIndex = [mFilterList indexOfSelectedItem]; + if (isHTML && filterList) { + filterIndex = [filterList indexOfSelectedItem]; dirBranch->SetIntPref("save_converter_index", filterIndex); } // Convert the content type to text/plain if it was selected in the filter. - if (isHTML && filterIndex == 2) + if (isHTML && filterIndex == eSaveFormatPlainText) mContentType = "text/plain"; nsCOMPtr sourceData; - if (isHTML && filterIndex != 1) + if (isHTML && filterIndex != eSaveFormatHTMLSource) sourceData = do_QueryInterface(mDocument); else sourceData = do_QueryInterface(mURL); diff --git a/chimera/src/download/nsDownloadListener.h b/chimera/src/download/nsDownloadListener.h index c76874c71d9..e69de29bb2d 100644 --- a/chimera/src/download/nsDownloadListener.h +++ b/chimera/src/download/nsDownloadListener.h @@ -1,93 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: NPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Netscape Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 2002 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Simon Fraser - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the NPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the NPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - - - -#import -#import - -#import "CHDownloadProgressDisplay.h" - -#include "nsString.h" -#include "nsIDownload.h" -#include "nsIWebProgressListener.h" -#include "nsIWebBrowserPersist.h" -#include "nsIURI.h" -#include "nsILocalFile.h" -#include "nsExternalHelperAppService.h" - - -// maybe this should replace nsHeaderSniffer too? - -class nsDownloadListener : public CHDownloader, - public nsIDownload, - public nsIWebProgressListener -{ -public: - nsDownloadListener(DownloadControllerFactory* inDownloadControllerFactory); - virtual ~nsDownloadListener(); - - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_NSIDOWNLOAD - NS_DECL_NSIWEBPROGRESSLISTENER - -public: - //void BeginDownload(); - void InitDialog(); - - virtual void PauseDownload(); - virtual void ResumeDownload(); - virtual void CancelDownload(); - virtual void DownloadDone(); - virtual void DetachDownloadDisplay(); - -private: - - // These two are mutually exclusive - nsCOMPtr mWebPersist; // Our web persist object. - nsCOMPtr mHelperAppLauncher; // If we're talking to uriloader - - nsCOMPtr mURI; // The URI of our source file. Null if we're saving a complete document. - nsCOMPtr mDestination; // Our destination URL. - PRInt64 mStartTime; // When the download started - PRPackedBool mBypassCache; // Whether we should bypass the cache or not. - PRPackedBool mNetworkTransfer; // true if the first OnStateChange has the NETWORK bit set - PRPackedBool mGotFirstStateChange; // true after we've seen the first OnStateChange - PRPackedBool mUserCanceled; // true if the user canceled the download -}; - diff --git a/chimera/src/download/nsDownloadListener.mm b/chimera/src/download/nsDownloadListener.mm index 8acb6b28c53..0fb52f20c6a 100644 --- a/chimera/src/download/nsDownloadListener.mm +++ b/chimera/src/download/nsDownloadListener.mm @@ -21,7 +21,7 @@ * * Contributor(s): * Simon Fraser - * + * Calum Robinson * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -46,20 +46,25 @@ #include "nsIURL.h" #include "netCore.h" -nsDownloadListener::nsDownloadListener(DownloadControllerFactory* inControllerFactory) -: CHDownloader(inControllerFactory) +nsDownloadListener::nsDownloadListener() +: mDownloadStatus(NS_OK) , mBypassCache(PR_FALSE) , mNetworkTransfer(PR_FALSE) , mGotFirstStateChange(PR_FALSE) , mUserCanceled(PR_FALSE) +, mSentCancel(PR_FALSE) { + mStartTime = LL_ZERO; } nsDownloadListener::~nsDownloadListener() { + // if we go away before the timer fires, cancel it + if (mEndRefreshTimer) + mEndRefreshTimer->Cancel(); } -NS_IMPL_ISUPPORTS_INHERITED2(nsDownloadListener, CHDownloader, nsIDownload, nsIWebProgressListener) +NS_IMPL_ISUPPORTS_INHERITED3(nsDownloadListener, CHDownloader, nsIDownload, nsIWebProgressListener, nsITimerCallback) #pragma mark - @@ -193,14 +198,14 @@ nsDownloadListener::OnProgressChange(nsIWebProgress *aWebProgress, PRInt32 aCurTotalProgress, PRInt32 aMaxTotalProgress) { - if (mUserCanceled) + if (mUserCanceled && !mSentCancel) { if (mHelperAppLauncher) mHelperAppLauncher->Cancel(); else if (aRequest) aRequest->Cancel(NS_BINDING_ABORTED); - mUserCanceled = false; + mSentCancel = PR_TRUE; } [mDownloadDisplay setProgressTo:aCurTotalProgress ofMax:aMaxTotalProgress]; @@ -236,7 +241,7 @@ nsDownloadListener::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *a // Implementation of nsIWebProgressListener /* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aStateFlags, in unsigned long aStatus); */ NS_IMETHODIMP -nsDownloadListener::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 aStateFlags, +nsDownloadListener::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 aStateFlags, PRUint32 aStatus) { // NSLog(@"State changed: state %u, status %u", aStateFlags, aStatus); @@ -250,29 +255,64 @@ nsDownloadListener::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRe // the window and controller. We will get this even in the event of a cancel, // so this is the only place in the listener where we should kill the download. if ((aStateFlags & STATE_STOP) && (!mNetworkTransfer || (aStateFlags & STATE_IS_NETWORK))) { - DownloadDone(); + DownloadDone(aStatus); } return NS_OK; } #pragma mark - +// nsITimerCallback implementation +NS_IMETHODIMP nsDownloadListener::Notify(nsITimer *timer) +{ + // resset the destination, since uniquifying the filename may have + // changed it + nsAutoString pathStr; + mDestination->GetPath(pathStr); + [mDownloadDisplay setDestinationPath: [NSString stringWith_nsAString:pathStr]]; + + // cancelling should give us a failure status + [mDownloadDisplay onEndDownload:(NS_SUCCEEDED(mDownloadStatus) && !mUserCanceled)]; + mEndRefreshTimer = NULL; + return NS_OK; +} + +#pragma mark - + void nsDownloadListener::InitDialog() { // dialog has to be shown before the outlets get hooked up - [mDownloadDisplay onStartDownload:(BOOL)IsFileSave()]; - if (mURI) { nsCAutoString spec; - mURI->GetSpec(spec); + + // we need to be careful not to show a password in the url + nsCAutoString userPassword; + mURI->GetUserPass(userPassword); + if (!userPassword.IsEmpty()) + { + // ugh, build it by hand + nsCAutoString hostport, path; + mURI->GetScheme(spec); + mURI->GetHostPort(hostport); + mURI->GetPath(path); + + spec.Append("://"); + spec.Append(hostport); + spec.Append(path); + } + else + mURI->GetSpec(spec); + [mDownloadDisplay setSourceURL: [NSString stringWithUTF8String:spec.get()]]; } nsAutoString pathStr; mDestination->GetPath(pathStr); [mDownloadDisplay setDestinationPath: [NSString stringWith_nsAString:pathStr]]; + + [mDownloadDisplay onStartDownload:IsFileSave()]; } void @@ -292,19 +332,19 @@ nsDownloadListener::CancelDownload() { mUserCanceled = PR_TRUE; - if (mWebPersist) + if (mWebPersist && !mSentCancel) { mWebPersist->CancelSave(); - mUserCanceled = PR_FALSE; + mSentCancel = PR_TRUE; } // delete any files we've created... - + // DownloadDone will get called (eventually) } void -nsDownloadListener::DownloadDone() +nsDownloadListener::DownloadDone(nsresult aStatus) { // break the reference cycle by removing ourselves as a listener if (mWebPersist) @@ -314,8 +354,23 @@ nsDownloadListener::DownloadDone() } mHelperAppLauncher = nsnull; - - [mDownloadDisplay onEndDownload]; + mDownloadStatus = aStatus; + + // hack alert! + // Our destination file gets uniquified after the OnStop notification is sent + // (in nsExternalAppHandler::ExecuteDesiredAction), so we never get a chance + // to figure out the final filename. To work around this, set a timer to fire + // in the near future, from which we'll send the done callback. + mEndRefreshTimer = do_CreateInstance("@mozilla.org/timer;1"); + if (mEndRefreshTimer) + { + nsresult rv = mEndRefreshTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT); // defaults to 1-shot, normal priority + if (NS_FAILED(rv)) + mEndRefreshTimer = NULL; + } + + if (!mEndRefreshTimer) // timer creation or init failed, so just do it now + [mDownloadDisplay onEndDownload:(NS_SUCCEEDED(aStatus) && !mUserCanceled)]; } // diff --git a/chimera/src/embedding/CHBrowserService.mm b/chimera/src/embedding/CHBrowserService.mm index 0026795c567..6c0133b34e2 100644 --- a/chimera/src/embedding/CHBrowserService.mm +++ b/chimera/src/embedding/CHBrowserService.mm @@ -38,7 +38,6 @@ #import "NSString+Utils.h" #import "CHBrowserService.h" -#import "CHDownloadFactories.h" #import "CHBrowserView.h" #include "nsIWindowWatcher.h" @@ -107,14 +106,6 @@ CHBrowserService::InitEmbedding() static NS_DEFINE_CID(kHelperDlgCID, NS_HELPERAPPLAUNCHERDIALOG_CID); nsresult rv = cr->RegisterFactory(kHelperDlgCID, NS_IHELPERAPPLAUNCHERDLG_CLASSNAME, NS_IHELPERAPPLAUNCHERDLG_CONTRACTID, sSingleton); - - // replace the downloader with our own which does not rely on the xpfe downlaod manager - nsCOMPtr downloadFactory; - rv = NewDownloadListenerFactory(getter_AddRefs(downloadFactory)); - if (NS_FAILED(rv)) return rv; - - static NS_DEFINE_CID(kDownloadCID, NS_DOWNLOAD_CID); - rv = cr->RegisterFactory(kDownloadCID, "Download", NS_DOWNLOAD_CONTRACTID, downloadFactory); return rv; } diff --git a/chimera/src/embedding/CHBrowserView.h b/chimera/src/embedding/CHBrowserView.h index c7f87ee2b90..ff000640c7e 100644 --- a/chimera/src/embedding/CHBrowserView.h +++ b/chimera/src/embedding/CHBrowserView.h @@ -163,9 +163,8 @@ enum { // nsIWebBrowserSetup methods - (void)setProperty:(unsigned int)property toValue:(unsigned int)value; -- (void)saveDocument:(BOOL)focusedFrame filterView:(NSView*)aFilterView filterList: (NSPopUpButton*)aFilterList; -- (void)saveURL: (NSView*)aFilterView filterList: (NSPopUpButton*)aFilterList - url: (NSString*)aURLSpec suggestedFilename: (NSString*)aFilename; +- (void)saveDocument:(BOOL)focusedFrame filterView:(NSView*)aFilterView; +- (void)saveURL:(NSView*)aFilterView url: (NSString*)aURLSpec suggestedFilename: (NSString*)aFilename; - (void)printDocument; - (void)pageSetup; diff --git a/chimera/src/embedding/CHBrowserView.mm b/chimera/src/embedding/CHBrowserView.mm index 43feb519bee..4179f8260eb 100644 --- a/chimera/src/embedding/CHBrowserView.mm +++ b/chimera/src/embedding/CHBrowserView.mm @@ -430,7 +430,6 @@ const char kDirServiceContractID[] = "@mozilla.org/file/directory_service;1"; suggestedFilename: (NSString*)aFileName bypassCache: (BOOL)aBypassCache filterView: (NSView*)aFilterView - filterList: (NSPopUpButton*)aFilterList { // Create our web browser persist object. This is the object that knows // how to actually perform the saving of the page (and of the images @@ -477,7 +476,7 @@ const char kDirServiceContractID[] = "@mozilla.org/file/directory_service;1"; [aFileName assignTo_nsAString:fileName]; nsHeaderSniffer* sniffer = new nsHeaderSniffer(webPersist, tmpFile, aURI, aDocument, postData, fileName, aBypassCache, - aFilterView, aFilterList); + aFilterView); if (!sniffer) return; webPersist->SetProgressListener(sniffer); // owned @@ -572,8 +571,7 @@ const char kDirServiceContractID[] = "@mozilla.org/file/directory_service;1"; return found; } -- (void)saveURL: (NSView*)aFilterView filterList: (NSPopUpButton*)aFilterList - url: (NSString*)aURLSpec suggestedFilename: (NSString*)aFilename +- (void)saveURL: (NSView*)aFilterView url: (NSString*)aURLSpec suggestedFilename: (NSString*)aFilename { nsCOMPtr url; nsresult rv = NS_NewURI(getter_AddRefs(url), [aURLSpec UTF8String]); @@ -584,8 +582,7 @@ const char kDirServiceContractID[] = "@mozilla.org/file/directory_service;1"; withDocument: nsnull suggestedFilename: aFilename bypassCache: YES - filterView: aFilterView - filterList: aFilterList]; + filterView: aFilterView]; } -(NSString*)getFocusedURLString @@ -616,7 +613,7 @@ const char kDirServiceContractID[] = "@mozilla.org/file/directory_service;1"; return [NSString stringWith_nsAString: urlStr]; } -- (void)saveDocument:(BOOL)focusedFrame filterView:(NSView*)aFilterView filterList: (NSPopUpButton*)aFilterList +- (void)saveDocument:(BOOL)focusedFrame filterView:(NSView*)aFilterView { if (!_webBrowser) return; @@ -656,8 +653,7 @@ const char kDirServiceContractID[] = "@mozilla.org/file/directory_service;1"; withDocument: domDocument suggestedFilename: @"" bypassCache: NO - filterView: aFilterView - filterList: aFilterList]; + filterView: aFilterView]; } -(void)doCommand:(const char*)commandName diff --git a/chimera/src/embedding/CHDownloadProgressDisplay.h b/chimera/src/embedding/CHDownloadProgressDisplay.h index 03b8e659354..e69de29bb2d 100644 --- a/chimera/src/embedding/CHDownloadProgressDisplay.h +++ b/chimera/src/embedding/CHDownloadProgressDisplay.h @@ -1,167 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Chimera code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 2002 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Simon Fraser - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/* - The classes and protocol in this file allow Cocoa applications to easily - reuse the underlying download implementation, which deals with the complexity - of Gecko's downloading callbacks. - - There are three things here: - - 1. The CHDownloadProgressDisplay protocol. - - This is a formal protocol that needs to be implemented by - a window controller for your progress window. Its methods - will be called by the underlying C++ downloading classes. - - 2. The Obj-C DownloadControllerFactory class. - - This class should be subclassed by an embedder, with an - implementation of 'createDownloadController' that hands back - a new instance of an NSWindowController that implements the - protocol. - - The underlying C++ classes use this factory to create the - progress window controller. - - 3. The CHDownloader C++ class - - This base class exists to hide the complextity of the download - listener classes (which deal with Gecko callbacks) from the - window controller. Embedders don't need to do anything with it. - - How these classes fit together: - - There are 2 ways in which a download is initiated: - - (i) File->Save. - - Chimera does a complex dance here in order to get certain - information about the data being downloaded (it needs to - start the download before it can read some optional MIME headers). - - CBrowserView creates an nsIWebBrowserPersist (WBP), and then a - nsHeaderSniffer, which implements nsIWebProgressListener and is set to - observer the WBP. When nsHeaderSniffer hears about the start of the - download, it decides on a file name, and what format to save the data - in. It then cancels the current WPB, makes another one, and does - a CreateInstance of an nsIDownload (making one of our nsDownloadListener - -- aka nsDownloder -- objects), and sets that as the nsIWebProgressListener. - The full download procedes from there. - - (ii) Click to download (e.g. FTP link) - - This is simpler. The backend (necko) does the CreateInstance of the - nsIDownload, and the download progresses. - - In both cases, creating the nsDownloadListener and calling its Init() method - calls nsDownloder::CreateDownloadDisplay(). The nsDownloder has as a member - variable a DownloadControllerFactory (see above), which got passed to it - via our XPCOM factory for nsIDownload objects. It then uses that DownloadControllerFactory - to get an instance of the download progress window controller, which then - shows the download progress window. - - Simple, eh? - -*/ - -#import - -#include "nsISupports.h" - -class CHDownloader; - -// a formal protocol for something that implements progress display -// Embedders can make a window controller that conforms to this -// protocol, and reuse nsDownloadListener to get download UI. -@protocol CHDownloadProgressDisplay - -- (void)onStartDownload:(BOOL)isFileSave; -- (void)onEndDownload; - -- (void)setProgressTo:(long)aCurProgress ofMax:(long)aMaxProgress; - -- (void)setDownloadListener:(CHDownloader*)aDownloader; -- (void)setSourceURL:(NSString*)aSourceURL; -- (void)setDestinationPath:(NSString*)aDestPath; - -@end - -// subclass this, and have your subclass instantiate and return your window -// controller in createDownloadController -@interface DownloadControllerFactory : NSObject -{ -} - -- (NSWindowController *)createDownloadController; - -@end - - -// Pure virtual base class for a generic downloader, that the progress UI can talk to. -// It implements nsISupports so that it can be refcounted. This class insulates the -// UI code from having to know too much about the nsIDownloadListener. -// It is responsible for creating the download UI, via the DownloadControllerFactory -// that it owns. -class CHDownloader : public nsISupports -{ -public: - CHDownloader(DownloadControllerFactory* inControllerFactory); - virtual ~CHDownloader(); - - NS_DECL_ISUPPORTS - - virtual void PauseDownload() = 0; - virtual void ResumeDownload() = 0; - virtual void CancelDownload() = 0; - virtual void DownloadDone() = 0; - virtual void DetachDownloadDisplay() = 0; // tell downloader to forget about its display - - virtual void CreateDownloadDisplay(); - -protected: - - PRBool IsFileSave() { return mIsFileSave; } - void SetIsFileSave(PRBool inIsFileSave) { mIsFileSave = inIsFileSave; } - -protected: - - DownloadControllerFactory* mControllerFactory; - id mDownloadDisplay; // something that implements the CHDownloadProgressDisplay protocol - PRBool mIsFileSave; // true if we're doing a save, rather than a download -}; - diff --git a/chimera/src/embedding/CHDownloadProgressDisplay.mm b/chimera/src/embedding/CHDownloadProgressDisplay.mm index 3f384b9fa90..e69de29bb2d 100644 --- a/chimera/src/embedding/CHDownloadProgressDisplay.mm +++ b/chimera/src/embedding/CHDownloadProgressDisplay.mm @@ -1,76 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Chimera code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 2002 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Simon Fraser - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#import "CHDownloadProgressDisplay.h" - - -@implementation DownloadControllerFactory - -- (NSWindowController *)createDownloadController -{ - // a dummy implementation. You should provide a subclass that - // returns an instance of your progress dialog controller. - return nil; -} - -@end - -#pragma mark - - -// see the header file for comments -CHDownloader::CHDownloader(DownloadControllerFactory* inControllerFactory) -: mControllerFactory(inControllerFactory) -, mDownloadDisplay(nil) -, mIsFileSave(PR_FALSE) -{ - NS_INIT_ISUPPORTS(); - [mControllerFactory retain]; -} - -CHDownloader::~CHDownloader() -{ - [mControllerFactory release]; -} - -NS_IMPL_ISUPPORTS1(CHDownloader, nsISupports); - -void -CHDownloader::CreateDownloadDisplay() -{ - mDownloadDisplay = [mControllerFactory createDownloadController]; - [mDownloadDisplay setDownloadListener:this]; -} diff --git a/chimera/src/extensions/CHStackView.h b/chimera/src/extensions/CHStackView.h new file mode 100644 index 00000000000..e69de29bb2d diff --git a/chimera/src/extensions/CHStackView.m b/chimera/src/extensions/CHStackView.m new file mode 100644 index 00000000000..e69de29bb2d diff --git a/chimera/src/extensions/NSView+Utils.h b/chimera/src/extensions/NSView+Utils.h new file mode 100644 index 00000000000..e69de29bb2d diff --git a/chimera/src/extensions/NSView+Utils.m b/chimera/src/extensions/NSView+Utils.m new file mode 100644 index 00000000000..e69de29bb2d diff --git a/chimera/src/extensions/RDFOutlineViewDataSource.h b/chimera/src/extensions/RDFOutlineViewDataSource.h index f75ab400132..81c6ce491ce 100644 --- a/chimera/src/extensions/RDFOutlineViewDataSource.h +++ b/chimera/src/extensions/RDFOutlineViewDataSource.h @@ -51,24 +51,31 @@ class nsIRDFService; @interface RDFOutlineViewItem : NSObject { nsIRDFResource* mResource; + unsigned int mCacheVersion; // if matches the cache version in the data source, + // cached values are valid + BOOL mExpandable; + int mNumChildren; + NSArray* mChildNodes; } -- (nsIRDFResource*) resource; -- (void) setResource: (nsIRDFResource*) aResource; +- (nsIRDFResource*)resource; // addRefs the result +- (void)setResource:(nsIRDFResource*) aResource; @end -@interface RDFOutlineViewDataSource : NSObject { - nsIRDFDataSource* mDataSource; - nsIRDFContainer* mContainer; - nsIRDFContainerUtils* mContainerUtils; - nsIRDFResource* mRootResource; - nsIRDFService* mRDFService; +@interface RDFOutlineViewDataSource : NSObject +{ + nsIRDFDataSource* mDataSource; + nsIRDFContainer* mContainer; + nsIRDFContainerUtils* mContainerUtils; + nsIRDFResource* mRootResource; + nsIRDFService* mRDFService; - IBOutlet ExtendedOutlineView* mOutlineView; + IBOutlet ExtendedOutlineView* mOutlineView; - NSMutableDictionary* mDictionary; + NSMutableDictionary* mDictionary; + unsigned int mCacheVersion; } // Initialization Methods @@ -85,7 +92,6 @@ class nsIRDFService; - (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item; - (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item; - (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item; -- (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item; // tooltip support from the ExtendedOutlineView. Override to provide a tooltip // other than the Name property for each item in the view. @@ -94,14 +100,14 @@ class nsIRDFService; - (void)reloadDataForItem:(id)item reloadChildren: (BOOL)aReloadChildren; // Implementation Methods -- (id) makeWrapperFor: (nsIRDFResource*) aRDFResource; +- (id)getWrapperFor:(nsIRDFResource*) aRDFResource; +- (void)invalidateCachedItems; // override to do something different with the cell data rather than just // return a string (add an icon in an attributed string, for example). --(id) createCellContents:(const nsAString&)inValue withColumn:(NSString*)inColumn byItem:(id) inItem; +- (id)createCellContents:(NSString*)inValue withColumn:(NSString*)inColumn byItem:(id)inItem; --(void) getPropertyString:(NSString*)inPropertyURI forItem:(RDFOutlineViewItem*)inItem - result:(PRUnichar**)outResult; +- (NSString*)getPropertyString:(NSString*)inPropertyURI forItem:(RDFOutlineViewItem*)inItem; @end diff --git a/chimera/src/extensions/RDFOutlineViewDataSource.mm b/chimera/src/extensions/RDFOutlineViewDataSource.mm index 9b5993d91d1..a293b6a23b2 100644 --- a/chimera/src/extensions/RDFOutlineViewDataSource.mm +++ b/chimera/src/extensions/RDFOutlineViewDataSource.mm @@ -41,6 +41,7 @@ #import "RDFOutlineViewDataSource.h" #import "CHBrowserService.h" +#include "nsCRT.h" #include "nsIRDFDataSource.h" #include "nsIRDFService.h" #include "nsIRDFLiteral.h" @@ -55,14 +56,116 @@ #include "nsXPIDLString.h" #include "nsString.h" -@interface RDFOutlineViewDataSource(Private); -- (void)registerForShutdownNotification; -- (void)cleanup; +@interface RDFOutlineViewItem(Private) + +- (unsigned int)cacheVersion; +- (void)setNumChildren:(int)numChildren isExpandable:(BOOL)expandable cacheVersion:(unsigned int)version; +- (void)setChildren:(NSArray*)childArray; +- (BOOL)cacheValid:(unsigned int)version needChildren:(BOOL)needChildren; +- (BOOL)cachedChildren; + +- (BOOL)isExpandable; +- (int)numChildren; +- (id)childAtIndex:(int)index; @end +@implementation RDFOutlineViewItem + +- (id)init +{ + if ((self = [super init])) + { + mCacheVersion = 0; + mExpandable = NO; + mNumChildren = 0; + } + return self; +} + +- (void)dealloc +{ + [mChildNodes release]; + NS_IF_RELEASE(mResource); + [super dealloc]; +} + +- (nsIRDFResource*)resource +{ + NS_IF_ADDREF(mResource); + return mResource; +} + +- (void)setResource:(nsIRDFResource*) aResource +{ + nsIRDFResource* oldResource = mResource; + NS_IF_ADDREF(mResource = aResource); + NS_IF_RELEASE(oldResource); +} + +- (unsigned int)cacheVersion +{ + return mCacheVersion; +} + +- (void)setNumChildren:(int)numChildren isExpandable:(BOOL)expandable cacheVersion:(unsigned int)version; +{ + mNumChildren = numChildren; + mExpandable = expandable; + mCacheVersion = version; +} + +- (void)setChildren:(NSArray*)childArray +{ + // childArray can legally be nil here. If it is, we're clearing the cached children + NSArray* oldChildren = mChildNodes; + mChildNodes = childArray; + [mChildNodes retain]; + [oldChildren release]; +} + +- (BOOL)cacheValid:(unsigned int)version needChildren:(BOOL)needChildren; +{ + return (mCacheVersion == version) && (needChildren ? (mChildNodes != nil) : 1); +} + +- (BOOL)cachedChildren +{ + return (mChildNodes != nil); +} + +- (BOOL)isExpandable +{ + return mExpandable; +} + +- (int)numChildren +{ + return mNumChildren; +} + +- (id)childAtIndex:(int)index +{ + if (mChildNodes) + return [mChildNodes objectAtIndex:index]; + + return nil; +} + +@end + +#pragma mark - + +@interface RDFOutlineViewDataSource(Private) + +- (void)registerForShutdownNotification; +- (void)cleanup; +- (void)updateItemProperties:(id)item enumerateChildren:(BOOL)doChildren; + +@end + @implementation RDFOutlineViewDataSource - (id)init @@ -70,6 +173,7 @@ if ((self = [super init])) { [self registerForShutdownNotification]; + mCacheVersion = 1; } return self; } @@ -78,7 +182,7 @@ { [[NSNotificationCenter defaultCenter] removeObserver:self]; - [self cleanup]; + [self cleanup]; [super dealloc]; } @@ -167,123 +271,62 @@ // XXX - For now, we'll just say that none of our items are editable, as we aren't using any // RDF datasources that are mutable. // -- (BOOL) outlineView: (NSOutlineView*) aOutlineView shouldEditTableColumn: (NSTableColumn*) aTableColumn +- (BOOL) outlineView: (NSOutlineView*)aOutlineView shouldEditTableColumn: (NSTableColumn*) aTableColumn item: (id) aItem { - return NO; + return NO; } -- (BOOL) outlineView: (NSOutlineView*) aOutlineView isItemExpandable: (id) aItem +- (BOOL) outlineView: (NSOutlineView*)aOutlineView isItemExpandable:(id)aItem { - if (!mDataSource) - return NO; - - if (!aItem) - return YES; // The root is always open - - nsCOMPtr itemResource = dont_AddRef([aItem resource]); - - PRBool isSeq = PR_FALSE; - mContainerUtils->IsSeq(mDataSource, itemResource, &isSeq); - if (isSeq) - return YES; - - nsCOMPtr childProperty; - mRDFService->GetResource("http://home.netscape.com/NC-rdf#child", getter_AddRefs(childProperty)); - - nsCOMPtr childNode; - mDataSource->GetTarget(itemResource, childProperty, PR_TRUE, getter_AddRefs(childNode)); - - return childNode != nsnull; + if (!mDataSource) + return NO; + + if (!aItem) + return YES; // The root is always open + + if (![aItem cacheValid:mCacheVersion needChildren:NO]) + [self updateItemProperties:aItem enumerateChildren:NO]; + + return [aItem isExpandable]; } -- (id) outlineView: (NSOutlineView*) aOutlineView child: (int) aIndex - ofItem: (id) aItem +- (id)outlineView:(NSOutlineView*)aOutlineView child:(int)aIndex ofItem:(id)aItem { - if (!mDataSource) - return nil; + if (!mDataSource) + return nil; + + if (!aItem) + { + nsCOMPtr rootResource = dont_AddRef([self rootResource]); + aItem = [self getWrapperFor:rootResource]; + } + + if (![aItem cacheValid:mCacheVersion needChildren:YES]) + [self updateItemProperties:aItem enumerateChildren:YES]; - nsCOMPtr resource = !aItem ? dont_AddRef([self rootResource]) : dont_AddRef([aItem resource]); - - nsCOMPtr ordinalResource; - mContainerUtils->IndexToOrdinalResource(aIndex + 1, getter_AddRefs(ordinalResource)); - - nsCOMPtr childNode; - mDataSource->GetTarget(resource, ordinalResource, PR_TRUE, getter_AddRefs(childNode)); - if (childNode) { - // Yay. A regular container. We don't need to count, we can go directly to - // our object. - nsCOMPtr childResource(do_QueryInterface(childNode)); - if (childResource) - return [self makeWrapperFor:childResource]; - } - else - { - // Oh well, not a regular container. We need to count, dagnabbit. - nsCOMPtr childProperty; - mRDFService->GetResource("http://home.netscape.com/NC-rdf#child", getter_AddRefs(childProperty)); - - nsCOMPtr childNodes; - mDataSource->GetTargets(resource, childProperty, PR_TRUE, getter_AddRefs(childNodes)); - - nsCOMPtr supp; - PRInt32 count = 0; - - PRBool hasMore = PR_FALSE; - while (NS_SUCCEEDED(childNodes->HasMoreElements(&hasMore)) && hasMore) - { - childNodes->GetNext(getter_AddRefs(supp)); - if (count == aIndex) - break; - count ++; - } - - nsCOMPtr childResource(do_QueryInterface(supp)); - if (childResource) { - return [self makeWrapperFor:childResource]; - } - } - - return nil; + return [aItem childAtIndex:aIndex]; } -- (int) outlineView: (NSOutlineView*) aOutlineView numberOfChildrenOfItem: (id) aItem; +- (int)outlineView:(NSOutlineView*)aOutlineView numberOfChildrenOfItem:(id) aItem; { - if (!mDataSource) - return 0; - - nsCOMPtr resource = dont_AddRef(aItem ? [aItem resource] : [self rootResource]); - - // XXX just assume NC:child is the only containment arc for now - nsCOMPtr childProperty; - mRDFService->GetResource("http://home.netscape.com/NC-rdf#child", getter_AddRefs(childProperty)); - - nsCOMPtr childNodes; - mDataSource->GetTargets(resource, childProperty, PR_TRUE, getter_AddRefs(childNodes)); - - PRBool hasMore = PR_FALSE; - PRInt32 count = 0; - - while (NS_SUCCEEDED(childNodes->HasMoreElements(&hasMore)) && hasMore) - { - nsCOMPtr supp; - childNodes->GetNext(getter_AddRefs(supp)); - count ++; - } - - if (count == 0) { - nsresult rv = mContainer->Init(mDataSource, resource); - if (NS_FAILED(rv)) - return 0; - - mContainer->GetCount(&count); - } - - return count; + if (!mDataSource) + return 0; + + if (!aItem) + { + nsCOMPtr rootResource = dont_AddRef([self rootResource]); + aItem = [self getWrapperFor:rootResource]; + } + + if (![aItem cacheValid:mCacheVersion needChildren:YES]) + [self updateItemProperties:aItem enumerateChildren:YES]; + + return [aItem numChildren]; } -- (id) outlineView: (NSOutlineView*) aOutlineView objectValueForTableColumn: (NSTableColumn*) aTableColumn - byItem: (id) aItem +- (id)outlineView:(NSOutlineView*)aOutlineView objectValueForTableColumn:(NSTableColumn*)aTableColumn + byItem:(id)aItem { if (!mDataSource || !aItem) return nil; @@ -291,25 +334,22 @@ // The table column's identifier is the RDF Resource URI of the property being displayed in // that column, e.g. "http://home.netscape.com/NC-rdf#Name" NSString* columnPropertyURI = [aTableColumn identifier]; - nsXPIDLString literalValue; - [self getPropertyString:columnPropertyURI forItem:aItem result:getter_Copies(literalValue)]; + NSString* propString = [self getPropertyString:columnPropertyURI forItem:aItem]; - return [self createCellContents:literalValue withColumn:columnPropertyURI byItem:aItem]; + return [self createCellContents:propString withColumn:columnPropertyURI byItem:aItem]; } - // // createCellContents:withColumn:byItem // // Constructs a NSString from the given string data for this item in the given column. // This should be overridden to do more fancy things, such as add an icon, etc. // --(id) createCellContents:(const nsAString&)inValue withColumn:(NSString*)inColumn byItem:(id) inItem +- (id)createCellContents:(NSString*)inValue withColumn:(NSString*)inColumn byItem:(id)inItem { - return [NSString stringWith_nsAString: inValue]; + return inValue; } - // // outlineView:tooltipForString // @@ -318,21 +358,9 @@ // - (NSString *)outlineView:(NSOutlineView *)outlineView tooltipStringForItem:(id)inItem { - nsXPIDLString literalValue; - [self getPropertyString:@"http://home.netscape.com/NC-rdf#Name" forItem:inItem result:getter_Copies(literalValue)]; - return [NSString stringWith_nsAString:literalValue]; + return [self getPropertyString:@"http://home.netscape.com/NC-rdf#Name" forItem:inItem]; } - -- (void) outlineView: (NSOutlineView*) aOutlineView setObjectValue: (id) aObject - forTableColumn: (NSTableColumn*) aTableColumn - byItem: (id) aItem -{ - -} - - - - (void) reloadDataForItem: (id) aItem reloadChildren: (BOOL) aReloadChildren { if (!aItem) @@ -341,7 +369,7 @@ [mOutlineView reloadItem: aItem reloadChildren: aReloadChildren]; } -- (id) makeWrapperFor: (nsIRDFResource*) aRDFResource +- (id)getWrapperFor:(nsIRDFResource*) aRDFResource { const char* k; aRDFResource->GetValueConst(&k); @@ -350,8 +378,9 @@ // see if we've created a wrapper already, if not, create a new wrapper object // and stash it in our dictionary RDFOutlineViewItem* item = [mDictionary objectForKey:key]; - if (!item) { - item = [[RDFOutlineViewItem alloc] init]; + if (!item) + { + item = [[[RDFOutlineViewItem alloc] init] autorelease]; [item setResource: aRDFResource]; [mDictionary setObject:item forKey:key]; // retains |item| } @@ -359,14 +388,56 @@ return item; } - --(void) getPropertyString:(NSString*)inPropertyURI forItem:(RDFOutlineViewItem*)inItem - result:(PRUnichar**)outResult +- (void)invalidateCachedItems { - if ( !outResult ) - return; - *outResult = nil; + mCacheVersion++; +} + +- (void)updateItemProperties:(id)item enumerateChildren:(BOOL)doChildren +{ + BOOL isExpandable = NO; + NSMutableArray* itemChildren = doChildren ? [[[NSMutableArray alloc] initWithCapacity:10] autorelease] : nil; + nsCOMPtr itemResource = dont_AddRef([item resource]); + + PRBool isSeq = PR_FALSE; + mContainerUtils->IsSeq(mDataSource, itemResource, &isSeq); + if (isSeq) + isExpandable = YES; + + nsCOMPtr childProperty; + mRDFService->GetResource("http://home.netscape.com/NC-rdf#child", getter_AddRefs(childProperty)); + + nsCOMPtr childNodes; + mDataSource->GetTargets(itemResource, childProperty, PR_TRUE, getter_AddRefs(childNodes)); + + PRBool hasMore = PR_FALSE; + while (NS_SUCCEEDED(childNodes->HasMoreElements(&hasMore)) && hasMore) + { + nsCOMPtr supp; + childNodes->GetNext(getter_AddRefs(supp)); + + nsCOMPtr childResource = do_QueryInterface(supp); + if (childResource) + { + id childItem = [self getWrapperFor:childResource]; + if (childItem) + { + isExpandable = YES; + if (!itemChildren) break; // know enough already + [itemChildren addObject:childItem]; + } + } + } + + // itemChildren will be nil here if we don't care about children, but that's OK. + // the setChildren call will clear the cached child list. + [item setNumChildren:[itemChildren count] isExpandable:isExpandable cacheVersion:mCacheVersion]; + [item setChildren:itemChildren]; +} + +- (NSString*)getPropertyString:(NSString*)inPropertyURI forItem:(RDFOutlineViewItem*)inItem +{ nsCOMPtr propertyResource; mRDFService->GetResource([inPropertyURI UTF8String], getter_AddRefs(propertyResource)); @@ -378,38 +449,20 @@ #if DEBUG NSLog(@"ValueNode is null in RDF objectValueForTableColumn"); #endif - return; + return @""; } nsCOMPtr valueLiteral(do_QueryInterface(valueNode)); if (!valueLiteral) - return; + return @""; - valueLiteral->GetValue(outResult); + const PRUnichar* value = NULL; + valueLiteral->GetValueConst(&value); + if (value) + return [NSString stringWithCharacters:value length:nsCRT::strlen(value)]; + + return @""; } -@end - -@implementation RDFOutlineViewItem - -- (void) dealloc -{ - NS_IF_RELEASE(mResource); - [super dealloc]; -} - -- (nsIRDFResource*) resource -{ - NS_IF_ADDREF(mResource); - return mResource; -} - -- (void) setResource: (nsIRDFResource*) aResource -{ - nsIRDFResource* oldResource = mResource; - NS_IF_ADDREF(mResource = aResource); - NS_IF_RELEASE(oldResource); -} - @end diff --git a/chimera/src/history/HistoryDataSource.h b/chimera/src/history/HistoryDataSource.h index ac3e29f437b..e69de29bb2d 100644 --- a/chimera/src/history/HistoryDataSource.h +++ b/chimera/src/history/HistoryDataSource.h @@ -1,65 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: NPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Netscape Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 2002 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Ben Goodger (Original Author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the NPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the NPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#import - -#import "RDFOutlineViewDataSource.h" - -class nsAString; -class HistoryDataSourceObserver; - -@class BrowserWindowController; - -@interface HistoryDataSource : RDFOutlineViewDataSource -{ - HistoryDataSourceObserver* mObserver; // STRONG ref, should be nsCOMPtr but can't - IBOutlet BrowserWindowController* mBrowserWindowController; -} - -// overridden to create a attributed string with icon --(id) createCellContents:(const nsAString&)inValue withColumn:(NSString*)inColumn byItem:(id) inItem; - -- (NSString *)outlineView:(NSOutlineView *)outlineView tooltipStringForItem:(id)inItem; - --(void) enableObserver; --(void) disableObserver; - --(IBAction)openHistoryItem: (id)aSender; --(IBAction)deleteHistoryItems: (id)aSender; - -@end diff --git a/chimera/src/history/HistoryDataSource.mm b/chimera/src/history/HistoryDataSource.mm index f1d040f99df..52a7a4bf7c3 100644 --- a/chimera/src/history/HistoryDataSource.mm +++ b/chimera/src/history/HistoryDataSource.mm @@ -63,33 +63,29 @@ class HistoryDataSourceObserver : public nsIRDFObserver { public: - HistoryDataSourceObserver(NSOutlineView* outlineView) : - mOutlineView(outlineView), mEnabled(false) + HistoryDataSourceObserver(HistoryDataSource* dataSource) + : mHistoryDataSource(dataSource) { NS_INIT_ISUPPORTS(); } - virtual ~HistoryDataSourceObserver() { } ; + virtual ~HistoryDataSourceObserver() { } NS_DECL_ISUPPORTS - NS_IMETHODIMP OnAssert(nsIRDFDataSource*, nsIRDFResource*, nsIRDFResource*, nsIRDFNode*) ; - NS_IMETHODIMP OnUnassert(nsIRDFDataSource*, nsIRDFResource*, nsIRDFResource*, nsIRDFNode*) { return NS_OK; } + NS_IMETHOD OnAssert(nsIRDFDataSource*, nsIRDFResource*, nsIRDFResource*, nsIRDFNode*); + NS_IMETHOD OnUnassert(nsIRDFDataSource*, nsIRDFResource*, nsIRDFResource*, nsIRDFNode*); - NS_IMETHODIMP OnMove(nsIRDFDataSource*, nsIRDFResource*, nsIRDFResource*, nsIRDFResource*, nsIRDFNode*) + NS_IMETHOD OnMove(nsIRDFDataSource*, nsIRDFResource*, nsIRDFResource*, nsIRDFResource*, nsIRDFNode*) { return NS_OK; } - NS_IMETHODIMP OnChange(nsIRDFDataSource*, nsIRDFResource*, nsIRDFResource*, nsIRDFNode*, nsIRDFNode*); + NS_IMETHOD OnChange(nsIRDFDataSource*, nsIRDFResource*, nsIRDFResource*, nsIRDFNode*, nsIRDFNode*); - NS_IMETHODIMP BeginUpdateBatch(nsIRDFDataSource*) { return NS_OK; } - NS_IMETHODIMP EndUpdateBatch(nsIRDFDataSource*) { return NS_OK; } - - void Enable() { mEnabled = true; } - void Disable() { mEnabled = false; } + NS_IMETHOD BeginUpdateBatch(nsIRDFDataSource*) { return NS_OK; } + NS_IMETHOD EndUpdateBatch(nsIRDFDataSource*) { return NS_OK; } private: - NSOutlineView* mOutlineView; - bool mEnabled; + HistoryDataSource* mHistoryDataSource; }; NS_IMPL_ISUPPORTS1(HistoryDataSourceObserver, nsIRDFObserver) @@ -105,15 +101,30 @@ NS_IMETHODIMP HistoryDataSourceObserver::OnAssert(nsIRDFDataSource*, nsIRDFResource*, nsIRDFResource* aProperty, nsIRDFNode*) { - if(mEnabled) { - const char* p; - aProperty->GetValueConst(&p); - if (strcmp("http://home.netscape.com/NC-rdf#Date", p) == 0) - [mOutlineView reloadData]; - } + const char* p; + aProperty->GetValueConst(&p); + if (strcmp("http://home.netscape.com/NC-rdf#Date", p) == 0) + [mHistoryDataSource setNeedsRefresh:YES]; + return NS_OK; } +// +// OnUnassert +// +// This gets called on redirects, when nsGlobalHistory::RemovePage is called. +// +NS_IMETHODIMP +HistoryDataSourceObserver::OnUnassert(nsIRDFDataSource*, nsIRDFResource*, + nsIRDFResource* aProperty, nsIRDFNode*) +{ + const char* p; + aProperty->GetValueConst(&p); + if (strcmp("http://home.netscape.com/NC-rdf#Date", p) == 0) + [mHistoryDataSource setNeedsRefresh:YES]; + + return NS_OK; +} // // OnChange @@ -125,12 +136,12 @@ NS_IMETHODIMP HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*, nsIRDFResource* aProperty, nsIRDFNode*, nsIRDFNode*) { - if(mEnabled) { - const char* p; - aProperty->GetValueConst(&p); - if (strcmp("http://home.netscape.com/NC-rdf#Date", p) == 0) - [mOutlineView reloadData]; - } + const char* p; + aProperty->GetValueConst(&p); + + if (strcmp("http://home.netscape.com/NC-rdf#Date", p) == 0) + [mHistoryDataSource setNeedsRefresh:YES]; + return NS_OK; } @@ -138,7 +149,7 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*, @interface HistoryDataSource(Private) -- (void)cleanup; +- (void)cleanupHistory; @end @@ -146,12 +157,12 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*, - (void) dealloc { - [self cleanup]; + [self cleanupHistory]; [super dealloc]; } // "non-virtual" cleanup method -- safe to call from dealloc. -- (void)cleanup +- (void)cleanupHistory { if (mDataSource && mObserver) { @@ -163,7 +174,7 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*, // "virtual" method; called from superclass - (void)cleanupDataSource { - [self cleanup]; + [self cleanupHistory]; [super cleanupDataSource]; } @@ -181,7 +192,8 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*, NS_ASSERTION(mRDFService, "Uh oh, RDF service not loaded in parent class"); - if ( !mDataSource ) { + if ( !mDataSource ) + { // Get the Global History DataSource mRDFService->GetDataSource("rdf:history", &mDataSource); // Get the Date Folder Root @@ -191,14 +203,15 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*, [mOutlineView setDoubleAction: @selector(openHistoryItem:)]; [mOutlineView setDeleteAction: @selector(deleteHistoryItems:)]; - mObserver = new HistoryDataSourceObserver(mOutlineView); + mObserver = new HistoryDataSourceObserver(self); if ( mObserver ) { NS_ADDREF(mObserver); mDataSource->AddObserver(mObserver); } [mOutlineView reloadData]; } - else { + else + { // everything is loaded, but we have to refresh our tree otherwise // changes that took place while the drawer was closed won't be noticed [mOutlineView reloadData]; @@ -207,18 +220,41 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*, NS_ASSERTION(mDataSource, "Uh oh, History RDF Data source not created"); } -- (void) enableObserver +- (void)enableObserver { - if ( mObserver ) - mObserver->Enable(); + mUpdatesEnabled = YES; } --(void) disableObserver +-(void)disableObserver { - if ( mObserver ) - mObserver->Disable(); + mUpdatesEnabled = NO; } +- (void)setNeedsRefresh:(BOOL)needsRefresh +{ + mNeedsRefresh = needsRefresh; +} + +- (BOOL)needsRefresh +{ + return mNeedsRefresh; +} + +- (void)refresh +{ + if (mNeedsRefresh) + { + [self invalidateCachedItems]; + if (mUpdatesEnabled) + { + // this can be very slow! See bug 180109. + //NSLog(@"history reload started"); + [self reloadDataForItem:nil reloadChildren:NO]; + //NSLog(@"history reload done"); + } + mNeedsRefresh = NO; + } +} // // createCellContents:withColumn:byItem @@ -226,31 +262,29 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*, // override to create an NSAttributedString instead of just the string with the // given text. We add an icon and adjust the positioning of the text w/in the cell // --(id) createCellContents:(const nsAString&)inValue withColumn:(NSString*)inColumn byItem:(id) inItem +-(id) createCellContents:(NSString*)inValue withColumn:(NSString*)inColumn byItem:(id) inItem { - NSMutableAttributedString *cellValue = [[NSMutableAttributedString alloc] init]; - - //Set cell's textual contents - [cellValue replaceCharactersInRange:NSMakeRange(0, [cellValue length]) withString:[NSString stringWith_nsAString:inValue]]; + if ([inValue length] == 0) + inValue = [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:inItem]; - if ([inColumn isEqualToString: @"http://home.netscape.com/NC-rdf#Name"]) { - NSMutableAttributedString *attachmentAttrString = nil; - NSFileWrapper *fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents:nil]; - NSTextAttachment *textAttachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper]; - NSCell *attachmentAttrStringCell; + NSMutableAttributedString *cellValue = [[[NSMutableAttributedString alloc] initWithString:inValue] autorelease]; + + if ([inColumn isEqualToString:@"http://home.netscape.com/NC-rdf#Name"]) + { + NSFileWrapper *fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents:nil]; + NSTextAttachment *textAttachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper]; - //Create an attributed string to hold the empty attachment, then release the components. - attachmentAttrString = [[NSMutableAttributedString attributedStringWithAttachment:textAttachment] retain]; + // Create an attributed string to hold the empty attachment, then release the components. + NSMutableAttributedString *attachmentAttrString = [NSMutableAttributedString attributedStringWithAttachment:textAttachment]; [textAttachment release]; [fileWrapper release]; //Get the cell of the text attachment. - attachmentAttrStringCell = (NSCell *)[(NSTextAttachment *)[attachmentAttrString attribute: + NSCell* attachmentAttrStringCell = (NSCell *)[(NSTextAttachment *)[attachmentAttrString attribute: NSAttachmentAttributeName atIndex:0 effectiveRange:nil] attachmentCell]; - if ([self outlineView:mOutlineView isItemExpandable:inItem]) { + if ([self outlineView:mOutlineView isItemExpandable:inItem]) [attachmentAttrStringCell setImage:[NSImage imageNamed:@"folder"]]; - } else [attachmentAttrStringCell setImage:[NSImage imageNamed:@"smallbookmark"]]; @@ -298,11 +332,8 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*, id item = [toDrag objectAtIndex: 0]; // if we have just one item, we add some more flavours - nsXPIDLString urlLiteral, nameLiteral; - [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:item result:getter_Copies(urlLiteral)]; - [self getPropertyString:@"http://home.netscape.com/NC-rdf#Name" forItem:item result:getter_Copies(nameLiteral)]; - NSString* url = [NSString stringWith_nsAString: urlLiteral]; - NSString* title = [NSString stringWith_nsAString: nameLiteral]; + NSString* url = [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:item]; + NSString* title = [self getPropertyString:@"http://home.netscape.com/NC-rdf#Name" forItem:item]; NSString *cleanedTitle = [title stringByReplacingCharactersInSet:[NSCharacterSet controlCharacterSet] withString:@" "]; [pboard declareURLPasteboardWithAdditionalTypes:[NSArray array] owner:self]; @@ -340,11 +371,8 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*, return; } - nsXPIDLString urlLiteral; - [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:item result:getter_Copies(urlLiteral)]; - // get uri - NSString* url = [NSString stringWith_nsAString: urlLiteral]; + NSString* url = [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:item]; [[mBrowserWindowController getBrowserWrapper] loadURI: url referrer: nil flags: NSLoadFlagsNone activate:YES]; } @@ -376,14 +404,15 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*, index = [currIndex intValue]; RDFOutlineViewItem* item = [mOutlineView itemAtRow: index]; if (![mOutlineView isExpandable: item]) { - nsXPIDLString urlLiteral; - [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:item result:getter_Copies(urlLiteral)]; - history->RemovePage(NS_ConvertUCS2toUTF8(urlLiteral).get()); + NSString* urlString = [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:item]; + history->RemovePage([urlString UTF8String]); } } history->EndBatchUpdate(); if ( clearSelectionWhenDone ) [mOutlineView deselectAll:self]; + + [self invalidateCachedItems]; [mOutlineView reloadData]; // necessary or the outline is really horked } } @@ -402,9 +431,8 @@ HistoryDataSourceObserver::OnChange(nsIRDFDataSource*, nsIRDFResource*, NSString* pageTitle = [super outlineView:outlineView tooltipStringForItem:inItem]; // append url - nsXPIDLString literalValue; - [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:inItem result:getter_Copies(literalValue)]; - return [NSString stringWithFormat:@"%@\n%@", pageTitle, [NSString stringWith_nsAString:literalValue]]; + NSString* url = [self getPropertyString:@"http://home.netscape.com/NC-rdf#URL" forItem:inItem]; + return [NSString stringWithFormat:@"%@\n%@", pageTitle, [url stringByTruncatingTo:80 at:kTruncateAtEnd]]; } return nil; } diff --git a/chimera/src/includes/ChimeraUIConstants.h b/chimera/src/includes/ChimeraUIConstants.h index b96c6e40dd7..e69de29bb2d 100644 --- a/chimera/src/includes/ChimeraUIConstants.h +++ b/chimera/src/includes/ChimeraUIConstants.h @@ -1,54 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: NPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Netscape Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 2002 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Simon Fraser - * - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the NPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the NPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - - -// Put UI constants (menu item tags etc) in this file to reduce the -// chance of conflicts. - -// Go menu - -// the tag of the separator after which to insert history menu items -const int kRendezvousRelatedItemTag = 3000; -const int kDividerTag = 4000; - - -// Bookmarks menu - -// the tag of the separator after which to insert bookmark items -const int kBookmarksDividerTag = -1; diff --git a/chimera/src/preferences/PreferenceManager.h b/chimera/src/preferences/PreferenceManager.h index 8273aca7a71..e69de29bb2d 100644 --- a/chimera/src/preferences/PreferenceManager.h +++ b/chimera/src/preferences/PreferenceManager.h @@ -1,72 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: NPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Netscape Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 2002 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the NPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the NPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#import -#import - -class nsIPref; - -@interface PreferenceManager : NSObject -{ - NSUserDefaults* mDefaults; - ICInstance mInternetConfig; - nsIPref* mPrefs; -} - -+ (PreferenceManager *)sharedInstance; - -- (id) init; -- (void) dealloc; -- (BOOL) initInternetConfig; -- (BOOL) initMozillaPrefs; -- (void) syncMozillaPrefs; -- (void) savePrefsFile; - -- (NSString *) getICStringPref:(ConstStr255Param) prefKey; -- (NSString *) homePage:(BOOL) checkStartupPagePref; -- (NSString *) searchPage; - -- (NSString*)getStringPref: (const char*)prefName withSuccess:(BOOL*)outSuccess; -- (NSColor*)getColorPref: (const char*)prefName withSuccess:(BOOL*)outSuccess; -- (BOOL)getBooleanPref: (const char*)prefName withSuccess:(BOOL*)outSuccess; -- (int)getIntPref: (const char*)prefName withSuccess:(BOOL*)outSuccess; - -- (void)setPref:(const char*)prefName toString:(NSString*)value; -- (void)setPref:(const char*)prefName toInt:(int)value; -- (void)setPref:(const char*)prefName toBoolean:(BOOL)value; - -@end diff --git a/chimera/src/preferences/PreferenceManager.mm b/chimera/src/preferences/PreferenceManager.mm index 18cf20c5680..8378bd39d82 100644 --- a/chimera/src/preferences/PreferenceManager.mm +++ b/chimera/src/preferences/PreferenceManager.mm @@ -38,6 +38,7 @@ #import #import + #import "PreferenceManager.h" #import "UserDefaults.h" #import "CHBrowserService.h" @@ -60,11 +61,23 @@ app_getModuleInfo(nsStaticModuleInfo **info, PRUint32 *count); @interface PreferenceManager(PreferenceManagerPrivate) ++ (PreferenceManager *) sharedInstanceDontCreate; + - (void)registerNotificationListener; - (void)termEmbedding: (NSNotification*)aNotification; - (void)xpcomTerminate: (NSNotification*)aNotification; +- (void)configureProxies; +- (BOOL)updateOneProxy:(NSDictionary*)configDict + protocol:(NSString*)protocol + proxyEnableKey:(NSString*)enableKey + proxyURLKey:(NSString*)urlKey + proxyPortKey:(NSString*)portKey; + +- (void)registerForProxyChanges; +- (BOOL)readSystemProxySettings; + @end @@ -76,7 +89,7 @@ static PreferenceManager* gSharedInstance = nil; static BOOL gMadePrefManager; #endif -+ (PreferenceManager *) sharedInstance ++ (PreferenceManager *)sharedInstance { if (!gSharedInstance) { @@ -88,13 +101,20 @@ static BOOL gMadePrefManager; gSharedInstance = [[PreferenceManager alloc] init]; } - return gSharedInstance; + return gSharedInstance; +} + ++ (PreferenceManager *)sharedInstanceDontCreate +{ + return gSharedInstance; } - (id) init { if ((self = [super init])) { + mRunLoopSource = NULL; + [self registerNotificationListener]; if ([self initInternetConfig] == NO) { @@ -115,6 +135,8 @@ static BOOL gMadePrefManager; - (void) dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; + if (self == gSharedInstance) + gSharedInstance = nil; [super dealloc]; } @@ -123,6 +145,13 @@ static BOOL gMadePrefManager; ::ICStop(mInternetConfig); mInternetConfig = nil; NS_IF_RELEASE(mPrefs); + // remove our runloop observer + if (mRunLoopSource) + { + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), mRunLoopSource, kCFRunLoopCommonModes); + CFRelease(mRunLoopSource); + mRunLoopSource = NULL; + } } - (void)xpcomTerminate: (NSNotification*)aNotification @@ -145,14 +174,14 @@ static BOOL gMadePrefManager; object: nil]; } -- (void) savePrefsFile +- (void)savePrefsFile { nsCOMPtr prefsService = do_GetService(NS_PREF_CONTRACTID); if (prefsService) prefsService->SavePrefFile(nsnull); } -- (BOOL) initInternetConfig +- (BOOL)initInternetConfig { OSStatus error; error = ::ICStart(&mInternetConfig, 'CHIM'); @@ -164,7 +193,7 @@ static BOOL gMadePrefManager; return YES; } -- (BOOL) initMozillaPrefs +- (BOOL)initMozillaPrefs { #ifdef _BUILD_STATIC_BIN @@ -246,15 +275,8 @@ static BOOL gMadePrefManager; return YES; } -- (void) syncMozillaPrefs +- (void)syncMozillaPrefs { - CFArrayRef cfArray; - CFDictionaryRef cfDictionary; - CFNumberRef cfNumber; - CFStringRef cfString; - char strbuf[1024]; - int numbuf; - if (!mPrefs) { NSLog(@"Mozilla prefs not set up successfully"); return; @@ -268,19 +290,101 @@ static BOOL gMadePrefManager; // fix up the cookie prefs. If 'p3p' or 'accept foreign cookies' are on, remap them to // something that chimera can deal with. PRInt32 acceptCookies = 0; - static const char* kCookieBehaviorPref = "network.cookie.cookieBehavior"; + static const char* kCookieBehaviorPref = "network.cookie.cookieBehavior"; mPrefs->GetIntPref(kCookieBehaviorPref, &acceptCookies); - if ( acceptCookies == 1 ) { // accept foreign cookies, assume off + if ( acceptCookies == 1 ) { // accept foreign cookies, assume off acceptCookies = 2; - mPrefs->SetIntPref(kCookieBehaviorPref, acceptCookies); - } + mPrefs->SetIntPref(kCookieBehaviorPref, acceptCookies); + } else if ( acceptCookies == 3 ) { // p3p, assume all cookies on acceptCookies = 0; - mPrefs->SetIntPref(kCookieBehaviorPref, acceptCookies); + mPrefs->SetIntPref(kCookieBehaviorPref, acceptCookies); } - + + [self configureProxies]; +} + +#pragma mark - + +- (void)configureProxies +{ + [self readSystemProxySettings]; + [self registerForProxyChanges]; +} + +static void SCProxiesChangedCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void * /* info */) +{ + PreferenceManager* prefsManager = [PreferenceManager sharedInstanceDontCreate]; + [prefsManager readSystemProxySettings]; +#if DEBUG + NSLog(@"Updating proxies"); +#endif +} + +- (void)registerForProxyChanges +{ + if (mRunLoopSource) // don't register twice + return; + + SCDynamicStoreContext context = {0, NULL, NULL, NULL, NULL}; + + SCDynamicStoreRef dynamicStoreRef = SCDynamicStoreCreate(NULL, CFSTR("ChimeraProxiesNotification"), SCProxiesChangedCallback, &context); + if (dynamicStoreRef) + { + CFStringRef proxyIdentifier = SCDynamicStoreKeyCreateProxies(NULL); + CFArrayRef keyList = CFArrayCreate(NULL, (const void **)&proxyIdentifier, 1, &kCFTypeArrayCallBacks); + + Boolean set = SCDynamicStoreSetNotificationKeys(dynamicStoreRef, keyList, NULL); + if (set) + { + mRunLoopSource = SCDynamicStoreCreateRunLoopSource(NULL, dynamicStoreRef, 0); + if (mRunLoopSource) + { + CFRunLoopAddSource(CFRunLoopGetCurrent(), mRunLoopSource, kCFRunLoopCommonModes); + // we keep the ref to the source, so that we can remove it when the prefs manager is cleaned up. + } + } + + CFRelease(proxyIdentifier); + CFRelease(keyList); + CFRelease(dynamicStoreRef); + } +} + +- (BOOL)updateOneProxy:(NSDictionary*)configDict + protocol:(NSString*)protocol + proxyEnableKey:(NSString*)enableKey + proxyURLKey:(NSString*)urlKey + proxyPortKey:(NSString*)portKey +{ + BOOL gotProxy = NO; + + BOOL enabled = (BOOL)[[configDict objectForKey:enableKey] intValue]; + if (enabled) + { + NSString* protocolProxy = [configDict objectForKey:urlKey]; + int proxyPort = [[configDict objectForKey:portKey] intValue]; + if ([protocolProxy length] > 0 && proxyPort != 0) + { + [self setPref:[[NSString stringWithFormat:@"network.proxy.%@", protocol] cString] toString:protocolProxy]; + [self setPref:[[NSString stringWithFormat:@"network.proxy.%@_port", protocol] cString] toInt:proxyPort]; + gotProxy = YES; + } + } + + return gotProxy; +} + +- (BOOL)readSystemProxySettings +{ + BOOL usingProxies = NO; + + PRInt32 proxyType, newProxyType; + mPrefs->GetIntPref("network.proxy.type", &proxyType); + newProxyType = proxyType; + if (proxyType == 0 || proxyType == 1) + { // get proxies from SystemConfiguration - mPrefs->SetIntPref("network.proxy.type", 0); // 0 == no proxies mPrefs->ClearUserPref("network.proxy.http"); mPrefs->ClearUserPref("network.proxy.http_port"); mPrefs->ClearUserPref("network.proxy.ssl"); @@ -293,94 +397,66 @@ static BOOL gMadePrefManager; mPrefs->ClearUserPref("network.proxy.socks_port"); mPrefs->ClearUserPref("network.proxy.no_proxies_on"); - if ((cfDictionary = SCDynamicStoreCopyProxies (NULL)) != NULL) { - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesHTTPEnable, (const void **)&cfNumber) == TRUE) { - if (CFNumberGetValue (cfNumber, kCFNumberIntType, &numbuf) == TRUE && numbuf == 1) { - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesHTTPProxy, (const void **)&cfString) == TRUE) { - if (CFStringGetCString (cfString, strbuf, sizeof(strbuf)-1, kCFStringEncodingASCII) == TRUE) { - mPrefs->SetCharPref("network.proxy.http", strbuf); - } - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesHTTPPort, (const void **)&cfNumber) == TRUE) { - if (CFNumberGetValue (cfNumber, kCFNumberIntType, &numbuf) == TRUE) { - mPrefs->SetIntPref("network.proxy.http_port", numbuf); - } - mPrefs->SetIntPref("network.proxy.type", 1); - } - } - } + NSDictionary* proxyConfigDict = (NSDictionary*)SCDynamicStoreCopyProxies(NULL); + if (proxyConfigDict) + { + BOOL gotAProxy = NO; + + gotAProxy |= [self updateOneProxy:proxyConfigDict protocol:@"http" + proxyEnableKey:(NSString*)kSCPropNetProxiesHTTPEnable + proxyURLKey:(NSString*)kSCPropNetProxiesHTTPProxy + proxyPortKey:(NSString*)kSCPropNetProxiesHTTPPort]; + + gotAProxy |= [self updateOneProxy:proxyConfigDict protocol:@"ssl" + proxyEnableKey:(NSString*)kSCPropNetProxiesHTTPSEnable + proxyURLKey:(NSString*)kSCPropNetProxiesHTTPSProxy + proxyPortKey:(NSString*)kSCPropNetProxiesHTTPSPort]; + + gotAProxy |= [self updateOneProxy:proxyConfigDict protocol:@"ftp" + proxyEnableKey:(NSString*)kSCPropNetProxiesFTPEnable + proxyURLKey:(NSString*)kSCPropNetProxiesFTPProxy + proxyPortKey:(NSString*)kSCPropNetProxiesFTPPort]; + + gotAProxy |= [self updateOneProxy:proxyConfigDict protocol:@"gopher" + proxyEnableKey:(NSString*)kSCPropNetProxiesGopherEnable + proxyURLKey:(NSString*)kSCPropNetProxiesGopherProxy + proxyPortKey:(NSString*)kSCPropNetProxiesGopherPort]; + + gotAProxy |= [self updateOneProxy:proxyConfigDict protocol:@"socks" + proxyEnableKey:(NSString*)kSCPropNetProxiesSOCKSEnable + proxyURLKey:(NSString*)kSCPropNetProxiesSOCKSProxy + proxyPortKey:(NSString*)kSCPropNetProxiesSOCKSPort]; + + if (gotAProxy) + { + newProxyType = 1; + + NSArray* exceptions = [proxyConfigDict objectForKey:(NSString*)kSCPropNetProxiesExceptionsList]; + if (exceptions) + { + NSString* sitesList = [exceptions componentsJoinedByString:@", "]; + if ([sitesList length] > 0) + [self setPref:"network.proxy.no_proxies_on" toString:sitesList]; } - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesHTTPSEnable, (const void **)&cfNumber) == TRUE) { - if (CFNumberGetValue (cfNumber, kCFNumberIntType, &numbuf) == TRUE && numbuf == 1) { - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesHTTPSProxy, (const void **)&cfString) == TRUE) { - if (CFStringGetCString (cfString, strbuf, sizeof(strbuf)-1, kCFStringEncodingASCII) == TRUE) { - mPrefs->SetCharPref("network.proxy.ssl", strbuf); - } - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesHTTPSPort, (const void **)&cfNumber) == TRUE) { - if (CFNumberGetValue (cfNumber, kCFNumberIntType, &numbuf) == TRUE) { - mPrefs->SetIntPref("network.proxy.ssl_port", numbuf); - } - mPrefs->SetIntPref("network.proxy.type", 1); - } - } - } - } - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesFTPEnable, (const void **)&cfNumber) == TRUE) { - if (CFNumberGetValue (cfNumber, kCFNumberIntType, &numbuf) == TRUE && numbuf == 1) { - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesFTPProxy, (const void **)&cfString) == TRUE) { - if (CFStringGetCString (cfString, strbuf, sizeof(strbuf)-1, kCFStringEncodingASCII) == TRUE) { - mPrefs->SetCharPref("network.proxy.ftp", strbuf); - } - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesFTPPort, (const void **)&cfNumber) == TRUE) { - if (CFNumberGetValue (cfNumber, kCFNumberIntType, &numbuf) == TRUE) { - mPrefs->SetIntPref("network.proxy.ftp_port", numbuf); - } - mPrefs->SetIntPref("network.proxy.type", 1); - } - } - } - } - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesGopherEnable, (const void **)&cfNumber) == TRUE) { - if (CFNumberGetValue (cfNumber, kCFNumberIntType, &numbuf) == TRUE && numbuf == 1) { - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesGopherProxy, (const void **)&cfString) == TRUE) { - if (CFStringGetCString (cfString, strbuf, sizeof(strbuf)-1, kCFStringEncodingASCII) == TRUE) { - mPrefs->SetCharPref("network.proxy.gopher", strbuf); - } - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesGopherPort, (const void **)&cfNumber) == TRUE) { - if (CFNumberGetValue (cfNumber, kCFNumberIntType, &numbuf) == TRUE) { - mPrefs->SetIntPref("network.proxy.gopher_port", numbuf); - } - mPrefs->SetIntPref("network.proxy.type", 1); - } - } - } - } - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesSOCKSEnable, (const void **)&cfNumber) == TRUE) { - if (CFNumberGetValue (cfNumber, kCFNumberIntType, &numbuf) == TRUE && numbuf == 1) { - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesSOCKSProxy, (const void **)&cfString) == TRUE) { - if (CFStringGetCString (cfString, strbuf, sizeof(strbuf)-1, kCFStringEncodingASCII) == TRUE) { - mPrefs->SetCharPref("network.proxy.socks", strbuf); - } - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesSOCKSPort, (const void **)&cfNumber) == TRUE) { - if (CFNumberGetValue (cfNumber, kCFNumberIntType, &numbuf) == TRUE) { - mPrefs->SetIntPref("network.proxy.socks_port", numbuf); - } - mPrefs->SetIntPref("network.proxy.type", 1); - } - } - } - } - if (CFDictionaryGetValueIfPresent (cfDictionary, kSCPropNetProxiesExceptionsList, (const void **)&cfArray) == TRUE) { - cfString = CFStringCreateByCombiningStrings (NULL, cfArray, CFSTR(", ")); - if (CFStringGetLength (cfString) > 0) { - if (CFStringGetCString (cfString, strbuf, sizeof(strbuf)-1, kCFStringEncodingASCII) == TRUE) { - mPrefs->SetCharPref("network.proxy.no_proxies_on", strbuf); - } - } - } - CFRelease (cfDictionary); + usingProxies = YES; + } + else + { + newProxyType = 0; + } + + [proxyConfigDict release]; } + + if (newProxyType != proxyType) + mPrefs->SetIntPref("network.proxy.type", 1); + } + + return usingProxies; } +#pragma mark - + - (NSString*)getStringPref: (const char*)prefName withSuccess:(BOOL*)outSuccess { NSString *prefValue = @""; @@ -406,16 +482,16 @@ static BOOL gMadePrefManager; { // colors are stored in HTML-like #FFFFFF strings NSString* colorString = [self getStringPref:prefName withSuccess:outSuccess]; - NSColor* returnColor = [NSColor blackColor]; + NSColor* returnColor = [NSColor blackColor]; if ([colorString hasPrefix:@"#"] && [colorString length] == 7) { unsigned int redInt, greenInt, blueInt; sscanf([colorString cString], "#%02x%02x%02x", &redInt, &greenInt, &blueInt); - float redFloat = ((float)redInt / 255.0); - float greenFloat = ((float)greenInt / 255.0); - float blueFloat = ((float)blueInt / 255.0); + float redFloat = ((float)redInt / 255.0); + float greenFloat = ((float)greenInt / 255.0); + float blueFloat = ((float)blueInt / 255.0); returnColor = [NSColor colorWithCalibratedRed:redFloat green:greenFloat blue:blueFloat alpha:1.0f]; } @@ -548,7 +624,7 @@ static BOOL gMadePrefManager; mPrefs->SetCharPref("browser.startup.homepage", [homepagePref UTF8String]); } else { - homepagePref = [self getStringPref:"browser.startup.homepage" withSuccess:NULL]; + homepagePref = [self getStringPref:"browser.startup.homepage" withSuccess:NULL]; } if (homepagePref && [homepagePref length] > 0 && ![homepagePref isEqualToString:@"HomePageDefault"])