diff --git a/mozilla/camino/Camino.xcode/project.pbxproj b/mozilla/camino/Camino.xcode/project.pbxproj index 3536670f303..644cdcbe93a 100644 --- a/mozilla/camino/Camino.xcode/project.pbxproj +++ b/mozilla/camino/Camino.xcode/project.pbxproj @@ -1387,6 +1387,48 @@ isa = PBXCopyFilesBuildPhase; runOnlyForDeploymentPostprocessing = 0; }; + 0F7EAA9609326B770082C3EA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = AutoSizingTextField.m; + path = src/extensions/AutoSizingTextField.m; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + 0F7EAA9709326B770082C3EA = { + fileRef = 0F7EAA9609326B770082C3EA; + isa = PBXBuildFile; + settings = { + }; + }; + 0F7EAA9809326B770082C3EA = { + fileRef = 0F7EAA9609326B770082C3EA; + isa = PBXBuildFile; + settings = { + }; + }; + 0F7EAA9909326B860082C3EA = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = AutoSizingTextField.h; + path = src/extensions/AutoSizingTextField.h; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + 0F7EAA9A09326B860082C3EA = { + fileRef = 0F7EAA9909326B860082C3EA; + isa = PBXBuildFile; + settings = { + }; + }; + 0F7EAA9B09326B860082C3EA = { + fileRef = 0F7EAA9909326B860082C3EA; + isa = PBXBuildFile; + settings = { + }; + }; 0F84BF1208862E3E00E23BC4 = { fileEncoding = 30; isa = PBXFileReference; @@ -1429,6 +1471,57 @@ settings = { }; }; + 0F8FC52C092ED71C0042429E = { + children = ( + 0F8FC52D092ED71C0042429E, + ); + isa = PBXVariantGroup; + name = PageInfo.nib; + path = ""; + refType = 4; + sourceTree = ""; + }; + 0F8FC52D092ED71C0042429E = { + isa = PBXFileReference; + lastKnownFileType = wrapper.nib; + name = English; + path = resources/localized/English.lproj/PageInfo.nib; + refType = 4; + sourceTree = ""; + }; + 0F8FC52E092ED71C0042429E = { + fileRef = 0F8FC52C092ED71C0042429E; + isa = PBXBuildFile; + settings = { + }; + }; + 0F8FC52F092ED71C0042429E = { + fileRef = 0F8FC52C092ED71C0042429E; + isa = PBXBuildFile; + settings = { + }; + }; + 0F8FC582092ED8C70042429E = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.objcpp; + name = PageInfoWindowController.mm; + path = src/browser/PageInfoWindowController.mm; + refType = 4; + sourceTree = ""; + }; + 0F8FC583092ED8C70042429E = { + fileRef = 0F8FC582092ED8C70042429E; + isa = PBXBuildFile; + settings = { + }; + }; + 0F8FC584092ED8C70042429E = { + fileRef = 0F8FC582092ED8C70042429E; + isa = PBXBuildFile; + settings = { + }; + }; 0FA8EF970423B1A500A80166 = { isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; @@ -2232,6 +2325,48 @@ settings = { }; }; + 0FD75057093ABEBA00B6A3A4 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = TruncatingTextFieldCell.h; + path = src/extensions/TruncatingTextFieldCell.h; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + 0FD75058093ABEBA00B6A3A4 = { + fileRef = 0FD75057093ABEBA00B6A3A4; + isa = PBXBuildFile; + settings = { + }; + }; + 0FD75059093ABEBA00B6A3A4 = { + fileRef = 0FD75057093ABEBA00B6A3A4; + isa = PBXBuildFile; + settings = { + }; + }; + 0FD7505A093ABEC600B6A3A4 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.objcpp; + name = TruncatingTextFieldCell.mm; + path = src/extensions/TruncatingTextFieldCell.mm; + refType = 4; + sourceTree = ""; + }; + 0FD7505B093ABEC600B6A3A4 = { + fileRef = 0FD7505A093ABEC600B6A3A4; + isa = PBXBuildFile; + settings = { + }; + }; + 0FD7505C093ABEC600B6A3A4 = { + fileRef = 0FD7505A093ABEC600B6A3A4; + isa = PBXBuildFile; + settings = { + }; + }; 0FD8181E08CB8E8900D8F88C = { children = ( 0FD8181F08CB8E8900D8F88C, @@ -3657,6 +3792,8 @@ 0F08FB1508D37DA90022DD45, 0F0F5E3D08FC660300B4EBCD, 0F07686B0927B0AA00E1BD6F, + 0F7EAA9B09326B860082C3EA, + 0FD75059093ABEBA00B6A3A4, ); isa = PBXHeadersBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -4284,6 +4421,7 @@ 0FBB8CCA08D260D800D58D8D, 0F01117408F2FE7C00423C02, 0FEA7E650926BFC600B06154, + 0F8FC52F092ED71C0042429E, ); isa = PBXResourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -4809,6 +4947,9 @@ 0F07686A0927B09E00E1BD6F, 0F07688F0927B0B300E1BD6F, 0F0768900927B0B600E1BD6F, + 0F8FC584092ED8C70042429E, + 0F7EAA9809326B770082C3EA, + 0FD7505C093ABEC600B6A3A4, ); isa = PBXSourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -7570,6 +7711,8 @@ 0F08FB1608D37DA90022DD45, 0F0F5E3E08FC660300B4EBCD, 0FEA7DDF0926BBEA00B06154, + 0F7EAA9A09326B860082C3EA, + 0FD75058093ABEBA00B6A3A4, ); isa = PBXHeadersBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -8203,6 +8346,7 @@ 0FBB8CCF08D260D800D58D8D, 0F01117508F2FE7C00423C02, 0FEA7E660926BFC600B06154, + 0F8FC52E092ED71C0042429E, ); isa = PBXResourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -8729,6 +8873,9 @@ 0F0F5E3B08FC65FB00B4EBCD, 0FEA7DE20926BBF500B06154, 0FEA7DE50926BC0C00B06154, + 0F8FC583092ED8C70042429E, + 0F7EAA9709326B770082C3EA, + 0FD7505B093ABEC600B6A3A4, ); isa = PBXSourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -14198,6 +14345,7 @@ F5DE10E90209DC0601A967DF, F528E21A020FD9620168DE43, F566BD1302EFA9AD01A967F3, + 0F8FC582092ED8C70042429E, ); isa = PBXGroup; name = Dialogs; @@ -16036,6 +16184,7 @@ children = ( F507A84103116E1D01026D5D, F507A84403116E5501026D5D, + 0F8FC52C092ED71C0042429E, 0FBC0EC90798F92600E8E0E2, 0FACBFEC07DC020D00DEE23A, F507A84A03116E6E01026D5D, @@ -16448,6 +16597,7 @@ F5B950BA030C833301A96654 = { children = ( 3489ADC90753B717005ADF6C, + 0F7EAA9909326B860082C3EA, F541495E02711B0001A80166, 0F0F5E3C08FC660300B4EBCD, F583E3C203B8228F01A80166, @@ -16475,6 +16625,7 @@ 3FF08F0606E7CF9C001C9B19, 3FF08F0706E7CF9C001C9B19, 3FF08F0806E7CF9C001C9B19, + 0FD75057093ABEBA00B6A3A4, ); isa = PBXGroup; name = Headers; @@ -16484,6 +16635,7 @@ F5B950BB030C833301A96654 = { children = ( 3489ADCA0753B717005ADF6C, + 0F7EAA9609326B770082C3EA, F541495F02711B0001A80166, 0F0F5E3908FC65FB00B4EBCD, F583E3BF03B8228701A80166, @@ -16512,6 +16664,7 @@ 3FF08EFD06E7CF86001C9B19, 3FF08EFE06E7CF86001C9B19, 3FF08EFF06E7CF86001C9B19, + 0FD7505A093ABEC600B6A3A4, ); isa = PBXGroup; name = Source; diff --git a/mozilla/camino/Makefile.in b/mozilla/camino/Makefile.in index d4a293d9a37..014ae119c72 100644 --- a/mozilla/camino/Makefile.in +++ b/mozilla/camino/Makefile.in @@ -42,6 +42,10 @@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk +DIRS = \ + IBPalette \ + $(NULL) + APP_NAME = Camino ifdef MOZ_DEBUG diff --git a/mozilla/camino/resources/application/ad_blocking.css b/mozilla/camino/resources/application/ad_blocking.css index b5372e1f11e..46aa8f89e99 100644 --- a/mozilla/camino/resources/application/ad_blocking.css +++ b/mozilla/camino/resources/application/ad_blocking.css @@ -83,6 +83,7 @@ embed[type="application/x-shockwave-flash"][src*=".tribalfusion.com/media/"], embed[type="application/x-shockwave-flash"][src*="/flash/promotions/"], embed[type="application/x-shockwave-flash"][src*=".adtrix.com"], embed[type="application/x-shockwave-flash"][src*=".netshelter.net"], +embed[type="application/x-shockwave-flash"][src*=".gms1.net"], img[src*="googlesyndication.com"], img[src*="mediaplex.com"], @@ -111,6 +112,7 @@ img[src*="kermit.macnn.com"], img[src*="media.adlegend.com"], img[src*=".adtrix.com"], img[src*=".netshelter.net"], +img[src*=".gms1.net"], iframe[src*="/ad."], iframe[src*="/ads."], @@ -156,6 +158,7 @@ iframe[src*=".yieldmanager.com"], iframe[src*=".mspaceads.com"], iframe[src*=".adtrix.com"], iframe[src*=".netshelter.net"], +iframe[src*=".gms1.net"], table#overtureLinksWrapper, table.adbritetable, diff --git a/mozilla/camino/resources/localized/English.lproj/BrowserWindow.nib/classes.nib b/mozilla/camino/resources/localized/English.lproj/BrowserWindow.nib/classes.nib index 650fdd481d1..01630bc653c 100644 --- a/mozilla/camino/resources/localized/English.lproj/BrowserWindow.nib/classes.nib +++ b/mozilla/camino/resources/localized/English.lproj/BrowserWindow.nib/classes.nib @@ -141,6 +141,8 @@ savePageAs = id; sendURL = id; sendURLFromLink = id; + showBookmarksInfo = id; + showPageInfo = id; smallerTextSize = id; stop = id; unblockAllSites = id; diff --git a/mozilla/camino/resources/localized/English.lproj/BrowserWindow.nib/info.nib b/mozilla/camino/resources/localized/English.lproj/BrowserWindow.nib/info.nib index fbad2dc92f3..5d58868e887 100644 --- a/mozilla/camino/resources/localized/English.lproj/BrowserWindow.nib/info.nib +++ b/mozilla/camino/resources/localized/English.lproj/BrowserWindow.nib/info.nib @@ -3,7 +3,7 @@ IBDocumentLocation - 3 3 530 384 0 0 1280 832 + 33 23 530 384 0 0 1600 1002 IBEditorPositions 1014 @@ -38,6 +38,6 @@ 889 IBSystem Version - 8C46 + 8F46 diff --git a/mozilla/camino/resources/localized/English.lproj/BrowserWindow.nib/keyedobjects.nib b/mozilla/camino/resources/localized/English.lproj/BrowserWindow.nib/keyedobjects.nib index f6e05ef1c06..6687cac6db4 100644 Binary files a/mozilla/camino/resources/localized/English.lproj/BrowserWindow.nib/keyedobjects.nib and b/mozilla/camino/resources/localized/English.lproj/BrowserWindow.nib/keyedobjects.nib differ diff --git a/mozilla/camino/resources/localized/English.lproj/CertificatesWindow.nib/info.nib b/mozilla/camino/resources/localized/English.lproj/CertificatesWindow.nib/info.nib index 7130de52dbd..dd655ea0cd0 100644 --- a/mozilla/camino/resources/localized/English.lproj/CertificatesWindow.nib/info.nib +++ b/mozilla/camino/resources/localized/English.lproj/CertificatesWindow.nib/info.nib @@ -14,6 +14,6 @@ IBFramework Version 437.0 IBSystem Version - 8C46 + 8F46 diff --git a/mozilla/camino/resources/localized/English.lproj/Localizable.strings b/mozilla/camino/resources/localized/English.lproj/Localizable.strings index bdf5fcb1ad4..4009c6c4f3a 100644 Binary files a/mozilla/camino/resources/localized/English.lproj/Localizable.strings and b/mozilla/camino/resources/localized/English.lproj/Localizable.strings differ diff --git a/mozilla/camino/resources/localized/English.lproj/MainMenu.nib/classes.nib b/mozilla/camino/resources/localized/English.lproj/MainMenu.nib/classes.nib index dc681c2066e..9c1a0c771f5 100644 --- a/mozilla/camino/resources/localized/English.lproj/MainMenu.nib/classes.nib +++ b/mozilla/camino/resources/localized/English.lproj/MainMenu.nib/classes.nib @@ -18,6 +18,8 @@ addBookmarkFolder = id; addBookmarkSeparator = id; fillForm = id; + getInfo = id; + showPageInfo = id; }; CLASS = FirstResponder; LANGUAGE = ObjC; @@ -47,10 +49,7 @@ emptyCache = id; exportBookmarks = id; feedbackLink = id; - findAgain = id; findInPage = id; - findPrevious = id; - getInfo = id; goBack = id; goForward = id; goHome = id; @@ -73,6 +72,7 @@ searchCustomizeLink = id; sendURL = id; setFileExtension = id; + showCertificates = id; showHistory = id; smallerTextSize = id; supportLink = id; diff --git a/mozilla/camino/resources/localized/English.lproj/MainMenu.nib/info.nib b/mozilla/camino/resources/localized/English.lproj/MainMenu.nib/info.nib index 2d5a1f65601..2d3bff63afa 100644 --- a/mozilla/camino/resources/localized/English.lproj/MainMenu.nib/info.nib +++ b/mozilla/camino/resources/localized/English.lproj/MainMenu.nib/info.nib @@ -3,7 +3,7 @@ IBDocumentLocation - 24 23 409 367 0 0 1600 1002 + 134 210 409 367 0 0 1600 1002 IBEditorPositions 29 @@ -15,7 +15,11 @@ IBFramework Version 437.0 + IBOpenObjects + + 29 + IBSystem Version - 8C46 + 8F46 diff --git a/mozilla/camino/resources/localized/English.lproj/MainMenu.nib/keyedobjects.nib b/mozilla/camino/resources/localized/English.lproj/MainMenu.nib/keyedobjects.nib index bc09d0274be..50692486af7 100644 Binary files a/mozilla/camino/resources/localized/English.lproj/MainMenu.nib/keyedobjects.nib and b/mozilla/camino/resources/localized/English.lproj/MainMenu.nib/keyedobjects.nib differ diff --git a/mozilla/camino/resources/localized/English.lproj/PageInfo.nib/classes.nib b/mozilla/camino/resources/localized/English.lproj/PageInfo.nib/classes.nib new file mode 100644 index 00000000000..ed35463171d --- /dev/null +++ b/mozilla/camino/resources/localized/English.lproj/PageInfo.nib/classes.nib @@ -0,0 +1,45 @@ +{ + IBClasses = ( + {CLASS = AutoSizingTextField; LANGUAGE = ObjC; SUPERCLASS = NSTextField; }, + { + CLASS = CHFlippedShrinkWrapView; + LANGUAGE = ObjC; + SUPERCLASS = CHShrinkWrapView; + }, + {CLASS = CHShrinkWrapView; LANGUAGE = ObjC; SUPERCLASS = NSView; }, + { + CLASS = CHStackView; + LANGUAGE = ObjC; + OUTLETS = {mDataSource = id; }; + SUPERCLASS = CHShrinkWrapView; + }, + { + ACTIONS = {saveTrustSettings = id; toggleDetails = id; toggleTrustSettings = id; }; + CLASS = CertificateView; + LANGUAGE = ObjC; + OUTLETS = {mDelegate = id; }; + SUPERCLASS = NSView; + }, + {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, + {CLASS = NSObject; LANGUAGE = ObjC; }, + { + ACTIONS = {viewCertificate = id; }; + CLASS = PageInfoWindowController; + LANGUAGE = ObjC; + OUTLETS = { + mConnectionDetailsField = NSTextField; + mConnectionImageView = NSImageView; + mConnectionTextField = NSTextField; + mPageLocationField = NSTextField; + mPageModDateField = NSTextField; + mPageTitleField = NSTextField; + mShowCertificateButton = NSButton; + mSiteVerifiedDetailsField = NSTextField; + mSiteVerifiedImageView = NSImageView; + mSiteVerifiedTextField = NSTextField; + }; + SUPERCLASS = NSWindowController; + } + ); + IBVersion = 1; +} \ No newline at end of file diff --git a/mozilla/camino/resources/localized/English.lproj/PageInfo.nib/info.nib b/mozilla/camino/resources/localized/English.lproj/PageInfo.nib/info.nib new file mode 100644 index 00000000000..a24ba7a9413 --- /dev/null +++ b/mozilla/camino/resources/localized/English.lproj/PageInfo.nib/info.nib @@ -0,0 +1,12 @@ + + + + + IBDocumentLocation + 18 49 367 240 0 0 1600 1002 + IBFramework Version + 437.0 + IBSystem Version + 8F46 + + diff --git a/mozilla/camino/resources/localized/English.lproj/PageInfo.nib/keyedobjects.nib b/mozilla/camino/resources/localized/English.lproj/PageInfo.nib/keyedobjects.nib new file mode 100644 index 00000000000..55625288eb6 Binary files /dev/null and b/mozilla/camino/resources/localized/English.lproj/PageInfo.nib/keyedobjects.nib differ diff --git a/mozilla/camino/resources/localized/English.lproj/ProgressDialog.nib/classes.nib b/mozilla/camino/resources/localized/English.lproj/ProgressDialog.nib/classes.nib index 41cdd20ab2e..78f330aab24 100644 --- a/mozilla/camino/resources/localized/English.lproj/ProgressDialog.nib/classes.nib +++ b/mozilla/camino/resources/localized/English.lproj/ProgressDialog.nib/classes.nib @@ -1,10 +1,16 @@ { IBClasses = ( + { + CLASS = CHFlippedShrinkWrapView; + LANGUAGE = ObjC; + SUPERCLASS = CHShrinkWrapView; + }, + {CLASS = CHShrinkWrapView; LANGUAGE = ObjC; SUPERCLASS = NSView; }, { CLASS = CHStackView; LANGUAGE = ObjC; OUTLETS = {mDataSource = id; }; - SUPERCLASS = NSView; + SUPERCLASS = CHShrinkWrapView; }, {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, {CLASS = NSObject; LANGUAGE = ObjC; }, diff --git a/mozilla/camino/resources/localized/English.lproj/ProgressDialog.nib/info.nib b/mozilla/camino/resources/localized/English.lproj/ProgressDialog.nib/info.nib index b4d63f2bc65..60d93dcf6fb 100644 --- a/mozilla/camino/resources/localized/English.lproj/ProgressDialog.nib/info.nib +++ b/mozilla/camino/resources/localized/English.lproj/ProgressDialog.nib/info.nib @@ -5,11 +5,7 @@ IBDocumentLocation 24 42 592 284 0 0 1600 1002 IBFramework Version - 439.0 - IBOpenObjects - - 121 - + 437.0 IBSystem Version 8F46 diff --git a/mozilla/camino/resources/localized/English.lproj/ProgressDialog.nib/keyedobjects.nib b/mozilla/camino/resources/localized/English.lproj/ProgressDialog.nib/keyedobjects.nib index 36f82d9f57c..edd8a773faa 100644 Binary files a/mozilla/camino/resources/localized/English.lproj/ProgressDialog.nib/keyedobjects.nib and b/mozilla/camino/resources/localized/English.lproj/ProgressDialog.nib/keyedobjects.nib differ diff --git a/mozilla/camino/resources/localized/English.lproj/ProgressView.nib/info.nib b/mozilla/camino/resources/localized/English.lproj/ProgressView.nib/info.nib index a1ada055463..3f6d5cb5f11 100644 --- a/mozilla/camino/resources/localized/English.lproj/ProgressView.nib/info.nib +++ b/mozilla/camino/resources/localized/English.lproj/ProgressView.nib/info.nib @@ -3,26 +3,21 @@ IBDocumentLocation - 101 124 448 284 0 0 1280 832 + 35 161 448 284 0 0 1600 1002 IBEditorPositions 5 - 339 461 346 92 0 0 1024 746 + 606 622 346 92 0 0 1600 1002 71 - 339 462 346 92 0 0 1024 746 + 606 622 346 92 0 0 1600 1002 IBFramework Version - 439.0 + 437.0 IBLockedObjects 5 - IBOpenObjects - - 71 - 5 - IBSystem Version - 8C46 + 8F46 diff --git a/mozilla/camino/resources/localized/English.lproj/ProgressView.nib/keyedobjects.nib b/mozilla/camino/resources/localized/English.lproj/ProgressView.nib/keyedobjects.nib index def1ec11a57..a19da7f88aa 100644 Binary files a/mozilla/camino/resources/localized/English.lproj/ProgressView.nib/keyedobjects.nib and b/mozilla/camino/resources/localized/English.lproj/ProgressView.nib/keyedobjects.nib differ diff --git a/mozilla/camino/resources/localized/English.lproj/ViewCertificateDialog.nib/info.nib b/mozilla/camino/resources/localized/English.lproj/ViewCertificateDialog.nib/info.nib index 43806a4ab75..77930a26534 100644 --- a/mozilla/camino/resources/localized/English.lproj/ViewCertificateDialog.nib/info.nib +++ b/mozilla/camino/resources/localized/English.lproj/ViewCertificateDialog.nib/info.nib @@ -7,6 +7,6 @@ IBFramework Version 437.0 IBSystem Version - 8C46 + 8F46 diff --git a/mozilla/camino/resources/localized/English.lproj/ViewCertificateDialog.nib/keyedobjects.nib b/mozilla/camino/resources/localized/English.lproj/ViewCertificateDialog.nib/keyedobjects.nib index a685aefbd64..56171e3cbaf 100644 Binary files a/mozilla/camino/resources/localized/English.lproj/ViewCertificateDialog.nib/keyedobjects.nib and b/mozilla/camino/resources/localized/English.lproj/ViewCertificateDialog.nib/keyedobjects.nib differ diff --git a/mozilla/camino/src/application/MainController.h b/mozilla/camino/src/application/MainController.h index b2d0e10ccd3..97ff32eebea 100644 --- a/mozilla/camino/src/application/MainController.h +++ b/mozilla/camino/src/application/MainController.h @@ -92,6 +92,7 @@ typedef enum EBookmarkOpenBehavior BOOL mGeckoInitted; BOOL mBookmarksMenuUpdatePending; BOOL mFileMenuUpdatePending; + BOOL mPageInfoUpdatePending; BookmarkMenu* mMenuBookmarks; BookmarkMenu* mDockBookmarks; @@ -120,7 +121,6 @@ typedef enum EBookmarkOpenBehavior // Edit menu actions. -(IBAction) findInPage:(id)aSender; --(IBAction) getInfo:(id)aSender; // Go menu actions. -(IBAction) goBack:(id)aSender; @@ -182,6 +182,7 @@ typedef enum EBookmarkOpenBehavior - (void)delayedFixCloseMenuItemKeyEquivalents; - (void)delayedAdjustBookmarksMenuItemsEnabling; +- (void)delayedUpdatePageInfo; - (NSView*)getSavePanelView; - (NSWindow*)getFrontmostBrowserWindow; diff --git a/mozilla/camino/src/application/MainController.mm b/mozilla/camino/src/application/MainController.mm index c984f7498c8..15bcd464963 100644 --- a/mozilla/camino/src/application/MainController.mm +++ b/mozilla/camino/src/application/MainController.mm @@ -66,6 +66,7 @@ #import "NetworkServices.h" #import "MVPreferencesController.h" #import "CertificatesWindowController.h" +#import "PageInfoWindowController.h" #import "FindDlgController.h" #import "PreferenceManager.h" #import "SharedMenusObj.h" @@ -386,6 +387,7 @@ const int kReuseWindowOnAE = 2; { [self delayedAdjustBookmarksMenuItemsEnabling]; [self delayedFixCloseMenuItemKeyEquivalents]; + [self delayedUpdatePageInfo]; } - (NSMenu *)applicationDockMenu:(NSApplication *)sender @@ -651,6 +653,7 @@ Otherwise, we return the URL we originally got. Right now this supports .url and } } +// XXX move to BWC -(IBAction)closeTab:(id)aSender { BrowserWindowController* browserController = [self getMainWindowBrowserController]; @@ -658,6 +661,7 @@ Otherwise, we return the URL we originally got. Right now this supports .url and [browserController closeCurrentTab:aSender]; } +// XXX move to BWC -(IBAction) previousTab:(id)aSender { BrowserWindowController* browserController = [self getMainWindowBrowserController]; @@ -665,6 +669,7 @@ Otherwise, we return the URL we originally got. Right now this supports .url and [browserController previousTab:aSender]; } +// XXX move to BWC -(IBAction) nextTab:(id)aSender { BrowserWindowController* browserController = [self getMainWindowBrowserController]; @@ -818,14 +823,7 @@ Otherwise, we return the URL we originally got. Right now this supports .url and [mFindDialog showWindow:self]; } - --(IBAction) getInfo:(id)aSender -{ - BrowserWindowController* browserController = [self getMainWindowBrowserController]; - if (browserController) - [browserController getInfo: aSender]; -} - +// XXX move to BWC -(IBAction) goBack:(id)aSender { BrowserWindowController* browserController = [self getMainWindowBrowserController]; @@ -833,6 +831,7 @@ Otherwise, we return the URL we originally got. Right now this supports .url and [browserController back: aSender]; } +// XXX move to BWC -(IBAction) goForward:(id)aSender { BrowserWindowController* browserController = [self getMainWindowBrowserController]; @@ -840,6 +839,7 @@ Otherwise, we return the URL we originally got. Right now this supports .url and [browserController forward: aSender]; } +// XXX move to BWC -(IBAction) doReload:(id)aSender { BrowserWindowController* browserController = [self getMainWindowBrowserController]; @@ -847,6 +847,7 @@ Otherwise, we return the URL we originally got. Right now this supports .url and [browserController reload: aSender]; } +// XXX move to BWC -(IBAction) reloadWithCharset:(id)aSender { // Figure out which charset to tell gecko to load based on the sender's tag. There @@ -869,6 +870,7 @@ Otherwise, we return the URL we originally got. Right now this supports .url and [self doReload:nil]; } +// XXX move to BWC -(IBAction) doStop:(id)aSender { BrowserWindowController* browserController = [self getMainWindowBrowserController]; @@ -1327,6 +1329,22 @@ Otherwise, we return the URL we originally got. Right now this supports .url and mFileMenuUpdatePending = NO; } +- (void)delayedUpdatePageInfo +{ + if (!mPageInfoUpdatePending) + { + [self performSelector:@selector(updatePageInfo) withObject:nil afterDelay:0]; + mPageInfoUpdatePending = YES; + } +} + +- (void)updatePageInfo +{ + BrowserWindowController* browserController = [self getMainWindowBrowserController]; + [[PageInfoWindowController visiblePageInfoWindowController] updateFromBrowserView:[browserController activeBrowserView]]; + mPageInfoUpdatePending = NO; +} + - (void)adjustTextEncodingMenu { BrowserWindowController* browserController = [self getMainWindowBrowserController]; @@ -1402,9 +1420,6 @@ Otherwise, we return the URL we originally got. Right now this supports .url and return NO; } - if ( action == @selector(getInfo:) ) - return (browserController && [browserController canGetInfo]); - // only enable newTab if there is a browser window frontmost, or if there is no window // (i.e. disable it for non-browser windows). if (action == @selector(newTab:)) diff --git a/mozilla/camino/src/browser/BrowserWindowController.h b/mozilla/camino/src/browser/BrowserWindowController.h index a993ccd0584..88b5b464931 100644 --- a/mozilla/camino/src/browser/BrowserWindowController.h +++ b/mozilla/camino/src/browser/BrowserWindowController.h @@ -95,6 +95,7 @@ typedef enum } ETabOpenPolicy; +@class CHBrowserView; @class BookmarkViewController; @class BookmarkToolbar; @class BrowserTabView; @@ -176,9 +177,6 @@ typedef enum // someone from messing up in the nib when making changes. NSView* mProgressSuperview; // WEAK ptr NSView* mPopupBlockSuperview; // WEAK ptr - - // saving window titles when opening the bookmark manager - NSString* mSavedTitle; } - (BrowserTabView*)getTabBrowser; @@ -188,9 +186,6 @@ typedef enum - (void)focusURLBar; - // call to update the image of the lock icon with a value from nsIWebProgressListener -- (void)updateLock:(unsigned int)securityState; - // call to update (show/hide) the image of the blocked-popup indicator and handle // the items of the popup un-blocker menu - (void)showPopupBlocked:(BOOL)inBlocked; @@ -232,8 +227,7 @@ typedef enum - (IBAction)biggerTextSize:(id)aSender; - (IBAction)smallerTextSize:(id)aSender; -- (void)getInfo:(id)sender; -- (BOOL)canGetInfo; +- (IBAction)getInfo:(id)sender; - (BOOL)shouldShowBookmarkToolbar; @@ -314,6 +308,9 @@ typedef enum - (IBAction)viewOnlyThisImage:(id)aSender; +- (IBAction)showPageInfo:(id)sender; +- (IBAction)showBookmarksInfo:(id)sender; + - (IBAction)addBookmark:(id)aSender; - (IBAction)addBookmarkForLink:(id)aSender; - (IBAction)addBookmarkFolder:(id)aSender; @@ -352,8 +349,8 @@ typedef enum // Accessor for the bm data source - (BookmarkViewController *)bookmarkViewController; -- (NSString*)savedTitle; -- (void)setSavedTitle:(NSString *)aTitle; +// Browser view of the frontmost tab (nil if bookmarks are showing?) +- (CHBrowserView*)activeBrowserView; // return a weak reference to the current web navigation object. Callers should // not hold onto this for longer than the current call unless they addref it. diff --git a/mozilla/camino/src/browser/BrowserWindowController.mm b/mozilla/camino/src/browser/BrowserWindowController.mm index 13c2bd61b63..ea5b6f3b5a6 100644 --- a/mozilla/camino/src/browser/BrowserWindowController.mm +++ b/mozilla/camino/src/browser/BrowserWindowController.mm @@ -48,6 +48,7 @@ #import "BookmarkManager.h" #import "AddBookmarkDialogController.h" #import "ProgressDlgController.h" +#import "PageInfoWindowController.h" #import "BrowserContentViews.h" #import "BrowserWrapper.h" @@ -436,6 +437,7 @@ enum BWCOpenDest { - (void)bookmarkableTitle:(NSString **)outTitle URL:(NSString**)outURLString forWrapper:(BrowserWrapper*)inWrapper; - (void)clearContextMenuTarget; +- (void)updateLock:(unsigned int)securityState; // create back/forward session history menus on toolbar button - (IBAction)backMenu:(id)inSender; @@ -466,7 +468,6 @@ enum BWCOpenDest { mProgressSuperview = nil; mBookmarkToolbarItem = nil; mSidebarToolbarItem = nil; - mSavedTitle = nil; // register for services NSArray* sendTypes = [NSArray arrayWithObjects:NSStringPboardType, nil]; @@ -669,16 +670,22 @@ enum BWCOpenDest { // it only works if it's here. [[[self window] undoManager] removeAllActions]; + // release top-level nib items + [mPageMenu release]; + [mImageMenu release]; + [mInputMenu release]; + [mLinkMenu release]; + [mMailToLinkMenu release]; + [mImageLinkMenu release]; + [mImageMailToLinkMenu release]; + [mTabMenu release]; + // active Gecko connections have already been shut down in |windowWillClose| // so we don't need to worry about that here. We only have to be careful // not to access anything related to the document, as it's been destroyed. The // superclass dealloc takes care of our child NSView's, which include the // BrowserWrappers and their child CHBrowserViews. - //if (mSidebarBrowserView) - // [mSidebarBrowserView windowClosed]; - - [mSavedTitle release]; [mProgress release]; [mPopupBlocked release]; [mSearchBar release]; @@ -1376,7 +1383,7 @@ enum BWCOpenDest { if (action == @selector(fillForm:)) return ![self bookmarkManagerIsVisible]; - + return YES; } @@ -1405,6 +1412,9 @@ enum BWCOpenDest { else [[self window] makeFirstResponder:[mBrowserView getBrowserView]]; } + + if ([[self window] isMainWindow]) + [[PageInfoWindowController visiblePageInfoWindowController] updateFromBrowserView:[self activeBrowserView]]; } - (void)setLoadingActive:(BOOL)active @@ -1461,10 +1471,8 @@ enum BWCOpenDest { [mURLBar setURI:url]; [mLocationSheetURLField setStringValue:url]; - // don't call [window display] here, no matter how much you might want - // to, because it forces a redraw of every view in the window and with a lot - // of tabs, it's dog slow. - // [[self window] display]; + if ([[self window] isMainWindow]) + [[PageInfoWindowController visiblePageInfoWindowController] updateFromBrowserView:[self activeBrowserView]]; } - (void)updateSiteIcons:(NSImage*)icon ignoreTyping:(BOOL)ignoreTyping @@ -1501,6 +1509,8 @@ enum BWCOpenDest { { // update bookmarks menu [[NSApp delegate] delayedAdjustBookmarksMenuItemsEnabling]; + + // should we change page info for bookmarks? } - (void)updateFromFrontmostTab @@ -2954,16 +2964,12 @@ enum BWCOpenDest { [[mBrowserView getBrowserView] smallerTextSize]; } -- (void)getInfo:(id)sender +- (IBAction)getInfo:(id)sender { - BookmarkViewController* bookmarksController = [self bookmarkViewControllerForCurrentTab]; - [bookmarksController ensureBookmarks]; - [bookmarksController showBookmarkInfo:sender]; -} - -- (BOOL)canGetInfo -{ - return [self singleBookmarkIsSelected]; + if ([self bookmarkManagerIsVisible]) + [self showBookmarksInfo:sender]; + else + [self showPageInfo:sender]; } - (BOOL)shouldShowBookmarkToolbar @@ -3281,6 +3287,21 @@ enum BWCOpenDest { } } +- (IBAction)showPageInfo:(id)sender +{ + PageInfoWindowController* pageInfoController = [PageInfoWindowController sharedPageInfoWindowController]; + + [pageInfoController updateFromBrowserView:[[self getBrowserWrapper] getBrowserView]]; + [[pageInfoController window] makeKeyAndOrderFront:nil]; +} + +- (IBAction)showBookmarksInfo:(id)sender +{ + BookmarkViewController* bookmarksController = [self bookmarkViewControllerForCurrentTab]; + [bookmarksController ensureBookmarks]; + [bookmarksController showBookmarkInfo:sender]; +} + - (BookmarkToolbar*) bookmarkToolbar { return mPersonalToolbar; @@ -3443,20 +3464,6 @@ enum BWCOpenDest { return sBrokenIcon; } -// return the window's saved title -- (NSString *)savedTitle -{ - return mSavedTitle; -} - -// save the window title before showing -// bookmark manager or History manager -- (void)setSavedTitle:(NSString *)aTitle -{ - [mSavedTitle autorelease]; - mSavedTitle = [aTitle retain]; -} - + (NSDictionary *)searchURLDictionary { static NSDictionary *searchURLDictionary = nil; @@ -3536,6 +3543,11 @@ enum BWCOpenDest { return [self bookmarkViewControllerForCurrentTab]; } +- (CHBrowserView*)activeBrowserView +{ + return [mBrowserView getBrowserView]; +} + - (id)windowWillReturnFieldEditor:(NSWindow *)aWindow toObject:(id)anObject { if ([anObject isEqual:mURLBar]) { diff --git a/mozilla/camino/src/browser/BrowserWrapper.mm b/mozilla/camino/src/browser/BrowserWrapper.mm index b5aac6f9bf8..918db98b5f2 100644 --- a/mozilla/camino/src/browser/BrowserWrapper.mm +++ b/mozilla/camino/src/browser/BrowserWrapper.mm @@ -261,20 +261,7 @@ static NSString* const kOfflineNotificationName = @"offlineModeChanged"; - (NSString*)pageTitle { - nsCOMPtr window = getter_AddRefs([mBrowserView getContentWindow]); - if (!window) - return @""; - - nsCOMPtr htmlDoc; - window->GetDocument(getter_AddRefs(htmlDoc)); - - nsCOMPtr htmlDocument(do_QueryInterface(htmlDoc)); - if (!htmlDocument) - return @""; - - nsAutoString titleString; - htmlDocument->GetTitle(titleString); - return [NSString stringWith_nsAString:titleString]; + return [mBrowserView pageTitle]; } - (NSImage*)siteIcon diff --git a/mozilla/camino/src/browser/PageInfoWindowController.h b/mozilla/camino/src/browser/PageInfoWindowController.h new file mode 100644 index 00000000000..0e85644fa40 --- /dev/null +++ b/mozilla/camino/src/browser/PageInfoWindowController.h @@ -0,0 +1,73 @@ +/* ***** 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 Camino 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 + +@class CertificateItem; +@class CHBrowserView; + +@interface PageInfoWindowController : NSWindowController +{ + // general tab + IBOutlet NSTextField* mPageTitleField; + IBOutlet NSTextField* mPageLocationField; + IBOutlet NSTextField* mPageModDateField; + + // security tab + IBOutlet NSImageView* mSiteVerifiedImageView; + IBOutlet NSTextField* mSiteVerifiedTextField; + IBOutlet NSTextField* mSiteVerifiedDetailsField; + IBOutlet NSButton* mShowCertificateButton; + + IBOutlet NSImageView* mConnectionImageView; + IBOutlet NSTextField* mConnectionTextField; + IBOutlet NSTextField* mConnectionDetailsField; + + CertificateItem* mCertificateItem; // retained +} + ++ (PageInfoWindowController*)sharedPageInfoWindowController; +// return nil if page info is not open ++ (PageInfoWindowController*)visiblePageInfoWindowController; + +- (IBAction)viewCertificate:(id)sender; + +- (void)updateFromBrowserView:(CHBrowserView*)inBrowserView; + + +@end diff --git a/mozilla/camino/src/browser/PageInfoWindowController.mm b/mozilla/camino/src/browser/PageInfoWindowController.mm new file mode 100644 index 00000000000..fdc3a480f44 --- /dev/null +++ b/mozilla/camino/src/browser/PageInfoWindowController.mm @@ -0,0 +1,287 @@ +/* ***** 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 Camino 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" + +#include "nsXPIDLString.h" + +#include "nsIDOMWindow.h" + +#include "nsISecureBrowserUI.h" +#include "nsISSLStatusProvider.h" +#include "nsISSLStatus.h" +#include "nsIX509Cert.h" +#include "nsIWebProgressListener.h" + +#import "CHBrowserView.h" + +#import "CertificateItem.h" +#import "CertificateView.h" +#import "ViewCertificateDialogController.h" + +#import "PageInfoWindowController.h" + + +static PageInfoWindowController* gSingletonPageInfoController; + +@interface PageInfoWindowController(Private) + +- (void)updateGeneralInfoFromBrowserView:(CHBrowserView*)inBrowserView; +- (void)updateSecurityInfoFromBrowserView:(CHBrowserView*)inBrowserView; + +- (void)clearInfo; +- (void)enableButtons; + +- (CertificateItem*)certificateItem; +- (void)setCertificateItem:(CertificateItem*)inCertItem; + +@end + +#pragma mark - + +@implementation PageInfoWindowController + ++ (PageInfoWindowController*)sharedPageInfoWindowController +{ + if (!gSingletonPageInfoController) + { + gSingletonPageInfoController = [[PageInfoWindowController alloc] initWithWindowNibName:@"PageInfo"]; + } + return gSingletonPageInfoController; +} + ++ (PageInfoWindowController*)visiblePageInfoWindowController +{ + return gSingletonPageInfoController; +} + +- (void)dealloc +{ + NSLog(@"%@ dealloc", self); + [mCertificateItem release]; + [super dealloc]; +} + +- (void)awakeFromNib +{ + [self setShouldCascadeWindows:NO]; + [[self window] setFrameAutosaveName:@"PageInfoWindow"]; +} + +- (void)windowDidLoad +{ + [self clearInfo]; +} + +- (void)windowWillClose:(NSNotification *)aNotification +{ + [self clearInfo]; // clear stuff + + if (self == gSingletonPageInfoController) + gSingletonPageInfoController = nil; + + // balance the init from when the window was shown + [self autorelease]; +} + +- (IBAction)viewCertificate:(id)sender +{ + if (mCertificateItem) + { + [ViewCertificateDialogController showCertificateWindowWithCertificateItem:mCertificateItem + certTypeForTrustSettings:nsIX509Cert::CA_CERT]; + } +} + +- (void)clearInfo +{ + [mPageTitleField setStringValue:@""]; + [mPageLocationField setStringValue:@""]; + [mPageModDateField setStringValue:@""]; + + [mSiteVerifiedTextField setStringValue:@""]; + [mSiteVerifiedDetailsField setStringValue:@""]; + [mSiteVerifiedImageView setImage:nil]; + + [mConnectionTextField setStringValue:@""]; + [mConnectionDetailsField setStringValue:@""]; + [mConnectionImageView setImage:nil]; + + [self setCertificateItem:nil]; +} + +- (void)enableButtons +{ + [mShowCertificateButton setEnabled:(mCertificateItem != nil)]; +} + +- (CertificateItem*)certificateItem +{ + return mCertificateItem; +} + +- (void)setCertificateItem:(CertificateItem*)inCertItem +{ + [mCertificateItem autorelease]; + mCertificateItem = [inCertItem retain]; + [self enableButtons]; +} + +- (void)updateFromBrowserView:(CHBrowserView*)inBrowserView +{ + [self window]; // force window loading + [self clearInfo]; + + if (!inBrowserView) return; + + [self updateGeneralInfoFromBrowserView:inBrowserView]; + [self updateSecurityInfoFromBrowserView:inBrowserView]; +} + +- (void)updateGeneralInfoFromBrowserView:(CHBrowserView*)inBrowserView +{ + nsCOMPtr contentWindow = [inBrowserView getContentWindow]; + if (!contentWindow) return; + + // general info + [mPageTitleField setStringValue:[inBrowserView pageTitle]]; + [mPageLocationField setStringValue:[inBrowserView getCurrentURI]]; + NSDate* lastModDate = [inBrowserView pageLastModifiedDate]; + + if (lastModDate) + { + NSString* dateFormat = NSLocalizedString(@"PageInfoDateFormat", @""); + NSDictionary* curCalendarLocale = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]; + + NSString* dateString = [lastModDate descriptionWithCalendarFormat:dateFormat + timeZone:nil + locale:curCalendarLocale]; + [mPageModDateField setStringValue:dateString]; + } +} + +- (void)updateSecurityInfoFromBrowserView:(CHBrowserView*)inBrowserView +{ + // let's see how many hoops we have to jump through + nsCOMPtr secureBrowserUI = [inBrowserView getSecureBrowserUI]; + + nsCOMPtr statusProvider = do_QueryInterface(secureBrowserUI); + if (!statusProvider) return; + + nsCOMPtr serverCert; + PRUint32 sekritKeyLength = 0; + NSString* cipherNameString = @""; + + nsCOMPtr secStatus; + statusProvider->GetSSLStatus(getter_AddRefs(secStatus)); + nsCOMPtr sslStatus = do_QueryInterface(secStatus); + if (sslStatus) + { + sslStatus->GetServerCert(getter_AddRefs(serverCert)); + sslStatus->GetSecretKeyLength(&sekritKeyLength); + + nsXPIDLCString cipherName; + sslStatus->GetCipherName(getter_Copies(cipherName)); + cipherNameString = [NSString stringWith_nsACString:cipherName]; + } + + // encryption info + PRUint32 pageState; + nsresult rv = secureBrowserUI->GetState(&pageState); + BOOL isBroken = NS_FAILED(rv) || (pageState == nsIWebProgressListener::STATE_IS_BROKEN); + + if (serverCert) + { + [mSiteVerifiedTextField setStringValue:NSLocalizedString(@"WebSiteVerified", @"")]; + + CertificateItem* certItem = [CertificateItem certificateItemWithCert:serverCert]; + NSString* issuerOrg = [certItem issuerOrganization]; + if ([issuerOrg length] == 0) + issuerOrg = [certItem issuerName]; + + NSString* detailsString = [NSString stringWithFormat:NSLocalizedString(@"WebSiteVerifiedDetailsFormat", @""), + [inBrowserView pageLocationHost], + issuerOrg]; + + [mSiteVerifiedDetailsField setStringValue:detailsString]; + [mSiteVerifiedImageView setImage:[NSImage imageNamed:@"security_lock"]]; + [self setCertificateItem:certItem]; + } + else + { + [mSiteVerifiedImageView setImage:[NSImage imageNamed:@"security_broken"]]; + [mSiteVerifiedTextField setStringValue:NSLocalizedString(@"WebSiteNotVerified", @"")]; + [mSiteVerifiedDetailsField setStringValue:@""]; + } + + if (isBroken) + { + [mConnectionTextField setStringValue:NSLocalizedString(@"WebSiteNotVerified", @"")]; + [mConnectionDetailsField setStringValue:NSLocalizedString(@"ConnectionMixedContentDetails", @"")]; + [mConnectionImageView setImage:[NSImage imageNamed:@"security_broken"]]; // XXX need "mixed" lock + } + else if (sekritKeyLength >= 90) + { + NSString* connectionString = [NSString stringWithFormat:NSLocalizedString(@"ConnectionStrongEncryptionFormat", @""), + cipherNameString, + sekritKeyLength]; + [mConnectionTextField setStringValue:connectionString]; + [mConnectionDetailsField setStringValue:NSLocalizedString(@"ConnectionStrongEncryptionDetails", @"")]; + [mConnectionImageView setImage:[NSImage imageNamed:@"security_lock"]]; + } + else if (sekritKeyLength > 0) + { + NSString* connectionString = [NSString stringWithFormat:NSLocalizedString(@"ConnectionWeakEncryptionFormat", @""), + cipherNameString, + sekritKeyLength]; + [mConnectionTextField setStringValue:connectionString]; + [mConnectionDetailsField setStringValue:NSLocalizedString(@"ConnectionWeakEncryptionDetails", @"")]; + [mConnectionImageView setImage:[NSImage imageNamed:@"security_lock"]]; // XXX nead "weak" lock + } + else + { + [mConnectionTextField setStringValue:NSLocalizedString(@"ConnectionNoneEncryption", @"")]; + [mConnectionDetailsField setStringValue:NSLocalizedString(@"ConnectionNoneEncryptionDetails", @"")]; + [mConnectionImageView setImage:[NSImage imageNamed:@"security_broken"]]; + } +} + +- (void)autosaveWindowFrame +{ +} + +@end diff --git a/mozilla/camino/src/download/ProgressDlgController.mm b/mozilla/camino/src/download/ProgressDlgController.mm index 595731df88e..a74dfe7f747 100644 --- a/mozilla/camino/src/download/ProgressDlgController.mm +++ b/mozilla/camino/src/download/ProgressDlgController.mm @@ -68,6 +68,8 @@ static NSString* const kProgressWindowFrameSaveName = @"ProgressWindow"; @end +#pragma mark - + @implementation ProgressDlgController static id gSharedProgressController = nil; @@ -88,7 +90,8 @@ static id gSharedProgressController = nil; -(id)init { - if ((self == [super initWithWindowNibName:@"ProgressDialog"])) { + if ((self = [super initWithWindowNibName:@"ProgressDialog"])) + { mProgressViewControllers = [[NSMutableArray alloc] init]; mDefaultWindowSize = [[self window] frame].size; // it would be nice if we could get the frame from the name, and then @@ -101,12 +104,17 @@ static id gSharedProgressController = nil; mShouldCloseWindow = NO; // We provide the views for the stack view, from mProgressViewControllers + [mStackView setShowsSeparators:YES]; [mStackView setDataSource:self]; + mSelectionPivotIndex = -1; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(DLInstanceSelected:) - name:@"DownloadInstanceSelected" object:nil]; + name:kDownloadInstanceSelectedNotificationName + object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(DLInstanceOpened:) - name:@"DownloadInstanceOpened" object:nil]; + name:kDownloadInstanceOpenedNotificationName + object:nil]; } return self; @@ -592,7 +600,7 @@ static id gSharedProgressController = nil; -(void)rebuildViews { - [mStackView reloadSubviews]; + [mStackView adaptToSubviews]; } -(int)numDownloadsInProgress @@ -990,14 +998,15 @@ static id gSharedProgressController = nil; CHStackView datasource methods */ --(int)subviewsForStackView:(CHStackView *)stackView +- (NSArray*)subviewsForStackView:(CHStackView *)stackView { - return [mProgressViewControllers count]; -} - --(NSView *)viewForStackView:(CHStackView *)aResizingView atIndex:(int)index -{ - return [((ProgressViewController*)[mProgressViewControllers objectAtIndex:index]) view]; + NSMutableArray* viewsArray = [NSMutableArray arrayWithCapacity:[mProgressViewControllers count]]; + + unsigned int numViews = [mProgressViewControllers count]; + for (unsigned int i = 0; i < numViews; i ++) + [viewsArray addObject:[((ProgressViewController*)[mProgressViewControllers objectAtIndex:i]) view]]; + + return viewsArray; } #pragma mark - diff --git a/mozilla/camino/src/download/ProgressView.h b/mozilla/camino/src/download/ProgressView.h index 3cf57ceac12..7d7f2c9376d 100644 --- a/mozilla/camino/src/download/ProgressView.h +++ b/mozilla/camino/src/download/ProgressView.h @@ -40,6 +40,9 @@ #import #import "ProgressViewController.h" +extern NSString* const kDownloadInstanceSelectedNotificationName; +extern NSString* const kDownloadInstanceOpenedNotificationName; + // // interface ProgressView // diff --git a/mozilla/camino/src/download/ProgressView.mm b/mozilla/camino/src/download/ProgressView.mm index 03223fb8c0a..393d1bd9ec1 100644 --- a/mozilla/camino/src/download/ProgressView.mm +++ b/mozilla/camino/src/download/ProgressView.mm @@ -40,6 +40,9 @@ #import "ProgressView.h" +NSString* const kDownloadInstanceSelectedNotificationName = @"DownloadInstanceSelected"; +NSString* const kDownloadInstanceOpenedNotificationName = @"DownloadInstanceOpened"; + @interface ProgressView(Private) -(BOOL)isSelected; @@ -87,14 +90,14 @@ } } [self setSelected:shouldSelect]; - [[NSNotificationCenter defaultCenter] postNotificationName:@"DownloadInstanceSelected" object:self]; + [[NSNotificationCenter defaultCenter] postNotificationName:kDownloadInstanceSelectedNotificationName object:self]; // after we've processed selection and modifiers, see if it's a double-click. If so, // send a notification off to the controller which will handle it accordingly. Doing it after // processing the modifiers allows someone to shift-dblClick and open all selected items // in the list in one action. if ([theEvent type] == NSLeftMouseDown && [theEvent clickCount] == 2) - [[NSNotificationCenter defaultCenter] postNotificationName:@"DownloadInstanceOpened" object:self]; + [[NSNotificationCenter defaultCenter] postNotificationName:kDownloadInstanceOpenedNotificationName object:self]; } -(int)lastModifier @@ -130,7 +133,7 @@ mLastModifier = kNoKey; // control is only special because it means its contextual menu time [self setSelected:YES]; [self display]; // change selection immediately - [[NSNotificationCenter defaultCenter] postNotificationName:@"DownloadInstanceSelected" object:self]; + [[NSNotificationCenter defaultCenter] postNotificationName:kDownloadInstanceSelectedNotificationName object:self]; } return [[self getController] contextualMenu]; } diff --git a/mozilla/camino/src/embedding/CHBrowserView.h b/mozilla/camino/src/embedding/CHBrowserView.h index 2b1f403a0fe..599703c9a55 100644 --- a/mozilla/camino/src/embedding/CHBrowserView.h +++ b/mozilla/camino/src/embedding/CHBrowserView.h @@ -50,14 +50,12 @@ class nsIDOMWindow; class nsIWebBrowser; class nsIDOMNode; class nsIDOMEvent; -class nsIWebBrowserFind; class nsIEventSink; class nsIDragHelperService; class nsIPrintSettings; class nsIURI; class nsISupports; - // Protocol implemented by anyone interested in progress // related to a BrowserView. A listener should explicitly // register itself with the view using the addListener @@ -176,8 +174,14 @@ enum { - (void)goForward; - (void)gotoIndex:(int)index; - (void)stop:(unsigned int)flags; + - (NSString*)getCurrentURI; +- (NSString*)pageLocation; // from window.location. can differ from the document's URI, and possibly from getCurrentURI +- (NSString*)pageLocationHost; +- (NSString*)pageTitle; +- (NSDate*)pageLastModifiedDate; + // nsIWebBrowserSetup methods - (void)setProperty:(unsigned int)property toValue:(unsigned int)value; diff --git a/mozilla/camino/src/embedding/CHBrowserView.mm b/mozilla/camino/src/embedding/CHBrowserView.mm index 4e1a1e3b852..f3495282608 100644 --- a/mozilla/camino/src/embedding/CHBrowserView.mm +++ b/mozilla/camino/src/embedding/CHBrowserView.mm @@ -20,6 +20,7 @@ * 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 @@ -37,6 +38,7 @@ #import "NSString+Utils.h" #import "NSPasteboard+Utils.h" +#import "NSDate+Utils.h" #import "CHClickListener.h" @@ -75,6 +77,7 @@ // Saving of links/images/docs #include "nsIWebBrowserFocus.h" #include "nsIDOMNSDocument.h" +#include "nsIDOMHTMLDocument.h" #include "nsIDOMLocation.h" #include "nsIWebBrowserPersist.h" #include "nsIProperties.h" @@ -131,9 +134,10 @@ const long NSFindPanelActionSetFindString = 7; - (nsIContentViewer*)getContentViewer; // addrefs return value - (float)getTextZoom; - (void)incrementTextZoom:(float)increment min:(float)min max:(float)max; -- (nsIDocShell*)getDocShell; +- (nsIDocShell*)getDocShell; // does NOT addref - (NSString*)getSelection; - +- (already_AddRefed)focussedDOMWindow; +- (NSString*)locationFromDOMWindow:(nsIDOMWindow*)inDOMWindow; - (void)ensurePrintSettings; - (void)savePrintSettings; @@ -345,6 +349,7 @@ const long NSFindPanelActionSetFindString = 7; _listener->SetContainer(container); } +// addrefs return value - (nsIDOMWindow*)getContentWindow { nsIDOMWindow* window = nsnull; @@ -489,6 +494,7 @@ const long NSFindPanelActionSetFindString = 7; browserSetup->SetProperty(property, value); } +// should we be using the window.location URL instead? see nsIDOMLocation.h - (NSString*)getCurrentURI { nsCOMPtr nav = do_QueryInterface(_webBrowser); @@ -505,6 +511,76 @@ const long NSFindPanelActionSetFindString = 7; return [NSString stringWithUTF8String:spec.get()]; } +- (NSString*)pageLocation +{ + nsCOMPtr contentWindow = getter_AddRefs([self getContentWindow]); + NSString* location = [self locationFromDOMWindow:contentWindow]; + return location ? location : @""; +} + +- (NSString*)pageLocationHost +{ + nsCOMPtr domWindow = getter_AddRefs([self getContentWindow]); + if (!domWindow) return @""; + nsCOMPtr domDocument; + domWindow->GetDocument(getter_AddRefs(domDocument)); + if (!domDocument) return @""; + nsCOMPtr nsDoc(do_QueryInterface(domDocument)); + if (!nsDoc) return @""; + + nsCOMPtr location; + nsDoc->GetLocation(getter_AddRefs(location)); + if (!location) return @""; + nsAutoString hostStr; + location->GetHost(hostStr); + + return [NSString stringWith_nsAString:hostStr]; +} + +- (NSString*)pageTitle +{ + nsCOMPtr window = getter_AddRefs([self getContentWindow]); + if (!window) + return @""; + + nsCOMPtr htmlDoc; + window->GetDocument(getter_AddRefs(htmlDoc)); + + nsCOMPtr htmlDocument(do_QueryInterface(htmlDoc)); + if (!htmlDocument) + return @""; + + nsAutoString titleString; + htmlDocument->GetTitle(titleString); + return [NSString stringWith_nsAString:titleString]; +} + +- (NSDate*)pageLastModifiedDate +{ + nsCOMPtr domWindow = getter_AddRefs([self getContentWindow]); + + nsCOMPtr domDocument; + domWindow->GetDocument(getter_AddRefs(domDocument)); + if (!domDocument) + return nil; + nsCOMPtr nsDoc(do_QueryInterface(domDocument)); + if (!nsDoc) + return nil; + + nsAutoString lastModifiedDate; + nsDoc->GetLastModified(lastModifiedDate); + + // sucks that we have to parse this back to a PRTime, thence back + // again to an NSDate. Why doesn't nsIDOMNSDocument have an accessor + // which can give me a date directly? + PRTime time; + PRStatus st = PR_ParseTimeString(NS_ConvertUCS2toUTF8(lastModifiedDate).get(), PR_FALSE /* local time */, &time); + if (st == PR_SUCCESS) + return [NSDate dateWithPRTime:time]; + + return nil; +} + - (CHBrowserListener*)getCocoaBrowserListener { return _listener; @@ -766,32 +842,46 @@ const long NSFindPanelActionSetFindString = 7; filterView: aFilterView]; } +- (already_AddRefed)focussedDOMWindow +{ + if (!_webBrowser) + return nsnull; + + nsCOMPtr wbf(do_QueryInterface(_webBrowser)); + nsIDOMWindow* domWindow; + wbf->GetFocusedWindow(&domWindow); + if (!domWindow) + _webBrowser->GetContentDOMWindow(&domWindow); + return domWindow; +} + +- (NSString*)locationFromDOMWindow:(nsIDOMWindow*)inDOMWindow +{ + if (!inDOMWindow) return nil; + nsCOMPtr domDocument; + inDOMWindow->GetDocument(getter_AddRefs(domDocument)); + if (!domDocument) + return nil; + nsCOMPtr nsDoc(do_QueryInterface(domDocument)); + if (!nsDoc) + return nil; + nsCOMPtr location; + nsDoc->GetLocation(getter_AddRefs(location)); + if (!location) + return nil; + nsAutoString urlStr; + location->GetHref(urlStr); + return [NSString stringWith_nsAString:urlStr]; +} + -(NSString*)getFocusedURLString { if (!_webBrowser) return @""; - nsCOMPtr wbf(do_QueryInterface(_webBrowser)); - nsCOMPtr domWindow; - wbf->GetFocusedWindow(getter_AddRefs(domWindow)); - if (!domWindow) - _webBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); - if (!domWindow) - return @""; - nsCOMPtr domDocument; - domWindow->GetDocument(getter_AddRefs(domDocument)); - if (!domDocument) - return @""; - nsCOMPtr nsDoc(do_QueryInterface(domDocument)); - if (!nsDoc) - return @""; - nsCOMPtr location; - nsDoc->GetLocation(getter_AddRefs(location)); - if (!location) - return @""; - nsAutoString urlStr; - location->GetHref(urlStr); - return [NSString stringWith_nsAString: urlStr]; + nsCOMPtr focussedWindow = [self focussedDOMWindow]; + NSString* locationString = [self locationFromDOMWindow:focussedWindow]; + return locationString ? locationString : @""; } - (void)saveDocument:(BOOL)focusedFrame filterView:(NSView*)aFilterView @@ -801,13 +891,9 @@ const long NSFindPanelActionSetFindString = 7; nsCOMPtr domWindow; if (focusedFrame) - { - nsCOMPtr wbf(do_QueryInterface(_webBrowser)); - wbf->GetFocusedWindow(getter_AddRefs(domWindow)); - } + domWindow = [self focussedDOMWindow]; else _webBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); - if (!domWindow) return; @@ -815,26 +901,19 @@ const long NSFindPanelActionSetFindString = 7; domWindow->GetDocument(getter_AddRefs(domDocument)); if (!domDocument) return; - nsCOMPtr nsDoc(do_QueryInterface(domDocument)); - if (!nsDoc) - return; - nsCOMPtr location; - nsDoc->GetLocation(getter_AddRefs(location)); - if (!location) - return; - nsAutoString urlStr; - location->GetHref(urlStr); + + NSString* windowLocation = [self locationFromDOMWindow:domWindow]; nsCOMPtr url; - nsresult rv = NS_NewURI(getter_AddRefs(url), NS_ConvertUCS2toUTF8(urlStr).get()); + nsresult rv = NS_NewURI(getter_AddRefs(url), [windowLocation UTF8String]); if (NS_FAILED(rv)) return; - [self saveInternal: url.get() - withDocument: domDocument - suggestedFilename: @"" - bypassCache: NO - filterView: aFilterView]; + [self saveInternal:url.get() + withDocument:domDocument + suggestedFilename:@"" + bypassCache:NO + filterView:aFilterView]; } -(void)doCommand:(const char*)commandName @@ -1011,38 +1090,6 @@ const long NSFindPanelActionSetFindString = 7; [[self getBrowserContainer] didDismissPrompt]; } -#if 0 -// how does this differ from getCurrentURI? --(NSString*)getCurrentURLSpec -{ - NSString* empty = @""; - if (!_webBrowser) - return empty; - nsCOMPtr domWindow; - _webBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); - if (!domWindow) - return empty; - - nsCOMPtr domDocument; - domWindow->GetDocument(getter_AddRefs(domDocument)); - if (!domDocument) - return empty; - - nsCOMPtr nsDoc(do_QueryInterface(domDocument)); - if (!nsDoc) - return empty; - - nsCOMPtr location; - nsDoc->GetLocation(getter_AddRefs(location)); - if (!location) - return empty; - - nsAutoString urlStr; - location->GetHref(urlStr); - return [NSString stringWith_nsAString: urlStr]; -} -#endif - - (void)setActive: (BOOL)aIsActive { nsCOMPtr wbf(do_QueryInterface(_webBrowser)); @@ -1095,7 +1142,7 @@ const long NSFindPanelActionSetFindString = 7; } } - +// does NOT addref return value - (nsIDocShell*)getDocShell { if (!_webBrowser) diff --git a/mozilla/camino/src/extensions/AutoSizingTextField.h b/mozilla/camino/src/extensions/AutoSizingTextField.h new file mode 100644 index 00000000000..48095fc4a81 --- /dev/null +++ b/mozilla/camino/src/extensions/AutoSizingTextField.h @@ -0,0 +1,55 @@ +/* ***** 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 + * Calum Robinson. + * 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 + +// +// AutoSizingTextField +// +// This is a text field that automatically adjusts its height +// to fit the text. The width remains unchanged. It will never +// shrink to be less that one lineheight tall. +// +// Can be used in Interface Builder, if you have built and installed +// the CaminoView.palette IB Palette. +// + +@interface AutoSizingTextField : NSTextField +{ + BOOL mSettingFrameSize; +} +@end diff --git a/mozilla/camino/src/extensions/AutoSizingTextField.m b/mozilla/camino/src/extensions/AutoSizingTextField.m new file mode 100644 index 00000000000..a8375a86d03 --- /dev/null +++ b/mozilla/camino/src/extensions/AutoSizingTextField.m @@ -0,0 +1,114 @@ +/* ***** 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 + * Calum Robinson. + * 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" +#import "AutoSizingTextField.h" + + +@interface AutoSizingTextField(Private) + +- (NSSize)sizeForFrame:(NSRect)inFrame; +- (void)adjustSize; + +@end + +#pragma mark - + +@implementation AutoSizingTextField + +- (void)setStringValue:(NSString*)inString +{ + [super setStringValue:inString]; + [self adjustSize]; +} + +- (void)setAttributedStringValue:(NSAttributedString *)inString +{ + [super setAttributedStringValue:inString]; + [self adjustSize]; +} + +- (void)setFrame:(NSRect)frameRect +{ + NSSize origSize = frameRect.size; + frameRect.size = [self sizeForFrame:frameRect]; + + if (![[self superview] isFlipped]) + frameRect.origin.y -= (frameRect.size.height - origSize.height); + + mSettingFrameSize = YES; + [super setFrame:frameRect]; + mSettingFrameSize = NO; +} + +- (void)setFrameSize:(NSSize)newSize +{ + if (mSettingFrameSize) + { + [super setFrameSize:newSize]; + return; + } + + NSRect newFrame = [self frame]; + newFrame.size = newSize; + [super setFrameSize:[self sizeForFrame:newFrame]]; +} + +- (NSSize)sizeForFrame:(NSRect)inFrame +{ + inFrame.size.height = 10000.0f; + NSSize newSize = [[self cell] cellSizeForBounds:inFrame]; + // don't let it get zero height + if (newSize.height == 0.0f) + { + NSFont* cellFont = [[self cell] font]; + float lineHeight = [cellFont ascender] - [cellFont descender]; + newSize.height = lineHeight; + } + + newSize.width = inFrame.size.width; + return newSize; +} + +- (void)adjustSize +{ + // NSLog(@"%@ adjustSize (%@)", self, [self stringValue]); + [self setFrameSizeMaintainingTopLeftOrigin:[self sizeForFrame:[self frame]]]; + //[self setFrameSize:[self sizeForFrame:[self frame]]]; +} + +@end diff --git a/mozilla/camino/src/extensions/CHStackView.h b/mozilla/camino/src/extensions/CHStackView.h index b9b338968a3..144405d5ece 100644 --- a/mozilla/camino/src/extensions/CHStackView.h +++ b/mozilla/camino/src/extensions/CHStackView.h @@ -20,6 +20,7 @@ * * 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 @@ -38,24 +39,98 @@ #import // views contained in the stack should send this notification when they change size -extern NSString* StackViewReloadNotificationName; +extern NSString* const kStackViewReloadNotificationName; // the stack view sends this notification after it has adjusted to subview sizes -extern NSString* StackViewResizedNotificationName; +extern NSString* const kStackViewResizedNotificationName; -@interface CHStackView : NSView + +// +// CHShrinkWrapView +// +// A view that resizes to contain its subviews. +// +// Early on, it will look at its subview positions, and calculate +// the "intrinsic padding" (i.e. the space around the subviews), +// and use this when sizing itself. It will then resize itself to +// contain its subviews, plus the padding, whenever one if its +// direct subviews resizes. +// +// Can be used in Interface Builder, if you have built and installed +// the CaminoView.palette IB Palette. +// + +@interface CHShrinkWrapView : NSView +{ + float mIntrinsicPadding[4]; // NSMinXEdge, NSMinYEdge, NSMaxXEdge, NSMaxYEdge + BOOL mFetchedIntrinsicPadding; + BOOL mPaddingSetManually; + BOOL mSelfResizing; +} + +// padding will normally be calculated automatically from the subview positions, +// but you can set it explicilty if you wish. +- (void)setIntrinsicPadding:(float)inPadding forEdge:(NSRectEdge)inEdge; +- (float)paddingForEdge:(NSRectEdge)inEdge; + +- (void)adaptToSubviews; + +@end + + + +// +// CHFlippedShrinkWrapView +// +// A subview of CHShrinkWrapView that is flipped. +// +// This is used when nesting a CHStackView inside an NSScrollView, +// because NSScrollView messes up is its containerView isn't flipped +// (really). +// +// If you have one of these in IB, editing contained views is broken +// (view outlines draw flipped, mouse interaction is busted). +// + +@interface CHFlippedShrinkWrapView : CHShrinkWrapView +{ +} + +@end + +// +// CHStackView +// +// A view that lays out its subviews top to bottom. +// +// It can either manage a static set of subviws as specified in +// the nib, or the subviews can be supplied by a "data source". +// If using a data source, the stack view can optionally insert +// a separator view after each supplied view. +// +// The data source, if used, must retain the views. +// +// Can be used in Interface Builder, if you have built and installed +// the CaminoView.palette IB Palette. +// + +@interface CHStackView : CHShrinkWrapView { IBOutlet id mDataSource; + BOOL mShowsSeparators; +// BOOL mIsResizingSubviews; } - (void)setDataSource:(id)aDataSource; -- (void)reloadSubviews; + +// default is NO +- (BOOL)showsSeparators; +- (void)setShowsSeparators:(BOOL)inShowSeparators; @end @protocol CHStackViewDataSource -- (int)subviewsForStackView:(CHStackView *)stackView; -- (NSView *)viewForStackView:(CHStackView *)stackView atIndex:(int)index; +- (NSArray*)subviewsForStackView:(CHStackView *)stackView; @end diff --git a/mozilla/camino/src/extensions/CHStackView.m b/mozilla/camino/src/extensions/CHStackView.m index 02018466783..c3e19331000 100644 --- a/mozilla/camino/src/extensions/CHStackView.m +++ b/mozilla/camino/src/extensions/CHStackView.m @@ -22,6 +22,7 @@ * Contributor(s): * Calum Robinson * Josh Aas + * 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 @@ -37,34 +38,292 @@ * * ***** 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 "NSView+Utils.h" #import "CHStackView.h" -NSString* StackViewReloadNotificationName = @"ReloadStackView"; -NSString* StackViewResizedNotificationName = @"StackViewResized"; +@interface NSObject(PrivateAPI) ++ (BOOL)isInInterfaceBuilder; ++ (BOOL)editingInInterfaceBuilder; +@end + +@interface CHShrinkWrapView(Private) + ++ (BOOL)drawPlacementRect; + +- (void)setupNotifications; +- (void)viewBoundsChangedNotification:(NSNotification*)inNotification; +- (void)viewFrameChangedNotification:(NSNotification*)inNotification; +- (void)recalcPadding; + +@end + +#pragma mark - + +@implementation CHShrinkWrapView + +- (id)initWithFrame:(NSRect)inFrame +{ + if ((self = [super initWithFrame:inFrame])) + { + [self setupNotifications]; + } + return self; +} + +- (id)initWithCoder:(NSCoder *)decoder +{ + if ((self = [super initWithCoder:decoder])) + { + [self setupNotifications]; + } + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder +{ + [super encodeWithCoder:coder]; +} + +- (void)awakeFromNib +{ +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [super dealloc]; +} + +- (void)drawRect:(NSRect)inRect +{ + if ([NSObject respondsToSelector:@selector(editingInInterfaceBuilder)] && + [NSObject editingInInterfaceBuilder]) + { + [[NSColor blueColor] set]; + NSFrameRect([self bounds]); + } +} + +- (void)setIntrinsicPadding:(float)inPadding forEdge:(NSRectEdge)inEdge +{ + if ((int)inEdge < 0 || (int)inEdge > 3) + return; + + mIntrinsicPadding[inEdge] = inPadding; + mPaddingSetManually = YES; +} + +- (float)paddingForEdge:(NSRectEdge)inEdge +{ + if ((int)inEdge < 0 || (int)inEdge > 3) + return 0.0f; + + return mIntrinsicPadding[inEdge]; +} + +- (void)didAddSubview:(NSView *)subview +{ + [subview setPostsBoundsChangedNotifications:YES]; + [subview setPostsFrameChangedNotifications:YES]; + + mFetchedIntrinsicPadding = NO; +} + +- (void)willRemoveSubview:(NSView *)subview +{ +} + +- (void)viewDidMoveToWindow +{ + if ([self window]) + { + [self adaptToSubviews]; + } +} + +- (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize +{ + BOOL alreadyResizing = mSelfResizing; + + // avoid layout out our subviews once for every subview resize... + mSelfResizing = YES; + [super resizeSubviewsWithOldSize:oldBoundsSize]; + mSelfResizing = alreadyResizing; + + // ...by doing it just once here + if (!alreadyResizing) + [self adaptToSubviews]; +} + +- (void)recalcPadding +{ + if (mPaddingSetManually || mFetchedIntrinsicPadding) + return; + + NSRect subframeBounds = NSZeroRect; + NSEnumerator* subviewsEnum = [[self subviews] objectEnumerator]; + NSView* curSubView; + while ((curSubView = [subviewsEnum nextObject])) + { + NSRect subviewFrame = [curSubView frame]; + subframeBounds = NSUnionRect(subviewFrame, subframeBounds); + } + + NSRect myBounds = [self bounds]; + mIntrinsicPadding[NSMinXEdge] = NSMinX(subframeBounds); + mIntrinsicPadding[NSMinYEdge] = NSMinY(subframeBounds); + mIntrinsicPadding[NSMaxXEdge] = NSWidth(myBounds) - NSMaxX(subframeBounds); + mIntrinsicPadding[NSMaxYEdge] = NSHeight(myBounds) - NSMaxY(subframeBounds); + + mFetchedIntrinsicPadding = YES; +} + +- (void)adaptToSubviews +{ + // we can't rely on -awakeFromNib being called in any particular order, + // so we have to call -recalcPadding here, rather than from -awakeFromNib. + [self recalcPadding]; + + if (mSelfResizing) return; + + if ([NSObject respondsToSelector:@selector(editingInInterfaceBuilder)] && + [NSObject editingInInterfaceBuilder]) + { + return; + } + +#if 0 + NSLog(@"%@ padding: %f %f %f %f", self, mIntrinsicPadding[0], + mIntrinsicPadding[1], + mIntrinsicPadding[2], + mIntrinsicPadding[3]); +#endif + + + NSRect subframeBounds = NSZeroRect; + NSEnumerator* subviewsEnum = [[self subviews] objectEnumerator]; + NSView* curSubView; + while ((curSubView = [subviewsEnum nextObject])) + { + NSRect subviewFrame = [curSubView frame]; + subframeBounds = NSUnionRect(subviewFrame, subframeBounds); + } + + subframeBounds.origin.x = mIntrinsicPadding[NSMinXEdge]; + subframeBounds.origin.y = mIntrinsicPadding[NSMinYEdge]; + + subframeBounds.size.width += mIntrinsicPadding[NSMaxXEdge]; + subframeBounds.size.height += mIntrinsicPadding[NSMaxYEdge]; + + NSSize curSize = [self frame].size; + NSSize newSize = curSize; + if (!([self autoresizingMask] & NSViewWidthSizable)) + newSize.width = NSMaxX(subframeBounds); + + if (!([self autoresizingMask] & NSViewHeightSizable)) + newSize.height = NSMaxY(subframeBounds); + + if (!NSEqualSizes(curSize, newSize)) + { + // NSLog(@"resize %@ to %@", self, NSStringFromSize(newSize)); + mSelfResizing = YES; + [self setFrameSizeMaintainingTopLeftOrigin:newSize]; + mSelfResizing = NO; + + [super setNeedsDisplay:YES]; + } +} + +- (void)setupNotifications +{ + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(viewBoundsChangedNotification:) + name:NSViewBoundsDidChangeNotification + object:nil]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(viewFrameChangedNotification:) + name:NSViewFrameDidChangeNotification + object:nil]; +} + +- (void)viewBoundsChangedNotification:(NSNotification*)inNotification +{ + NSView* changedView = [inNotification object]; + if (changedView == self) + [self recalcPadding]; + else if ([self hasSubview:changedView]) + [self adaptToSubviews]; +} + +- (void)viewFrameChangedNotification:(NSNotification*)inNotification +{ + NSView* changedView = [inNotification object]; + if (changedView == self) + [self recalcPadding]; + else if ([self hasSubview:changedView]) + [self adaptToSubviews]; +} + +- (BOOL)isFlipped +{ + // not flipped because that IB freaks out when editing if it is + return NO; +} + +@end + + +#pragma mark - + +@implementation CHFlippedShrinkWrapView + +- (BOOL)isFlipped +{ + return YES; +} + +@end + +#pragma mark - + +NSString* const kStackViewReloadNotificationName = @"ReloadStackView"; +NSString* const kStackViewResizedNotificationName = @"StackViewResized"; + +@interface CHStackView(Private) + +- (NSArray*)managedSubviews; + +@end @implementation CHStackView -(id)initWithFrame:(NSRect)frameRect { - if ((self = [super initWithFrame:frameRect])) { - // Register for notifications when one of the subviews changes size + if ((self = [super initWithFrame:frameRect])) + { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadNotification:) - name:StackViewReloadNotificationName + name:kStackViewReloadNotificationName object:nil]; } return self; } +- (void)awakeFromNib +{ + // if we're thawed from a nib, and we don't have any subviews, then we seem + // to have subview resizing turned off, but we want it on. + [self setAutoresizesSubviews:YES]; + + if ([super respondsToSelector:@selector(awakeFromNib)]) + [super awakeFromNib]; + + [self adaptToSubviews]; +} + -(void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; @@ -74,66 +333,144 @@ NSString* StackViewResizedNotificationName = @"StackViewResized"; -(void)setDataSource:(id)aDataSource { mDataSource = aDataSource; // should this retain? - [self reloadSubviews]; + [self adaptToSubviews]; } -(void)reloadNotification:(NSNotification*)notification { - [self reloadSubviews]; + [self adaptToSubviews]; } --(void)reloadSubviews +- (void)didAddSubview:(NSView *)subview { - NSRect newFrame = [self frame]; - NSSize oldSize = [self bounds].size; - int i, subviewCount = [mDataSource subviewsForStackView:self]; - NSPoint nextOrigin = NSZeroPoint; - - // maintain the width of the stack view, assuming that it's scaled by its superview. - newFrame.size.height = 0.0; - - [self removeAllSubviews]; - - for (i = 0; i < subviewCount; i++) { - NSView *subview = [mDataSource viewForStackView:self atIndex:i]; - NSRect subviewFrame = [subview frame]; - NSBox *separator; - - 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]; - - // always add a separator - 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]; + [super didAddSubview:subview]; + // [subview setAutoresizingMask:([subview autoresizingMask] | NSViewMinYMargin)]; +} + +- (void)drawRect:(NSRect)inRect +{ + if ([NSObject respondsToSelector:@selector(editingInInterfaceBuilder)] && + [NSObject editingInInterfaceBuilder]) + { + [[NSColor orangeColor] set]; + NSFrameRect([self bounds]); + } +} + +-(void)adaptToSubviews +{ + if (mSelfResizing) return; // avoid re-entry + + if ([NSObject respondsToSelector:@selector(editingInInterfaceBuilder)] && + [NSObject editingInInterfaceBuilder]) + { + return; } + + // NSLog(@"%@ frame %@", self, NSStringFromRect([self frame])); + const float kSeparatorHeight = 1.0f; - NSRect newBounds = newFrame; - newBounds.origin = NSZeroPoint; + NSSize mySize = [self frame].size; + NSSize oldSize = mySize; + + float totalHeightOfSubviews = 0.0f; + // we're not flipped because that freaks out editing in IB. So + // we have to do this in 2 passes; one to resize the subviews, and + // a second to place them (after sizing ourselves). + NSEnumerator* stackViewsEnum = [[self managedSubviews] objectEnumerator]; + NSView* curView; + while ((curView = [stackViewsEnum nextObject])) + { + NSSize subviewFrameSize = [curView frame].size; + + unsigned int autoResizeMask = [curView autoresizingMask]; + if ((autoResizeMask & NSViewWidthSizable) && (subviewFrameSize.width != mySize.width)) + { + subviewFrameSize.width = mySize.width; + mSelfResizing = YES; + [curView setFrameSize:subviewFrameSize]; + mSelfResizing = NO; + + // setting the width may have changed the height, so fetch it again + subviewFrameSize = [curView frame].size; + } + + totalHeightOfSubviews += subviewFrameSize.height; + + if (mShowsSeparators && mDataSource) + totalHeightOfSubviews += kSeparatorHeight; + } + + // resize self now + mySize.height = totalHeightOfSubviews; - [self setFrame:newFrame]; + mSelfResizing = YES; + [self setFrameSizeMaintainingTopLeftOrigin:mySize]; + mSelfResizing = NO; [self setNeedsDisplay:YES]; - [[NSNotificationCenter defaultCenter] postNotificationName:StackViewResizedNotificationName + // now place the subviews + if (mDataSource) + [self removeAllSubviews]; // should we keep a copy of the array to make sure they survive? + + float curMaxY = totalHeightOfSubviews; + + stackViewsEnum = [[self managedSubviews] objectEnumerator]; + while ((curView = [stackViewsEnum nextObject])) + { + NSRect subviewFrame = [curView frame]; + + curMaxY -= NSHeight(subviewFrame); + subviewFrame.origin.y = curMaxY; + + mSelfResizing = YES; + [curView setFrameOrigin:subviewFrame.origin]; + mSelfResizing = NO; + + if (mDataSource) + [self addSubview:curView]; + + if (mShowsSeparators && mDataSource) + { + curMaxY -= kSeparatorHeight; + + NSBox* separator = [[NSBox alloc] initWithFrame: + NSMakeRect(subviewFrame.origin.x, curMaxY, NSWidth(subviewFrame), kSeparatorHeight)]; + [separator setBoxType:NSBoxSeparator]; + [separator setAutoresizingMask:NSViewWidthSizable]; + [self addSubview:separator]; + [separator release]; + } + } + + [[NSNotificationCenter defaultCenter] postNotificationName:kStackViewResizedNotificationName object:self userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSValue valueWithSize:oldSize], @"oldsize", nil]]; } +- (BOOL)showsSeparators +{ + return mShowsSeparators; +} + +- (void)setShowsSeparators:(BOOL)inShowSeparators +{ + mShowsSeparators = inShowSeparators; +} + -(BOOL)isFlipped { - return YES; + // not flipped because that IB freaks out when editing if it is + // (so the math is harder in -adaptToSubviews. oh well). + return NO; +} + +- (NSArray*)managedSubviews +{ + if (mDataSource) + return [mDataSource subviewsForStackView:self]; + + return [self subviews]; } @end diff --git a/mozilla/camino/src/extensions/NSView+Utils.h b/mozilla/camino/src/extensions/NSView+Utils.h index 9446d10d952..94088dd7190 100644 --- a/mozilla/camino/src/extensions/NSView+Utils.h +++ b/mozilla/camino/src/extensions/NSView+Utils.h @@ -67,4 +67,12 @@ BOOL CHCloseSizes(NSSize aSize, NSSize bSize, float slop); - (void)removeAllSubviews; +// is 'inView' an immediate subview of the receiver +- (BOOL)hasSubview:(NSView*)inView; + +- (void)setFrameSizeMaintainingTopLeftOrigin:(NSSize)inNewSize; + +// convert inRect to view coords depending on whether the view is flipped +- (NSRect)subviewRectFromTopRelativeRect:(NSRect)inRect; + @end diff --git a/mozilla/camino/src/extensions/NSView+Utils.m b/mozilla/camino/src/extensions/NSView+Utils.m index a93b8287ba3..eaeef06016f 100644 --- a/mozilla/camino/src/extensions/NSView+Utils.m +++ b/mozilla/camino/src/extensions/NSView+Utils.m @@ -191,4 +191,33 @@ static void RedistributeSpace(int resizeMask, float newWidth, /* in out */ float [subviewsArray release]; } +- (BOOL)hasSubview:(NSView*)inView +{ + return [[self subviews] containsObject:inView]; +} + +- (void)setFrameSizeMaintainingTopLeftOrigin:(NSSize)inNewSize +{ + if ([[self superview] isFlipped]) + [self setFrameSize:inNewSize]; + else + { + NSRect newFrame = [self frame]; + newFrame.origin.y -= (inNewSize.height - newFrame.size.height); + newFrame.size = inNewSize; + [self setFrame:newFrame]; + } +} + +- (NSRect)subviewRectFromTopRelativeRect:(NSRect)inRect +{ + if ([self isFlipped]) + return inRect; + + NSRect theRect = inRect; + theRect.origin.y = NSHeight([self bounds]) - NSMaxY(inRect); + return theRect; +} + + @end diff --git a/mozilla/camino/src/extensions/TruncatingTextFieldCell.h b/mozilla/camino/src/extensions/TruncatingTextFieldCell.h new file mode 100644 index 00000000000..0114f080b72 --- /dev/null +++ b/mozilla/camino/src/extensions/TruncatingTextFieldCell.h @@ -0,0 +1,61 @@ +/* ***** 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 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 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 "NSString+Utils.h" // for ETruncationType + +// +// TruncatingTextFieldCell +// +// Text field cell that can be used to truncate text in a text field. +// +// Use by creating one and setting it as the cell on an NSTextField. +// + +@interface TruncatingTextFieldCell : NSTextFieldCell +{ + NSString* mOriginalStringValue; // copy of the whole string + ETruncationType mTruncationPosition; +} + +- (id)initTextCell:(NSString*)inTextValue truncation:(ETruncationType)truncType; + +- (void)setTruncationPosition:(ETruncationType)truncType; +- (ETruncationType)truncationPosition; + +@end diff --git a/mozilla/camino/src/extensions/TruncatingTextFieldCell.mm b/mozilla/camino/src/extensions/TruncatingTextFieldCell.mm new file mode 100644 index 00000000000..61058ecf5f8 --- /dev/null +++ b/mozilla/camino/src/extensions/TruncatingTextFieldCell.mm @@ -0,0 +1,122 @@ +/* ***** 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 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 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 "TruncatingTextFieldCell.h" + +@interface TruncatingTextFieldCell(Private) + +- (NSString*)truncatedStringForRect:(NSRect)inRect; +- (NSDictionary*)fontAttributes; +- (NSRect)textBoundsForFrame:(NSRect)inFrameRect; + +@end + +@implementation TruncatingTextFieldCell + +// designated initializer +- (id)initTextCell:(NSString*)inTextValue +{ + if ((self = [super initTextCell:inTextValue])) + { + mTruncationPosition = kTruncateAtEnd; + } + return self; +} + +- (id)initTextCell:(NSString*)inTextValue truncation:(ETruncationType)truncType +{ + if ((self = [self initTextCell:inTextValue])) + { + mTruncationPosition = truncType; + } + return self; +} + +- (void)setTruncationPosition:(ETruncationType)truncType +{ + mTruncationPosition = truncType; + // redo truncation? +} + +- (ETruncationType)truncationPosition +{ + return mTruncationPosition; +} + +- (void)setStringValue:(NSString*)inValue +{ + NSString* oldValue = mOriginalStringValue; + mOriginalStringValue = [inValue retain]; + [oldValue release]; + [super setStringValue:inValue]; +} + +- (NSString*)stringValue +{ + return mOriginalStringValue; +} + +- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView +{ + [super setStringValue:[self truncatedStringForRect:cellFrame]]; + [super drawInteriorWithFrame:cellFrame inView:controlView]; +} + +- (NSString*)truncatedStringForRect:(NSRect)inRect +{ + NSRect textRect = [self textBoundsForFrame:inRect]; + return [mOriginalStringValue stringByTruncatingToWidth:NSWidth(textRect) + at:mTruncationPosition + withAttributes:[self fontAttributes]]; +} + +- (NSDictionary*)fontAttributes +{ + return [NSDictionary dictionaryWithObject:[self font] forKey:NSFontAttributeName]; +} + +- (NSRect)textBoundsForFrame:(NSRect)inFrameRect +{ + // values derived empirically + return NSInsetRect(inFrameRect, 2.0f, 0.0f); +} + +@end + diff --git a/mozilla/camino/src/security/CertificateView.h b/mozilla/camino/src/security/CertificateView.h index dd5b417d4bf..0dd64aa469b 100644 --- a/mozilla/camino/src/security/CertificateView.h +++ b/mozilla/camino/src/security/CertificateView.h @@ -37,13 +37,18 @@ * ***** END LICENSE BLOCK ***** */ #import +#import "CHStackView.h" @class CertificateItem; // this is a view that builds its contents dynamically from the cert. -@interface CertificateView : NSView +@interface CertificateView : CHShrinkWrapView { - NSView* mContentView; // created dynamically, retained + CHStackView* mContentView; // created dynamically, retained + + NSView* mTrustItemsView; // weak + NSView* mDetailsItemsView; // weak + BOOL mDetailsExpanded; BOOL mTrustExpanded; diff --git a/mozilla/camino/src/security/CertificateView.mm b/mozilla/camino/src/security/CertificateView.mm index bc48852cbb9..bbc2d608593 100644 --- a/mozilla/camino/src/security/CertificateView.mm +++ b/mozilla/camino/src/security/CertificateView.mm @@ -50,35 +50,20 @@ #import "nsServiceManagerUtils.h" +#import "AutoSizingTextField.h" + +#import "CHStackView.h" #import "CertificateItem.h" #import "CertificateView.h" -#pragma mark CertificateContentsView -#pragma mark - - -@interface CertificateContentsView : NSView -{ -} -@end - -@implementation CertificateContentsView - -- (BOOL)isFlipped -{ - return YES; -} - -@end - -#pragma mark - - const float kCertImageViewSize = 64.0f; const float kCertHeaderFieldVerticalGap = 4.0f; const float kCertHeaderFieldRightGap = 4.0f; const float kStatusImageSize = 12.0f; const float kGroupHeaderLeftOffset = 4.0f; +const float kGapAboveGroup = 2.0f; const float kGapUnderGroupHeader = 5.0f; const float kDisclosureLabelGap = 4.0f; @@ -87,12 +72,14 @@ const float kDisclosureButtonSize = 12.0f; const float kGeneralRightGap = 4.0f; const float kHeaderLeftOffset = 16.0f; -const float kGapUnderHeader = 5.0f; +const float kGapAboveHeader = 2.0f; +const float kGapUnderHeader = 3.0f; const float kGapUnderGroup = 5.0f; const float kLabelLeftOffset = 16.0f; const float kLabelGutterWidth = 10.0f; -const float kGapUnderLine = 5.0f; +const float kGapUnderLine = 5.0f; +const float kGapUnderCheckboxLine = 3.0f; #pragma mark - #pragma mark CertificateView @@ -102,20 +89,25 @@ const float kGapUnderLine = 5.0f; - (float)labelColumnWidth; -- (NSTextField*)textFieldWithInitialFrame:(NSRect)inFrame stringValue:(NSString*)inString small:(BOOL)useSmallFont bold:(BOOL)useBold; +- (CHShrinkWrapView*)containerViewWithTopPadding:(float)inTop bottomPadding:(float)inBottom; +- (NSTextField*)textFieldWithInitialFrame:(NSRect)inFrame stringValue:(NSString*)inString autoSizing:(BOOL)inAutosize small:(BOOL)useSmallFont bold:(BOOL)useBold; -- (void)addGroupingWithKey:(NSString*)inLabelKey expanded:(BOOL)inExpanded action:(SEL)inAction atOffset:(float*)ioOffset; -- (void)addHeaderWithKey:(NSString*)inLabelKey atOffset:(float*)ioOffset; -- (void)addLineWithLabelKey:(NSString*)inLabelKey data:(NSString*)inData atOffset:(float*)ioOffset ignoreBlankLines:(BOOL)inIgnoreBlank; -- (void)addScrollingTextFieldWithLabelKey:(NSString*)inLabelKey data:(NSString*)inData atOffset:(float*)ioOffset ignoreBlankLines:(BOOL)inIgnoreBlank; -- (NSButton*)addButtonLineWithLabelKey:(NSString*)inLabelKey buttonLabelKey:(NSString*)buttonKey action:(SEL)inAction atOffset:(float*)ioOffset; -- (NSButton*)addCheckboxLineWithLabelKey:(NSString*)inLabelKey buttonLabelKey:(NSString*)buttonKey action:(SEL)inAction atOffset:(float*)ioOffset; +- (CHStackView *)groupingWithKey:(NSString*)inLabelKey expanded:(BOOL)inExpanded action:(SEL)inAction; +- (NSView*)headerWithKey:(NSString*)inLabelKey; +- (NSTextField*)addLineLabelWithKey:(NSString*)inLabelKey toView:(NSView*)inLineContainerView; +- (NSView*)wholeLineLabelWithKey:(NSString*)inLabelKey; +- (NSView*)lineWithLabelKey:(NSString*)inLabelKey data:(NSString*)inData ignoreBlankLines:(BOOL)inIgnoreBlank; +- (NSView*)scrollingTextFieldWithLabelKey:(NSString*)inLabelKey data:(NSString*)inData ignoreBlankLines:(BOOL)inIgnoreBlank; +- (NSView*)buttonLineWithLabelKey:(NSString*)inLabelKey buttonLabelKey:(NSString*)buttonKey action:(SEL)inAction button:(NSButton**)outButton; +- (NSView*)checkboxLineWithLabelKey:(NSString*)inLabelKey buttonLabelKey:(NSString*)buttonKey action:(SEL)inAction button:(NSButton**)outButton; - (void)refreshView; -- (float)rebuildCertHeader; +- (void)rebuildCertHeader; - (void)rebuildCertContent; -- (float)rebuildDetails:(float)inOffset; -- (float)rebuildTrustSettings:(float)inOffset; + +- (void)rebuildDetails; +- (void)rebuildTrustSettings; + - (BOOL)showTrustSettings; - (IBAction)trustCheckboxClicked:(id)inSender; @@ -290,13 +282,83 @@ const float kGapUnderLine = 5.0f; - (float)labelColumnWidth { - // measure all the label strings? - return 120.0f; + static BOOL sGotWidth = NO; + static float sLongestLabelWidth = 0.0f; + + if (!sGotWidth) + { + NSArray* labelKeys = [NSArray arrayWithObjects: + @"IssuedTo", + @"OwnerCommonName", + @"OwnerEmailAddress", + @"OwnerOrganization", + @"OwnerOrgUnit", + @"Version", + @"SerialNumber", + @"IssuedBy", + @"IssuerCommonName", + @"IssuerOrganization", + @"IssuerOrgUnit", + @"ShowIssuerCertLabel", + @"Validity", + @"NotBeforeLocalTime", + @"NotAfterLocalTime", + @"SigAlgorithm", + @"Signature", + @"PublicKeyInfo", + @"PublicKeyAlgorithm", + @"PublicKey", + @"UsagesTitle", + @"Usages", + @"Fingerprints", + @"SHA1Fingerprint", + @"MD5Fingerprint", + nil]; + + float maxWidth = 0.0f; + NSDictionary* fontAttributes = [NSDictionary dictionaryWithObject:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]] + forKey:NSFontAttributeName]; + NSEnumerator* keysEnum = [labelKeys objectEnumerator]; + NSString* curKey; + while ((curKey = [keysEnum nextObject])) + { + NSString* theLabel = NSLocalizedStringFromTable(curKey, @"CertificateDialogs", @""); + NSSize stringSize = [theLabel sizeWithAttributes:fontAttributes]; + if (stringSize.width > maxWidth) + maxWidth = stringSize.width; + } + + if (maxWidth < 120.0f) + maxWidth = 120.0f; + + sLongestLabelWidth = maxWidth; + sGotWidth = YES; + } + + return sLongestLabelWidth; } -- (NSTextField*)textFieldWithInitialFrame:(NSRect)inFrame stringValue:(NSString*)inString small:(BOOL)useSmallFont bold:(BOOL)useBold +- (CHShrinkWrapView*)containerViewWithTopPadding:(float)inTop bottomPadding:(float)inBottom { - NSTextField* theTextField = [[[NSTextField alloc] initWithFrame:inFrame] autorelease]; + // the origin of the rect doesn't matter, and we'll resize the height later + NSRect headerRect = NSMakeRect(0, 0, NSWidth([self frame]), NSHeight([self frame])); + CHShrinkWrapView* containerView = [[[CHShrinkWrapView alloc] initWithFrame:headerRect] autorelease]; + [containerView setIntrinsicPadding:kGroupHeaderLeftOffset forEdge:NSMinXEdge]; + [containerView setIntrinsicPadding:inBottom forEdge:NSMinYEdge]; + [containerView setIntrinsicPadding:kGroupHeaderLeftOffset forEdge:NSMaxXEdge]; + [containerView setIntrinsicPadding:inTop forEdge:NSMaxYEdge]; + [containerView setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin]; + return containerView; +} + +- (NSTextField*)textFieldWithInitialFrame:(NSRect)inFrame stringValue:(NSString*)inString autoSizing:(BOOL)inAutosize small:(BOOL)useSmallFont bold:(BOOL)useBold +{ + NSTextField* theTextField; + if (inAutosize) + theTextField = [[[AutoSizingTextField alloc] initWithFrame:inFrame] autorelease]; + else + theTextField = [[[NSTextField alloc] initWithFrame:inFrame] autorelease]; + [theTextField setEditable:NO]; [theTextField setSelectable:YES]; NSFont* fieldFont; @@ -310,210 +372,241 @@ const float kGapUnderLine = 5.0f; [theTextField setDrawsBackground:NO]; [theTextField setBezeled:NO]; [theTextField setStringValue:inString ? inString : @""]; - [[theTextField cell] setWraps:NO]; + [[theTextField cell] setWraps:inAutosize]; + [theTextField setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin]; NSSize theCellSize = [[theTextField cell] cellSizeForBounds:inFrame]; theCellSize.width = NSWidth(inFrame); // keep the provided width - [theTextField setFrameSize:theCellSize]; - //[theTextField sizeToFit]; + [theTextField setFrameSizeMaintainingTopLeftOrigin:theCellSize]; return theTextField; } -- (void)addGroupingWithKey:(NSString*)inLabelKey expanded:(BOOL)inExpanded action:(SEL)inAction atOffset:(float*)ioOffset +- (CHStackView *)groupingWithKey:(NSString*)inLabelKey expanded:(BOOL)inExpanded action:(SEL)inAction { - NSRect lineRect = NSMakeRect(kGroupHeaderLeftOffset, *ioOffset + kGroupHeaderLeftOffset, NSWidth([self frame]) - 2 * kGroupHeaderLeftOffset, 100.0f); + NSRect stackFrame = [self bounds]; + + CHStackView* groupContainer = [[[CHStackView alloc] initWithFrame:stackFrame] autorelease]; + [groupContainer setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin]; + + NSView* lineContainer = [self containerViewWithTopPadding:kGapAboveGroup bottomPadding:kGapUnderGroupHeader]; - NSRect buttonRect; + NSRect lineRect = NSMakeRect(kGroupHeaderLeftOffset, 0.0f, NSWidth([self frame]) - 2 * kGroupHeaderLeftOffset, 100.0f); + + NSRect buttonRect = NSMakeRect(0, 0, kDisclosureButtonSize, kDisclosureButtonSize); buttonRect.origin = lineRect.origin; buttonRect.size = NSMakeSize(kDisclosureButtonSize, kDisclosureButtonSize); - NSButton* theButton = [[[NSButton alloc] initWithFrame:buttonRect] autorelease]; + NSButton* theButton = [[[NSButton alloc] initWithFrame:[groupContainer subviewRectFromTopRelativeRect:buttonRect]] autorelease]; [theButton setBordered:NO]; [theButton setImage: inExpanded ? [NSImage imageNamed:@"triangle_down_normal"] : [NSImage imageNamed:@"triangle_right_normal"]]; [theButton setAlternateImage:inExpanded ? [NSImage imageNamed:@"triangle_down_pressed"] : [NSImage imageNamed:@"triangle_right_pressed"]]; [theButton setButtonType:NSMomentaryChangeButton]; [theButton setAction:inAction]; [theButton setTarget:self]; - [mContentView addSubview:theButton]; + [theButton setAutoresizingMask:NSViewMinYMargin]; + [lineContainer addSubview:theButton]; lineRect.origin.x = NSMaxX(buttonRect) + kDisclosureLabelGap; NSString* theLabel = NSLocalizedStringFromTable(inLabelKey, @"CertificateDialogs", @""); - NSTextField* headerField = [self textFieldWithInitialFrame:lineRect stringValue:theLabel small:YES bold:YES]; - [mContentView addSubview:headerField]; + NSTextField* headerField = [self textFieldWithInitialFrame:[groupContainer subviewRectFromTopRelativeRect:lineRect] stringValue:theLabel autoSizing:NO small:YES bold:YES]; + [lineContainer addSubview:headerField]; - float buttonBottom = NSMaxY([theButton frame]); - float labelBottom = NSMaxY([headerField frame]); - float maxYPos = (buttonBottom > labelBottom) ? buttonBottom : labelBottom; - - *ioOffset = maxYPos + kGapUnderGroupHeader; + [groupContainer addSubview:lineContainer]; + return groupContainer; } -- (void)addHeaderWithKey:(NSString*)inLabelKey atOffset:(float*)ioOffset +- (NSView*)headerWithKey:(NSString*)inLabelKey { + NSView* headerContainer = [self containerViewWithTopPadding:kGapAboveHeader bottomPadding:kGapUnderHeader]; + float labelOffset = kGroupHeaderLeftOffset + kDisclosureButtonSize + kDisclosureLabelGap; - NSRect headerRect = NSMakeRect(labelOffset, *ioOffset, NSWidth([self frame]) - labelOffset - kGeneralRightGap, 100.0f); + NSRect headerRect = NSMakeRect(labelOffset, 0.0f, [self labelColumnWidth], 100.0f); NSString* theLabel = NSLocalizedStringFromTable(inLabelKey, @"CertificateDialogs", @""); - NSTextField* headerField = [self textFieldWithInitialFrame:headerRect stringValue:theLabel small:YES bold:YES]; - [mContentView addSubview:headerField]; + NSTextField* headerField = [self textFieldWithInitialFrame:[headerContainer subviewRectFromTopRelativeRect:headerRect] stringValue:theLabel autoSizing:NO small:YES bold:YES]; + [headerField setAlignment:NSRightTextAlignment]; + [headerField setTextColor:[NSColor lightGrayColor]]; + [headerField setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin]; + [headerContainer addSubview:headerField]; - *ioOffset = NSMaxY([headerField frame]) + kGapUnderHeader; + NSFont* labelFont = [[headerField cell] font]; + float baselineOffset = [labelFont ascender]; + + float xPos = kLabelLeftOffset + [self labelColumnWidth] + kLabelGutterWidth; + NSRect boxFrame = NSMakeRect(xPos, baselineOffset, NSWidth([self frame]) - xPos - kLabelLeftOffset, 2.0f); + + NSBox* lineBox = [[[NSBox alloc] initWithFrame:[headerContainer subviewRectFromTopRelativeRect:boxFrame]] autorelease]; + [lineBox setBoxType:NSBoxSeparator]; + [lineBox setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin]; + [headerContainer addSubview:lineBox]; + + return headerContainer; } -// returns current V offset -- (void)addLineWithLabelKey:(NSString*)inLabelKey data:(NSString*)inData atOffset:(float*)ioOffset ignoreBlankLines:(BOOL)inIgnoreBlank +- (NSTextField*)addLineLabelWithKey:(NSString*)inLabelKey toView:(NSView*)inLineContainerView +{ + float labelOffset = kGroupHeaderLeftOffset + kDisclosureButtonSize + kDisclosureLabelGap; + NSRect labelRect = NSMakeRect(labelOffset, 0.0f, [self labelColumnWidth], 100.0f); + + NSString* theLabel = NSLocalizedStringFromTable(inLabelKey, @"CertificateDialogs", @""); + NSTextField* labelField = [self textFieldWithInitialFrame:[inLineContainerView subviewRectFromTopRelativeRect:labelRect] stringValue:theLabel autoSizing:NO small:YES bold:NO]; + [labelField setAlignment:NSRightTextAlignment]; + [labelField setTextColor:[NSColor darkGrayColor]]; + [labelField setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin]; + [inLineContainerView addSubview:labelField]; + return labelField; +} + +- (NSView*)wholeLineLabelWithKey:(NSString*)inLabelKey +{ + NSView* lineContainer = [self containerViewWithTopPadding:0.0f bottomPadding:kGapUnderLine]; + + float labelOffset = kGroupHeaderLeftOffset + kDisclosureButtonSize + kDisclosureLabelGap; + NSRect labelRect = NSMakeRect(labelOffset, 0.0f, NSWidth([self frame]) - labelOffset, 100.0f); + + NSString* theLabel = NSLocalizedStringFromTable(inLabelKey, @"CertificateDialogs", @""); + NSTextField* labelField = [self textFieldWithInitialFrame:[lineContainer subviewRectFromTopRelativeRect:labelRect] stringValue:theLabel autoSizing:YES small:YES bold:NO]; + [lineContainer addSubview:labelField]; + return lineContainer; +} + +- (NSView*)lineWithLabelKey:(NSString*)inLabelKey data:(NSString*)inData ignoreBlankLines:(BOOL)inIgnoreBlank { if (inIgnoreBlank && [inData length] == 0) - return; - - float labelOffset = kGroupHeaderLeftOffset + kDisclosureButtonSize + kDisclosureLabelGap; - NSRect labelRect = NSMakeRect(labelOffset, *ioOffset, NSWidth([self frame]) - labelOffset - kGeneralRightGap, 100.0f); - - NSString* theLabel = NSLocalizedStringFromTable(inLabelKey, @"CertificateDialogs", @""); - NSTextField* labelField = [self textFieldWithInitialFrame:labelRect stringValue:theLabel small:YES bold:NO]; - [mContentView addSubview:labelField]; + return nil; + + NSView* lineContainer = [self containerViewWithTopPadding:0.0f bottomPadding:kGapUnderLine]; + [self addLineLabelWithKey:inLabelKey toView:lineContainer]; float xPos = kLabelLeftOffset + [self labelColumnWidth] + kLabelGutterWidth; - NSRect dataRect = NSMakeRect(xPos, *ioOffset, NSWidth([self frame]) - xPos - kLabelLeftOffset, 100.0f); - NSTextField* dataField = [self textFieldWithInitialFrame:dataRect stringValue:inData small:YES bold:NO]; - [dataField setAutoresizingMask:NSViewWidthSizable | NSViewMaxYMargin]; - [mContentView addSubview:dataField]; - - float labelBottom = NSMaxY([labelField frame]); - float dataBottom = NSMaxY([dataField frame]); - float maxYPos = (dataBottom > labelBottom) ? dataBottom : labelBottom; - - *ioOffset = maxYPos + kGapUnderLine; + NSRect dataRect = NSMakeRect(xPos, 0.0f, NSWidth([self frame]) - xPos - kLabelLeftOffset, 100.0f); + NSTextField* dataField = [self textFieldWithInitialFrame:[lineContainer subviewRectFromTopRelativeRect:dataRect] stringValue:inData autoSizing:YES small:YES bold:NO]; + [lineContainer addSubview:dataField]; + return lineContainer; } -- (void)addScrollingTextFieldWithLabelKey:(NSString*)inLabelKey data:(NSString*)inData atOffset:(float*)ioOffset ignoreBlankLines:(BOOL)inIgnoreBlank +- (NSView*)scrollingTextFieldWithLabelKey:(NSString*)inLabelKey data:(NSString*)inData ignoreBlankLines:(BOOL)inIgnoreBlank { if (inIgnoreBlank && [inData length] == 0) - return; + return nil; - float labelOffset = kGroupHeaderLeftOffset + kDisclosureButtonSize + kDisclosureLabelGap; - NSRect labelRect = NSMakeRect(labelOffset, *ioOffset, NSWidth([self frame]) - labelOffset - kGeneralRightGap, 100.0f); - - NSString* theLabel = NSLocalizedStringFromTable(inLabelKey, @"CertificateDialogs", @""); - NSTextField* labelField = [self textFieldWithInitialFrame:labelRect stringValue:theLabel small:YES bold:NO]; - [mContentView addSubview:labelField]; + NSView* lineContainer = [self containerViewWithTopPadding:0.0f bottomPadding:kGapUnderLine]; + [self addLineLabelWithKey:inLabelKey toView:lineContainer]; float xPos = kLabelLeftOffset + [self labelColumnWidth] + kLabelGutterWidth; - NSRect dataRect = NSMakeRect(xPos, *ioOffset, NSWidth([self frame]) - xPos - kLabelLeftOffset, 56.0f); - + NSRect dataRect = NSMakeRect(xPos, 0.0f, NSWidth([self frame]) - xPos - kLabelLeftOffset, 56.0f); + dataRect = [lineContainer subviewRectFromTopRelativeRect:dataRect]; + NSScrollView* dataScrollView = [[[NSScrollView alloc] initWithFrame:dataRect] autorelease]; NSTextView* scrolledTextView = [[[NSTextView alloc] initWithFrame:dataRect] autorelease]; [dataScrollView setHasVerticalScroller:YES]; [dataScrollView setBorderType:NSBezelBorder]; - [dataScrollView setAutoresizingMask:NSViewWidthSizable | NSViewMaxYMargin]; + [dataScrollView setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin]; [[dataScrollView verticalScroller] setControlSize:NSSmallControlSize]; if (inData) [[[scrolledTextView textStorage] mutableString] setString:[inData stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]]; [scrolledTextView setFont:[NSFont fontWithName:@"Monaco" size:10.0f]]; [scrolledTextView setEditable:NO]; - [dataScrollView setAutoresizingMask:NSViewWidthSizable]; [dataScrollView setDocumentView:scrolledTextView]; - [mContentView addSubview:dataScrollView]; - - float labelBottom = NSMaxY([labelField frame]); - float dataBottom = NSMaxY([dataScrollView frame]); - float maxYPos = (dataBottom > labelBottom) ? dataBottom : labelBottom; - - *ioOffset = maxYPos + kGapUnderLine; + [lineContainer addSubview:dataScrollView]; + return lineContainer; } -- (NSButton*)addButtonLineWithLabelKey:(NSString*)inLabelKey buttonLabelKey:(NSString*)buttonKey action:(SEL)inAction atOffset:(float*)ioOffset +- (NSView*)buttonLineWithLabelKey:(NSString*)inLabelKey buttonLabelKey:(NSString*)buttonKey action:(SEL)inAction button:(NSButton**)outButton { - float labelOffset = kGroupHeaderLeftOffset + kDisclosureButtonSize + kDisclosureLabelGap; - NSRect labelRect = NSMakeRect(labelOffset, *ioOffset, NSWidth([self frame]) - labelOffset - kGeneralRightGap, 100.0f); - - NSString* theLabel = NSLocalizedStringFromTable(inLabelKey, @"CertificateDialogs", @""); - NSTextField* labelField = [self textFieldWithInitialFrame:labelRect stringValue:theLabel small:YES bold:NO]; - [mContentView addSubview:labelField]; + NSView* lineContainer = [self containerViewWithTopPadding:0.0f bottomPadding:kGapUnderLine]; + [self addLineLabelWithKey:inLabelKey toView:lineContainer]; float xPos = kLabelLeftOffset + [self labelColumnWidth] + kLabelGutterWidth; - NSRect buttonRect = NSMakeRect(xPos, *ioOffset, NSWidth([self frame]) - xPos - kLabelLeftOffset, 100.0f); - NSButton* theButton = [[[NSButton alloc] initWithFrame:buttonRect] autorelease]; + NSRect buttonRect = NSMakeRect(xPos, 0.0f, NSWidth([self frame]) - xPos - kLabelLeftOffset, 100.0f); + NSButton* theButton = [[[NSButton alloc] initWithFrame:[lineContainer subviewRectFromTopRelativeRect:buttonRect]] autorelease]; [theButton setTitle:NSLocalizedStringFromTable(buttonKey, @"CertificateDialogs", @"")]; [theButton setBezelStyle:NSRoundedBezelStyle]; [theButton setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; [[theButton cell] setControlSize:NSSmallControlSize]; - [theButton sizeToFit]; + //[theButton sizeToFit]; + NSSize theCellSize = [[theButton cell] cellSizeForBounds:[theButton frame]]; + [theButton setFrameSizeMaintainingTopLeftOrigin:theCellSize]; + + [theButton setAutoresizingMask:NSViewMinYMargin]; + [theButton setAction:inAction]; [theButton setTarget:self]; - [mContentView addSubview:theButton]; + [lineContainer addSubview:theButton]; - float labelBottom = NSMaxY([labelField frame]); - float buttonBottom = NSMaxY([theButton frame]); - float maxYPos = (buttonBottom > labelBottom) ? buttonBottom : labelBottom; - - *ioOffset = maxYPos + kGapUnderLine; - return theButton; + if (outButton) + *outButton = theButton; + + return lineContainer; } -- (NSButton*)addCheckboxLineWithLabelKey:(NSString*)inLabelKey buttonLabelKey:(NSString*)buttonKey action:(SEL)inAction atOffset:(float*)ioOffset +- (NSView*)checkboxLineWithLabelKey:(NSString*)inLabelKey buttonLabelKey:(NSString*)buttonKey action:(SEL)inAction button:(NSButton**)outButton { - float labelOffset = kGroupHeaderLeftOffset + kDisclosureButtonSize + kDisclosureLabelGap; - NSRect labelRect = NSMakeRect(labelOffset, *ioOffset, NSWidth([self frame]) - labelOffset - kGeneralRightGap, 100.0f); - - NSString* theLabel = NSLocalizedStringFromTable(inLabelKey, @"CertificateDialogs", @""); - NSTextField* labelField = [self textFieldWithInitialFrame:labelRect stringValue:theLabel small:YES bold:NO]; - [mContentView addSubview:labelField]; + NSView* lineContainer = [self containerViewWithTopPadding:0.0f bottomPadding:kGapUnderCheckboxLine]; + + if ([inLabelKey length] > 0) + [self addLineLabelWithKey:inLabelKey toView:lineContainer]; float xPos = kLabelLeftOffset + [self labelColumnWidth] + kLabelGutterWidth; - NSRect buttonRect = NSMakeRect(xPos, *ioOffset, NSWidth([self frame]) - xPos - kLabelLeftOffset, 100.0f); - NSButton* theButton = [[[NSButton alloc] initWithFrame:buttonRect] autorelease]; + NSRect buttonRect = NSMakeRect(xPos, 0.0f, NSWidth([self frame]) - xPos - kLabelLeftOffset, 100.0f); + NSButton* theButton = [[[NSButton alloc] initWithFrame:[lineContainer subviewRectFromTopRelativeRect:buttonRect]] autorelease]; [theButton setTitle:NSLocalizedStringFromTable(buttonKey, @"CertificateDialogs", @"")]; [theButton setButtonType:NSSwitchButton]; [theButton setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; [[theButton cell] setControlSize:NSSmallControlSize]; - [theButton sizeToFit]; - [theButton setAutoresizingMask:NSViewWidthSizable | NSViewMaxYMargin]; + // resize maintaining the width + NSRect wideButtonRect = buttonRect; + wideButtonRect.size.width = 1000.0f; // if the width is narrow, -cellSizeForBounds: returns a greater height, which we don't want. + NSSize theCellSize = [[theButton cell] cellSizeForBounds:wideButtonRect]; + theCellSize.width = NSWidth(buttonRect); + [theButton setFrameSizeMaintainingTopLeftOrigin:theCellSize]; + + [theButton setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin]; [theButton setAction:inAction]; [theButton setTarget:self]; - [mContentView addSubview:theButton]; + [lineContainer addSubview:theButton]; - float labelBottom = NSMaxY([labelField frame]); - float buttonBottom = NSMaxY([theButton frame]); - float maxYPos = (buttonBottom > labelBottom) ? buttonBottom : labelBottom; - - *ioOffset = maxYPos + kGapUnderLine; - return theButton; + if (outButton) + *outButton = theButton; + + return lineContainer; } -- (float)rebuildDetails:(float)inOffset +- (void)rebuildDetails { - float curOffset = inOffset; - [self addGroupingWithKey:@"CertDetailsGroupHeader" expanded:mDetailsExpanded action:@selector(toggleDetails:) atOffset:&curOffset]; - curOffset += kGapUnderHeader; + mDetailsItemsView = [self groupingWithKey:@"CertDetailsGroupHeader" expanded:mDetailsExpanded action:@selector(toggleDetails:)]; + [mContentView addSubview:mDetailsItemsView]; if (!mDetailsExpanded) - return curOffset; - - [self addHeaderWithKey:@"IssuedTo" atOffset:&curOffset]; + return; + + // + // NOTE: add label string keys to the array in -labelColumnWidth if you add new ones. + // + [mDetailsItemsView addSubview:[self headerWithKey:@"IssuedTo"]]; // Owner stuff - [self addLineWithLabelKey:@"OwnerCommonName" data:[mCertItem commonName] atOffset:&curOffset ignoreBlankLines:YES]; - [self addLineWithLabelKey:@"OwnerEmailAddress" data:[mCertItem emailAddress] atOffset:&curOffset ignoreBlankLines:YES]; - [self addLineWithLabelKey:@"OwnerOrganization" data:[mCertItem organization] atOffset:&curOffset ignoreBlankLines:YES]; - [self addLineWithLabelKey:@"OwnerOrgUnit" data:[mCertItem organizationalUnit] atOffset:&curOffset ignoreBlankLines:YES]; - [self addLineWithLabelKey:@"Version" data:[mCertItem version] atOffset:&curOffset ignoreBlankLines:YES]; - [self addLineWithLabelKey:@"SerialNumber" data:[mCertItem serialNumber] atOffset:&curOffset ignoreBlankLines:YES]; + [mDetailsItemsView addSubview:[self lineWithLabelKey:@"OwnerCommonName" data:[mCertItem commonName] ignoreBlankLines:YES]]; + + [mDetailsItemsView addSubview:[self lineWithLabelKey:@"OwnerEmailAddress" data:[mCertItem emailAddress] ignoreBlankLines:YES]]; + [mDetailsItemsView addSubview:[self lineWithLabelKey:@"OwnerOrganization" data:[mCertItem organization] ignoreBlankLines:YES]]; + [mDetailsItemsView addSubview:[self lineWithLabelKey:@"OwnerOrgUnit" data:[mCertItem organizationalUnit] ignoreBlankLines:YES]]; + [mDetailsItemsView addSubview:[self lineWithLabelKey:@"Version" data:[mCertItem version] ignoreBlankLines:YES]]; + [mDetailsItemsView addSubview:[self lineWithLabelKey:@"SerialNumber" data:[mCertItem serialNumber] ignoreBlankLines:YES]]; // Issuer stuff - curOffset += kGapUnderGroup; - [self addHeaderWithKey:@"IssuedBy" atOffset:&curOffset]; + [mDetailsItemsView addSubview:[self headerWithKey:@"IssuedBy"]]; - [self addLineWithLabelKey:@"IssuerCommonName" data:[mCertItem issuerCommonName] atOffset:&curOffset ignoreBlankLines:YES]; - [self addLineWithLabelKey:@"IssuerOrganization" data:[mCertItem issuerOrganization] atOffset:&curOffset ignoreBlankLines:YES]; - [self addLineWithLabelKey:@"IssuerOrgUnit" data:[mCertItem issuerOrganizationalUnit] atOffset:&curOffset ignoreBlankLines:YES]; + [mDetailsItemsView addSubview:[self lineWithLabelKey:@"IssuerCommonName" data:[mCertItem issuerCommonName] ignoreBlankLines:YES]]; + [mDetailsItemsView addSubview:[self lineWithLabelKey:@"IssuerOrganization" data:[mCertItem issuerOrganization] ignoreBlankLines:YES]]; + [mDetailsItemsView addSubview:[self lineWithLabelKey:@"IssuerOrgUnit" data:[mCertItem issuerOrganizationalUnit] ignoreBlankLines:YES]]; nsCOMPtr issuerCert; nsIX509Cert* thisCert = [mCertItem cert]; @@ -521,93 +614,83 @@ const float kGapUnderLine = 5.0f; thisCert->GetIssuer(getter_AddRefs(issuerCert)); if (issuerCert && ![mCertItem isSameCertAs:issuerCert]) { - [self addButtonLineWithLabelKey:@"ShowIssuerCertLabel" - buttonLabelKey:@"ShowIssuerCertButton" - action:@selector(showIssuerCert:) - atOffset:&curOffset]; + [mDetailsItemsView addSubview:[self buttonLineWithLabelKey:@"ShowIssuerCertLabel" + buttonLabelKey:@"ShowIssuerCertButton" + action:@selector(showIssuerCert:) + button:NULL]]; } // validity - curOffset += kGapUnderGroup; - [self addHeaderWithKey:@"Validity" atOffset:&curOffset]; + [mDetailsItemsView addSubview:[self headerWithKey:@"Validity"]]; - [self addLineWithLabelKey:@"NotBeforeLocalTime" data:[mCertItem longValidFromString] atOffset:&curOffset ignoreBlankLines:NO]; - [self addLineWithLabelKey:@"NotAfterLocalTime" data:[mCertItem longExpiresString] atOffset:&curOffset ignoreBlankLines:NO]; + [mDetailsItemsView addSubview:[self lineWithLabelKey:@"NotBeforeLocalTime" data:[mCertItem longValidFromString] ignoreBlankLines:NO]]; + [mDetailsItemsView addSubview:[self lineWithLabelKey:@"NotAfterLocalTime" data:[mCertItem longExpiresString] ignoreBlankLines:NO]]; // signature - [self addLineWithLabelKey:@"SigAlgorithm" data:[mCertItem signatureAlgorithm] atOffset:&curOffset ignoreBlankLines:NO]; - [self addScrollingTextFieldWithLabelKey:@"Signature" data:[mCertItem signatureValue] atOffset:&curOffset ignoreBlankLines:NO]; + [mDetailsItemsView addSubview:[self lineWithLabelKey:@"SigAlgorithm" data:[mCertItem signatureAlgorithm] ignoreBlankLines:NO]]; + [mDetailsItemsView addSubview:[self scrollingTextFieldWithLabelKey:@"Signature" data:[mCertItem signatureValue] ignoreBlankLines:NO]]; // public key info - curOffset += kGapUnderGroup; - [self addHeaderWithKey:@"PublicKeyInfo" atOffset:&curOffset]; - [self addLineWithLabelKey:@"PublicKeyAlgorithm" data:[mCertItem publicKeyAlgorithm] atOffset:&curOffset ignoreBlankLines:NO]; - //[self addLineWithLabelKey:@"PublicKeySize" data:[mCertItem publicKeySizeBits] atOffset:&curOffset ignoreBlankLines:NO]; - [self addScrollingTextFieldWithLabelKey:@"PublicKey" data:[mCertItem publicKey] atOffset:&curOffset ignoreBlankLines:NO]; + [mDetailsItemsView addSubview:[self headerWithKey:@"PublicKeyInfo"]]; + + [mDetailsItemsView addSubview:[self lineWithLabelKey:@"PublicKeyAlgorithm" data:[mCertItem publicKeyAlgorithm] ignoreBlankLines:NO]]; + //[self lineWithLabelKey:@"PublicKeySize" data:[mCertItem publicKeySizeBits] ignoreBlankLines:NO]; + [mDetailsItemsView addSubview:[self scrollingTextFieldWithLabelKey:@"PublicKey" data:[mCertItem publicKey] ignoreBlankLines:NO]]; // usages NSArray* certUsages = [mCertItem validUsages]; if ([certUsages count]) { - curOffset += kGapUnderGroup; - [self addHeaderWithKey:@"UsagesTitle" atOffset:&curOffset]; + [mDetailsItemsView addSubview:[self headerWithKey:@"UsagesTitle"]]; for (unsigned int i = 0; i < [certUsages count]; i ++) { NSString* labelKey = (i == 0) ? @"Usages" : @""; - [self addLineWithLabelKey:labelKey data:[certUsages objectAtIndex:i] atOffset:&curOffset ignoreBlankLines:NO]; + [mDetailsItemsView addSubview:[self lineWithLabelKey:labelKey data:[certUsages objectAtIndex:i] ignoreBlankLines:NO]]; } } // fingerprints - curOffset += kGapUnderGroup; - [self addHeaderWithKey:@"Fingerprints" atOffset:&curOffset]; + [mDetailsItemsView addSubview:[self headerWithKey:@"Fingerprints"]]; - [self addLineWithLabelKey:@"SHA1Fingerprint" data:[mCertItem sha1Fingerprint] atOffset:&curOffset ignoreBlankLines:NO]; - [self addLineWithLabelKey:@"MD5Fingerprint" data:[mCertItem md5Fingerprint] atOffset:&curOffset ignoreBlankLines:NO]; - - curOffset += kGapUnderGroup; - return curOffset; + [mDetailsItemsView addSubview:[self lineWithLabelKey:@"SHA1Fingerprint" data:[mCertItem sha1Fingerprint] ignoreBlankLines:NO]]; + [mDetailsItemsView addSubview:[self lineWithLabelKey:@"MD5Fingerprint" data:[mCertItem md5Fingerprint] ignoreBlankLines:NO]]; } -- (float)rebuildTrustSettings:(float)inOffset +- (void)rebuildTrustSettings { - float curOffset = inOffset; - - [self addGroupingWithKey:@"CertTrustGroupHeader" expanded:mTrustExpanded action:@selector(toggleTrustSettings:) atOffset:&curOffset]; - curOffset += kGapUnderHeader; + mTrustItemsView = [self groupingWithKey:@"CertTrustGroupHeader" expanded:mTrustExpanded action:@selector(toggleTrustSettings:)]; + [mContentView addSubview:mTrustItemsView]; if (!mTrustExpanded) - return curOffset; + return; // XXX do we need a more comprehensive check than this? BOOL enableCheckboxes = YES; // [mCertItem isValid] || [mCertItem isUntrustedRootCACert]; // XXX only show relevant checkboxes? (see nsNSSCertificateDB::SetCertTrust) // XXX only show checkboxes for allowed usages? - [self addLineWithLabelKey:@"TrustSettingsLabel" data:@"" atOffset:&curOffset ignoreBlankLines:NO]; - mTrustForWebSitesCheckbox = [self addCheckboxLineWithLabelKey:@"" - buttonLabelKey:@"TrustWebSitesCheckboxLabel" - action:@selector(trustCheckboxClicked:) - atOffset:&curOffset]; + [mTrustItemsView addSubview:[self wholeLineLabelWithKey:@"TrustSettingsLabel"]]; + [mTrustItemsView addSubview:[self checkboxLineWithLabelKey:@"" + buttonLabelKey:@"TrustWebSitesCheckboxLabel" + action:@selector(trustCheckboxClicked:) + button:&mTrustForWebSitesCheckbox]]; + [mTrustForWebSitesCheckbox setState:mTrustedForWebSites]; [mTrustForWebSitesCheckbox setEnabled:enableCheckboxes]; - mTrustForEmailCheckbox = [self addCheckboxLineWithLabelKey:@"" + [mTrustItemsView addSubview:[self checkboxLineWithLabelKey:@"" buttonLabelKey:@"TrustEmailUsersCheckboxLabel" action:@selector(trustCheckboxClicked:) - atOffset:&curOffset]; + button:&mTrustForEmailCheckbox]]; [mTrustForEmailCheckbox setState:mTrustedForEmail]; [mTrustForEmailCheckbox setEnabled:enableCheckboxes]; - mTrustForObjSigningCheckbox = [self addCheckboxLineWithLabelKey:@"" - buttonLabelKey:@"TrustObjectSignersCheckboxLabel" - action:@selector(trustCheckboxClicked:) - atOffset:&curOffset]; + [mTrustItemsView addSubview:[self checkboxLineWithLabelKey:@"" + buttonLabelKey:@"TrustObjectSignersCheckboxLabel" + action:@selector(trustCheckboxClicked:) + button:&mTrustForObjSigningCheckbox]]; [mTrustForObjSigningCheckbox setState:mTrustedForObjectSigning]; [mTrustForObjSigningCheckbox setEnabled:enableCheckboxes]; - - curOffset += kGapUnderGroup; - return curOffset; } - (void)refreshView @@ -620,58 +703,63 @@ const float kGapUnderLine = 5.0f; mTrustForEmailCheckbox = nil; mTrustForObjSigningCheckbox = nil; - float headerHeight = [self rebuildCertHeader]; - - NSRect contentFrame = [self bounds]; - NSRect headerRect, contentsRect; - NSDivideRect(contentFrame, &headerRect, &contentsRect, headerHeight, NSMinYEdge); - - mContentView = [[CertificateContentsView alloc] initWithFrame:contentsRect]; + mContentView = [[CHStackView alloc] initWithFrame:[self bounds]]; [mContentView setAutoresizingMask:NSViewWidthSizable | NSViewMaxYMargin]; + + [self setIntrinsicPadding:0.0f forEdge:NSMinXEdge]; + [self setIntrinsicPadding:0.0f forEdge:NSMinYEdge]; + [self setIntrinsicPadding:0.0f forEdge:NSMaxXEdge]; + [self setIntrinsicPadding:0.0f forEdge:NSMaxYEdge]; + [self addSubview:mContentView]; + [self rebuildCertHeader]; [self rebuildCertContent]; } -- (float)rebuildCertHeader +- (void)rebuildCertHeader { // We do all this laborious manual view construction to avoid having to load a nib file each // time. This way, we can just have a single custom view in the nib, and do everything in code. - // cert image - NSRect certImageFrame = NSMakeRect(kGroupHeaderLeftOffset, kGroupHeaderLeftOffset, kCertImageViewSize, kCertImageViewSize); - NSImageView* certImageView = [[[NSImageView alloc] initWithFrame:certImageFrame] autorelease]; - [certImageView setImage:[NSImage imageNamed:@"certificate"]]; - [self addSubview:certImageView]; - - // description + // container for the header float headerFieldsLeftEdge = kGroupHeaderLeftOffset + kCertImageViewSize + kGroupHeaderLeftOffset; float headerFieldYOffset = kGroupHeaderLeftOffset; float headerFieldWith = NSWidth([self frame]) - headerFieldYOffset - kCertHeaderFieldRightGap; + NSView* headerContainer = [self containerViewWithTopPadding:0.0f bottomPadding:kGapUnderGroup]; + + // cert image + NSRect certImageFrame = NSMakeRect(0.0f, 0.0f, kCertImageViewSize, kCertImageViewSize); + NSImageView* certImageView = [[[NSImageView alloc] initWithFrame:[headerContainer subviewRectFromTopRelativeRect:certImageFrame]] autorelease]; + [certImageView setImage:[NSImage imageNamed:@"certificate"]]; + [certImageView setAutoresizingMask:NSViewMinYMargin]; + [headerContainer addSubview:certImageView]; + + // description NSRect decriptionRect = NSMakeRect(headerFieldsLeftEdge, headerFieldYOffset, headerFieldWith, 100.0f); - NSTextField* descField = [self textFieldWithInitialFrame:decriptionRect stringValue:[mCertItem displayName] small:NO bold:NO]; - [self addSubview:descField]; + NSTextField* descField = [self textFieldWithInitialFrame:[headerContainer subviewRectFromTopRelativeRect:decriptionRect] stringValue:[mCertItem displayName] autoSizing:NO small:NO bold:NO]; + [headerContainer addSubview:descField]; headerFieldYOffset += NSHeight([descField frame]) + kCertHeaderFieldVerticalGap; // issuer info NSRect issuerRect = NSMakeRect(headerFieldsLeftEdge, headerFieldYOffset, headerFieldWith, 100.0f); NSString* formatString = NSLocalizedStringFromTable(@"IssuedByHeaderFormat", @"CertificateDialogs", @""); NSString* issuerString = [NSString stringWithFormat:formatString, [mCertItem issuerCommonName]]; - NSTextField* issuerField = [self textFieldWithInitialFrame:issuerRect stringValue:issuerString small:YES bold:NO]; - [self addSubview:issuerField]; + NSTextField* issuerField = [self textFieldWithInitialFrame:[headerContainer subviewRectFromTopRelativeRect:issuerRect] stringValue:issuerString autoSizing:NO small:YES bold:NO]; + [headerContainer addSubview:issuerField]; headerFieldYOffset += NSHeight([issuerField frame]) + kCertHeaderFieldVerticalGap; // expiry info NSRect expiryRect = NSMakeRect(headerFieldsLeftEdge, headerFieldYOffset, headerFieldWith, 100.0f); formatString = NSLocalizedStringFromTable(@"ExpiresHeaderFormat", @"CertificateDialogs", @""); NSString* expiryString = [NSString stringWithFormat:formatString, [mCertItem longExpiresString]]; - NSTextField* expiryField = [self textFieldWithInitialFrame:expiryRect stringValue:expiryString small:YES bold:NO]; - [self addSubview:expiryField]; + NSTextField* expiryField = [self textFieldWithInitialFrame:[headerContainer subviewRectFromTopRelativeRect:expiryRect] stringValue:expiryString autoSizing:NO small:YES bold:NO]; + [headerContainer addSubview:expiryField]; headerFieldYOffset += NSHeight([expiryField frame]) + kCertHeaderFieldVerticalGap; NSRect statusImageRect = NSMakeRect(headerFieldsLeftEdge, headerFieldYOffset, kStatusImageSize, kStatusImageSize); - NSImageView* statusImageView = [[[NSImageView alloc] initWithFrame:statusImageRect] autorelease]; + NSImageView* statusImageView = [[[NSImageView alloc] initWithFrame:[headerContainer subviewRectFromTopRelativeRect:statusImageRect]] autorelease]; NSString* imageName = @""; if ([mCertItem isUntrustedRootCACert]) @@ -682,44 +770,34 @@ const float kGapUnderLine = 5.0f; imageName = @"mini_cert_invalid"; [statusImageView setImage:[NSImage imageNamed:imageName]]; - [self addSubview:statusImageView]; + [statusImageView setAutoresizingMask:NSViewMinYMargin]; + [headerContainer addSubview:statusImageView]; // status info float statusLeftEdge = headerFieldsLeftEdge + kStatusImageSize + kGroupHeaderLeftOffset; float statusFieldWith = NSWidth([self frame]) - statusLeftEdge - kCertHeaderFieldRightGap; NSRect statusRect = NSMakeRect(statusLeftEdge, headerFieldYOffset, statusFieldWith, 100.0f); - NSTextField* statusField = [self textFieldWithInitialFrame:statusRect stringValue:@"" small:YES bold:NO]; + NSTextField* statusField = [self textFieldWithInitialFrame:[headerContainer subviewRectFromTopRelativeRect:statusRect] stringValue:@"" autoSizing:NO small:YES bold:NO]; [statusField setAttributedStringValue:[mCertItem attributedLongValidityString]]; - [statusField sizeToFit]; - [self addSubview:statusField]; + [headerContainer addSubview:statusField]; - headerFieldYOffset += NSHeight([statusField frame]) + kCertHeaderFieldVerticalGap; - return headerFieldYOffset; + [mContentView addSubview:headerContainer]; } - (void)rebuildCertContent { // blow away the subviews of the content view - [mContentView removeAllSubviews]; + [mTrustItemsView removeFromSuperviewWithoutNeedingDisplay]; + mTrustItemsView = nil; + + [mDetailsItemsView removeFromSuperviewWithoutNeedingDisplay]; + mDetailsItemsView = nil; - float curHeight = 0.0f; if ([self showTrustSettings]) - curHeight = [self rebuildTrustSettings:curHeight]; + [self rebuildTrustSettings]; - curHeight = [self rebuildDetails:curHeight]; - - // make sure the details view is big enough to contain all its subviews - NSSize curSize = [mContentView frame].size; - curSize.height = curHeight; - [mContentView setFrameSize:curSize]; - - // and then resize us too - NSRect contentViewFrame = [mContentView frame]; - float myHeight = NSHeight(contentViewFrame) + NSMinY(contentViewFrame); - curSize = [self frame].size; - curSize.height = myHeight; - [self setFrameSize:curSize]; + [self rebuildDetails]; } - (void)certificateChanged:(NSNotification*)inNotification